Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
 
19
*/
20
// r_sprite.c
21
 
22
#include "quakedef.h"
23
#include "r_local.h"
24
 
25
static int				clip_current;
26
static vec5_t			clip_verts[2][MAXWORKINGVERTS];
27
static int				sprite_width, sprite_height;
28
 
29
spritedesc_t			r_spritedesc;
30
 
31
 
32
/*
33
================
34
R_RotateSprite
35
================
36
*/
37
void R_RotateSprite (float beamlength)
38
{
39
	vec3_t	vec;
40
 
41
	if (beamlength == 0.0)
42
		return;
43
 
44
	VectorScale (r_spritedesc.vpn, -beamlength, vec);
45
	VectorAdd (r_entorigin, vec, r_entorigin);
46
	VectorSubtract (modelorg, vec, modelorg);
47
}
48
 
49
 
50
/*
51
=============
52
R_ClipSpriteFace
53
 
54
Clips the winding at clip_verts[clip_current] and changes clip_current
55
Throws out the back side
56
==============
57
*/
58
int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
59
{
60
	int		i, outcount;
61
	float	dists[MAXWORKINGVERTS+1];
62
	float	frac, clipdist, *pclipnormal;
63
	float	*in, *instep, *outstep, *vert2;
64
 
65
	clipdist = pclipplane->dist;
66
	pclipnormal = pclipplane->normal;
67
 
68
// calc dists
69
	if (clip_current)
70
	{
71
		in = clip_verts[1][0];
72
		outstep = clip_verts[0][0];
73
		clip_current = 0;
74
	}
75
	else
76
	{
77
		in = clip_verts[0][0];
78
		outstep = clip_verts[1][0];
79
		clip_current = 1;
80
	}
81
 
82
	instep = in;
83
	for (i=0 ; i
84
	{
85
		dists[i] = DotProduct (instep, pclipnormal) - clipdist;
86
	}
87
 
88
// handle wraparound case
89
	dists[nump] = dists[0];
90
	Q_memcpy (instep, in, sizeof (vec5_t));
91
 
92
 
93
// clip the winding
94
	instep = in;
95
	outcount = 0;
96
 
97
	for (i=0 ; i
98
	{
99
		if (dists[i] >= 0)
100
		{
101
			Q_memcpy (outstep, instep, sizeof (vec5_t));
102
			outstep += sizeof (vec5_t) / sizeof (float);
103
			outcount++;
104
		}
105
 
106
		if (dists[i] == 0 || dists[i+1] == 0)
107
			continue;
108
 
109
		if ( (dists[i] > 0) == (dists[i+1] > 0) )
110
			continue;
111
 
112
	// split it into a new vertex
113
		frac = dists[i] / (dists[i] - dists[i+1]);
114
 
115
		vert2 = instep + sizeof (vec5_t) / sizeof (float);
116
 
117
		outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
118
		outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
119
		outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
120
		outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
121
		outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
122
 
123
		outstep += sizeof (vec5_t) / sizeof (float);
124
		outcount++;
125
	}
126
 
127
	return outcount;
128
}
129
 
130
 
131
/*
132
================
133
R_SetupAndDrawSprite
134
================
135
*/
136
void R_SetupAndDrawSprite ()
137
{
138
	int			i, nump;
139
	float		dot, scale, *pv;
140
	vec5_t		*pverts;
141
	vec3_t		left, up, right, down, transformed, local;
142
	emitpoint_t	outverts[MAXWORKINGVERTS+1], *pout;
143
 
144
	dot = DotProduct (r_spritedesc.vpn, modelorg);
145
 
146
// backface cull
147
	if (dot >= 0)
148
		return;
149
 
150
// build the sprite poster in worldspace
151
	VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
152
	VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
153
	VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
154
	VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
155
 
156
	pverts = clip_verts[0];
157
 
158
	pverts[0][0] = r_entorigin[0] + up[0] + left[0];
159
	pverts[0][1] = r_entorigin[1] + up[1] + left[1];
160
	pverts[0][2] = r_entorigin[2] + up[2] + left[2];
161
	pverts[0][3] = 0;
162
	pverts[0][4] = 0;
163
 
164
	pverts[1][0] = r_entorigin[0] + up[0] + right[0];
165
	pverts[1][1] = r_entorigin[1] + up[1] + right[1];
166
	pverts[1][2] = r_entorigin[2] + up[2] + right[2];
167
	pverts[1][3] = sprite_width;
168
	pverts[1][4] = 0;
169
 
170
	pverts[2][0] = r_entorigin[0] + down[0] + right[0];
171
	pverts[2][1] = r_entorigin[1] + down[1] + right[1];
172
	pverts[2][2] = r_entorigin[2] + down[2] + right[2];
173
	pverts[2][3] = sprite_width;
174
	pverts[2][4] = sprite_height;
175
 
176
	pverts[3][0] = r_entorigin[0] + down[0] + left[0];
177
	pverts[3][1] = r_entorigin[1] + down[1] + left[1];
178
	pverts[3][2] = r_entorigin[2] + down[2] + left[2];
179
	pverts[3][3] = 0;
180
	pverts[3][4] = sprite_height;
181
 
182
// clip to the frustum in worldspace
183
	nump = 4;
184
	clip_current = 0;
185
 
186
	for (i=0 ; i<4 ; i++)
187
	{
188
		nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
189
		if (nump < 3)
190
			return;
191
		if (nump >= MAXWORKINGVERTS)
192
			Sys_Error("R_SetupAndDrawSprite: too many points");
193
	}
194
 
195
// transform vertices into viewspace and project
196
	pv = &clip_verts[clip_current][0][0];
197
	r_spritedesc.nearzi = -999999;
198
 
199
	for (i=0 ; i
200
	{
201
		VectorSubtract (pv, r_origin, local);
202
		TransformVector (local, transformed);
203
 
204
		if (transformed[2] < NEAR_CLIP)
205
			transformed[2] = NEAR_CLIP;
206
 
207
		pout = &outverts[i];
208
		pout->zi = 1.0 / transformed[2];
209
		if (pout->zi > r_spritedesc.nearzi)
210
			r_spritedesc.nearzi = pout->zi;
211
 
212
		pout->s = pv[3];
213
		pout->t = pv[4];
214
 
215
		scale = xscale * pout->zi;
216
		pout->u = (xcenter + scale * transformed[0]);
217
 
218
		scale = yscale * pout->zi;
219
		pout->v = (ycenter - scale * transformed[1]);
220
 
221
		pv += sizeof (vec5_t) / sizeof (*pv);
222
	}
223
 
224
// draw it
225
	r_spritedesc.nump = nump;
226
	r_spritedesc.pverts = outverts;
227
	D_DrawSprite ();
228
}
229
 
230
 
231
/*
232
================
233
R_GetSpriteframe
234
================
235
*/
236
mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
237
{
238
	mspritegroup_t	*pspritegroup;
239
	mspriteframe_t	*pspriteframe;
240
	int				i, numframes, frame;
241
	float			*pintervals, fullinterval, targettime, time;
242
 
243
	frame = currententity->frame;
244
 
245
	if ((frame >= psprite->numframes) || (frame < 0))
246
	{
247
		Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
248
		frame = 0;
249
	}
250
 
251
	if (psprite->frames[frame].type == SPR_SINGLE)
252
	{
253
		pspriteframe = psprite->frames[frame].frameptr;
254
	}
255
	else
256
	{
257
		pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
258
		pintervals = pspritegroup->intervals;
259
		numframes = pspritegroup->numframes;
260
		fullinterval = pintervals[numframes-1];
261
 
262
		time = cl.time + currententity->syncbase;
263
 
264
	// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
265
	// are positive, so we don't have to worry about division by 0
266
		targettime = time - ((int)(time / fullinterval)) * fullinterval;
267
 
268
		for (i=0 ; i<(numframes-1) ; i++)
269
		{
270
			if (pintervals[i] > targettime)
271
				break;
272
		}
273
 
274
		pspriteframe = pspritegroup->frames[i];
275
	}
276
 
277
	return pspriteframe;
278
}
279
 
280
 
281
/*
282
================
283
R_DrawSprite
284
================
285
*/
286
void R_DrawSprite (void)
287
{
288
	int				i;
289
	msprite_t		*psprite;
290
	vec3_t			tvec;
291
	float			dot, angle, sr, cr;
292
 
293
	psprite = currententity->model->cache.data;
294
 
295
	r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
296
 
297
	sprite_width = r_spritedesc.pspriteframe->width;
298
	sprite_height = r_spritedesc.pspriteframe->height;
299
 
300
// TODO: make this caller-selectable
301
	if (psprite->type == SPR_FACING_UPRIGHT)
302
	{
303
	// generate the sprite's axes, with vup straight up in worldspace, and
304
	// r_spritedesc.vright perpendicular to modelorg.
305
	// This will not work if the view direction is very close to straight up or
306
	// down, because the cross product will be between two nearly parallel
307
	// vectors and starts to approach an undefined state, so we don't draw if
308
	// the two vectors are less than 1 degree apart
309
		tvec[0] = -modelorg[0];
310
		tvec[1] = -modelorg[1];
311
		tvec[2] = -modelorg[2];
312
		VectorNormalize (tvec);
313
		dot = tvec[2];	// same as DotProduct (tvec, r_spritedesc.vup) because
314
						//  r_spritedesc.vup is 0, 0, 1
315
		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
316
			return;
317
		r_spritedesc.vup[0] = 0;
318
		r_spritedesc.vup[1] = 0;
319
		r_spritedesc.vup[2] = 1;
320
		r_spritedesc.vright[0] = tvec[1];
321
								// CrossProduct(r_spritedesc.vup, -modelorg,
322
		r_spritedesc.vright[1] = -tvec[0];
323
								//              r_spritedesc.vright)
324
		r_spritedesc.vright[2] = 0;
325
		VectorNormalize (r_spritedesc.vright);
326
		r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
327
		r_spritedesc.vpn[1] = r_spritedesc.vright[0];
328
		r_spritedesc.vpn[2] = 0;
329
					// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
330
					//  r_spritedesc.vpn)
331
	}
332
	else if (psprite->type == SPR_VP_PARALLEL)
333
	{
334
	// generate the sprite's axes, completely parallel to the viewplane. There
335
	// are no problem situations, because the sprite is always in the same
336
	// position relative to the viewer
337
		for (i=0 ; i<3 ; i++)
338
		{
339
			r_spritedesc.vup[i] = vup[i];
340
			r_spritedesc.vright[i] = vright[i];
341
			r_spritedesc.vpn[i] = vpn[i];
342
		}
343
	}
344
	else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
345
	{
346
	// generate the sprite's axes, with vup straight up in worldspace, and
347
	// r_spritedesc.vright parallel to the viewplane.
348
	// This will not work if the view direction is very close to straight up or
349
	// down, because the cross product will be between two nearly parallel
350
	// vectors and starts to approach an undefined state, so we don't draw if
351
	// the two vectors are less than 1 degree apart
352
		dot = vpn[2];	// same as DotProduct (vpn, r_spritedesc.vup) because
353
						//  r_spritedesc.vup is 0, 0, 1
354
		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
355
			return;
356
		r_spritedesc.vup[0] = 0;
357
		r_spritedesc.vup[1] = 0;
358
		r_spritedesc.vup[2] = 1;
359
		r_spritedesc.vright[0] = vpn[1];
360
										// CrossProduct (r_spritedesc.vup, vpn,
361
		r_spritedesc.vright[1] = -vpn[0];	//  r_spritedesc.vright)
362
		r_spritedesc.vright[2] = 0;
363
		VectorNormalize (r_spritedesc.vright);
364
		r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
365
		r_spritedesc.vpn[1] = r_spritedesc.vright[0];
366
		r_spritedesc.vpn[2] = 0;
367
					// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
368
					//  r_spritedesc.vpn)
369
	}
370
	else if (psprite->type == SPR_ORIENTED)
371
	{
372
	// generate the sprite's axes, according to the sprite's world orientation
373
		AngleVectors (currententity->angles, r_spritedesc.vpn,
374
					  r_spritedesc.vright, r_spritedesc.vup);
375
	}
376
	else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
377
	{
378
	// generate the sprite's axes, parallel to the viewplane, but rotated in
379
	// that plane around the center according to the sprite entity's roll
380
	// angle. So vpn stays the same, but vright and vup rotate
381
		angle = currententity->angles[ROLL] * (M_PI*2 / 360);
382
		sr = sin(angle);
383
		cr = cos(angle);
384
 
385
		for (i=0 ; i<3 ; i++)
386
		{
387
			r_spritedesc.vpn[i] = vpn[i];
388
			r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
389
			r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
390
		}
391
	}
392
	else
393
	{
394
		Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
395
	}
396
 
397
	R_RotateSprite (psprite->beamlength);
398
 
399
	R_SetupAndDrawSprite ();
400
}
401