1747 lines
49 KiB
Mathematica
1747 lines
49 KiB
Mathematica
|
//
|
||
|
// Entity.m
|
||
|
/*
|
||
|
*
|
||
|
* Oolite
|
||
|
*
|
||
|
* Created by Giles Williams on Sat Apr 03 2004.
|
||
|
* Copyright (c) 2004 for aegidian.org. All rights reserved.
|
||
|
*
|
||
|
|
||
|
Copyright (c) 2004, Giles C Williams
|
||
|
All rights reserved.
|
||
|
|
||
|
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License.
|
||
|
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/
|
||
|
or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
|
||
|
|
||
|
You are free:
|
||
|
|
||
|
• to copy, distribute, display, and perform the work
|
||
|
• to make derivative works
|
||
|
|
||
|
Under the following conditions:
|
||
|
|
||
|
• Attribution. You must give the original author credit.
|
||
|
|
||
|
• Noncommercial. You may not use this work for commercial purposes.
|
||
|
|
||
|
• Share Alike. If you alter, transform, or build upon this work,
|
||
|
you may distribute the resulting work only under a license identical to this one.
|
||
|
|
||
|
For any reuse or distribution, you must make clear to others the license terms of this work.
|
||
|
|
||
|
Any of these conditions can be waived if you get permission from the copyright holder.
|
||
|
|
||
|
Your fair use and other rights are in no way affected by the above.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#import "Entity.h"
|
||
|
|
||
|
#import "vector.h"
|
||
|
#import "Universe.h"
|
||
|
#import "TextureStore.h"
|
||
|
#import "ResourceManager.h"
|
||
|
|
||
|
// global flag for VAR
|
||
|
BOOL global_usingVAR;
|
||
|
BOOL global_testForVAR;
|
||
|
|
||
|
static Universe *data_store_universe;
|
||
|
|
||
|
@implementation Entity
|
||
|
|
||
|
// class methods, they set the underlying data_storage universe
|
||
|
+ (void) setDataStore:(Universe *)univ
|
||
|
{
|
||
|
if (univ)
|
||
|
data_store_universe = univ;
|
||
|
//NSLog(@"--- Universe for Data Storage set to %@", univ);
|
||
|
|
||
|
global_usingVAR = NO;
|
||
|
global_testForVAR = YES;
|
||
|
}
|
||
|
|
||
|
+ (Universe *) dataStore
|
||
|
{
|
||
|
return data_store_universe;
|
||
|
}
|
||
|
|
||
|
- (id) init
|
||
|
{
|
||
|
self = [super init];
|
||
|
//
|
||
|
quaternion_set_identity(&q_rotation);
|
||
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
||
|
//
|
||
|
position = make_vector( 0.0, 0.0, 0.0);
|
||
|
//
|
||
|
zero_distance = 0.0; // 10 km
|
||
|
no_draw_distance = 100000.0; // 10 km
|
||
|
//
|
||
|
distance_travelled = 0.0;
|
||
|
//
|
||
|
energy = 0.0;
|
||
|
//
|
||
|
collision_radius = 0.0;
|
||
|
//
|
||
|
collidingEntities = [[NSMutableArray alloc] initWithCapacity:16]; // alloc automatically retains
|
||
|
//
|
||
|
scan_class = CLASS_NOT_SET;
|
||
|
//
|
||
|
universal_id = NO_TARGET;
|
||
|
universe = nil;
|
||
|
//
|
||
|
is_smooth_shaded = NO;
|
||
|
//
|
||
|
n_vertices = 0;
|
||
|
n_faces = 0;
|
||
|
//
|
||
|
displayListName = 0;
|
||
|
//
|
||
|
status = STATUS_DEMO;
|
||
|
//
|
||
|
basefile = @"No Model";
|
||
|
//
|
||
|
throw_sparks = NO;
|
||
|
//
|
||
|
usingVAR = NO;
|
||
|
//
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
- (void) dealloc
|
||
|
{
|
||
|
if (universe) [universe release];
|
||
|
if (basefile) [basefile release];
|
||
|
if (collidingEntities) [collidingEntities release];
|
||
|
[super dealloc];
|
||
|
}
|
||
|
|
||
|
- (void) warnAboutHostiles
|
||
|
{
|
||
|
// do nothing for now, this can be expanded in sub classes
|
||
|
NSLog(@"***** Entity does nothing in warnAboutHostiles");
|
||
|
}
|
||
|
|
||
|
- (Universe *) universe
|
||
|
{
|
||
|
return universe;
|
||
|
}
|
||
|
|
||
|
- (void) setUniverse:(Universe *)univ
|
||
|
{
|
||
|
if (univ)
|
||
|
{
|
||
|
if (universe) [universe release];
|
||
|
universe = [univ retain];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (universe) [universe release];
|
||
|
universe = nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) setUniversal_id:(int)uid
|
||
|
{
|
||
|
universal_id = uid;
|
||
|
}
|
||
|
|
||
|
- (int) universal_id
|
||
|
{
|
||
|
return universal_id;
|
||
|
}
|
||
|
|
||
|
- (BOOL) throwingSparks
|
||
|
{
|
||
|
return throw_sparks;
|
||
|
}
|
||
|
|
||
|
- (void) setThrowSparks:(BOOL) value
|
||
|
{
|
||
|
throw_sparks = value;
|
||
|
}
|
||
|
|
||
|
- (void) throwSparks;
|
||
|
{
|
||
|
// do nothing for now
|
||
|
}
|
||
|
|
||
|
- (BOOL) isSmoothShaded
|
||
|
{
|
||
|
return is_smooth_shaded;
|
||
|
}
|
||
|
- (void) setSmoothShaded:(BOOL) value
|
||
|
{
|
||
|
is_smooth_shaded = value;
|
||
|
}
|
||
|
|
||
|
- (void) setOwner:(Entity *) ent
|
||
|
{
|
||
|
int owner_id = [ent universal_id];
|
||
|
if (universe)
|
||
|
{
|
||
|
if ([universe entityForUniversalID:owner_id] == ent) // check to make sure it's kosher
|
||
|
owner = owner_id;
|
||
|
else
|
||
|
owner = NO_TARGET;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
owner = owner_id; // if the universe hasn't been initialised yet, trust the sender
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (Entity *) owner
|
||
|
{
|
||
|
return [universe entityForUniversalID:owner];
|
||
|
}
|
||
|
|
||
|
- (void) setModel:(NSString *) modelName
|
||
|
{
|
||
|
// clear old data
|
||
|
if (basefile) [basefile release];
|
||
|
basefile = [modelName retain];
|
||
|
//
|
||
|
[self regenerateDisplayList];
|
||
|
//
|
||
|
[self loadData:basefile];
|
||
|
//
|
||
|
[self checkNormalsAndAdjustWinding];
|
||
|
//
|
||
|
if (is_smooth_shaded)
|
||
|
[self calculateVertexNormals];
|
||
|
// set the collision radius
|
||
|
//
|
||
|
collision_radius = [self findCollisionRadius];
|
||
|
//NSLog(@"Entity with model '%@' collision radius set to %f",modelName, collision_radius);
|
||
|
//
|
||
|
}
|
||
|
- (NSString *) getModel
|
||
|
{
|
||
|
return basefile;
|
||
|
}
|
||
|
|
||
|
- (void) setPosition:(Vector) posn
|
||
|
{
|
||
|
position.x = posn.x;
|
||
|
position.y = posn.y;
|
||
|
position.z = posn.z;
|
||
|
}
|
||
|
|
||
|
- (void) setPosition:(GLfloat) x:(GLfloat) y:(GLfloat) z
|
||
|
{
|
||
|
position.x = x;
|
||
|
position.y = y;
|
||
|
position.z = z;
|
||
|
}
|
||
|
|
||
|
- (double) getZeroDistance
|
||
|
{
|
||
|
// NSLog(@"DEBUG %@ %.1f", self, zero_distance);
|
||
|
return zero_distance;
|
||
|
}
|
||
|
|
||
|
- (Vector) relative_position
|
||
|
{
|
||
|
return relative_position;
|
||
|
}
|
||
|
|
||
|
- (NSComparisonResult) compareZeroDistance:(Entity *)otherEntity;
|
||
|
{
|
||
|
if (zero_distance > [otherEntity getZeroDistance])
|
||
|
return NSOrderedAscending;
|
||
|
else
|
||
|
return NSOrderedDescending;
|
||
|
}
|
||
|
|
||
|
- (BoundingBox) getBoundingBox
|
||
|
{
|
||
|
return boundingBox;
|
||
|
}
|
||
|
|
||
|
- (GLfloat) mass
|
||
|
{
|
||
|
return mass;
|
||
|
}
|
||
|
|
||
|
- (void) setQRotation:(Quaternion) quat
|
||
|
{
|
||
|
q_rotation = quat;
|
||
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
||
|
}
|
||
|
|
||
|
- (Quaternion) QRotation
|
||
|
{
|
||
|
return q_rotation;
|
||
|
}
|
||
|
|
||
|
- (void) setVelocity:(Vector) vel
|
||
|
{
|
||
|
velocity = vel;
|
||
|
}
|
||
|
|
||
|
- (Vector) getVelocity
|
||
|
{
|
||
|
return velocity;
|
||
|
}
|
||
|
|
||
|
- (double) getVelocityAsSpeed
|
||
|
{
|
||
|
return sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
|
||
|
}
|
||
|
|
||
|
- (double) distance_travelled
|
||
|
{
|
||
|
return distance_travelled;
|
||
|
}
|
||
|
|
||
|
- (void) setDistanceTravelled: (double) value
|
||
|
{
|
||
|
distance_travelled = value;
|
||
|
}
|
||
|
|
||
|
- (void) setStatus:(int) stat
|
||
|
{
|
||
|
status = stat;
|
||
|
}
|
||
|
|
||
|
- (int) getStatus
|
||
|
{
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
- (void) setScanClass:(int) s_class
|
||
|
{
|
||
|
scan_class = s_class;
|
||
|
}
|
||
|
|
||
|
- (int) scanClass
|
||
|
{
|
||
|
return scan_class;
|
||
|
}
|
||
|
|
||
|
- (void) setEnergy:(double) amount
|
||
|
{
|
||
|
energy = amount;
|
||
|
}
|
||
|
|
||
|
- (double) getEnergy
|
||
|
{
|
||
|
return energy;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
- (void) applyRoll:(GLfloat) roll andClimb:(GLfloat) climb
|
||
|
{
|
||
|
quaternion_rotate_about_z( &q_rotation, -roll);
|
||
|
quaternion_rotate_about_x( &q_rotation, -climb);
|
||
|
|
||
|
quaternion_normalise(&q_rotation);
|
||
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
||
|
}
|
||
|
|
||
|
- (void) applyRoll:(GLfloat) roll climb:(GLfloat) climb andYaw:(GLfloat) yaw
|
||
|
{
|
||
|
quaternion_rotate_about_z( &q_rotation, -roll);
|
||
|
quaternion_rotate_about_x( &q_rotation, -climb);
|
||
|
quaternion_rotate_about_y( &q_rotation, -yaw);
|
||
|
|
||
|
quaternion_normalise(&q_rotation);
|
||
|
quaternion_into_gl_matrix(q_rotation, rotMatrix);
|
||
|
}
|
||
|
|
||
|
- (void) moveForward:(double) amount
|
||
|
{
|
||
|
Vector forward = vector_forward_from_quaternion(q_rotation);
|
||
|
distance_travelled += amount;
|
||
|
position.x += amount * forward.x;
|
||
|
position.y += amount * forward.y;
|
||
|
position.z += amount * forward.z;
|
||
|
}
|
||
|
|
||
|
- (GLfloat *) rotationMatrix
|
||
|
{
|
||
|
return rotMatrix;
|
||
|
}
|
||
|
|
||
|
- (Vector) getPosition
|
||
|
{
|
||
|
return position;
|
||
|
}
|
||
|
|
||
|
- (Vector) getViewpointPosition
|
||
|
{
|
||
|
return position;
|
||
|
}
|
||
|
|
||
|
|
||
|
- (BOOL) canCollide
|
||
|
{
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
- (double) collisionRadius
|
||
|
{
|
||
|
return collision_radius;
|
||
|
}
|
||
|
|
||
|
- (void) setCollisionRadius:(double) amount
|
||
|
{
|
||
|
collision_radius = amount;
|
||
|
}
|
||
|
|
||
|
- (NSMutableArray *) collisionArray
|
||
|
{
|
||
|
return collidingEntities;
|
||
|
}
|
||
|
|
||
|
|
||
|
- (void) drawEntity:(BOOL) immediate :(BOOL) translucent
|
||
|
{
|
||
|
// roll out each face and vertex in turn
|
||
|
//
|
||
|
// int fi,vi;
|
||
|
int ti;
|
||
|
GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
|
||
|
if (is_smooth_shaded)
|
||
|
glShadeModel(GL_SMOOTH);
|
||
|
else
|
||
|
glShadeModel(GL_FLAT);
|
||
|
|
||
|
//
|
||
|
if (!translucent)
|
||
|
{
|
||
|
if (basefile)
|
||
|
{
|
||
|
if (immediate)
|
||
|
{
|
||
|
#ifdef GNUSTEP
|
||
|
// TODO: Find out what these APPLE functions can be replaced with
|
||
|
#else
|
||
|
if (usingVAR)
|
||
|
glBindVertexArrayAPPLE(gVertexArrayRangeObjects[0]);
|
||
|
#endif
|
||
|
|
||
|
// if (usingVAR)
|
||
|
// NSLog(@"DEBUG using accelerated memory technique to draw %@ (%@)", self, basefile);
|
||
|
//
|
||
|
//
|
||
|
// experimental gap removal (draws flat polys)
|
||
|
//
|
||
|
glDepthMask(GL_FALSE); // don't write to depth buffer
|
||
|
GLfloat amb_diff0[] = { 0.5, 0.5, 0.5, 1.0};
|
||
|
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, amb_diff0);
|
||
|
glColor4f( 0.25, 0.25, 0.25, 1.0); // gray
|
||
|
|
||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||
|
glDisableClientState(GL_INDEX_ARRAY);
|
||
|
glDisableClientState(GL_EDGE_FLAG_ARRAY);
|
||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
glVertexPointer( 3, GL_FLOAT, 0, entityData.vertex_array);
|
||
|
|
||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||
|
glNormalPointer( GL_FLOAT, 0, entityData.normal_array);
|
||
|
|
||
|
glDrawArrays( GL_TRIANGLES, 0, entityData.n_triangles);
|
||
|
|
||
|
glDepthMask(GL_TRUE);
|
||
|
|
||
|
//
|
||
|
// now the textures ...
|
||
|
//
|
||
|
|
||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||
|
glTexCoordPointer( 2, GL_FLOAT, 0, entityData.texture_uv_array);
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
|
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
|
||
|
|
||
|
for (ti = 1; ti <= n_textures; ti++)
|
||
|
{
|
||
|
glBindTexture(GL_TEXTURE_2D, texture_name[ti]);
|
||
|
glDrawArrays( GL_TRIANGLES, triangle_range[ti].location, triangle_range[ti].length);
|
||
|
}
|
||
|
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (displayListName != 0)
|
||
|
glCallList(displayListName);
|
||
|
else
|
||
|
{
|
||
|
[self initialiseTextures];
|
||
|
[self generateDisplayList];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NSLog(@"ERROR no basefile for entity %@");
|
||
|
NSBeep();
|
||
|
}
|
||
|
}
|
||
|
glShadeModel(GL_SMOOTH);
|
||
|
}
|
||
|
|
||
|
- (void) drawSubEntity:(BOOL) immediate :(BOOL) translucent
|
||
|
{
|
||
|
if ((owner != NO_TARGET)&&(universe))
|
||
|
{
|
||
|
// this test provides an opportunity to do simple LoD culling
|
||
|
//
|
||
|
zero_distance = [[universe entityForUniversalID:owner] getZeroDistance];
|
||
|
if (zero_distance > no_draw_distance)
|
||
|
{
|
||
|
//NSLog(@"DEBUG - sub entity '%@' too far away to draw", self);
|
||
|
return; // TOO FAR AWAY
|
||
|
}
|
||
|
}
|
||
|
if (status != STATUS_ACTIVE)
|
||
|
{
|
||
|
if ((![universe reducedDetail])||(status == STATUS_EFFECT)) // don't draw passive subentities except exhausts in reduced detail mode.
|
||
|
{
|
||
|
glPushMatrix();
|
||
|
|
||
|
// position and orientation is relative to owner
|
||
|
|
||
|
//NSLog(@"DEBUG drawing passive subentity at %.3f, %.3f, %.3f", position.x, position.y, position.z);
|
||
|
|
||
|
glTranslated( position.x, position.y, position.z);
|
||
|
glMultMatrixf(rotMatrix);
|
||
|
|
||
|
[self drawEntity:immediate :translucent];
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
// NSLog(@"drawn static entity : %@", basefile);
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Vector abspos; // STATUS_ACTIVE means it is in control of it's own orientation
|
||
|
abspos = position;
|
||
|
Entity* father = [self owner];
|
||
|
GLfloat* r_mat = [father rotationMatrix];
|
||
|
while (father)
|
||
|
{
|
||
|
mult_vector_gl_matrix(&abspos, r_mat);
|
||
|
Vector pos = [father getPosition];
|
||
|
abspos.x += pos.x; abspos.y += pos.y; abspos.z += pos.z;
|
||
|
father = [father owner];
|
||
|
r_mat = [father rotationMatrix];
|
||
|
}
|
||
|
glPopMatrix(); // one down
|
||
|
glPushMatrix();
|
||
|
// position and orientation is absolute
|
||
|
glTranslated( abspos.x, abspos.y, abspos.z);
|
||
|
|
||
|
glMultMatrixf(rotMatrix);
|
||
|
|
||
|
[self drawEntity:immediate :translucent];
|
||
|
|
||
|
// NSLog(@"drawn active entity : %@", basefile);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) initialiseTextures
|
||
|
{
|
||
|
// roll out each face and tetxure in turn
|
||
|
//
|
||
|
int fi,ti ;
|
||
|
//
|
||
|
for (fi = 0; fi < n_faces; fi++)
|
||
|
{
|
||
|
// texture
|
||
|
if ((faces[fi].texName == 0)&&(faces[fi].textureFile))
|
||
|
{
|
||
|
// load texture into Universe texturestore
|
||
|
//NSLog(@"Off to load %@",faces[fi].textureFile);
|
||
|
if (universe)
|
||
|
{
|
||
|
faces[fi].texName = [[universe textureStore] getTextureNameFor:faces[fi].textureFile];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (ti = 1; ti <= n_textures; ti++)
|
||
|
{
|
||
|
if (!texture_name[ti])
|
||
|
{
|
||
|
texture_name[ti] = [[universe textureStore] getTextureNameFor:texture_file[ti]];
|
||
|
// NSLog(@"DEBUG (initialiseTextures) Processed textureFile : %@ to texName : %d", entityData[ti].textureFile, entityData[ti].texName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) regenerateDisplayList
|
||
|
{
|
||
|
glDeleteLists(displayListName,1);
|
||
|
displayListName = 0;
|
||
|
}
|
||
|
|
||
|
- (void) generateDisplayList
|
||
|
{
|
||
|
displayListName = glGenLists(1);
|
||
|
if (displayListName != 0)
|
||
|
{
|
||
|
glNewList(displayListName, GL_COMPILE);
|
||
|
[self drawEntity:YES:NO];
|
||
|
glEndList();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) update:(double) delta_t
|
||
|
{
|
||
|
Entity* player = [universe entityZero];
|
||
|
if (player)
|
||
|
{
|
||
|
Vector p0 = [player getPosition];
|
||
|
relative_position = make_vector( position.x - p0.x, position.y - p0.y, position.z - p0.z);
|
||
|
zero_distance = magnitude2(relative_position);
|
||
|
}
|
||
|
else
|
||
|
zero_distance = -1;
|
||
|
}
|
||
|
|
||
|
- (void) saveToLastFrame
|
||
|
{
|
||
|
double t_now = [universe getTime];
|
||
|
if (t_now >= track_time + 0.1) // update every 1/10 of a second
|
||
|
{
|
||
|
// save previous data
|
||
|
track_time = t_now;
|
||
|
track[track_index].position = position;
|
||
|
track[track_index].q_rotation = q_rotation;
|
||
|
track[track_index].timeframe = track_time;
|
||
|
track_index = (track_index + 1 ) & 0xff;
|
||
|
// if ([self isKindOfClass:[PlayerEntity class]])
|
||
|
// NSLog(@"Saving frame %d %.2f", track_index, track_time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (BOOL) resetToTime:(double) t_frame // timeframe is relative to now ie. -0.5 = half a second ago.
|
||
|
{
|
||
|
if (t_frame >= 0)
|
||
|
return NO;
|
||
|
|
||
|
Frame selectedFrame = [self frameAtTime:t_frame];
|
||
|
[self setPosition:selectedFrame.position];
|
||
|
[self setQRotation:selectedFrame.q_rotation];
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
- (Frame) frameAtTime:(double) t_frame // t_frame is relative to now ie. -0.5 = half a second ago.
|
||
|
{
|
||
|
Frame result;
|
||
|
result.position = position;
|
||
|
result.q_rotation = q_rotation;
|
||
|
result.timeframe = [universe getTime];
|
||
|
//
|
||
|
if (t_frame >= 0.0)
|
||
|
return result;
|
||
|
//
|
||
|
double moment_in_time = [universe getTime] + t_frame;
|
||
|
if (moment_in_time >= track_time) // between the last saved frame and now
|
||
|
{
|
||
|
int t1 = (track_index - 1)&0xff; // last saved moment
|
||
|
double period = result.timeframe - track_time;
|
||
|
double f0 = (result.timeframe - moment_in_time)/period;
|
||
|
double f1 = 1 - f0;
|
||
|
Vector posn;
|
||
|
posn.x = f0 * result.position.x + f1 * track[t1].position.x;
|
||
|
posn.y = f0 * result.position.y + f1 * track[t1].position.y;
|
||
|
posn.z = f0 * result.position.z + f1 * track[t1].position.z;
|
||
|
Quaternion qrot;
|
||
|
qrot.w = f0 * result.q_rotation.w + f1 * track[t1].q_rotation.w;
|
||
|
qrot.x = f0 * result.q_rotation.x + f1 * track[t1].q_rotation.x;
|
||
|
qrot.y = f0 * result.q_rotation.y + f1 * track[t1].q_rotation.y;
|
||
|
qrot.z = f0 * result.q_rotation.z + f1 * track[t1].q_rotation.z;
|
||
|
result.position = posn;
|
||
|
result.q_rotation = qrot;
|
||
|
result.timeframe = moment_in_time;
|
||
|
return result;
|
||
|
}
|
||
|
//
|
||
|
if (moment_in_time < track[track_index].timeframe) // more than 256 frames back
|
||
|
{
|
||
|
return track[track_index];
|
||
|
}
|
||
|
//
|
||
|
int t1 = (track_index - 1)&0xff;
|
||
|
while (moment_in_time < track[t1].timeframe)
|
||
|
t1 = (t1 - 1) & 0xff;
|
||
|
int t0 = (t1 + 1) & 0xff;
|
||
|
// interpolate between t0 and t1
|
||
|
double period = track[0].timeframe - track[1].timeframe;
|
||
|
double f0 = (track[t0].timeframe - moment_in_time)/period;
|
||
|
double f1 = 1 - f0;
|
||
|
Vector posn;
|
||
|
posn.x = f0 * track[t0].position.x + f1 * track[t1].position.x;
|
||
|
posn.y = f0 * track[t0].position.y + f1 * track[t1].position.y;
|
||
|
posn.z = f0 * track[t0].position.z + f1 * track[t1].position.z;
|
||
|
Quaternion qrot;
|
||
|
qrot.w = f0 * track[t0].q_rotation.w + f1 * track[t1].q_rotation.w;
|
||
|
qrot.x = f0 * track[t0].q_rotation.x + f1 * track[t1].q_rotation.x;
|
||
|
qrot.y = f0 * track[t0].q_rotation.y + f1 * track[t1].q_rotation.y;
|
||
|
qrot.z = f0 * track[t0].q_rotation.z + f1 * track[t1].q_rotation.z;
|
||
|
result.position = posn;
|
||
|
result.q_rotation = qrot;
|
||
|
result.timeframe = moment_in_time;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
- (void) loadData:(NSString *) filename
|
||
|
{
|
||
|
NSScanner *scanner;
|
||
|
NSString *data = nil;
|
||
|
NSMutableArray *lines;
|
||
|
BOOL failFlag = NO;
|
||
|
NSString *failString = @"***** ";
|
||
|
int i, j;
|
||
|
|
||
|
BOOL using_preloaded = NO;
|
||
|
|
||
|
if (data_store_universe)
|
||
|
{
|
||
|
if ([[data_store_universe preloadedDataFiles] objectForKey:filename])
|
||
|
{
|
||
|
// NSLog(@"Reusing data for %@ from [data_store_universe preloadedDataFiles]", filename);
|
||
|
data = (NSString *)[[data_store_universe preloadedDataFiles] objectForKey:filename];
|
||
|
using_preloaded = YES;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
data = [ResourceManager stringFromFilesNamed:filename inFolder:@"Models"];
|
||
|
if (data != nil)
|
||
|
[[data_store_universe preloadedDataFiles] setObject:data forKey:filename];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// failsafe in case the stored data fails
|
||
|
if (data == nil)
|
||
|
{
|
||
|
data = [ResourceManager stringFromFilesNamed:filename inFolder:@"Models"];
|
||
|
using_preloaded = NO;
|
||
|
}
|
||
|
|
||
|
// strip out comments and commas between values
|
||
|
//
|
||
|
lines = [NSMutableArray arrayWithArray:[data componentsSeparatedByString:@"\n"]];
|
||
|
for (i = 0; i < [ lines count]; i++)
|
||
|
{
|
||
|
NSString *line = [lines objectAtIndex:i];
|
||
|
NSArray *parts;
|
||
|
//
|
||
|
// comments
|
||
|
//
|
||
|
parts = [line componentsSeparatedByString:@"#"];
|
||
|
line = [parts objectAtIndex:0];
|
||
|
parts = [line componentsSeparatedByString:@"//"];
|
||
|
line = [parts objectAtIndex:0];
|
||
|
//
|
||
|
// commas
|
||
|
//
|
||
|
line = [[line componentsSeparatedByString:@","] componentsJoinedByString:@" "];
|
||
|
//
|
||
|
[lines replaceObjectAtIndex:i withObject:line];
|
||
|
}
|
||
|
data = [lines componentsJoinedByString:@"\n"];
|
||
|
|
||
|
//NSLog(@"More data:\n%@",data);
|
||
|
|
||
|
scanner = [NSScanner scannerWithString:data];
|
||
|
|
||
|
// get number of vertices
|
||
|
//
|
||
|
[scanner setScanLocation:0]; //reset
|
||
|
//[scanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:nil];
|
||
|
if ([scanner scanString:@"NVERTS" intoString:nil])
|
||
|
{
|
||
|
int n_v;
|
||
|
if ([scanner scanInt:&n_v])
|
||
|
n_vertices = n_v;
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read value of NVERTS\n",failString];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read NVERTS\n",failString];
|
||
|
}
|
||
|
|
||
|
// get number of faces
|
||
|
//
|
||
|
//[scanner setScanLocation:0]; //reset
|
||
|
if ([scanner scanString:@"NFACES" intoString:nil])
|
||
|
{
|
||
|
int n_f;
|
||
|
if ([scanner scanInt:&n_f])
|
||
|
n_faces = n_f;
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read value of NFACES\n",failString];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read NFACES\n",failString];
|
||
|
}
|
||
|
|
||
|
// get vertex data
|
||
|
//
|
||
|
//[scanner setScanLocation:0]; //reset
|
||
|
if ([scanner scanString:@"VERTEX" intoString:nil])
|
||
|
{
|
||
|
for (j = 0; j < n_vertices; j++)
|
||
|
{
|
||
|
float x, y, z;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
if (![scanner scanFloat:&x])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&y])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&z])
|
||
|
failFlag = YES;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
vertices[j].x = x; vertices[j].y = y; vertices[j].z = z;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read a value for vertex[%d] in VERTEX\n", failString, j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to find VERTEX data\n",failString];
|
||
|
}
|
||
|
|
||
|
// get face data
|
||
|
//
|
||
|
if ([scanner scanString:@"FACES" intoString:nil])
|
||
|
{
|
||
|
for (j = 0; j < n_faces; j++)
|
||
|
{
|
||
|
int r, g, b;
|
||
|
float nx, ny, nz;
|
||
|
int n_v;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
// colors
|
||
|
//
|
||
|
if (![scanner scanInt:&r])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanInt:&g])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanInt:&b])
|
||
|
failFlag = YES;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
faces[j].red = r/255.0; faces[j].green = g/255.0; faces[j].blue = b/255.0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read a color for face[%d] in FACES\n", failString, j];
|
||
|
}
|
||
|
|
||
|
// normal
|
||
|
//
|
||
|
if (![scanner scanFloat:&nx])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&ny])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&nz])
|
||
|
failFlag = YES;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
faces[j].normal.x = nx; faces[j].normal.y = ny; faces[j].normal.z = nz;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read a normal for face[%d] in FACES\n", failString, j];
|
||
|
}
|
||
|
|
||
|
// vertices
|
||
|
//
|
||
|
if ([scanner scanInt:&n_v])
|
||
|
{
|
||
|
faces[j].n_verts = n_v;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read number of vertices for face[%d] in FACES\n", failString, j];
|
||
|
}
|
||
|
//
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
int vi;
|
||
|
for (i = 0; i < n_v; i++)
|
||
|
{
|
||
|
if ([scanner scanInt:&vi])
|
||
|
{
|
||
|
faces[j].vertex[i] = vi;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read vertex[%d] for face[%d] in FACES\n", failString, i, j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to find FACES data\n",failString];
|
||
|
}
|
||
|
|
||
|
NSMutableDictionary* facesForTexture = [NSMutableDictionary dictionaryWithCapacity:MAX_TEXTURES_PER_ENTITY];
|
||
|
|
||
|
// get textures data
|
||
|
//
|
||
|
if ([scanner scanString:@"TEXTURES" intoString:nil])
|
||
|
{
|
||
|
for (j = 0; j < n_faces; j++)
|
||
|
{
|
||
|
NSString *texfile;
|
||
|
float max_x, max_y;
|
||
|
float s, t;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
// texfile
|
||
|
//
|
||
|
[scanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:nil];
|
||
|
if (![scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:&texfile])
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read texture filename for face[%d] in TEXTURES\n", failString, j];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
faces[j].textureFile = [texfile retain];
|
||
|
|
||
|
// create/extend a list of faces for this texture
|
||
|
NSMutableArray* facesForThisTexture;
|
||
|
if ([facesForTexture objectForKey:texfile])
|
||
|
facesForThisTexture = (NSMutableArray*)[facesForTexture objectForKey:texfile];
|
||
|
else
|
||
|
facesForThisTexture = [NSMutableArray arrayWithCapacity:32];
|
||
|
[facesForThisTexture addObject:[NSNumber numberWithInt:j]];
|
||
|
[facesForTexture setObject:facesForThisTexture forKey:texfile];
|
||
|
|
||
|
}
|
||
|
faces[j].texName = 0;
|
||
|
|
||
|
// texture size
|
||
|
//
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
if (![scanner scanFloat:&max_x])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&max_y])
|
||
|
failFlag = YES;
|
||
|
if (failFlag)
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read texture size for max_x and max_y in face[%d] in TEXTURES\n", failString, j];
|
||
|
}
|
||
|
|
||
|
// vertices
|
||
|
//
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
for (i = 0; i < faces[j].n_verts; i++)
|
||
|
{
|
||
|
if (![scanner scanFloat:&s])
|
||
|
failFlag = YES;
|
||
|
if (![scanner scanFloat:&t])
|
||
|
failFlag = YES;
|
||
|
if (!failFlag)
|
||
|
{
|
||
|
faces[j].s[i] = s / max_x; faces[j].t[i] = t / max_y;
|
||
|
|
||
|
//NSLog(@" st %f %f", faces[j].s[i], faces[j].t[i]);
|
||
|
}
|
||
|
else
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to read s t coordinates for vertex[%d] in face[%d] in TEXTURES\n", failString, i, j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
failFlag = YES;
|
||
|
failString = [NSString stringWithFormat:@"%@Failed to find TEXTURES data\n",failString];
|
||
|
}
|
||
|
|
||
|
// NSLog(@"Loading data for %@: facesForTexture:\n%@", filename, [facesForTexture description]);
|
||
|
|
||
|
// check normals before creating new textures
|
||
|
//
|
||
|
[self checkNormalsAndAdjustWinding];
|
||
|
|
||
|
if ((failFlag)&&([failString rangeOfString:@"TEXTURES"].location != NSNotFound))
|
||
|
{
|
||
|
//NSLog(@"Off to make new textures!");
|
||
|
[self fakeTexturesWithImageFile:@"metal.png" andMaxSize:NSMakeSize(256.0,256.0)];
|
||
|
|
||
|
// dump out data for ships with faked textures
|
||
|
//if ([self isKindOfClass:[ShipEntity class]])
|
||
|
// //NSLog(@"Faked Texture coordinates for this model :\n\n%@\n\n", [self toString]);
|
||
|
}
|
||
|
|
||
|
if (failFlag)
|
||
|
NSLog([NSString stringWithFormat:@"%@ ..... from %@ %@", failString, filename, (using_preloaded)? @"(from preloaded data)" : @"(from file)"]);
|
||
|
|
||
|
// set the collision radius
|
||
|
//
|
||
|
collision_radius = [self findCollisionRadius];
|
||
|
//
|
||
|
[self setUpVertexArrays];
|
||
|
//
|
||
|
|
||
|
//
|
||
|
usingVAR = [self OGL_InitVAR];
|
||
|
//
|
||
|
if (usingVAR)
|
||
|
{
|
||
|
[self OGL_AssignVARMemory:sizeof(EntityData) :(void *)&entityData :0];
|
||
|
}
|
||
|
//
|
||
|
|
||
|
}
|
||
|
|
||
|
- (void) checkNormalsAndAdjustWinding
|
||
|
{
|
||
|
Vector calculatedNormal;
|
||
|
int i, j;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
Vector v0, v1, v2, norm;
|
||
|
v0 = vertices[faces[i].vertex[0]];
|
||
|
v1 = vertices[faces[i].vertex[1]];
|
||
|
v2 = vertices[faces[i].vertex[2]];
|
||
|
norm = faces[i].normal;
|
||
|
calculatedNormal = normal_to_surface (v2, v1, v0);
|
||
|
if ((norm.x == 0.0)&&(norm.y == 0.0)&&(norm.z == 0.0))
|
||
|
{
|
||
|
//NSLog(@"Using calculated normal for face %d", i);
|
||
|
faces[i].normal = normal_to_surface (v0, v1, v2);
|
||
|
norm = normal_to_surface (v0, v1, v2);
|
||
|
}
|
||
|
if ((norm.x*calculatedNormal.x < 0)||(norm.y*calculatedNormal.y < 0)||(norm.z*calculatedNormal.z < 0))
|
||
|
{
|
||
|
// normal lies in the WRONG direction!
|
||
|
// reverse the winding
|
||
|
int v[faces[i].n_verts];
|
||
|
GLfloat s[faces[i].n_verts];
|
||
|
GLfloat t[faces[i].n_verts];
|
||
|
|
||
|
//
|
||
|
//NSLog(@"Normal pointing the wrong way for winding on face %d", i);
|
||
|
//
|
||
|
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
v[j] = faces[i].vertex[faces[i].n_verts - 1 - j];
|
||
|
s[j] = faces[i].s[faces[i].n_verts - 1 - j];
|
||
|
t[j] = faces[i].t[faces[i].n_verts - 1 - j];
|
||
|
}
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
faces[i].vertex[j] = v[j];
|
||
|
faces[i].s[j] = s[j];
|
||
|
faces[i].t[j] = t[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) calculateVertexNormals
|
||
|
{
|
||
|
int i,j,k;
|
||
|
for (i = 0; i < n_vertices; i++)
|
||
|
{
|
||
|
int shared_faces = 0;
|
||
|
Vector normal_sum;
|
||
|
normal_sum.x = 0.0; normal_sum.y = 0.0; normal_sum.z = 0.0;
|
||
|
for (j = 0; j < n_faces; j++)
|
||
|
{
|
||
|
BOOL is_shared = NO;
|
||
|
for (k = 0; (k < faces[j].n_verts)&&(!is_shared); k++)
|
||
|
is_shared = (faces[j].vertex[k] == i);
|
||
|
if (is_shared)
|
||
|
{
|
||
|
normal_sum.x += faces[j].normal.x; normal_sum.y += faces[j].normal.y; normal_sum.z += faces[j].normal.z;
|
||
|
shared_faces++;
|
||
|
}
|
||
|
}
|
||
|
normal_sum = unit_vector(&normal_sum);
|
||
|
vertex_normal[i].x = normal_sum.x;
|
||
|
vertex_normal[i].y = normal_sum.y;
|
||
|
vertex_normal[i].z = normal_sum.z;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void) setUpVertexArrays
|
||
|
{
|
||
|
NSMutableDictionary* texturesProcessed = [NSMutableDictionary dictionaryWithCapacity:MAX_TEXTURES_PER_ENTITY];
|
||
|
|
||
|
int face, fi, vi, texi;
|
||
|
|
||
|
// base model, flat shaded, all triangles
|
||
|
int tri_index = 0;
|
||
|
int uv_index = 0; // not used
|
||
|
int vertex_index = 0;
|
||
|
int normal_index = 0;
|
||
|
entityData.textureFile = nil;
|
||
|
entityData.texName = 0;
|
||
|
|
||
|
texi = 1; // index of first texture
|
||
|
|
||
|
for (face = 0; face < n_faces; face++)
|
||
|
{
|
||
|
NSString* tex_string = faces[face].textureFile;
|
||
|
if (![texturesProcessed objectForKey:tex_string])
|
||
|
{
|
||
|
// do this texture
|
||
|
triangle_range[texi].location = tri_index;
|
||
|
texture_file[texi] = tex_string;
|
||
|
texture_name[texi] = faces[face].texName;
|
||
|
|
||
|
for (fi = 0; fi < n_faces; fi++)
|
||
|
{
|
||
|
Vector normal;
|
||
|
int v;
|
||
|
if (!is_smooth_shaded)
|
||
|
normal = faces[fi].normal;
|
||
|
if ([faces[fi].textureFile isEqual:tex_string])
|
||
|
{
|
||
|
for (vi = 0; vi < 3; vi++)
|
||
|
{
|
||
|
v = faces[fi].vertex[vi];
|
||
|
if (is_smooth_shaded)
|
||
|
normal = vertex_normal[v];
|
||
|
entityData.index_array[tri_index++] = vertex_index;
|
||
|
entityData.vertex_array[vertex_index++] = vertices[v];
|
||
|
entityData.normal_array[normal_index++] = normal;
|
||
|
entityData.texture_uv_array[uv_index++] = faces[fi].s[vi];
|
||
|
entityData.texture_uv_array[uv_index++] = faces[fi].t[vi];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
triangle_range[texi].length = tri_index - triangle_range[texi].location;
|
||
|
|
||
|
// NSLog(@"DEBUG processing %@ texture %@ texName %d triangles %d to %d",
|
||
|
// basefile, texture_file[texi], texture_name[texi], triangle_range[texi].location, triangle_range[texi].location + triangle_range[texi].length);
|
||
|
|
||
|
//finally...
|
||
|
[texturesProcessed setObject:tex_string forKey:tex_string]; // note this texture done
|
||
|
texi++;
|
||
|
}
|
||
|
}
|
||
|
entityData.n_triangles = tri_index; // total number of triangle vertices
|
||
|
triangle_range[0] = NSMakeRange( 0, tri_index);
|
||
|
|
||
|
n_textures = texi - 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
- (double) findCollisionRadius
|
||
|
{
|
||
|
int i;
|
||
|
double d_squared, result, length_longest_axis, length_shortest_axis;
|
||
|
|
||
|
result = 0.0;
|
||
|
bounding_box_reset(&boundingBox);
|
||
|
|
||
|
for (i = 0; i < n_vertices; i++)
|
||
|
{
|
||
|
d_squared = vertices[i].x*vertices[i].x + vertices[i].y*vertices[i].y + vertices[i].z*vertices[i].z;
|
||
|
if (d_squared > result)
|
||
|
result = d_squared;
|
||
|
bounding_box_add_vector(&boundingBox,vertices[i]);
|
||
|
}
|
||
|
|
||
|
length_longest_axis = boundingBox.max_x - boundingBox.min_x;
|
||
|
if (boundingBox.max_y - boundingBox.min_y > length_longest_axis)
|
||
|
length_longest_axis = boundingBox.max_y - boundingBox.min_y;
|
||
|
if (boundingBox.max_z - boundingBox.min_z > length_longest_axis)
|
||
|
length_longest_axis = boundingBox.max_z - boundingBox.min_z;
|
||
|
|
||
|
length_shortest_axis = boundingBox.max_x - boundingBox.min_x;
|
||
|
if (boundingBox.max_y - boundingBox.min_y < length_shortest_axis)
|
||
|
length_shortest_axis = boundingBox.max_y - boundingBox.min_y;
|
||
|
if (boundingBox.max_z - boundingBox.min_z < length_shortest_axis)
|
||
|
length_shortest_axis = boundingBox.max_z - boundingBox.min_z;
|
||
|
|
||
|
d_squared = (length_longest_axis + length_shortest_axis) * (length_longest_axis + length_shortest_axis) * 0.25; // square of average length
|
||
|
no_draw_distance = d_squared * NO_DRAW_DISTANCE_FACTOR * NO_DRAW_DISTANCE_FACTOR; // no longer based on the collision radius
|
||
|
|
||
|
mass = (boundingBox.max_x - boundingBox.min_x) * (boundingBox.max_y - boundingBox.min_y) * (boundingBox.max_z - boundingBox.min_z);
|
||
|
|
||
|
// NSLog(@"%@ has mass %.3f", basefile, mass);
|
||
|
|
||
|
return sqrt(result);
|
||
|
}
|
||
|
|
||
|
|
||
|
- (BoundingBox) findBoundingBoxRelativeTo:(Entity *)other InVectors:(Vector) _i :(Vector) _j :(Vector) _k
|
||
|
{
|
||
|
Vector pv, rv;
|
||
|
Vector rpos = position;
|
||
|
Vector opv = [other getPosition];
|
||
|
rpos.x -= opv.x; rpos.y -= opv.y; rpos.z -= opv.z;
|
||
|
rv.x = dot_product(_i,rpos);
|
||
|
rv.y = dot_product(_j,rpos);
|
||
|
rv.z = dot_product(_k,rpos);
|
||
|
BoundingBox result;
|
||
|
bounding_box_reset_to_vector(&result,rv);
|
||
|
int i;
|
||
|
for (i = 0; i < n_vertices; i++)
|
||
|
{
|
||
|
pv.x = rpos.x + vertices[i].x;
|
||
|
pv.y = rpos.y + vertices[i].y;
|
||
|
pv.z = rpos.z + vertices[i].z;
|
||
|
rv.x = dot_product(_i,pv);
|
||
|
rv.y = dot_product(_j,pv);
|
||
|
rv.z = dot_product(_k,pv);
|
||
|
bounding_box_add_vector(&result,rv);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
- (BoundingBox) findBoundingBoxRelativeToPosition:(Vector)opv InVectors:(Vector) _i :(Vector) _j :(Vector) _k
|
||
|
{
|
||
|
Vector pv, rv;
|
||
|
Vector rpos = position;
|
||
|
rpos.x -= opv.x; rpos.y -= opv.y; rpos.z -= opv.z;
|
||
|
rv.x = dot_product(_i,rpos);
|
||
|
rv.y = dot_product(_j,rpos);
|
||
|
rv.z = dot_product(_k,rpos);
|
||
|
BoundingBox result;
|
||
|
bounding_box_reset_to_vector(&result,rv);
|
||
|
int i;
|
||
|
for (i = 0; i < n_vertices; i++)
|
||
|
{
|
||
|
pv.x = rpos.x + vertices[i].x;
|
||
|
pv.y = rpos.y + vertices[i].y;
|
||
|
pv.z = rpos.z + vertices[i].z;
|
||
|
rv.x = dot_product(_i,pv);
|
||
|
rv.y = dot_product(_j,pv);
|
||
|
rv.z = dot_product(_k,pv);
|
||
|
bounding_box_add_vector(&result,rv);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
- (BOOL) checkCloseCollisionWith:(Entity *)other
|
||
|
{
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
- (void) takeEnergyDamage:(double) amount from:(Entity *) ent becauseOf:(Entity *) other
|
||
|
{
|
||
|
}
|
||
|
|
||
|
- (NSString *) toString
|
||
|
{
|
||
|
// produce a file from the original data
|
||
|
int i,j, r,g,b;
|
||
|
NSString *result;
|
||
|
NSString *boilerplate = @"# This is a file adapted from the model files for Java Elite\n# which in turn are based on the data released by Ian Bell\n# in the file b7051600.zip at\n# http://www.users.waitrose.com/~elitearc2/elite/archive/b7051600.zip\n#";
|
||
|
result = [NSString stringWithFormat:@"%@\n# %@\n#\n\nNVERTS %d\nNFACES %d\n\nVERTEX\n", boilerplate, basefile, n_vertices, n_faces];
|
||
|
for (i = 0; i < n_vertices; i++)
|
||
|
{
|
||
|
result = [NSString stringWithFormat:@"%@%f,\t%f,\t%f\n", result, vertices[i].x, vertices[i].y, vertices[i].z];
|
||
|
if ((i % 5)==4)
|
||
|
result = [NSString stringWithFormat:@"%@\n", result];
|
||
|
}
|
||
|
result = [NSString stringWithFormat:@"%@\nFACES\n", result];
|
||
|
//
|
||
|
//NSLog(result);
|
||
|
//
|
||
|
for (j = 0; j < n_faces; j++)
|
||
|
{
|
||
|
r = (int)(faces[j].red * 255.0); g = (int)(faces[j].green * 255.0); b = (int)(faces[j].blue * 255.0);
|
||
|
result = [NSString stringWithFormat:@"%@%d, %d, %d,\t", result, r, g, b];
|
||
|
result = [NSString stringWithFormat:@"%@%f, %f, %f,\t", result, faces[j].normal.x, faces[j].normal.y, faces[j].normal.z];
|
||
|
result = [NSString stringWithFormat:@"%@%d,\t", result, faces[j].n_verts];
|
||
|
for (i = 0; i < faces[j].n_verts; i++)
|
||
|
{
|
||
|
result = [NSString stringWithFormat:@"%@%d ", result, faces[j].vertex[i]];
|
||
|
}
|
||
|
result = [NSString stringWithFormat:@"%@\n", result];
|
||
|
}
|
||
|
if (universe)
|
||
|
{
|
||
|
result = [NSString stringWithFormat:@"%@\nTEXTURES\n", result];
|
||
|
for (j = 0; j < n_faces; j++)
|
||
|
{
|
||
|
NSSize texSize = [[universe textureStore] getSizeOfTexture:faces[j].textureFile];
|
||
|
result = [NSString stringWithFormat:@"%@%@\t%d %d", result, faces[j].textureFile, (int)texSize.width, (int)texSize.height];
|
||
|
for (i = 0; i < faces[j].n_verts; i++)
|
||
|
{
|
||
|
int s = (int)(faces[j].s[i] * texSize.width);
|
||
|
int t = (int)(faces[j].t[i] * texSize.height);
|
||
|
result = [NSString stringWithFormat:@"%@\t%d %d", result, s, t];
|
||
|
}
|
||
|
result = [NSString stringWithFormat:@"%@\n", result];
|
||
|
}
|
||
|
}
|
||
|
result = [NSString stringWithFormat:@"%@\nEND\n", result];
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
- (void) fakeTexturesWithImageFile: (NSString *) textureFile andMaxSize:(NSSize) maxSize
|
||
|
{
|
||
|
int i, j, k;
|
||
|
Vector vec;
|
||
|
int nf = 0;
|
||
|
int fi[MAX_FACES_PER_ENTITY];
|
||
|
float max_s, min_s, max_t, min_t, st_width, st_height;
|
||
|
float tolerance;
|
||
|
Face fa[MAX_FACES_PER_ENTITY];
|
||
|
int faces_to_match;
|
||
|
BOOL face_matched[MAX_FACES_PER_ENTITY];
|
||
|
|
||
|
tolerance = 1.00;
|
||
|
faces_to_match = n_faces;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
face_matched[i] = NO;
|
||
|
}
|
||
|
while (faces_to_match > 0)
|
||
|
{
|
||
|
tolerance -= 0.05;
|
||
|
|
||
|
// Top (+y) first
|
||
|
vec.x = 0.0; vec.y = 1.0; vec.z = 0.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = vertices[faces[i].vertex[j]].x;
|
||
|
t = vertices[faces[i].vertex[j]].z;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
//
|
||
|
//NSLog(@"TOP st_width %f st_height %f maxSize.height %f maxSize.width %f", st_width, st_height, maxSize.width, maxSize.height);
|
||
|
//
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"top_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = vertices[faces[i].vertex[k]].x;
|
||
|
t = vertices[faces[i].vertex[k]].z;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
//
|
||
|
// TESTING
|
||
|
//
|
||
|
fa[i].t[k] = maxSize.height - fa[i].t[k]; // REVERSE t locations
|
||
|
//
|
||
|
//NSLog(@"%f, %f", fa[i].s[k], fa[i].t[k]);
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Bottom (-y)
|
||
|
vec.x = 0.0; vec.y = -1.0; vec.z = 0.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = -vertices[faces[i].vertex[j]].x;
|
||
|
t = -vertices[faces[i].vertex[j]].z;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"bottom_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = -vertices[faces[i].vertex[k]].x;
|
||
|
t = -vertices[faces[i].vertex[k]].z;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Right (+x)
|
||
|
vec.x = 1.0; vec.y = 0.0; vec.z = 0.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = vertices[faces[i].vertex[j]].z;
|
||
|
t = vertices[faces[i].vertex[j]].y;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"right_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = vertices[faces[i].vertex[k]].z;
|
||
|
t = vertices[faces[i].vertex[k]].y;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Left (-x)
|
||
|
vec.x = -1.0; vec.y = 0.0; vec.z = 0.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = -vertices[faces[i].vertex[j]].z;
|
||
|
t = -vertices[faces[i].vertex[j]].y;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"left_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = -vertices[faces[i].vertex[k]].z;
|
||
|
t = -vertices[faces[i].vertex[k]].y;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Front (+z)
|
||
|
vec.x = 0.0; vec.y = 0.0; vec.z = 1.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = vertices[faces[i].vertex[j]].x;
|
||
|
t = vertices[faces[i].vertex[j]].y;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"front_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = vertices[faces[i].vertex[k]].x;
|
||
|
t = vertices[faces[i].vertex[k]].y;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Back (-z)
|
||
|
vec.x = 0.0; vec.y = 0.0; vec.z = -1.0;
|
||
|
// build list of faces that face in that direction...
|
||
|
nf = 0;
|
||
|
max_s = -999999.0; min_s = 999999.0;
|
||
|
max_t = -999999.0; min_t = 999999.0;
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
float s, t;
|
||
|
float g = dot_product(vec, faces[i].normal) * sqrt(2.0);
|
||
|
if ((g >= tolerance)&&(!face_matched[i]))
|
||
|
{
|
||
|
fi[nf++] = i;
|
||
|
face_matched[i] = YES;
|
||
|
faces_to_match--;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
s = -vertices[faces[i].vertex[j]].x;
|
||
|
t = -vertices[faces[i].vertex[j]].y;
|
||
|
max_s = (max_s > s) ? max_s:s ; min_s = (min_s < s) ? min_s:s ;
|
||
|
max_t = (max_t > t) ? max_t:t ; min_t = (min_t < t) ? min_t:t ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
st_width = max_s - min_s;
|
||
|
st_height = max_t - min_t;
|
||
|
for (j = 0; j < nf; j++)
|
||
|
{
|
||
|
i = fi[j];
|
||
|
//fa[i] = faces[i];
|
||
|
fa[i].textureFile = [NSString stringWithFormat:@"back_%@", textureFile];
|
||
|
for (k = 0; k < faces[i].n_verts; k++)
|
||
|
{
|
||
|
float s, t;
|
||
|
s = -vertices[faces[i].vertex[k]].x;
|
||
|
t = -vertices[faces[i].vertex[k]].y;
|
||
|
fa[i].s[k] = (s - min_s) * maxSize.width / st_width;
|
||
|
fa[i].t[k] = (t - min_t) * maxSize.height / st_height;
|
||
|
}
|
||
|
}
|
||
|
//NSLog(@"%d / %d faces matched at tolerance: %f", n_faces - faces_to_match, n_faces, tolerance);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < n_faces; i++)
|
||
|
{
|
||
|
NSString *result;
|
||
|
faces[i].textureFile = [fa[i].textureFile retain];
|
||
|
faces[i].texName = 0;
|
||
|
for (j = 0; j < faces[i].n_verts; j++)
|
||
|
{
|
||
|
//
|
||
|
//NSLog(@"face[%d] %f, %f", i, fa[i].s[j], fa[i].t[j]);
|
||
|
//
|
||
|
faces[i].s[j] = fa[i].s[j] / maxSize.width;
|
||
|
faces[i].t[j] = fa[i].t[j] / maxSize.height;
|
||
|
}
|
||
|
result = [NSString stringWithFormat:@"%@\t%d %d", faces[i].textureFile, (int)maxSize.width, (int)maxSize.height];
|
||
|
//NSLog(@"face[%d] : %@", i, result);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// COMMON OGL STUFF
|
||
|
|
||
|
- (BOOL) OGL_InitVAR
|
||
|
{
|
||
|
short i;
|
||
|
static char* s;
|
||
|
|
||
|
if (global_testForVAR)
|
||
|
{
|
||
|
global_testForVAR = NO; // no need for further tests after this
|
||
|
|
||
|
// see if we have supported hardware
|
||
|
s = (char *)glGetString(GL_EXTENSIONS); // get extensions list
|
||
|
|
||
|
if (strstr(s, "GL_APPLE_vertex_array_range") == nil)
|
||
|
{
|
||
|
global_usingVAR &= NO;
|
||
|
NSLog(@"Vertex Array Range optimisation - not supported");
|
||
|
return NO;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NSLog(@"Vertex Array Range optimisation - supported");
|
||
|
global_usingVAR |= YES;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!global_usingVAR)
|
||
|
return NO;
|
||
|
#ifdef GNUSTEP
|
||
|
// TODO: Find out what these APPLE functions do
|
||
|
#else
|
||
|
glGenVertexArraysAPPLE(NUM_VERTEX_ARRAY_RANGES, &gVertexArrayRangeObjects[0]);
|
||
|
#endif
|
||
|
|
||
|
// INIT OUR DATA
|
||
|
//
|
||
|
// None of the VAR objects has been assigned to any data yet,
|
||
|
// so here we just initialize our info. We'll assign the VAR objects
|
||
|
// to data later.
|
||
|
//
|
||
|
|
||
|
for (i = 0; i < NUM_VERTEX_ARRAY_RANGES; i++)
|
||
|
{
|
||
|
gVertexArrayRangeData[i].rangeSize = 0;
|
||
|
gVertexArrayRangeData[i].dataBlockPtr = nil;
|
||
|
gVertexArrayRangeData[i].forceUpdate = true;
|
||
|
gVertexArrayRangeData[i].activated = false;
|
||
|
}
|
||
|
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
- (void) OGL_AssignVARMemory:(long) size :(void *) data :(Byte) whichVAR
|
||
|
{
|
||
|
if (whichVAR >= NUM_VERTEX_ARRAY_RANGES)
|
||
|
{
|
||
|
NSLog(@"VAR is out of range!");
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
gVertexArrayRangeData[whichVAR].rangeSize = size;
|
||
|
gVertexArrayRangeData[whichVAR].dataBlockPtr = data;
|
||
|
gVertexArrayRangeData[whichVAR].forceUpdate = true;
|
||
|
}
|
||
|
|
||
|
- (void) OGL_UpdateVAR
|
||
|
{
|
||
|
long size;
|
||
|
Byte i;
|
||
|
|
||
|
for (i = 0; i < NUM_VERTEX_ARRAY_RANGES; i++)
|
||
|
{
|
||
|
// SEE IF THIS VAR IS USED
|
||
|
|
||
|
size = gVertexArrayRangeData[i].rangeSize;
|
||
|
if (size == 0)
|
||
|
continue;
|
||
|
|
||
|
|
||
|
// SEE IF VAR NEEDS UPDATING
|
||
|
|
||
|
if (!gVertexArrayRangeData[i].forceUpdate)
|
||
|
continue;
|
||
|
|
||
|
#ifdef GNUSTEP
|
||
|
// TODO: find out what non-AAPL OpenGL stuff is equivalent
|
||
|
#else
|
||
|
// BIND THIS VAR OBJECT SO WE CAN DO STUFF TO IT
|
||
|
glBindVertexArrayAPPLE(gVertexArrayRangeObjects[i]);
|
||
|
|
||
|
// SEE IF THIS IS THE FIRST TIME IN
|
||
|
|
||
|
if (!gVertexArrayRangeData[i].activated)
|
||
|
{
|
||
|
glVertexArrayRangeAPPLE(size, gVertexArrayRangeData[i].dataBlockPtr);
|
||
|
glVertexArrayParameteriAPPLE(GL_VERTEX_ARRAY_STORAGE_HINT_APPLE,GL_STORAGE_SHARED_APPLE);
|
||
|
|
||
|
// you MUST call this flush to get the data primed!
|
||
|
|
||
|
glFlushVertexArrayRangeAPPLE(size, gVertexArrayRangeData[i].dataBlockPtr);
|
||
|
glEnableClientState(GL_VERTEX_ARRAY_RANGE_APPLE);
|
||
|
gVertexArrayRangeData[i].activated = true;
|
||
|
}
|
||
|
|
||
|
// ALREADY ACTIVE, SO JUST UPDATING
|
||
|
|
||
|
else
|
||
|
{
|
||
|
glFlushVertexArrayRangeAPPLE(size, gVertexArrayRangeData[i].dataBlockPtr);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
gVertexArrayRangeData[i].forceUpdate = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@end
|
||
|
|