oolite/ParticleEntity.m
Dylan Smith 207a37d0bc more merges
git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@174 127b21dd-08f5-0310-b4b7-95ae10353056
2005-10-26 20:20:45 +00:00

1774 lines
47 KiB
Objective-C

//
// ParticleEntity.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 "ParticleEntity.h"
#import "entities.h"
#import "Universe.h"
#import "AI.h"
#import "TextureStore.h"
@implementation ParticleEntity
static Vector circleVertex[65]; // holds vector coordinates for a unit circle
- (id) init
{
self = [super init];
//
quaternion_set_identity(&q_rotation);
quaternion_into_gl_matrix(q_rotation, rotMatrix);
//
position.x = 0.0;
position.y = 0.0;
position.z = 0.0;
//
status = STATUS_EFFECT;
time_counter = 0.0;
//
particle_type = PARTICLE_TEST;
//
basefile = @"Particle";
textureNameString = @"blur256.png";
[self setColor:[NSColor greenColor]];
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize(32.0,32.0);
//
owner = NO_TARGET;
//
collision_radius = 32.0;
//
int i;
for (i = 0; i < 65; i++)
{
circleVertex[i].x = sin(i * PI / 32.0);
circleVertex[i].y = cos(i * PI / 32.0);
circleVertex[i].z = 0.0;
}
//
isParticle = YES;
//
return self;
}
- (id) initLaserFromShip:(ShipEntity *) ship view:(int) view
{
self = [super init];
//
if (!ship)
return self;
//
status = STATUS_EFFECT;
position = ship->position;
q_rotation = ship->q_rotation;
if (ship->isPlayer)
q_rotation.w = -q_rotation.w; //reverse view direction for the player
Vector v_up = vector_up_from_quaternion(q_rotation);
Vector v_forward = vector_forward_from_quaternion(q_rotation);
Vector v_right = vector_right_from_quaternion(q_rotation);
double fs = [ship flight_speed];
velocity = make_vector( v_forward.x * fs, v_forward.y * fs, v_forward.z * fs);
double distance;
switch (view)
{
case VIEW_FORWARD :
distance = [ship getBoundingBox].max_z;
position.x += distance * v_forward.x; position.y += distance * v_forward.y; position.z += distance * v_forward.z;
break;
case VIEW_AFT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI);
distance = [ship getBoundingBox].min_z;
position.x += distance * v_forward.x; position.y += distance * v_forward.y; position.z += distance * v_forward.z;
break;
case VIEW_PORT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI/2.0);
distance = [ship getBoundingBox].min_x;
position.x += distance * v_right.x; position.y += distance * v_right.y; position.z += distance * v_right.z;
break;
case VIEW_STARBOARD :
quaternion_rotate_about_axis(&q_rotation, v_up, -PI/2.0);
distance = [ship getBoundingBox].max_x;
position.x += distance * v_right.x; position.y += distance * v_right.y; position.z += distance * v_right.z;
break;
}
quaternion_into_gl_matrix(q_rotation, rotMatrix);
//
if ((ship)&&(ship->isPlayer))
{
position.x -= WEAPON_OFFSET_DOWN * v_up.x; position.y -= WEAPON_OFFSET_DOWN * v_up.y; position.z -= WEAPON_OFFSET_DOWN * v_up.z; // offset below the view line
}
//
time_counter = 0.0;
//
particle_type = PARTICLE_LASER_BEAM_RED;
//
[self setColor:[NSColor redColor]];
//
duration = PARTICLE_LASER_DURATION;
//
[self setOwner:ship];
//
collision_radius = [ship weapon_range];
//
isParticle = YES;
//
return self;
}
- (id) initLaserFromShip:(ShipEntity *) ship view:(int) view offset:(Vector)offset
{
self = [super init];
//
if (!ship)
return self;
//
status = STATUS_EFFECT;
position = ship->position;
q_rotation = ship->q_rotation;
if (ship->isPlayer)
q_rotation.w = -q_rotation.w; //reverse view direction for the player
Vector v_up = vector_up_from_quaternion(q_rotation);
Vector v_forward = vector_forward_from_quaternion(q_rotation);
Vector v_right = vector_right_from_quaternion(q_rotation);
double fs = [ship flight_speed];
velocity = make_vector( v_forward.x * fs, v_forward.y * fs, v_forward.z * fs);
// NSLog(@"DEBUG firing laser with offset [ %.3f, %.3f, %.3f]", offset.x, offset.y, offset.z);
position.x += offset.x * v_right.x + offset.y * v_up.x + offset.z * v_forward.x;
position.y += offset.x * v_right.y + offset.y * v_up.y + offset.z * v_forward.y;
position.z += offset.x * v_right.z + offset.y * v_up.z + offset.z * v_forward.z;
switch (view)
{
case VIEW_AFT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI);
break;
case VIEW_PORT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI/2.0);
break;
case VIEW_STARBOARD :
quaternion_rotate_about_axis(&q_rotation, v_up, -PI/2.0);
break;
}
quaternion_into_gl_matrix(q_rotation, rotMatrix);
//
time_counter = 0.0;
//
particle_type = PARTICLE_LASER_BEAM_RED;
//
[self setColor:[NSColor redColor]];
//
duration = PARTICLE_LASER_DURATION;
//
[self setOwner:ship];
//
collision_radius = [ship weapon_range];
//
isParticle = YES;
//
return self;
}
- (id) initLaserFromSubentity:(ShipEntity *) subent view:(int) view
{
self = [super init];
//
if (!subent)
return self;
Entity* parent = [subent owner];
if (!parent)
return self;
//
status = STATUS_EFFECT;
BoundingBox bbox = [subent getBoundingBox];
Vector midfrontplane = make_vector( 0.5 * (bbox.max_x + bbox.min_x), 0.5 * (bbox.max_y + bbox.min_y), bbox.max_z);
position = [subent absolutePositionForSubentityOffset:midfrontplane];
q_rotation = parent->q_rotation;
if (parent->isPlayer)
q_rotation.w = -q_rotation.w; //reverse view direction for the player
Vector v_up = vector_up_from_quaternion(q_rotation);
Vector v_forward = vector_forward_from_quaternion(q_rotation);
Vector v_right = vector_right_from_quaternion(q_rotation);
double fs = [(ShipEntity*)parent flight_speed];
velocity = make_vector( v_forward.x * fs, v_forward.y * fs, v_forward.z * fs);
double distance;
switch (view)
{
case VIEW_FORWARD :
distance = [subent getBoundingBox].max_z;
position.x += distance * v_forward.x; position.y += distance * v_forward.y; position.z += distance * v_forward.z;
break;
case VIEW_AFT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI);
distance = [subent getBoundingBox].min_z;
position.x += distance * v_forward.x; position.y += distance * v_forward.y; position.z += distance * v_forward.z;
break;
case VIEW_PORT :
quaternion_rotate_about_axis(&q_rotation, v_up, PI/2.0);
distance = [subent getBoundingBox].min_x;
position.x += distance * v_right.x; position.y += distance * v_right.y; position.z += distance * v_right.z;
break;
case VIEW_STARBOARD :
quaternion_rotate_about_axis(&q_rotation, v_up, -PI/2.0);
distance = [subent getBoundingBox].max_x;
position.x += distance * v_right.x; position.y += distance * v_right.y; position.z += distance * v_right.z;
break;
}
quaternion_into_gl_matrix(q_rotation, rotMatrix);
//
if (parent->isPlayer)
{
position.x -= WEAPON_OFFSET_DOWN * v_up.x; position.y -= WEAPON_OFFSET_DOWN * v_up.y; position.z -= WEAPON_OFFSET_DOWN * v_up.z; // offset below the view line
}
//
time_counter = 0.0;
//
particle_type = PARTICLE_LASER_BEAM_RED;
//
[self setColor:[NSColor redColor]];
//
duration = PARTICLE_LASER_DURATION;
//
[self setOwner:parent];
//
collision_radius = [subent weapon_range];
//
isParticle = YES;
//
return self;
}
- (id) initExhaustFromShip:(ShipEntity *) ship offsetVector:(Vector) offset scaleVector:(Vector) scale
{
self = [super init]; // sets rotMatrix and q_rotation to initial identities
//
status = STATUS_EFFECT;
exhaustScale = scale;
position.x = offset.x; // position is relative to owner
position.y = offset.y;
position.z = offset.z;
particle_type = PARTICLE_EXHAUST;
//
[self setOwner:ship];
//
collision_radius = [self findCollisionRadius];
actual_radius = collision_radius;
//
isParticle = YES;
//
return self;
}
- (id) initExhaustFromShip:(ShipEntity *) ship details:(NSString *) details
{
NSArray *values = [Entity scanTokensFromString:details];
if ([values count] != 6)
return nil;
Vector offset, scale;
offset.x = [(NSString *)[values objectAtIndex:0] doubleValue];
offset.y = [(NSString *)[values objectAtIndex:1] doubleValue];
offset.z = [(NSString *)[values objectAtIndex:2] doubleValue];
scale.x = [(NSString *)[values objectAtIndex:3] doubleValue];
scale.y = [(NSString *)[values objectAtIndex:4] doubleValue];
scale.z = [(NSString *)[values objectAtIndex:5] doubleValue];
self = [super init];
//
status = STATUS_EFFECT;
exhaustScale = scale;
// NSLog(@"Adding an exhaust to %@ >>%@<< scale: ( %3.1f, %3.1f, %3.1f)", ship, details, exhaustScale.x, exhaustScale.y, exhaustScale.z);
position.x = offset.x; // position is relative to owner
position.y = offset.y;
position.z = offset.z;
particle_type = PARTICLE_EXHAUST;
//
[self setOwner:ship];
//
isParticle = YES;
//
return self;
}
- (id) initECMMineFromShip:(ShipEntity *) ship
{
self = [super init];
if (!ship)
return self;
//
time_counter = 0.0;
activation_time = 0.5;
duration = 2.0;
position = ship->position;
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
//NSLog(@"```firing ECM at ( %3.1f, %3.1f, %3.1f)", position.x, position.y, position.z);
//
particle_type = PARTICLE_ECM_MINE;
//
[self setOwner:ship];
//
isParticle = YES;
//
return self;
}
- (id) initEnergyMineFromShip:(ShipEntity *) ship
{
self = [super init];
//
if (!ship)
return self;
//
time_counter = 0.0;
duration = 20.0;
position = ship->position;
//
[self setVelocity:make_vector( 0, 0, 0)];
//
[self setColor:[NSColor blueColor]];
//
alpha = 0.5;
collision_radius = 0;
//
status = STATUS_EFFECT;
scan_class = CLASS_MINE;
//
// NSLog(@"```firing Energy Bomb at ( %3.1f, %3.1f, %3.1f)", position.x, position.y, position.z);
//
particle_type = PARTICLE_ENERGY_MINE;
//
[self setOwner:[ship owner]];
//
isParticle = YES;
//
return self;
}
- (id) initHyperringFromShip:(ShipEntity *) ship
{
self = [super init];
//
time_counter = 0.0;
duration = 2.0;
if (!ship)
{
NSLog(@"ERROR - initHyperringFromShip:NULL");
return self;
}
size.width = ship->collision_radius * 0.5;
size.height = size.width * 1.25;
ring_inner_radius = size.width;
ring_outer_radius = size.height;
position = ship->position;
[self setQRotation:ship->q_rotation];
[self setVelocity:[ship getVelocity]];
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_HYPERRING;
int i;
for (i = 0; i < 65; i++)
{
circleVertex[i].x = sin(i * PI / 32.0);
circleVertex[i].y = cos(i * PI / 32.0);
circleVertex[i].z = 0.0;
}
//
[self setOwner:ship];
//
isParticle = YES;
//
return self;
}
- (id) initFragburstFromPosition:(Vector) fragPos
{
int speed_low = 200;
int speed_high = 800;
int n_fragments = 32;
int i;
//
self = [super init];
//
basefile = @"Particle";
textureNameString = @"blur256.png";
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize(32.0,32.0);
//
n_vertices = n_fragments;
time_counter = 0.0;
duration = 1.5;
position = fragPos;
[self setColor:[NSColor yellowColor]];
//
for (i = 0 ; i < n_vertices; i++)
{
int speed = (ranrot_rand() % (speed_high - speed_low)) + speed_low;
vertices[i] = make_vector(0,0,0); // position
vertex_normal[i].x = (ranrot_rand() % speed) - speed / 2; // velocity
vertex_normal[i].y = (ranrot_rand() % speed) - speed / 2;
vertex_normal[i].z = (ranrot_rand() % speed) - speed / 2;
faces[i].red = color_fv[0] + (randf() - 0.5) * 0.1; // color
faces[i].green = color_fv[2] + (randf() - 0.5) * 0.1;
faces[i].blue = color_fv[1] + (randf() - 0.5) * 0.1;
faces[i].normal.x = 16.0 * speed_low / speed; // size
}
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_FRAGBURST;
//
collision_radius = 0;
energy = 0;
owner = NO_TARGET;
//
isParticle = YES;
//
return self;
}
- (id) initFragburstSize:(GLfloat) fragSize FromPosition:(Vector) fragPos
{
int speed_low = 100;
int speed_high = 400;
int n_fragments = 0.4 * fragSize;
if (n_fragments > 63)
n_fragments = 63; // must also be less than MAX_FACES_PER_ENTITY
n_fragments |= 12;
int i;
//
self = [super init];
//
basefile = @"Particle";
textureNameString = @"blur256.png";
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize( fragSize, fragSize);
//
n_vertices = n_fragments;
time_counter = 0.0;
duration = 1.5;
position = fragPos;
[self setColor:[NSColor colorWithCalibratedHue:0.12 + 0.08 * randf() saturation:1.0 brightness:1.0 alpha:1.0]]; // yellow/orage (0.12) through yellow (0.1667) to yellow/slightly green (0.20)
//
for (i = 0 ; i < n_fragments; i++)
{
GLfloat speed = speed_low + 0.5 * (randf()+randf()) * (speed_high - speed_low); // speed tends toward mean of speed_high and speed_low
vertices[i] = make_vector(0,0,0); // position
vertex_normal[i] = make_vector(randf() - 0.5, randf() - 0.5, randf() - 0.5);
vertex_normal[i] = unit_vector(&vertex_normal[i]);
vertex_normal[i].x *= speed; // velocity
vertex_normal[i].y *= speed;
vertex_normal[i].z *= speed;
Vector col = make_vector(color_fv[0] * 0.1 * (9.5 + randf()), color_fv[1] * 0.1 * (9.5 + randf()), color_fv[2] * 0.1 * (9.5 + randf()));
col = unit_vector(&col);
faces[i].red = col.x;
faces[i].green = col.y;
faces[i].blue = col.z;
faces[i].normal.x = 16.0 * speed_low / speed;
}
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_FRAGBURST;
//
collision_radius = 0;
energy = 0;
owner = NO_TARGET;
//
isParticle = YES;
//
return self;
}
- (id) initBurst2FromPosition:(Vector) fragPos
{
int speed_low = 40;
int speed_high = 160;
int n_fragments = 8;
int i;
//
self = [super init];
//
basefile = @"Particle";
textureNameString = @"blur256.png";
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize(32.0,32.0);
//
n_vertices = n_fragments;
time_counter = 0.0;
duration = 1.5;
position = fragPos;
//
for (i = 0 ; i < n_vertices; i++)
{
int speed = speed_low + ranrot_rand() % (speed_high - speed_low);
vertices[i] = make_vector(0,0,0);
vertex_normal[i].x = (ranrot_rand() % speed) - speed / 2;
vertex_normal[i].y = (ranrot_rand() % speed) - speed / 2;
vertex_normal[i].z = (ranrot_rand() % speed) - speed / 2;
}
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_BURST2;
//
collision_radius = 0;
energy = 0;
[self setColor:[[NSColor yellowColor] blendedColorWithFraction:0.5 ofColor:[NSColor whiteColor]]];
owner = NO_TARGET;
//
isParticle = YES;
//
return self;
}
- (id) initBurst2Size:(GLfloat) burstSize FromPosition:(Vector) fragPos
{
int speed_low = 1 + burstSize * 0.5;
int speed_high = speed_low * 4;
int n_fragments = 0.2 * burstSize;
if (n_fragments > 15)
n_fragments = 15; // must also be less than MAX_FACES_PER_ENTITY
n_fragments |= 3;
int i;
//
self = [super init];
//
basefile = @"Particle";
textureNameString = @"blur256.png";
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize( burstSize, burstSize);
//
n_vertices = n_fragments;
time_counter = 0.0;
duration = 1.0;
position = fragPos;
//
[self setColor:[[NSColor yellowColor] blendedColorWithFraction:0.5 ofColor:[NSColor whiteColor]]];
//
for (i = 0 ; i < n_fragments; i++)
{
GLfloat speed = speed_low + 0.5 * (randf()+randf()) * (speed_high - speed_low); // speed tends toward mean of speed_high and speed_low
vertices[i] = make_vector(0,0,0); // position
vertex_normal[i] = make_vector(randf() - 0.5, randf() - 0.5, randf() - 0.5);
vertex_normal[i] = unit_vector(&vertex_normal[i]);
vertex_normal[i].x *= speed; // velocity
vertex_normal[i].y *= speed;
vertex_normal[i].z *= speed;
Vector col = make_vector(color_fv[0] * 0.1 * (9.5 + randf()), color_fv[1] * 0.1 * (9.5 + randf()), color_fv[2] * 0.1 * (9.5 + randf()));
col = unit_vector(&col);
faces[i].red = col.x;
faces[i].green = col.y;
faces[i].blue = col.z;
faces[i].normal.z = 1.0;
}
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_BURST2;
//
collision_radius = 0;
energy = 0;
owner = NO_TARGET;
//
isParticle = YES;
//
return self;
}
- (id) initFlashSize:(GLfloat) flashSize FromPosition:(Vector) fragPos
{
//
self = [super init];
//
basefile = @"Particle";
textureNameString = @"flare256.png";
//
texName = 0;
[self initialiseTexture: textureNameString];
size = NSMakeSize( flashSize, flashSize);
//
time_counter = 0.0;
duration = 0.4;
position = fragPos;
//
[self setColor:[NSColor whiteColor]];
color_fv[3] = 1.0;
//
status = STATUS_EFFECT;
scan_class = CLASS_NO_DRAW;
//
particle_type = PARTICLE_FLASH;
//
collision_radius = 0;
energy = 0;
owner = NO_TARGET;
//
isParticle = YES;
//
// NSLog(@"DEBUG *FLASH* initialised at [ %.2f, %.2f, %.2f]", fragPos.x, fragPos.y, fragPos.z);
return self;
}
- (void) dealloc
{
if (textureNameString) [textureNameString release];
if (color) [color release];
[super dealloc];
}
- (NSString*) description
{
NSString* type_string;
switch (particle_type)
{
case PARTICLE_SHOT_GREEN_PLASMA :
type_string = @"PARTICLE_SHOT_GREEN_PLASMA"; break;
case PARTICLE_SHOT_YELLOW_PLASMA :
type_string = @"PARTICLE_SHOT_YELLOW_PLASMA"; break;
case PARTICLE_SHOT_PLASMA :
type_string = @"PARTICLE_SHOT_PLASMA"; break;
case PARTICLE_ENERGY_MINE :
type_string = @"PARTICLE_ENERGY_MINE"; break;
case PARTICLE_TEST :
type_string = @"PARTICLE_TEST"; break;
case PARTICLE_LASER_BEAM_RED :
type_string = @"PARTICLE_LASER_BEAM_RED"; break;
case PARTICLE_LASER_BEAM :
type_string = @"PARTICLE_LASER_BEAM"; break;
case PARTICLE_EXPLOSION :
type_string = @"PARTICLE_EXPLOSION"; break;
case PARTICLE_SHOT_EXPIRED :
type_string = @"PARTICLE_SHOT_EXPIRED"; break;
case PARTICLE_EXHAUST :
type_string = @"PARTICLE_EXHAUST"; break;
case PARTICLE_HYPERRING :
type_string = @"PARTICLE_HYPERRING"; break;
case PARTICLE_FLASHER :
type_string = @"PARTICLE_FLASHER"; break;
case PARTICLE_MARKER :
type_string = @"PARTICLE_MARKER"; break;
case PARTICLE_ECM_MINE :
type_string = @"PARTICLE_ECM_MINE"; break;
case PARTICLE_SPARK :
type_string = @"PARTICLE_SPARK"; break;
case PARTICLE_FRAGBURST :
type_string = @"PARTICLE_FRAGBURST"; break;
case PARTICLE_BURST2 :
type_string = @"PARTICLE_BURST2"; break;
default :
type_string = @"UNKNOWN";
}
NSString* result = [[NSString alloc] initWithFormat:@"<ParticleEntity %d %@ ttl: %.3fs>", particle_type, type_string, duration - time_counter];
return [result autorelease];
}
- (BOOL) canCollide
{
switch (particle_type)
{
case PARTICLE_TEST :
case PARTICLE_LASER_BEAM_RED :
case PARTICLE_LASER_BEAM :
case PARTICLE_EXPLOSION :
case PARTICLE_SHOT_EXPIRED :
case PARTICLE_EXHAUST :
case PARTICLE_HYPERRING :
case PARTICLE_FLASHER :
case PARTICLE_MARKER :
case PARTICLE_ECM_MINE :
case PARTICLE_SPARK :
case PARTICLE_FRAGBURST :
case PARTICLE_BURST2 :
case PARTICLE_FLASH :
return NO;
break;
default :
return (time_counter > 0.05); // can't collide for the first .05s
break;
}
}
- (BOOL) checkCloseCollisionWith:(Entity *)other
{
if (particle_type == PARTICLE_ENERGY_MINE)
return YES;
if (other == [self owner])
return NO;
return !(other->isParticle);
}
- (void) setTexture:(NSString *) filename
{
if (filename)
{
if (textureNameString) [textureNameString release];
textureNameString = filename;
[textureNameString retain];
[self initialiseTexture: textureNameString];
}
}
- (void) setColor:(NSColor *) a_color
{
if (!a_color)
return;
NSColor *rgbColor = [a_color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
if (color) [color release];
color = [rgbColor retain];
color_fv[0] = [color redComponent];
color_fv[1] = [color greenComponent];
color_fv[2] = [color blueComponent];
}
- (void) setParticleType:(int) p_type
{
particle_type = p_type;
}
- (int) particleType
{
return particle_type;
}
- (void) setDuration:(double) dur
{
duration = dur;
time_counter = 0.0;
}
- (void) setSize:(NSSize) siz
{
size = siz;
collision_radius = sqrt (size.width * size.width + size.height * size.height);
no_draw_distance = collision_radius * collision_radius * NO_DRAW_DISTANCE_FACTOR * NO_DRAW_DISTANCE_FACTOR;
}
- (NSSize) size
{
return size;
}
- (void) initialiseTexture: (NSString *) name
{
if (universe)
{
texName = [[universe textureStore] getTextureNameFor:name];
}
}
- (void) update:(double) delta_t
{
// NSLog(@"DEBUG update for %@",self);
[super update:delta_t];
time_counter += delta_t;
if (universe)
{
switch (particle_type)
{
case PARTICLE_TEST :
case PARTICLE_SHOT_EXPIRED :
case PARTICLE_SHOT_YELLOW_PLASMA :
case PARTICLE_SPARK :
case PARTICLE_SHOT_GREEN_PLASMA :
case PARTICLE_MARKER :
case PARTICLE_FLASHER :
case PARTICLE_SHOT_PLASMA :
case PARTICLE_EXPLOSION :
case PARTICLE_FRAGBURST :
case PARTICLE_BURST2 :
case PARTICLE_FLASH :
{
Entity* player = [universe entityZero];
if (!texName)
[self initialiseTexture: textureNameString];
if (player)
{
q_rotation = player->q_rotation; // Really simple billboard routine
q_rotation.w = -q_rotation.w;
quaternion_into_gl_matrix(q_rotation, rotMatrix);
}
}
break;
}
switch (particle_type)
{
case PARTICLE_TEST :
alpha = (sin(time_counter) + 2.0) / 3.0;
break;
case PARTICLE_EXPLOSION :
[self updateExplosion:delta_t];
break;
case PARTICLE_HYPERRING :
[self updateHyperring:delta_t];
break;
case PARTICLE_LASER_BEAM_RED :
case PARTICLE_LASER_BEAM :
[self updateLaser:delta_t];
break;
case PARTICLE_EXHAUST :
[self updateExhaust2:delta_t];
break;
case PARTICLE_ECM_MINE :
[self updateECMMine:delta_t];
break;
case PARTICLE_ENERGY_MINE :
[self updateEnergyMine:delta_t];
break;
case PARTICLE_FLASHER :
[self updateFlasher:delta_t];
break;
case PARTICLE_SPARK :
[self updateSpark:delta_t];
break;
case PARTICLE_FRAGBURST :
[self updateFragburst:delta_t];
break;
case PARTICLE_BURST2 :
[self updateBurst2:delta_t];
break;
case PARTICLE_FLASH :
[self updateFlash:delta_t];
break;
case PARTICLE_SHOT_EXPIRED :
case PARTICLE_SHOT_YELLOW_PLASMA :
case PARTICLE_SHOT_GREEN_PLASMA :
case PARTICLE_MARKER :
case PARTICLE_SHOT_PLASMA :
default : // hoping to correct the multiplying-entities problem
[self updateShot:delta_t];
break;
}
}
}
- (void) updateExplosion:(double) delta_t
{
float diameter = (1.0 + time_counter)*64.0;
[self setSize:NSMakeSize(diameter, diameter)];
alpha = (duration - time_counter);
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateFlasher:(double) delta_t
{
// NSLog(@"DEBUG updating flasher %@",self);
alpha = 0.5 * sin(duration * PI * (time_counter + energy)) + 0.5;
}
- (void) updateECMMine:(double) delta_t
{
if (time_counter > activation_time)
{
// do ecm stuff
double radius = 0.5 * activation_time * SCANNER_MAX_RANGE;
if (radius > SCANNER_MAX_RANGE)
radius = SCANNER_MAX_RANGE;
NSArray* targets = [universe getEntitiesWithinRange:radius ofEntity:self];
if ([targets count] > 0)
{
int i;
for (i = 0; i < [targets count]; i++)
{
Entity *e2 = [targets objectAtIndex:i];
if (e2->isShip)
[[(ShipEntity *)e2 getAI] reactToMessage:@"ECM"];
}
}
activation_time += 0.5; // go off every half second
}
if (time_counter > duration) // until the timer runs out!
[universe removeEntity:self];
}
- (void) updateEnergyMine:(double) delta_t
{
// new billboard routine (working at last!)
Entity* player = [universe entityZero];
Vector v0 = position;
Vector p0 = (player)? player->position : make_vector(0,0,0);
v0.x -= p0.x; v0.y -= p0.y; v0.z -= p0.z; // vector from player to position
if (v0.x||v0.y||v0.z)
v0 = unit_vector(&v0);
else
v0.z = 1.0;
//equivalent of v_forward
Vector arb1;
if ((v0.x == 0.0)&&(v0.y == 0.0))
{
arb1.x = 1.0; arb1.y = 0.0; arb1.z = 0.0; // arbitrary axis - not aligned with v0
}
else
{
arb1.x = 0.0; arb1.y = 0.0; arb1.z = 1.0;
}
Vector v1 = cross_product( v0, arb1 ); // 90 degrees to (v0 x arb1)
//equivalent of v_right
Vector v2 = cross_product( v0, v1 ); // 90 degrees to (v0 x v1)
//equivalent of v_up
vectors_into_gl_matrix( v0, v1, v2, rotMatrix);
//
// end of new billboard routine
double tf = time_counter / duration;
double stf = tf * tf;
double expansion_speed = 0.0;
if (time_counter > 0)
expansion_speed = 240 + 10 / (tf * tf);
if (expansion_speed > 1000.0)
expansion_speed = 1000.0;
velocity.z = expansion_speed;
collision_radius += delta_t * expansion_speed; // expand
energy = 10000 - 9000 * tf; // 10000 -> 1000
alpha = 0.5 * ((0.025 / tf) + 1.0 - stf);
if (alpha > 1.0) alpha = 1.0;
color_fv[0] = 1.0 - 5.0 * tf;
if (color_fv[0] > 1.0) color_fv[0] = 1.0;
if (color_fv[0] < 0.0) color_fv[0] = 0.25 * tf * randf();
color_fv[1] = 1.0 - 5.0 * tf;
if (color_fv[1] > 1.0) color_fv[1] = 1.0;
if (color_fv[1] < 0.0) color_fv[1] = 0.0;
if ([collidingEntities count] > 0)
{
int i;
for (i = 0; i < [collidingEntities count]; i++)
{
Entity * e = (Entity *)[collidingEntities objectAtIndex:i];
[e takeEnergyDamage:energy from:self becauseOf:[self owner]];
}
}
if (time_counter > duration) // until the timer runs out!
[universe removeEntity:self];
}
- (void) updateShot:(double) delta_t
{
if ([collidingEntities count] > 0)
{
int i;
for (i = 0; i < [collidingEntities count]; i++)
{
Entity * e = (Entity *)[collidingEntities objectAtIndex:i];
if (e != [self owner])
{
// NSLog(@"DEBUG %@ taking damage from %@", e, [self owner]);
[e takeEnergyDamage:energy from:self becauseOf:[self owner]];
velocity.x = 0.0;
velocity.y = 0.0;
velocity.z = 0.0;
[self setColor:[NSColor redColor]];
[self setSize:NSMakeSize(64.0,64.0)];
duration = 2.0;
time_counter = 0.0;
particle_type = PARTICLE_EXPLOSION;
}
}
}
position.x += velocity.x * delta_t;
position.y += velocity.y * delta_t;
position.z += velocity.z * delta_t;
alpha = (duration - time_counter);
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateSpark:(double) delta_t
{
position.x += velocity.x * delta_t;
position.y += velocity.y * delta_t;
position.z += velocity.z * delta_t;
alpha = (duration - time_counter) / duration;
if (alpha < 0.0) alpha = 0.0;
if (alpha > 1.0) alpha = 1.0;
// fade towards transparent red
color_fv[0] = alpha * [color redComponent] + (1.0 - alpha) * 1.0;
color_fv[1] = alpha * [color greenComponent];// + (1.0 - alpha) * 0.0;
color_fv[2] = alpha * [color blueComponent];// + (1.0 - alpha) * 0.0;
// disappear eventually
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateLaser:(double) delta_t
{
position.x += velocity.x * delta_t;
position.y += velocity.y * delta_t;
position.z += velocity.z * delta_t;
alpha = (duration - time_counter) / PARTICLE_LASER_DURATION;
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateHyperring:(double) delta_t
{
position.x += velocity.x * delta_t;
position.y += velocity.y * delta_t;
position.z += velocity.z * delta_t;
alpha = (duration - time_counter) / PARTICLE_LASER_DURATION;
ring_inner_radius += delta_t * size.width * 1.1;
ring_outer_radius += delta_t * size.height;
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateFragburst:(double) delta_t
{
int i;
//
for (i = 0 ; i < n_vertices; i++)
{
GLfloat du = 0.5 + 0.03125 * (32 - i);
GLfloat alf = 1.0 - time_counter / du;
if (alf < 0.0) alf = 0.0;
if (alf > 1.0) alf = 1.0;
faces[i].normal.z = alf;
vertices[i].x += vertex_normal[i].x * delta_t;
vertices[i].y += vertex_normal[i].y * delta_t;
vertices[i].z += vertex_normal[i].z * delta_t;
}
// disappear eventually
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateBurst2:(double) delta_t
{
int i;
size.width = (1.0 + time_counter) * size.height; // current size vs starting size
//
GLfloat di = 1.0 / (n_vertices - 1);
for (i = 0 ; i < n_vertices; i++)
{
GLfloat du = duration * (0.5 + di * i);
GLfloat alf = 1.0 - time_counter / du;
if (alf < 0.0) alf = 0.0;
if (alf > 1.0) alf = 1.0;
// faces[i].green *= alf;
// faces[i].blue *= alf;
faces[i].normal.z = alf;
vertices[i].x += vertex_normal[i].x * delta_t;
vertices[i].y += vertex_normal[i].y * delta_t;
vertices[i].z += vertex_normal[i].z * delta_t;
}
// disappear eventually
if (time_counter > duration)
[universe removeEntity:self];
}
- (void) updateFlash:(double) delta_t
{
double tf = duration * 0.667;
double tf1 = duration - tf;
// scale up
float growth = 12000; // * duration / time_counter;
size.width += delta_t * growth;
size.height = size.width;
// fade up
if ((time_counter)&&(time_counter < tf))
alpha = time_counter/tf;
// fade out
if (time_counter > tf)
alpha = (duration - time_counter)/tf1;
// disappear eventually
if (time_counter > duration)
[universe removeEntity:self];
// NSLog(@"DEBUG *FLASH* time: %.2f size: %.2f alpha: %.2f", time_counter, size.width, alpha);
}
- (void) updateExhaust2:(double) delta_t
{
GLfloat ex_emissive[4] = {0.6, 0.8, 1.0, 0.9}; // pale blue
GLfloat s1[8] = { 0.0, 0.707, 1.0, 0.707, 0.0, -0.707, -1.0, -0.707};
GLfloat c1[8] = { 1.0, 0.707, 0.0, -0.707, -1.0, -0.707, 0.0, 0.707};
ShipEntity *ship =(ShipEntity *)[universe entityForUniversalID:owner];
if (!ship)
return;
Frame zero;
zero.q_rotation = ship->q_rotation;
int dam = [ship damage];
double flare_length = [ship speed_factor];
if (!flare_length) // don't draw if there's no fire!
return;
double flare_factor = flare_length * ex_emissive[3];
double red_factor = flare_length * ex_emissive[0] * (ranrot_rand() % 11) * 0.1; // random fluctuations
double green_factor = flare_length * ex_emissive[1];
if (flare_length > 1.0) // afterburner!
{
red_factor = 1.5;
flare_length = 1.0 + 0.25 * flare_length;
}
if ((ranrot_rand() % 50) < dam - 50) // flicker the damaged engines
red_factor = 0.0;
if ((ranrot_rand() % 40) < dam - 60)
green_factor = 0.0;
if ((ranrot_rand() % 25) < dam - 75)
flare_factor = 0.0;
if (flare_length < 0.1) flare_length = 0.1;
Vector currentPos = ship->position;
Vector master_i = vector_right_from_quaternion(ship->q_rotation);
Vector vi,vj,vk;
vi = master_i;
vj = vector_up_from_quaternion(ship->q_rotation);
vk = cross_product( vi, vj);
zero.position = make_vector( currentPos.x + vi.x * position.x + vj.x * position.y + vk.x * position.z,
currentPos.y + vi.y * position.x + vj.y * position.y + vk.y * position.z,
currentPos.z + vi.z * position.x + vj.z * position.y + vk.z * position.z);
GLfloat i01 = -0.03;// * flare_length;
GLfloat i04 = -0.12;// * flare_length;
GLfloat i06 = -0.25;// * flare_length;
GLfloat i08 = -0.32;// * flare_length;
GLfloat i10 = -0.40;// * flare_length;
Frame f01 = [self frameAtTime: i01 fromFrame: zero];
Frame f03 = [self frameAtTime: i04 fromFrame: zero];
Frame f06 = [self frameAtTime: i06 fromFrame: zero];
Frame f08 = [self frameAtTime: i08 fromFrame: zero];
Frame f10 = [self frameAtTime: i10 fromFrame: zero];
int ci = 0;
int iv = 0;
int i;
float r1;
//
ex_emissive[3] = flare_factor; // fade alpha towards rear of exhaust
ex_emissive[1] = green_factor; // diminish green part towards rear of exhaust
ex_emissive[0] = red_factor; // diminish red part towards rear of exhaust
verts[iv++] = f03.position.x;// + zero.k.x * flare_factor * 4.0;
verts[iv++] = f03.position.y;// + zero.k.y * flare_factor * 4.0;
verts[iv++] = f03.position.z;// + zero.k.z * flare_factor * 4.0;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
//
ex_emissive[3] = 0.9 * flare_factor; // fade alpha towards rear of exhaust
ex_emissive[1] = 0.9 * green_factor; // diminish green part towards rear of exhaust
ex_emissive[0] = 0.9 * red_factor; // diminish red part towards rear of exhaust
Vector k1 = f01.k;
Vector j1 = cross_product( master_i, k1);
Vector i1 = cross_product( j1, k1);
f01.position = make_vector(zero.position.x - vk.x, zero.position.y - vk.y, zero.position.z - vk.z);// 1m out from zero
// i1 = vi;
// j1 = vj; // initial vars
i1.x *= exhaustScale.x; i1.y *= exhaustScale.x; i1.z *= exhaustScale.x;
j1.x *= exhaustScale.y; j1.y *= exhaustScale.y; j1.z *= exhaustScale.y;
for (i = 0; i < 8; i++)
{
verts[iv++] = f01.position.x + s1[i] * i1.x + c1[i] * j1.x;
verts[iv++] = f01.position.y + s1[i] * i1.y + c1[i] * j1.y;
verts[iv++] = f01.position.z + s1[i] * i1.z + c1[i] * j1.z;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
}
//
ex_emissive[3] = 0.6 * flare_factor; // fade alpha towards rear of exhaust
ex_emissive[1] = 0.6 * green_factor; // diminish green part towards rear of exhaust
ex_emissive[0] = 0.6 * red_factor; // diminish red part towards rear of exhaust
k1 = f03.k;
j1 = cross_product( master_i, k1);
i1 = cross_product( j1, k1);
i1.x *= exhaustScale.x; i1.y *= exhaustScale.x; i1.z *= exhaustScale.x;
j1.x *= exhaustScale.y; j1.y *= exhaustScale.y; j1.z *= exhaustScale.y;
for (i = 0; i < 8; i++)
{
r1 = randf();
verts[iv++] = f03.position.x + s1[i] * i1.x + c1[i] * j1.x + r1 * k1.x;
verts[iv++] = f03.position.y + s1[i] * i1.y + c1[i] * j1.y + r1 * k1.y;
verts[iv++] = f03.position.z + s1[i] * i1.z + c1[i] * j1.z + r1 * k1.z;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
}
//
ex_emissive[3] = 0.4 * flare_factor; // fade alpha towards rear of exhaust
ex_emissive[1] = 0.4 * green_factor; // diminish green part towards rear of exhaust
ex_emissive[0] = 0.4 * red_factor; // diminish red part towards rear of exhaust
k1 = f06.k;
j1 = cross_product( master_i, k1);
i1 = cross_product( j1, k1);
i1.x *= 0.8 * exhaustScale.x; i1.y *= 0.8 * exhaustScale.x; i1.z *= 0.8 * exhaustScale.x;
j1.x *= 0.8 * exhaustScale.y; j1.y *= 0.8 * exhaustScale.y; j1.z *= 0.8 * exhaustScale.y;
for (i = 0; i < 8; i++)
{
r1 = randf();
verts[iv++] = f06.position.x + s1[i] * i1.x + c1[i] * j1.x + r1 * k1.x;
verts[iv++] = f06.position.y + s1[i] * i1.y + c1[i] * j1.y + r1 * k1.y;
verts[iv++] = f06.position.z + s1[i] * i1.z + c1[i] * j1.z + r1 * k1.z;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
}
//
ex_emissive[3] = 0.2 * flare_factor; // fade alpha towards rear of exhaust
ex_emissive[1] = 0.2 * green_factor; // diminish green part towards rear of exhaust
ex_emissive[0] = 0.2 * red_factor; // diminish red part towards rear of exhaust
k1 = f08.k;
j1 = cross_product( master_i, k1);
i1 = cross_product( j1, k1);
i1.x *= 0.5 * exhaustScale.x; i1.y *= 0.5 * exhaustScale.x; i1.z *= 0.5 * exhaustScale.x;
j1.x *= 0.5 * exhaustScale.y; j1.y *= 0.5 * exhaustScale.y; j1.z *= 0.5 * exhaustScale.y;
for (i = 0; i < 8; i++)
{
r1 = randf();
verts[iv++] = f08.position.x + s1[i] * i1.x + c1[i] * j1.x + r1 * k1.x;
verts[iv++] = f08.position.y + s1[i] * i1.y + c1[i] * j1.y + r1 * k1.y;
verts[iv++] = f08.position.z + s1[i] * i1.z + c1[i] * j1.z + r1 * k1.z;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
}
//
ex_emissive[3] = 0.0; // fade alpha towards rear of exhaust
ex_emissive[1] = 0.0; // diminish green part towards rear of exhaust
ex_emissive[0] = 0.0; // diminish red part towards rear of exhaust
verts[iv++] = f10.position.x;
verts[iv++] = f10.position.y;
verts[iv++] = f10.position.z;
exhaustBaseColors[ci++] = ex_emissive[0];
exhaustBaseColors[ci++] = ex_emissive[1];
exhaustBaseColors[ci++] = ex_emissive[2];
exhaustBaseColors[ci++] = ex_emissive[3];
}
- (void) drawEntity:(BOOL) immediate :(BOOL) translucent;
{
NSString* debug_type = @"PLAIN";
if (!universe)
return;
if ([universe breakPatternHide])
return; // DON'T DRAW DURING BREAK PATTERN
if ((particle_type == PARTICLE_FLASHER)&&(zero_distance > no_draw_distance)) return; // TOO FAR AWAY TO SEE
if (translucent)
{
switch (particle_type)
{
case PARTICLE_LASER_BEAM_RED :
[self drawLaser];
debug_type = @"PARTICLE_LASER_BEAM_RED";
break;
case PARTICLE_EXHAUST :
[self drawExhaust2];
debug_type = @"PARTICLE_EXHAUST";
break;
case PARTICLE_HYPERRING :
[self drawHyperring];
debug_type = @"PARTICLE_HYPERRING";
break;
case PARTICLE_ECM_MINE :
// not a visible entity
debug_type = @"PARTICLE_ECM_MINE";
break;
case PARTICLE_ENERGY_MINE :
[self drawEnergyMine];
debug_type = @"PARTICLE_ENERGY_MINE";
break;
case PARTICLE_FRAGBURST :
[self drawFragburst];
debug_type = @"PARTICLE_FRAGBURST";
break;
case PARTICLE_BURST2 :
[self drawBurst2];
debug_type = @"PARTICLE_BURST2";
break;
case PARTICLE_FLASH :
debug_type = @"PARTICLE_FLASH";
[self drawParticle];
break;
default :
[self drawParticle];
break;
}
}
checkGLErrors([NSString stringWithFormat:@"ParticleEntity after drawing %@ %@", self, debug_type]);
}
- (void) drawSubEntity:(BOOL) immediate :(BOOL) translucent
{
// NSLog(@"DEBUG drawing subentity %@ for %@", self, [universe entityForUniversalID:owner]);
if (particle_type == PARTICLE_EXHAUST)
{
if (translucent)
[self drawExhaust2];
return;
}
Entity* my_owner = [universe entityForUniversalID:owner];
if (my_owner)
{
// this test provides an opportunity to do simple LoD culling
//
zero_distance = my_owner->zero_distance;
if (zero_distance > no_draw_distance)
return; // TOO FAR AWAY TO DRAW
}
if ((particle_type == PARTICLE_FLASHER)&&(status != STATUS_INACTIVE))
{
Vector abspos = position; // in control of it's own orientation
Entity* father = my_owner;
GLfloat* r_mat = [father rotationMatrix];
while (father)
{
mult_vector_gl_matrix(&abspos, r_mat);
Vector pos = father->position;
abspos.x += pos.x; abspos.y += pos.y; abspos.z += pos.z;
if ([father owner] != father)
father = [father owner];
else
father = nil;
r_mat = [father rotationMatrix];
}
glPopMatrix(); // restore zero!
glPushMatrix();
// position and orientation is absolute
glTranslatef( abspos.x, abspos.y, abspos.z);
glMultMatrixf(rotMatrix);
[self drawEntity:immediate :translucent];
}
}
- (void) drawParticle
{
int viewdir;
double xx = size.width / 2.0;
double yy = size.height / 2.0;
if (alpha < 0.0)
alpha = 0.0; // clamp the alpha value
if (alpha > 1.0)
alpha = 1.0; // clamp the alpha value
color_fv[3] = alpha;
// movies:
// draw data required xx, yy, color_fv[0], color_fv[1], color_fv[2]
glEnable(GL_TEXTURE_2D);
glPushMatrix();
if (particle_type == PARTICLE_FLASHER)
glColor4f( color_fv[0], color_fv[1], color_fv[2], alpha);
else
glColor4f(1.0, 1.0, 1.0, alpha);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color_fv);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glBindTexture(GL_TEXTURE_2D, texName);
glBegin(GL_QUADS);
viewdir = [universe viewDir];
switch (viewdir)
{
case VIEW_AFT :
glTexCoord2f(0.0, 1.0);
glVertex3f(xx, -yy, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(-xx, -yy, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(-xx, yy, 0);
glTexCoord2f(0.0, 0.0);
glVertex3f(xx, yy, 0);
break;
case VIEW_STARBOARD :
glTexCoord2f(0.0, 1.0);
glVertex3f(0, -yy, xx);
glTexCoord2f(1.0, 1.0);
glVertex3f(0, -yy, -xx);
glTexCoord2f(1.0, 0.0);
glVertex3f(0, yy, -xx);
glTexCoord2f(0.0, 0.0);
glVertex3f(0, yy, xx);
break;
case VIEW_PORT :
glTexCoord2f(0.0, 1.0);
glVertex3f(0, -yy, -xx);
glTexCoord2f(1.0, 1.0);
glVertex3f(0, -yy, xx);
glTexCoord2f(1.0, 0.0);
glVertex3f(0, yy, xx);
glTexCoord2f(0.0, 0.0);
glVertex3f(0, yy, -xx);
break;
default :
glTexCoord2f(0.0, 1.0);
glVertex3f(-xx, -yy, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(xx, -yy, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(xx, yy, 0);
glTexCoord2f(0.0, 0.0);
glVertex3f(-xx, yy, 0);
break;
}
glEnd();
glPopMatrix();
}
- (void) drawLaser
{
color_fv[3] = 0.75; // set alpha
glDisable(GL_CULL_FACE); // face culling
// movies:
// draw data required collision_radius, color_fv[0], color_fv[1], color_fv[2]
glDisable(GL_TEXTURE_2D);
glColor4fv(color_fv);
glBegin(GL_QUADS);
glVertex3f(0.25, 0.0, 0.0);
glVertex3f(0.25, 0.0, collision_radius);
glVertex3f(-0.25, 0.0, collision_radius);
glVertex3f(-0.25, 0.0, 0.0);
glVertex3f(0.0, 0.25, 0.0);
glVertex3f(0.0, 0.25, collision_radius);
glVertex3f(0.0, -0.25, collision_radius);
glVertex3f(0.0, -0.25, 0.0);
glEnd();
glEnable(GL_CULL_FACE); // face culling
}
- (void) drawExhaust2
{
GLuint tfan1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 1}; // initial fan 0..9
GLuint qstrip1[18] = { 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16, 1, 9}; // first quadstrip 10..27
GLuint qstrip2[18] = { 9, 17, 10, 18, 11, 19, 12, 20, 13, 21, 14, 22, 15, 23, 16, 24, 9, 17}; // second quadstrip 28..45
GLuint qstrip3[18] = { 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 22, 30, 23, 31, 24, 32, 17, 25}; // third quadstrip 46..63
GLuint tfan2[10] = { 33, 25, 26, 27, 28, 29, 30, 31, 32, 25}; // final fan 64..73
ShipEntity *ship =(ShipEntity *)[universe entityForUniversalID:owner];
if (!ship)
return;
double flare_length = [ship speed_factor];
if (!flare_length) // don't draw if there's no fire!
return;
glPopMatrix(); // restore absolute positioning
glPushMatrix(); // restore absolute positioning
glDisable( GL_TEXTURE_2D);
glDisable( GL_CULL_FACE); // face culling
glShadeModel( GL_SMOOTH);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer( 3, GL_FLOAT, 0, verts);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer( 4, GL_FLOAT, 0, exhaustBaseColors);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_EDGE_FLAG_ARRAY);
//
glDrawElements( GL_TRIANGLE_FAN, 10, GL_UNSIGNED_INT, tfan1);
glDrawElements( GL_QUAD_STRIP, 18, GL_UNSIGNED_INT, qstrip1);
glDrawElements( GL_QUAD_STRIP, 18, GL_UNSIGNED_INT, qstrip2);
glDrawElements( GL_QUAD_STRIP, 18, GL_UNSIGNED_INT, qstrip3);
glDrawElements( GL_TRIANGLE_FAN, 10, GL_UNSIGNED_INT, tfan2);
glEnable( GL_CULL_FACE); // face culling
glEnable( GL_TEXTURE_2D);
}
- (void) drawHyperring
{
int i;
GLfloat aleph = (alpha < 2.0) ? alpha*0.5 : 1.0;
GLfloat ex_em_hi[4] = {0.6, 0.8, 1.0, aleph}; // pale blue
GLfloat ex_em_lo[4] = {0.2, 0.0, 1.0, 0.0}; // purplish-blue-black
glPushMatrix();
glDisable(GL_CULL_FACE); // face culling
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
//NSLog(@"... drawing hyppering inner_radius:%.1f alpha:%.2f", ring_inner_radius, aleph);
// movies:
// draw data required ring_inner_radius, ring_outer_radius
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i < 65; i++)
{
glColor4fv(ex_em_lo);
glVertex3f( ring_inner_radius*circleVertex[i].x, ring_inner_radius*circleVertex[i].y, ring_inner_radius*circleVertex[i].z );
glColor4fv(ex_em_hi);
glVertex3f( ring_outer_radius*circleVertex[i].x, ring_outer_radius*circleVertex[i].y, ring_outer_radius*circleVertex[i].z );
}
glEnd();
glEnable(GL_CULL_FACE); // face culling
glPopMatrix();
}
- (void) drawEnergyMine
{
double szd = sqrt(zero_distance);
color_fv[3] = alpha; // set alpha
glDisable(GL_CULL_FACE); // face culling
glDisable(GL_TEXTURE_2D);
int step = 4;
glColor4fv( color_fv);
glBegin(GL_TRIANGLE_FAN);
//
drawBallVertices( collision_radius, step, szd);
//
glEnd();
// NSLog(@"DEBUG ENERGY BOMB radius: %.3f, expansion: %.3f, color: [ %.3f, %.3f, %.3f, %.3f]", collision_radius, velocity.z, color_fv[0], color_fv[1], color_fv[2], alpha);
glEnable(GL_CULL_FACE); // face culling
}
- (void) drawFragburst
{
int i;
int viewdir = universe->viewDirection;
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, texName);
glPushMatrix();
glBegin(GL_QUADS);
for (i = 0; i < n_vertices; i++)
{
glColor4f( faces[i].red, faces[i].green, faces[i].blue, faces[i].normal.z);
drawQuadForView( viewdir, vertices[i].x, vertices[i].y, vertices[i].z, faces[i].normal.x, faces[i].normal.x);
}
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
- (void) drawBurst2
{
int i;
int viewdir = universe->viewDirection;
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, texName);
glPushMatrix();
glBegin(GL_QUADS);
for (i = 0; i < n_vertices; i++)
{
glColor4f( faces[i].red, faces[i].green, faces[i].blue, faces[i].normal.z);
drawQuadForView( viewdir, vertices[i].x, vertices[i].y, vertices[i].z, size.width, size.width);
}
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
//- (void) drawFlash
//{
//
//// NSLog(@"DEBUG *FLASH* being drawn at [ %.2f, %.2f, %.2f] size %.2f", position.x, position.y, position.z, size.width);
//
// alpha = color_fv[3];
// [self drawParticle];
//}
void drawQuadForView(int viewdir, GLfloat x, GLfloat y, GLfloat z, GLfloat xx, GLfloat yy)
{
switch (viewdir)
{
case VIEW_AFT :
glTexCoord2f(0.0, 1.0); glVertex3f(x+xx, y-yy, z);
glTexCoord2f(1.0, 1.0); glVertex3f(x-xx, y-yy, z);
glTexCoord2f(1.0, 0.0); glVertex3f(x-xx, y+yy, z);
glTexCoord2f(0.0, 0.0); glVertex3f(x+xx, y+yy, z);
break;
case VIEW_STARBOARD :
glTexCoord2f(0.0, 1.0); glVertex3f(x, y-yy, z+xx);
glTexCoord2f(1.0, 1.0); glVertex3f(x, y-yy, z-xx);
glTexCoord2f(1.0, 0.0); glVertex3f(x, y+yy, z-xx);
glTexCoord2f(0.0, 0.0); glVertex3f(x, y+yy, z+xx);
break;
case VIEW_PORT :
glTexCoord2f(0.0, 1.0); glVertex3f(x, y-yy, z-xx);
glTexCoord2f(1.0, 1.0); glVertex3f(x, y-yy, z+xx);
glTexCoord2f(1.0, 0.0); glVertex3f(x, y+yy, z+xx);
glTexCoord2f(0.0, 0.0); glVertex3f(x, y+yy, z-xx);
break;
default :
glTexCoord2f(0.0, 1.0); glVertex3f(x-xx, y-yy, z);
glTexCoord2f(1.0, 1.0); glVertex3f(x+xx, y-yy, z);
glTexCoord2f(1.0, 0.0); glVertex3f(x+xx, y+yy, z);
glTexCoord2f(0.0, 0.0); glVertex3f(x-xx, y+yy, z);
break;
}
}
@end