Line data Source code
1 0 : /*
2 :
3 : OOLaserShotEntity.m
4 :
5 :
6 : Oolite
7 : Copyright (C) 2004-2013 Giles C Williams and contributors
8 :
9 : This program is free software; you can redistribute it and/or
10 : modify it under the terms of the GNU General Public License
11 : as published by the Free Software Foundation; either version 2
12 : of the License, or (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 : MA 02110-1301, USA.
23 :
24 : */
25 :
26 : #import "OOLaserShotEntity.h"
27 : #import "Universe.h"
28 : #import "ShipEntity.h"
29 : #import "OOMacroOpenGL.h"
30 :
31 : #import "OOTexture.h"
32 : #import "OOGraphicsResetManager.h"
33 :
34 : #import "MyOpenGLView.h"
35 :
36 :
37 0 : #define kLaserDuration (0.09) // seconds
38 :
39 : // Default colour
40 0 : #define kLaserRed (1.0f)
41 0 : #define kLaserGreen (0.0f)
42 0 : #define kLaserBlue (0.0f)
43 :
44 : // Brightness - set to 1.0 for legacy laser appearance
45 0 : #define kLaserBrightness (5.0f)
46 :
47 : // Constant alpha
48 0 : #define kLaserAlpha (0.45f / kLaserBrightness)
49 :
50 0 : #define kLaserCoreWidth (0.4f)
51 0 : #define kLaserFlareWidth (1.8f)
52 0 : #define kLaserHalfWidth (3.6f)
53 :
54 0 : static OOTexture *sShotTexture = nil;
55 0 : static OOTexture *sShotTexture2 = nil;
56 :
57 : @implementation OOLaserShotEntity
58 :
59 0 : - (instancetype) initLaserFromShip:(ShipEntity *)srcEntity direction:(OOWeaponFacing)direction offset:(Vector)offset
60 : {
61 : if (!(self = [super init])) return nil;
62 :
63 : ShipEntity *ship = [srcEntity rootShipEntity];
64 : Vector middle = OOBoundingBoxCenter([srcEntity boundingBox]);
65 :
66 : NSCParameterAssert([srcEntity isShip] && [ship isShip]);
67 :
68 : [self setStatus:STATUS_EFFECT];
69 :
70 : if (ship == srcEntity)
71 : {
72 : // main laser offset
73 : [self setPosition:HPvector_add([ship position], vectorToHPVector(OOVectorMultiplyMatrix(offset, [ship drawRotationMatrix])))];
74 : }
75 : else
76 : {
77 : // subentity laser
78 : [self setPosition:[srcEntity absolutePositionForSubentityOffset:vectorToHPVector(middle)]];
79 : }
80 :
81 : Quaternion q = kIdentityQuaternion;
82 : Vector q_up = vector_up_from_quaternion(q);
83 : Quaternion q0 = [ship normalOrientation];
84 : velocity = vector_multiply_scalar(vector_forward_from_quaternion(q0), [ship flightSpeed]);
85 :
86 : switch (direction)
87 : {
88 : case WEAPON_FACING_NONE:
89 : case WEAPON_FACING_FORWARD:
90 : break;
91 :
92 : case WEAPON_FACING_AFT:
93 : quaternion_rotate_about_axis(&q, q_up, M_PI);
94 : break;
95 :
96 : case WEAPON_FACING_PORT:
97 : quaternion_rotate_about_axis(&q, q_up, M_PI/2.0);
98 : break;
99 :
100 : case WEAPON_FACING_STARBOARD:
101 : quaternion_rotate_about_axis(&q, q_up, -M_PI/2.0);
102 : break;
103 : }
104 :
105 : [self setOrientation:quaternion_multiply(q,q0)];
106 : [self setOwner:ship];
107 : [self setRange:[srcEntity weaponRange]];
108 : _lifetime = kLaserDuration;
109 :
110 : _color[0] = kLaserRed/3.0;
111 : _color[1] = kLaserGreen/3.0;
112 : _color[2] = kLaserBlue/3.0;
113 : _color[3] = kLaserAlpha;
114 :
115 : _offset = (ship == srcEntity) ? offset : middle;
116 : _relOrientation = q;
117 :
118 : return self;
119 : }
120 :
121 :
122 : + (instancetype) laserFromShip:(ShipEntity *)ship direction:(OOWeaponFacing)direction offset:(Vector)offset
123 : {
124 : return [[[self alloc] initLaserFromShip:ship direction:direction offset:offset] autorelease];
125 : }
126 :
127 :
128 0 : - (void) dealloc
129 : {
130 : [self setColor:nil];
131 :
132 : [super dealloc];
133 : }
134 :
135 :
136 0 : - (NSString *) descriptionComponents
137 : {
138 : return [NSString stringWithFormat:@"ttl: %.3fs - %@ orientation %@", _lifetime, [super descriptionComponents], QuaternionDescription([self orientation])];
139 : }
140 :
141 :
142 : - (void) setColor:(OOColor *)color
143 : {
144 : _color[0] = kLaserBrightness * [color redComponent]/3.0;
145 : _color[1] = kLaserBrightness * [color greenComponent]/3.0;
146 : _color[2] = kLaserBrightness * [color blueComponent]/3.0;
147 : // Ignore alpha; _color[3] is constant.
148 : }
149 :
150 :
151 : - (void) setRange:(GLfloat)range
152 : {
153 : _range = range;
154 : [self setCollisionRadius:range];
155 : }
156 :
157 :
158 0 : - (void) update:(OOTimeDelta)delta_t
159 : {
160 : [super update:delta_t];
161 : _lifetime -= delta_t;
162 : ShipEntity *ship = [self owner];
163 :
164 : if ([ship isPlayer])
165 : {
166 : /*
167 : Reposition this shot accurately. This overrides integration over
168 : velocity in -[Entity update:], which is considered sufficient for
169 : NPC ships.
170 : */
171 : [self setPosition:HPvector_add([ship position], vectorToHPVector(OOVectorMultiplyMatrix(_offset, [ship drawRotationMatrix])))];
172 : [self setOrientation:quaternion_multiply(_relOrientation, [ship normalOrientation])];
173 : }
174 :
175 : if (_lifetime < 0)
176 : {
177 : [UNIVERSE removeEntity:self];
178 : }
179 : }
180 :
181 :
182 0 : static const GLfloat kLaserVertices[] =
183 : {
184 : 1.0f, 0.0f, 0.0f,
185 : 1.0f, 0.0f, 1.0f,
186 : -1.0f, 0.0f, 1.0f,
187 : -1.0f, 0.0f, 0.0f,
188 :
189 : 0.0f, 1.0f, 0.0f,
190 : 0.0f, 1.0f, 1.0f,
191 : 0.0f, -1.0f, 1.0f,
192 : 0.0f, -1.0f, 0.0f,
193 : };
194 :
195 :
196 0 : - (void) drawImmediate:(bool)immediate translucent:(bool)translucent
197 : {
198 : if (!translucent || [UNIVERSE breakPatternHide]) return;
199 :
200 : OO_ENTER_OPENGL();
201 : OOSetOpenGLState(OPENGL_STATE_ADDITIVE_BLENDING);
202 :
203 :
204 : /* FIXME: spread damage across the lifetime of the shot,
205 : hurting whatever is hit in a given frame.
206 : -- Ahruman 2011-01-31
207 : */
208 : OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
209 : OOGL(glEnable(GL_TEXTURE_2D));
210 : OOGLPushModelView();
211 :
212 : OOGLScaleModelView(make_vector(kLaserHalfWidth, kLaserHalfWidth, _range));
213 : [[self texture1] apply];
214 : GLfloat s = sinf([UNIVERSE getTime]);
215 : GLfloat phase = s*(_range/200.0f);
216 : GLfloat phase2 = (1.0f+s)*(_range/200.0f);
217 : GLfloat phase3 = -s*(_range/500.0f);
218 : GLfloat phase4 = -(1.0f+s)*(_range/500.0f);
219 :
220 : GLfloat laserTexCoords[] =
221 : {
222 : 0.0f, phase, 0.0f, phase2, 1.0f, phase2, 1.0f, phase,
223 :
224 : 0.0f, phase, 0.0f, phase2, 1.0f, phase2, 1.0f, phase
225 : };
226 : GLfloat laserTexCoords2[] =
227 : {
228 : 0.0f, phase3, 0.0f, phase4, 1.0f, phase4, 1.0f, phase3,
229 :
230 : 0.0f, phase3, 0.0f, phase4, 1.0f, phase4, 1.0f, phase3
231 : };
232 :
233 : OOGL(glColor4fv(_color));
234 : glVertexPointer(3, GL_FLOAT, 0, kLaserVertices);
235 : glTexCoordPointer(2, GL_FLOAT, 0, laserTexCoords2);
236 : glDrawArrays(GL_QUADS, 0, 8);
237 :
238 : OOGLScaleModelView(make_vector(kLaserCoreWidth / kLaserHalfWidth, kLaserCoreWidth / kLaserHalfWidth, 1.0));
239 : OOGL(glColor4f(kLaserBrightness,kLaserBrightness,kLaserBrightness,0.9));
240 : glDrawArrays(GL_QUADS, 0, 8);
241 :
242 : [[self texture2] apply];
243 : OOGLScaleModelView(make_vector(kLaserFlareWidth / kLaserCoreWidth, kLaserFlareWidth / kLaserCoreWidth, 1.0));
244 : OOGL(glColor4f(_color[0],_color[1],_color[2],0.9));
245 : glTexCoordPointer(2, GL_FLOAT, 0, laserTexCoords);
246 : glDrawArrays(GL_QUADS, 0, 8);
247 :
248 : OOGLPopModelView();
249 : OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
250 : OOGL(glDisable(GL_TEXTURE_2D));
251 :
252 : OOVerifyOpenGLState();
253 : OOCheckOpenGLErrors(@"OOLaserShotEntity after drawing %@", self);
254 : }
255 :
256 :
257 0 : - (BOOL) isEffect
258 : {
259 : return YES;
260 : }
261 :
262 :
263 0 : - (BOOL) canCollide
264 : {
265 : return NO;
266 : }
267 :
268 : - (OOTexture *) texture1
269 : {
270 : return [OOLaserShotEntity outerTexture];
271 : }
272 :
273 :
274 : - (OOTexture *) texture2
275 : {
276 : return [OOLaserShotEntity innerTexture];
277 : }
278 :
279 :
280 : + (void) setUpTexture
281 : {
282 : if (sShotTexture == nil)
283 : {
284 : sShotTexture = [[OOTexture textureWithName:@"oolite-laser-blur.png"
285 : inFolder:@"Textures"
286 : options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask | kOOTextureRepeatT
287 : anisotropy:kOOTextureDefaultAnisotropy / 2.0
288 : lodBias:0.0] retain];
289 : [[OOGraphicsResetManager sharedManager] registerClient:(id<OOGraphicsResetClient>)[OOLaserShotEntity class]];
290 :
291 : sShotTexture2 = [[OOTexture textureWithName:@"oolite-laser-blur2.png"
292 : inFolder:@"Textures"
293 : options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask | kOOTextureRepeatT
294 : anisotropy:kOOTextureDefaultAnisotropy / 2.0
295 : lodBias:0.0] retain];
296 : }
297 : }
298 :
299 :
300 : + (OOTexture *) innerTexture
301 : {
302 : if (sShotTexture2 == nil) [self setUpTexture];
303 : return sShotTexture2;
304 : }
305 :
306 :
307 : + (OOTexture *) outerTexture
308 : {
309 : if (sShotTexture == nil) [self setUpTexture];
310 : return sShotTexture;
311 : }
312 :
313 :
314 0 : + (void) resetGraphicsState
315 : {
316 : [sShotTexture release];
317 : sShotTexture = nil;
318 : [sShotTexture2 release];
319 : sShotTexture2 = nil;
320 : }
321 :
322 :
323 : @end
324 :
325 :
|