1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
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, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // tr_surf.c
25 
26 #include "../server/exe_headers.h"
27 
28 #include "tr_local.h"
29 
30 /*
31 
32   THIS ENTIRE FILE IS BACK END
33 
34 backEnd.currentEntity will be valid.
35 
36 Tess_Begin has already been called for the surface's shader.
37 
38 The modelview matrix will be set.
39 
40 It is safe to actually issue drawing commands here if you don't want to
41 use the shader system.
42 */
43 
44 
45 //============================================================================
46 
47 
48 /*
49 ==============
50 RB_CheckOverflow
51 ==============
52 */
RB_CheckOverflow(int verts,int indexes)53 void RB_CheckOverflow( int verts, int indexes ) {
54 	if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
55 		&& tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
56 		return;
57 	}
58 
59 	RB_EndSurface();
60 
61 	if ( verts >= SHADER_MAX_VERTEXES ) {
62 		Com_Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
63 	}
64 	if ( indexes >= SHADER_MAX_INDEXES ) {
65 		Com_Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
66 	}
67 
68 	RB_BeginSurface(tess.shader, tess.fogNum );
69 }
70 
71 
72 /*
73 ==============
74 RB_AddQuadStampExt
75 ==============
76 */
RB_AddQuadStampExt(vec3_t origin,vec3_t left,vec3_t up,byte * color,float s1,float t1,float s2,float t2)77 void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {
78 	vec3_t		normal;
79 	int			ndx;
80 
81 	RB_CHECKOVERFLOW( 4, 6 );
82 
83 	ndx = tess.numVertexes;
84 
85 	// triangle indexes for a simple quad
86 	tess.indexes[ tess.numIndexes ] = ndx;
87 	tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
88 	tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
89 
90 	tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
91 	tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
92 	tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
93 
94 	tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
95 	tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
96 	tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
97 
98 	tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
99 	tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
100 	tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
101 
102 	tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
103 	tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
104 	tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
105 
106 	tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
107 	tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
108 	tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
109 
110 
111 	// constant normal all the way around
112 	VectorSubtract( vec3_origin, backEnd.viewParms.ori.axis[0], normal );
113 
114 	tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];
115 	tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];
116 	tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];
117 
118 	// standard square texture coordinates
119 	tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;
120 	tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;
121 
122 	tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;
123 	tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;
124 
125 	tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;
126 	tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;
127 
128 	tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;
129 	tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;
130 
131 	// constant color all the way around
132 	// should this be identity and let the shader specify from entity?
133 	byteAlias_t *baSource = (byteAlias_t *)color, *baDest;
134 	baDest = (byteAlias_t *)&tess.vertexColors[ndx + 0];
135 	baDest->ui = baSource->ui;
136 	baDest = (byteAlias_t *)&tess.vertexColors[ndx + 1];
137 	baDest->ui = baSource->ui;
138 	baDest = (byteAlias_t *)&tess.vertexColors[ndx + 2];
139 	baDest->ui = baSource->ui;
140 	baDest = (byteAlias_t *)&tess.vertexColors[ndx + 3];
141 	baDest->ui = baSource->ui;
142 
143 	tess.numVertexes += 4;
144 	tess.numIndexes += 6;
145 }
146 
147 /*
148 ==============
149 RB_AddQuadStamp
150 ==============
151 */
RB_AddQuadStamp(vec3_t origin,vec3_t left,vec3_t up,byte * color)152 void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {
153 	RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
154 }
155 
156 /*
157 ==============
158 RB_SurfaceSprite
159 ==============
160 */
RB_SurfaceSprite(void)161 static void RB_SurfaceSprite( void ) {
162 	vec3_t		left, up;
163 	float		radius;
164 
165 	// calculate the xyz locations for the four corners
166 	radius = backEnd.currentEntity->e.radius;
167 	if ( backEnd.currentEntity->e.rotation == 0 ) {
168 		VectorScale( backEnd.viewParms.ori.axis[1], radius, left );
169 		VectorScale( backEnd.viewParms.ori.axis[2], radius, up );
170 	} else {
171 		float	s, c;
172 		float	ang;
173 
174 		ang = M_PI * backEnd.currentEntity->e.rotation / 180;
175 		s = sin( ang );
176 		c = cos( ang );
177 
178 		VectorScale( backEnd.viewParms.ori.axis[1], c * radius, left );
179 		VectorMA( left, -s * radius, backEnd.viewParms.ori.axis[2], left );
180 
181 		VectorScale( backEnd.viewParms.ori.axis[2], c * radius, up );
182 		VectorMA( up, s * radius, backEnd.viewParms.ori.axis[1], up );
183 	}
184 	if ( backEnd.viewParms.isMirror ) {
185 		VectorSubtract( vec3_origin, left, left );
186 	}
187 
188 	RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
189 }
190 
191 /*
192 =======================
193 RB_SurfaceOrientedQuad
194 =======================
195 */
RB_SurfaceOrientedQuad(void)196 static void RB_SurfaceOrientedQuad( void )
197 {
198 	vec3_t	left, up;
199 	float	radius;
200 
201 	// calculate the xyz locations for the four corners
202 	radius = backEnd.currentEntity->e.radius;
203 	MakeNormalVectors( backEnd.currentEntity->e.axis[0], left, up );
204 
205 	if ( backEnd.currentEntity->e.rotation == 0 )
206 	{
207 		VectorScale( left, radius, left );
208 		VectorScale( up, radius, up );
209 	}
210 	else
211 	{
212 		vec3_t	tempLeft, tempUp;
213 		float	s, c;
214 		float	ang;
215 
216 		ang = M_PI * backEnd.currentEntity->e.rotation / 180;
217 		s = sin( ang );
218 		c = cos( ang );
219 
220 		// Use a temp so we don't trash the values we'll need later
221 		VectorScale( left, c * radius, tempLeft );
222 		VectorMA( tempLeft, -s * radius, up, tempLeft );
223 
224 		VectorScale( up, c * radius, tempUp );
225 		VectorMA( tempUp, s * radius, left, up ); // no need to use the temp anymore, so copy into the dest vector ( up )
226 
227 		// This was copied for safekeeping, we're done, so we can move it back to left
228 		VectorCopy( tempLeft, left );
229 	}
230 
231 	if ( backEnd.viewParms.isMirror )
232 	{
233 		VectorSubtract( vec3_origin, left, left );
234 	}
235 
236 	RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
237 }
238 
239 /*
240 ==============
241 RB_SurfaceLine
242 ==============
243 */
244 //
245 //	Values for a proper line render primitive...
246 //		Width
247 //		STScale (how many times to loop a texture)
248 //		alpha
249 //		RGB
250 //
251 //  Values for proper line object...
252 //		lifetime
253 //		dscale
254 //		startalpha, endalpha
255 //		startRGB, endRGB
256 //
257 
DoLine(const vec3_t start,const vec3_t end,const vec3_t up,float spanWidth)258 static void DoLine( const vec3_t start, const vec3_t end, const vec3_t up, float spanWidth )
259 {
260 	float		spanWidth2;
261 	int			vbase;
262 
263 	RB_CHECKOVERFLOW( 4, 6 );
264 
265 	vbase = tess.numVertexes;
266 
267 	spanWidth2 = -spanWidth;
268 
269 	VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
270 	tess.texCoords[tess.numVertexes][0][0] = 0;
271 	tess.texCoords[tess.numVertexes][0][1] = 0;
272 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];// * 0.25;//wtf??not sure why the code would be doing this
273 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];// * 0.25;
274 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];// * 0.25;
275 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25;
276 	tess.numVertexes++;
277 
278 	VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );
279 	tess.texCoords[tess.numVertexes][0][0] = 1;//backEnd.currentEntity->e.shaderTexCoord[0];
280 	tess.texCoords[tess.numVertexes][0][1] = 0;
281 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
282 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
283 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
284 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
285 	tess.numVertexes++;
286 
287 	VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );
288 
289 	tess.texCoords[tess.numVertexes][0][0] = 0;
290 	tess.texCoords[tess.numVertexes][0][1] = 1;//backEnd.currentEntity->e.shaderTexCoord[1];
291 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
292 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
293 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
294 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
295 	tess.numVertexes++;
296 
297 	VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
298 	tess.texCoords[tess.numVertexes][0][0] = 1;//backEnd.currentEntity->e.shaderTexCoord[0];
299 	tess.texCoords[tess.numVertexes][0][1] = 1;//backEnd.currentEntity->e.shaderTexCoord[1];
300 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
301 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
302 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
303 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
304 	tess.numVertexes++;
305 
306 	tess.indexes[tess.numIndexes++] = vbase;
307 	tess.indexes[tess.numIndexes++] = vbase + 1;
308 	tess.indexes[tess.numIndexes++] = vbase + 2;
309 
310 	tess.indexes[tess.numIndexes++] = vbase + 2;
311 	tess.indexes[tess.numIndexes++] = vbase + 1;
312 	tess.indexes[tess.numIndexes++] = vbase + 3;
313 }
314 
DoLine2(const vec3_t start,const vec3_t end,const vec3_t up,float spanWidth,float spanWidth2,const float tcStart,const float tcEnd)315 static void DoLine2( const vec3_t start, const vec3_t end, const vec3_t up, float spanWidth, float spanWidth2, const float tcStart, const float tcEnd )
316 {
317 	int			vbase;
318 
319 	RB_CHECKOVERFLOW( 4, 6 );
320 
321 	vbase = tess.numVertexes;
322 
323 	VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
324 	tess.texCoords[tess.numVertexes][0][0] = 0;
325 	tess.texCoords[tess.numVertexes][0][1] = tcStart;
326 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];// * 0.25;//wtf??not sure why the code would be doing this
327 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];// * 0.25;
328 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];// * 0.25;
329 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25;
330 	tess.numVertexes++;
331 
332 	VectorMA( start, -spanWidth, up, tess.xyz[tess.numVertexes] );
333 	tess.texCoords[tess.numVertexes][0][0] = 1;//backEnd.currentEntity->e.shaderTexCoord[0];
334 	tess.texCoords[tess.numVertexes][0][1] = tcStart;
335 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
336 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
337 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
338 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
339 	tess.numVertexes++;
340 
341 	VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
342 
343 	tess.texCoords[tess.numVertexes][0][0] = 0;
344 	tess.texCoords[tess.numVertexes][0][1] = tcEnd;//backEnd.currentEntity->e.shaderTexCoord[1];
345 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
346 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
347 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
348 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
349 	tess.numVertexes++;
350 
351 	VectorMA( end, -spanWidth2, up, tess.xyz[tess.numVertexes] );
352 	tess.texCoords[tess.numVertexes][0][0] = 1;//backEnd.currentEntity->e.shaderTexCoord[0];
353 	tess.texCoords[tess.numVertexes][0][1] = tcEnd;//backEnd.currentEntity->e.shaderTexCoord[1];
354 	tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
355 	tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
356 	tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
357 	tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];
358 	tess.numVertexes++;
359 
360 	tess.indexes[tess.numIndexes++] = vbase;
361 	tess.indexes[tess.numIndexes++] = vbase + 1;
362 	tess.indexes[tess.numIndexes++] = vbase + 2;
363 
364 	tess.indexes[tess.numIndexes++] = vbase + 2;
365 	tess.indexes[tess.numIndexes++] = vbase + 1;
366 	tess.indexes[tess.numIndexes++] = vbase + 3;
367 }
368 
369 //-----------------
370 // RB_SurfaceLine
371 //-----------------
RB_SurfaceLine(void)372 static void RB_SurfaceLine( void )
373 {
374 	refEntity_t *e;
375 	vec3_t		right;
376 	vec3_t		start, end;
377 	vec3_t		v1, v2;
378 
379 	e = &backEnd.currentEntity->e;
380 
381 	VectorCopy( e->oldorigin, end );
382 	VectorCopy( e->origin, start );
383 
384 	// compute side vector
385 	VectorSubtract( start, backEnd.viewParms.ori.origin, v1 );
386 	VectorSubtract( end, backEnd.viewParms.ori.origin, v2 );
387 	CrossProduct( v1, v2, right );
388 	VectorNormalize( right );
389 
390 	DoLine( start, end, right, e->radius);
391 }
392 
393 /*
394 ==============
395 RB_SurfaceCylinder
396 ==============
397 */
398 
399 #define NUM_CYLINDER_SEGMENTS 40
400 
401 // e->origin holds the bottom point
402 // e->oldorigin holds the top point
403 // e->radius holds the radius
404 
405 // If a cylinder has a tapered end that has a very small radius, the engine converts it to a cone.  Not a huge savings, but the texture mapping is slightly better
406 //	and it uses half as many indicies as the cylinder version
407 //-------------------------------------
RB_SurfaceCone(void)408 static void RB_SurfaceCone( void )
409 //-------------------------------------
410 {
411 	static vec3_t points[NUM_CYLINDER_SEGMENTS];
412 	vec3_t		vr, vu, midpoint;
413 	vec3_t		tapered, base;
414 	float		detail, length;
415 	int			i;
416 	int			segments;
417 	refEntity_t *e;
418 
419 	e = &backEnd.currentEntity->e;
420 
421 	//Work out the detail level of this cylinder
422 	VectorAdd( e->origin, e->oldorigin, midpoint );
423 	VectorScale(midpoint, 0.5, midpoint);		// Average start and end
424 
425 	VectorSubtract( midpoint, backEnd.viewParms.ori.origin, midpoint );
426 	length = VectorNormalize( midpoint );
427 
428 	// this doesn't need to be perfect....just a rough compensation for zoom level is enough
429 	length *= (backEnd.viewParms.fovX / 90.0f);
430 
431 	detail = 1 - ((float) length / 2048 );
432 	segments = NUM_CYLINDER_SEGMENTS * detail;
433 
434 	// 3 is the absolute minimum, but the pop between 3-8 is too noticeable
435 	if ( segments < 8 )
436 	{
437 		segments = 8;
438 	}
439 
440 	if ( segments > NUM_CYLINDER_SEGMENTS )
441 	{
442 		segments = NUM_CYLINDER_SEGMENTS;
443 	}
444 
445 	// Get the direction vector
446 	MakeNormalVectors( e->axis[0], vr, vu );
447 
448 	// we only need to rotate around the larger radius, the smaller radius get's welded
449 	if ( e->radius < e->backlerp )
450 	{
451 		VectorScale( vu, e->backlerp, vu );
452 		VectorCopy( e->origin, base );
453 		VectorCopy( e->oldorigin, tapered );
454 	}
455 	else
456 	{
457 		VectorScale( vu, e->radius, vu );
458 		VectorCopy( e->origin, tapered );
459 		VectorCopy( e->oldorigin, base );
460 	}
461 
462 
463 	// Calculate the step around the cylinder
464 	detail = 360.0f / (float)segments;
465 
466 	for ( i = 0; i < segments; i++ )
467 	{
468 		// ring
469 		RotatePointAroundVector( points[i], e->axis[0], vu, detail * i );
470 		VectorAdd( points[i], base, points[i] );
471 	}
472 
473 	// Calculate the texture coords so the texture can wrap around the whole cylinder
474 	detail = 1.0f / (float)segments;
475 
476 	RB_CHECKOVERFLOW( 2 * (segments+1), 3 * segments ); // this isn't 100% accurate
477 
478 	int vbase = tess.numVertexes;
479 
480 	for ( i = 0; i < segments; i++ )
481 	{
482  		VectorCopy( points[i], tess.xyz[tess.numVertexes] );
483 		tess.texCoords[tess.numVertexes][0][0] = detail * i;
484 		tess.texCoords[tess.numVertexes][0][1] = 1.0f;
485 		tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
486 		tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
487 		tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
488 		tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
489 		tess.numVertexes++;
490 
491 		// We could add this vert once, but using the given texture mapping method, we need to generate different texture coordinates
492 		VectorCopy( tapered, tess.xyz[tess.numVertexes] );
493 		tess.texCoords[tess.numVertexes][0][0] = detail * i + detail * 0.5f; // set the texture coordinates to the point half-way between the untapered ends....but on the other end of the texture
494 		tess.texCoords[tess.numVertexes][0][1] = 0.0f;
495 		tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
496 		tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
497 		tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
498 		tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
499 		tess.numVertexes++;
500 	}
501 
502 	// last point has the same verts as the first, but does not share the same tex coords, so we have to duplicate it
503  	VectorCopy( points[0], tess.xyz[tess.numVertexes] );
504 	tess.texCoords[tess.numVertexes][0][0] = detail * i;
505 	tess.texCoords[tess.numVertexes][0][1] = 1.0f;
506 	tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
507 	tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
508 	tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
509 	tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
510 	tess.numVertexes++;
511 
512  	VectorCopy( tapered, tess.xyz[tess.numVertexes] );
513 	tess.texCoords[tess.numVertexes][0][0] = detail * i + detail * 0.5f;
514 	tess.texCoords[tess.numVertexes][0][1] = 0.0f;
515 	tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
516 	tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
517 	tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
518 	tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
519 	tess.numVertexes++;
520 
521 	// do the welding
522 	for ( i = 0; i < segments; i++ )
523 	{
524 		tess.indexes[tess.numIndexes++] = vbase;
525 		tess.indexes[tess.numIndexes++] = vbase + 1;
526 		tess.indexes[tess.numIndexes++] = vbase + 2;
527 
528 		vbase += 2;
529 	}
530 }
531 
532 //-------------------------------------
RB_SurfaceCylinder(void)533 static void RB_SurfaceCylinder( void )
534 //-------------------------------------
535 {
536 	static vec3_t lower_points[NUM_CYLINDER_SEGMENTS], upper_points[NUM_CYLINDER_SEGMENTS];
537 	vec3_t		vr, vu, midpoint, v1;
538 	float		detail, length;
539 	int			i;
540 	int			segments;
541 	refEntity_t *e;
542 
543 	e = &backEnd.currentEntity->e;
544 
545 	// check for tapering
546 	if ( !( e->radius < 0.3f && e->backlerp < 0.3f) && ( e->radius < 0.3f || e->backlerp < 0.3f ))
547 	{
548 		// One end is sufficiently tapered to consider changing it to a cone
549 		RB_SurfaceCone();
550 		return;
551 	}
552 
553 	//Work out the detail level of this cylinder
554 	VectorAdd( e->origin, e->oldorigin, midpoint );
555 	VectorScale(midpoint, 0.5, midpoint);		// Average start and end
556 
557 	VectorSubtract( midpoint, backEnd.viewParms.ori.origin, midpoint );
558 	length = VectorNormalize( midpoint );
559 
560 	// this doesn't need to be perfect....just a rough compensation for zoom level is enough
561 	length *= (backEnd.viewParms.fovX / 90.0f);
562 
563 	detail = 1 - ((float) length / 2048 );
564 	segments = NUM_CYLINDER_SEGMENTS * detail;
565 
566 	// 3 is the absolute minimum, but the pop between 3-8 is too noticeable
567 	if ( segments < 8 )
568 	{
569 		segments = 8;
570 	}
571 
572 	if ( segments > NUM_CYLINDER_SEGMENTS )
573 	{
574 		segments = NUM_CYLINDER_SEGMENTS;
575 	}
576 
577 	//Get the direction vector
578 	MakeNormalVectors( e->axis[0], vr, vu );
579 
580 	VectorScale( vu, e->radius, v1 );	// size1
581 	VectorScale( vu, e->backlerp, vu );	// size2
582 
583 	// Calculate the step around the cylinder
584 	detail = 360.0f / (float)segments;
585 
586 	for ( i = 0; i < segments; i++ )
587 	{
588 		//Upper ring
589 		RotatePointAroundVector( upper_points[i], e->axis[0], vu, detail * i );
590 		VectorAdd( upper_points[i], e->origin, upper_points[i] );
591 
592 		//Lower ring
593 		RotatePointAroundVector( lower_points[i], e->axis[0], v1, detail * i );
594 		VectorAdd( lower_points[i], e->oldorigin, lower_points[i] );
595 	}
596 
597 	// Calculate the texture coords so the texture can wrap around the whole cylinder
598 	detail = 1.0f / (float)segments;
599 
600 	RB_CHECKOVERFLOW( 2 * (segments+1), 6 * segments ); // this isn't 100% accurate
601 
602 	int vbase = tess.numVertexes;
603 
604 	for ( i = 0; i < segments; i++ )
605 	{
606  		VectorCopy( upper_points[i], tess.xyz[tess.numVertexes] );
607 		tess.texCoords[tess.numVertexes][0][0] = detail * i;
608 		tess.texCoords[tess.numVertexes][0][1] = 1.0f;
609 		tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
610 		tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
611 		tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
612 		tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
613 		tess.numVertexes++;
614 
615 		VectorCopy( lower_points[i], tess.xyz[tess.numVertexes] );
616 		tess.texCoords[tess.numVertexes][0][0] = detail * i;
617 		tess.texCoords[tess.numVertexes][0][1] = 0.0f;
618 		tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
619 		tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
620 		tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
621 		tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
622 		tess.numVertexes++;
623 	}
624 
625 	// last point has the same verts as the first, but does not share the same tex coords, so we have to duplicate it
626  	VectorCopy( upper_points[0], tess.xyz[tess.numVertexes] );
627 	tess.texCoords[tess.numVertexes][0][0] = detail * i;
628 	tess.texCoords[tess.numVertexes][0][1] = 1.0f;
629 	tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
630 	tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
631 	tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
632 	tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
633 	tess.numVertexes++;
634 
635  	VectorCopy( lower_points[0], tess.xyz[tess.numVertexes] );
636 	tess.texCoords[tess.numVertexes][0][0] = detail * i;
637 	tess.texCoords[tess.numVertexes][0][1] = 0.0f;
638 	tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
639 	tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
640 	tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
641 	tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
642 	tess.numVertexes++;
643 
644 	// glue the verts
645 	for ( i = 0; i < segments; i++ )
646 	{
647 		tess.indexes[tess.numIndexes++] = vbase;
648 		tess.indexes[tess.numIndexes++] = vbase + 1;
649 		tess.indexes[tess.numIndexes++] = vbase + 2;
650 
651 		tess.indexes[tess.numIndexes++] = vbase + 2;
652 		tess.indexes[tess.numIndexes++] = vbase + 1;
653 		tess.indexes[tess.numIndexes++] = vbase + 3;
654 
655 		vbase += 2;
656 	}
657 }
658 
659 static vec3_t sh1, sh2;
660 static int f_count;
661 
662 // Up front, we create a random "shape", then apply that to each line segment...and then again to each of those segments...kind of like a fractal
663 //----------------------------------------------------------------------------
CreateShape()664 static void CreateShape()
665 //----------------------------------------------------------------------------
666 {
667 	VectorSet( sh1, 0.66f,// + Q_flrand(-1.0f, 1.0f) * 0.1f,	// fwd
668 				0.08f + Q_flrand(-1.0f, 1.0f) * 0.02f,
669 				0.08f + Q_flrand(-1.0f, 1.0f) * 0.02f );
670 
671 	// it seems to look best to have a point on one side of the ideal line, then the other point on the other side.
672 	VectorSet( sh2, 0.33f,// + Q_flrand(-1.0f, 1.0f) * 0.1f,	// fwd
673 					-sh1[1] + Q_flrand(-1.0f, 1.0f) * 0.02f,	// forcing point to be on the opposite side of the line -- right
674 					-sh1[2] + Q_flrand(-1.0f, 1.0f) * 0.02f );// up
675 }
676 
677 //----------------------------------------------------------------------------
ApplyShape(vec3_t start,vec3_t end,vec3_t right,float sradius,float eradius,int count,float startPerc,float endPerc)678 static void ApplyShape( vec3_t start, vec3_t end, vec3_t right, float sradius, float eradius, int count, float startPerc, float endPerc )
679 //----------------------------------------------------------------------------
680 {
681 	vec3_t	point1, point2, fwd;
682 	vec3_t	rt, up;
683 	float	perc, dis;
684 
685     if ( count < 1 )
686 	{
687 		// done recursing
688 		DoLine2( start, end, right, sradius, eradius, startPerc, endPerc );
689 		return;
690 	}
691 
692     CreateShape();
693 
694 	VectorSubtract( end, start, fwd );
695 	dis = VectorNormalize( fwd ) * 0.7f;
696 	MakeNormalVectors( fwd, rt, up );
697 
698 	perc = sh1[0];
699 
700 	VectorScale( start, perc, point1 );
701 	VectorMA( point1, 1.0f - perc, end, point1 );
702 	VectorMA( point1, dis * sh1[1], rt, point1 );
703 	VectorMA( point1, dis * sh1[2], up, point1 );
704 
705 	// do a quick and dirty interpolation of the radius at that point
706 	float rads1, rads2;
707 
708 	rads1 = sradius * 0.666f + eradius * 0.333f;
709 	rads2 = sradius * 0.333f + eradius * 0.666f;
710 
711 	// recursion
712     ApplyShape( start, point1, right, sradius, rads1, count - 1, startPerc, startPerc * 0.666f + endPerc * 0.333f );
713 
714 	perc = sh2[0];
715 
716 	VectorScale( start, perc, point2 );
717 	VectorMA( point2, 1.0f - perc, end, point2 );
718 	VectorMA( point2, dis * sh2[1], rt, point2 );
719 	VectorMA( point2, dis * sh2[2], up, point2 );
720 
721 	// recursion
722     ApplyShape( point2, point1, right, rads1, rads2, count - 1, startPerc * 0.333f + endPerc * 0.666f, startPerc * 0.666f + endPerc * 0.333f );
723 	ApplyShape( point2, end, right, rads2, eradius, count - 1, startPerc * 0.333f + endPerc * 0.666f, endPerc );
724 }
725 
726 //----------------------------------------------------------------------------
DoBoltSeg(vec3_t start,vec3_t end,vec3_t right,float radius)727 static void DoBoltSeg( vec3_t start, vec3_t end, vec3_t right, float radius )
728 //----------------------------------------------------------------------------
729 {
730 	refEntity_t *e;
731 	vec3_t fwd, old;
732 	vec3_t cur, off={10,10,10};
733 	vec3_t rt, up;
734 	vec3_t temp;
735 	int		i;
736     float dis, oldPerc = 0.0f, perc, oldRadius, newRadius;
737 
738 	e = &backEnd.currentEntity->e;
739 
740 	VectorSubtract( end, start, fwd );
741 	dis = VectorNormalize( fwd );
742 
743 	if (dis > 2000)	//freaky long
744 	{
745 //		ri.Printf( PRINT_WARNING, "DoBoltSeg: insane distance.\n" );
746 		dis = 2000;
747 	}
748 	MakeNormalVectors( fwd, rt, up );
749 
750 	VectorCopy( start, old );
751 
752 	newRadius = oldRadius = radius;
753 
754     for ( i = 16; i <= dis; i+= 16 )
755 	{
756 		// because of our large step size, we may not actually draw to the end.  In this case, fudge our percent so that we are basically complete
757 		if ( i + 16 > dis )
758 		{
759 			perc = 1.0f;
760 		}
761 		else
762 		{
763 			// percentage of the amount of line completed
764 			perc = (float)i / dis;
765 		}
766 
767 		// create our level of deviation for this point
768 		VectorScale( fwd, Q_crandom(&e->frame) * 3.0f, temp );				// move less in fwd direction, chaos also does not affect this
769 		VectorMA( temp, Q_crandom(&e->frame) * 7.0f * e->angles[0], rt, temp );	// move more in direction perpendicular to line, angles is really the chaos
770 		VectorMA( temp, Q_crandom(&e->frame) * 7.0f * e->angles[0], up, temp );	// move more in direction perpendicular to line
771 
772 		// track our total level of offset from the ideal line
773 		VectorAdd( off, temp, off );
774 
775         // Move from start to end, always adding our current level of offset from the ideal line
776 		//	Even though we are adding a random offset.....by nature, we always move from exactly start....to end
777 		VectorAdd( start, off, cur );
778 		VectorScale( cur, 1.0f - perc, cur );
779 		VectorMA( cur, perc, end, cur );
780 
781 		if ( e->renderfx & RF_TAPERED )
782 		{
783 			// This does pretty close to perfect tapering since apply shape interpolates the old and new as it goes along.
784 			//	by using one minus the square, the radius stays fairly constant, then drops off quickly at the very point of the bolt
785 			oldRadius = radius * (1.0f-oldPerc*oldPerc);
786 			newRadius = radius * (1.0f-perc*perc);
787 		}
788 
789 		// Apply the random shape to our line seg to give it some micro-detail-jaggy-coolness.
790 		ApplyShape( cur, old, right, newRadius, oldRadius, 2 - r_lodbias->integer, 0, 1 );
791 
792 		// randomly split off to create little tendrils, but don't do it too close to the end and especially if we are not even of the forked variety
793         if (( e->renderfx & RF_FORKED ) && f_count > 0 && Q_random(&e->frame) > 0.93f && (1.0f - perc) > 0.8f )
794 		{
795 			vec3_t newDest;
796 
797 			f_count--;
798 
799 			// Pick a point somewhere between the current point and the final endpoint
800 			VectorAdd( cur, e->oldorigin, newDest );
801 			VectorScale( newDest, 0.5f, newDest );
802 
803 			// And then add some crazy offset
804 			for ( int t = 0; t < 3; t++ )
805 			{
806 				newDest[t] += Q_crandom(&e->frame) * 80;
807 			}
808 
809 			// we could branch off using OLD and NEWDEST, but that would allow multiple forks...whereas, we just want simpler brancing
810             DoBoltSeg( cur, newDest, right, newRadius );
811 		}
812 
813 		// Current point along the line becomes our new old attach point
814 		VectorCopy( cur, old );
815 		oldPerc = perc;
816 	}
817 }
818 
819 //------------------------------------------
RB_SurfaceElectricity()820 static void RB_SurfaceElectricity()
821 //------------------------------------------
822 {
823 	refEntity_t *e;
824 	vec3_t		right, fwd;
825 	vec3_t		start, end;
826 	vec3_t		v1, v2;
827 	float		radius, perc = 1.0f, dis;
828 
829 	e = &backEnd.currentEntity->e;
830 	radius = e->radius;
831 
832 	VectorCopy( e->origin, start );
833 
834 	VectorSubtract( e->oldorigin, start, fwd );
835 	dis = VectorNormalize( fwd );
836 
837 	// see if we should grow from start to end
838 	if ( e->renderfx & RF_GROW )
839 	{
840 		perc = 1.0f - ( e->endTime - tr.refdef.time ) / e->angles[1]/*duration*/;
841 
842 		if ( perc > 1.0f )
843 		{
844 			perc = 1.0f;
845 		}
846 		else if ( perc < 0.0f )
847 		{
848 			perc = 0.0f;
849 		}
850 	}
851 
852 	VectorMA( start, perc * dis, fwd, e->oldorigin );
853 	VectorCopy( e->oldorigin, end );
854 
855 	// compute side vector
856 	VectorSubtract( start, backEnd.viewParms.ori.origin, v1 );
857 	VectorSubtract( end, backEnd.viewParms.ori.origin, v2 );
858 	CrossProduct( v1, v2, right );
859 	VectorNormalize( right );
860 
861 	// allow now more than three branches on branch type electricity
862 	f_count = 3;
863     DoBoltSeg( start, end, right, radius );
864 }
865 
866 /*
867 =============
868 RB_SurfacePolychain
869 =============
870 */
871 /* // we could try to do something similar to this to get better normals into the tess for these types of surfs.  As it stands, any shader pass that
872 //	requires a normal ( env map ) will not work properly since the normals seem to essentially be random garbage.
873 void RB_SurfacePolychain( srfPoly_t *p ) {
874 	int		i;
875 	int		numv;
876 	vec3_t	a,b,normal={1,0,0};
877 
878 	RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
879 
880 	if ( p->numVerts >= 3 )
881 	{
882 		VectorSubtract( p->verts[0].xyz, p->verts[1].xyz, a );
883 		VectorSubtract( p->verts[2].xyz, p->verts[1].xyz, b );
884 		CrossProduct( a,b, normal );
885 		VectorNormalize( normal );
886 	}
887 
888 	// fan triangles into the tess array
889 	numv = tess.numVertexes;
890 	for ( i = 0; i < p->numVerts; i++ ) {
891 		VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
892 		tess.texCoords[numv][0][0] = p->verts[i].st[0];
893 		tess.texCoords[numv][0][1] = p->verts[i].st[1];
894 		VectorCopy( normal, tess.normal[numv] );
895 		*(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
896 
897 		numv++;
898 	}
899 
900 	// generate fan indexes into the tess array
901 	for ( i = 0; i < p->numVerts-2; i++ ) {
902 		tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
903 		tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
904 		tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
905 		tess.numIndexes += 3;
906 	}
907 
908 	tess.numVertexes = numv;
909 }
910 */
RB_SurfacePolychain(srfPoly_t * p)911 void RB_SurfacePolychain( srfPoly_t *p ) {
912 	int		i;
913 	int		numv;
914 
915 	RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
916 
917 	// fan triangles into the tess array
918 	numv = tess.numVertexes;
919 	for ( i = 0; i < p->numVerts; i++ ) {
920 		VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
921 		tess.texCoords[numv][0][0] = p->verts[i].st[0];
922 		tess.texCoords[numv][0][1] = p->verts[i].st[1];
923 		byteAlias_t *baDest = (byteAlias_t *)&tess.vertexColors[numv++],
924 			*baSource = (byteAlias_t *)&p->verts[ i ].modulate;
925 		baDest->i = baSource->i;
926 	}
927 
928 	// generate fan indexes into the tess array
929 	for ( i = 0; i < p->numVerts-2; i++ ) {
930 		tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
931 		tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
932 		tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
933 		tess.numIndexes += 3;
934 	}
935 
936 	tess.numVertexes = numv;
937 }
938 
ComputeFinalVertexColor(const byte * colors)939 inline static uint32_t ComputeFinalVertexColor( const byte *colors ) {
940 	int k;
941 	byteAlias_t result;
942 	uint32_t r, g, b;
943 
944 	for ( k=0; k<4; k++ )
945 		result.b[k] = colors[k];
946 
947 	if ( tess.shader->lightmapIndex[0] != LIGHTMAP_BY_VERTEX )
948 		return result.ui;
949 
950 	if ( r_fullbright->integer ) {
951 		result.b[0] = 255;
952 		result.b[1] = 255;
953 		result.b[2] = 255;
954 		return result.ui;
955 	}
956 	// an optimization could be added here to compute the style[0] (which is always the world normal light)
957 	r = g = b = 0;
958 	for( k=0; k<MAXLIGHTMAPS; k++ ) {
959 		if ( tess.shader->styles[k] < LS_UNUSED ) {
960 			byte *styleColor = styleColors[tess.shader->styles[k]];
961 
962 			r += (uint32_t)(*colors++) * (uint32_t)(*styleColor++);
963 			g += (uint32_t)(*colors++) * (uint32_t)(*styleColor++);
964 			b += (uint32_t)(*colors++) * (uint32_t)(*styleColor);
965 			colors++;
966 		}
967 		else
968 			break;
969 	}
970 	result.b[0] = Com_Clamp( 0, 255, r >> 8 );
971 	result.b[1] = Com_Clamp( 0, 255, g >> 8 );
972 	result.b[2] = Com_Clamp( 0, 255, b >> 8 );
973 
974 	return result.ui;
975 }
976 
977 /*
978 =============
979 RB_SurfaceTriangles
980 =============
981 */
RB_SurfaceTriangles(srfTriangles_t * srf)982 void RB_SurfaceTriangles( srfTriangles_t *srf ) {
983 	int			i, k;
984 	drawVert_t	*dv;
985 	float		*xyz, *normal, *texCoords;
986 	byte		*color;
987 	int			dlightBits;
988 
989 	dlightBits = srf->dlightBits;
990 	tess.dlightBits |= dlightBits;
991 
992 	RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );
993 
994 	for ( i = 0 ; i < srf->numIndexes ; i += 3 ) {
995 		tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];
996 		tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];
997 		tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];
998 	}
999 	tess.numIndexes += srf->numIndexes;
1000 
1001 	dv = srf->verts;
1002 	xyz = tess.xyz[ tess.numVertexes ];
1003 	normal = tess.normal[ tess.numVertexes ];
1004 	texCoords = tess.texCoords[ tess.numVertexes ][0];
1005 	color = tess.vertexColors[ tess.numVertexes ];
1006 
1007 	for ( i = 0 ; i < srf->numVerts ; i++, dv++)
1008 	{
1009 		xyz[0] = dv->xyz[0];
1010 		xyz[1] = dv->xyz[1];
1011 		xyz[2] = dv->xyz[2];
1012 		xyz += 4;
1013 
1014 		//if ( needsNormal )
1015 		{
1016 			normal[0] = dv->normal[0];
1017 			normal[1] = dv->normal[1];
1018 			normal[2] = dv->normal[2];
1019 		}
1020 		normal += 4;
1021 
1022 		texCoords[0] = dv->st[0];
1023 		texCoords[1] = dv->st[1];
1024 
1025 		for(k=0;k<MAXLIGHTMAPS;k++)
1026 		{
1027 			if (tess.shader->lightmapIndex[k] >= 0)
1028 			{
1029 				texCoords[2+(k*2)] = dv->lightmap[k][0];
1030 				texCoords[2+(k*2)+1] = dv->lightmap[k][1];
1031 			}
1032 			else
1033 			{	// can't have an empty slot in the middle, so we are done
1034 				break;
1035 			}
1036 		}
1037 		texCoords += NUM_TEX_COORDS*2;
1038 
1039 		*(unsigned *)color = ComputeFinalVertexColor((byte *)dv->color);
1040 		color += 4;
1041 	}
1042 
1043 	for ( i = 0 ; i < srf->numVerts ; i++ ) {
1044 		tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;
1045 	}
1046 
1047 	tess.numVertexes += srf->numVerts;
1048 }
1049 
1050 
1051 
1052 /*
1053 ==============
1054 RB_SurfaceBeam
1055 ==============
1056 */
RB_SurfaceBeam(void)1057 static void RB_SurfaceBeam( void )
1058 {
1059 #define NUM_BEAM_SEGS 6
1060 	refEntity_t *e;
1061 	int	i;
1062 	vec3_t perpvec;
1063 	vec3_t direction, normalized_direction;
1064 	vec3_t	start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
1065 	vec3_t oldorigin, origin;
1066 
1067 	e = &backEnd.currentEntity->e;
1068 
1069 	oldorigin[0] = e->oldorigin[0];
1070 	oldorigin[1] = e->oldorigin[1];
1071 	oldorigin[2] = e->oldorigin[2];
1072 
1073 	origin[0] = e->origin[0];
1074 	origin[1] = e->origin[1];
1075 	origin[2] = e->origin[2];
1076 
1077 	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
1078 	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
1079 	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
1080 
1081 	if ( VectorNormalize( normalized_direction ) == 0 )
1082 		return;
1083 
1084 	PerpendicularVector( perpvec, normalized_direction );
1085 
1086 	VectorScale( perpvec, 4, perpvec );
1087 
1088 	for ( i = 0; i < NUM_BEAM_SEGS ; i++ )
1089 	{
1090 		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
1091 //		VectorAdd( start_points[i], origin, start_points[i] );
1092 		VectorAdd( start_points[i], direction, end_points[i] );
1093 	}
1094 
1095 	GL_Bind( tr.whiteImage );
1096 
1097 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1098 
1099 	switch(e->skinNum)
1100 	{
1101 	case 1://Green
1102 		qglColor3f( 0, 1, 0 );
1103 		break;
1104 	case 2://Blue
1105 		qglColor3f( 0.5, 0.5, 1 );
1106 		break;
1107 	case 0://red
1108 	default:
1109 		qglColor3f( 1, 0, 0 );
1110 		break;
1111 	}
1112 
1113 	qglBegin( GL_TRIANGLE_STRIP );
1114 	for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
1115 		qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );
1116 		qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );
1117 	}
1118 	qglEnd();
1119 }
1120 
1121 
1122 //------------------
1123 // DoSprite
1124 //------------------
DoSprite(vec3_t origin,float radius,float rotation)1125 static void DoSprite( vec3_t origin, float radius, float rotation )
1126 {
1127 	float	s, c;
1128 	float	ang;
1129 	vec3_t	left, up;
1130 
1131 	ang = M_PI * rotation / 180.0f;
1132 	s = sin( ang );
1133 	c = cos( ang );
1134 
1135 	VectorScale( backEnd.viewParms.ori.axis[1], c * radius, left );
1136 	VectorMA( left, -s * radius, backEnd.viewParms.ori.axis[2], left );
1137 
1138 	VectorScale( backEnd.viewParms.ori.axis[2], c * radius, up );
1139 	VectorMA( up, s * radius, backEnd.viewParms.ori.axis[1], up );
1140 
1141 	if ( backEnd.viewParms.isMirror )
1142 	{
1143 		VectorSubtract( vec3_origin, left, left );
1144 	}
1145 
1146 	RB_AddQuadStamp( origin, left, up, backEnd.currentEntity->e.shaderRGBA );
1147 }
1148 
1149 //------------------
1150 // RB_SurfaceSaber
1151 //------------------
RB_SurfaceSaberGlow()1152 static void RB_SurfaceSaberGlow()
1153 {
1154 	vec3_t		end;
1155 	refEntity_t *e;
1156 
1157 	e = &backEnd.currentEntity->e;
1158 
1159 	// Render the glow part of the blade
1160 	for ( float i = e->saberLength; i > 0; i -= e->radius * 0.65f )
1161 	{
1162 		VectorMA( e->origin, i, e->axis[0], end );
1163 
1164 		DoSprite( end, e->radius, 0.0f );//Q_flrand(0.0f, 1.0f) * 360.0f );
1165 		e->radius += 0.017f;
1166 	}
1167 
1168 	// Big hilt sprite
1169 	// Please don't kill me Pat...I liked the hilt glow blob, but wanted a subtle pulse.:)  Feel free to ditch it if you don't like it.  --Jeff
1170 	// Please don't kill me Jeff...  The pulse is good, but now I want the halo bigger if the saber is shorter...  --Pat
1171 	DoSprite( e->origin, 5.5f + Q_flrand(0.0f, 1.0f) * 0.25f, 0.0f );//Q_flrand(0.0f, 1.0f) * 360.0f );
1172 }
1173 
1174 /*
1175 ** LerpMeshVertexes
1176 */
LerpMeshVertexes(md3Surface_t * surf,float backlerp)1177 static void LerpMeshVertexes (md3Surface_t *surf, float backlerp)
1178 {
1179 	short	*oldXyz, *newXyz, *oldNormals, *newNormals;
1180 	float	*outXyz, *outNormal;
1181 	float	oldXyzScale, newXyzScale;
1182 	float	oldNormalScale, newNormalScale;
1183 	int		vertNum;
1184 	unsigned lat, lng;
1185 	int		numVerts;
1186 
1187 	outXyz = tess.xyz[tess.numVertexes];
1188 	outNormal = tess.normal[tess.numVertexes];
1189 
1190 	newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
1191 		+ (backEnd.currentEntity->e.frame * surf->numVerts * 4);
1192 	newNormals = newXyz + 3;
1193 
1194 	newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
1195 	newNormalScale = 1.0 - backlerp;
1196 
1197 	numVerts = surf->numVerts;
1198 
1199 	if ( backlerp == 0 ) {
1200 		//
1201 		// just copy the vertexes
1202 		//
1203 		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
1204 			newXyz += 4, newNormals += 4,
1205 			outXyz += 4, outNormal += 4)
1206 		{
1207 
1208 			outXyz[0] = newXyz[0] * newXyzScale;
1209 			outXyz[1] = newXyz[1] * newXyzScale;
1210 			outXyz[2] = newXyz[2] * newXyzScale;
1211 
1212 			lat = ( newNormals[0] >> 8 ) & 0xff;
1213 			lng = ( newNormals[0] & 0xff );
1214 			lat *= (FUNCTABLE_SIZE/256);
1215 			lng *= (FUNCTABLE_SIZE/256);
1216 
1217 			// decode X as cos( lat ) * sin( long )
1218 			// decode Y as sin( lat ) * sin( long )
1219 			// decode Z as cos( long )
1220 			outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
1221 			outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
1222 			outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
1223 		}
1224 	} else {
1225 		//
1226 		// interpolate and copy the vertex and normal
1227 		//
1228 		oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
1229 			+ (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
1230 		oldNormals = oldXyz + 3;
1231 
1232 		oldXyzScale = MD3_XYZ_SCALE * backlerp;
1233 		oldNormalScale = backlerp;
1234 
1235 		for (vertNum=0 ; vertNum < numVerts ; vertNum++,
1236 			oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
1237 			outXyz += 4, outNormal += 4)
1238 		{
1239 			vec3_t uncompressedOldNormal, uncompressedNewNormal;
1240 
1241 			// interpolate the xyz
1242 			outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
1243 			outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
1244 			outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
1245 
1246 			// FIXME: interpolate lat/long instead?
1247 			lat = ( newNormals[0] >> 8 ) & 0xff;
1248 			lng = ( newNormals[0] & 0xff );
1249 			lat *= 4;
1250 			lng *= 4;
1251 			uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
1252 			uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
1253 			uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
1254 
1255 			lat = ( oldNormals[0] >> 8 ) & 0xff;
1256 			lng = ( oldNormals[0] & 0xff );
1257 			lat *= 4;
1258 			lng *= 4;
1259 
1260 			uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
1261 			uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
1262 			uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
1263 
1264 			outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
1265 			outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
1266 			outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
1267 
1268 			VectorNormalize (outNormal);
1269 		}
1270 	}
1271 }
1272 
1273 /*
1274 =============
1275 RB_SurfaceMesh
1276 =============
1277 */
RB_SurfaceMesh(md3Surface_t * surface)1278 void RB_SurfaceMesh(md3Surface_t *surface) {
1279 	int				j;
1280 	float			backlerp;
1281 	int				*triangles;
1282 	float			*texCoords;
1283 	int				indexes;
1284 	int				Bob, Doug;
1285 	int				numVerts;
1286 
1287 	if (  backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
1288 		backlerp = 0;
1289 	} else  {
1290 		backlerp = backEnd.currentEntity->e.backlerp;
1291 	}
1292 
1293 	RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 );
1294 
1295 	LerpMeshVertexes (surface, backlerp);
1296 
1297 	triangles = (int *) ((byte *)surface + surface->ofsTriangles);
1298 	indexes = surface->numTriangles * 3;
1299 	Bob = tess.numIndexes;
1300 	Doug = tess.numVertexes;
1301 	for (j = 0 ; j < indexes ; j++) {
1302 		tess.indexes[Bob + j] = Doug + triangles[j];
1303 	}
1304 	tess.numIndexes += indexes;
1305 
1306 	texCoords = (float *) ((byte *)surface + surface->ofsSt);
1307 
1308 	numVerts = surface->numVerts;
1309 	for ( j = 0; j < numVerts; j++ ) {
1310 		tess.texCoords[Doug + j][0][0] = texCoords[j*2+0];
1311 		tess.texCoords[Doug + j][0][1] = texCoords[j*2+1];
1312 		// FIXME: fill in lightmapST for completeness?
1313 	}
1314 
1315 	tess.numVertexes += surface->numVerts;
1316 }
1317 
1318 
1319 /*
1320 ==============
1321 RB_SurfaceFace
1322 ==============
1323 */
RB_SurfaceFace(srfSurfaceFace_t * surf)1324 void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
1325 	int			i, j, k;
1326 	unsigned int *indices;
1327 	glIndex_t	*tessIndexes;
1328 	float		*v;
1329 	float		*normal;
1330 	int			ndx;
1331 	int			Bob;
1332 	int			numPoints;
1333 	int			dlightBits;
1334 	byteAlias_t	ba;
1335 
1336 	RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );
1337 
1338 	dlightBits = surf->dlightBits;
1339 	tess.dlightBits |= dlightBits;
1340 
1341 	indices = ( unsigned * ) ( ( ( char  * ) surf ) + surf->ofsIndices );
1342 
1343 	Bob = tess.numVertexes;
1344 	tessIndexes = tess.indexes + tess.numIndexes;
1345 	for ( i = surf->numIndices-1 ; i >= 0  ; i-- ) {
1346 		tessIndexes[i] = indices[i] + Bob;
1347 	}
1348 
1349 	tess.numIndexes += surf->numIndices;
1350 
1351 	v = surf->points[0];
1352 
1353 	ndx = tess.numVertexes;
1354 
1355 	numPoints = surf->numPoints;
1356 
1357 	//if ( tess.shader->needsNormal )
1358 	{
1359 		normal = surf->plane.normal;
1360 		for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {
1361 			VectorCopy( normal, tess.normal[ndx] );
1362 		}
1363 	}
1364 
1365 	for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) {
1366 		VectorCopy( v, tess.xyz[ndx]);
1367 		tess.texCoords[ndx][0][0] = v[3];
1368 		tess.texCoords[ndx][0][1] = v[4];
1369 		for(k=0;k<MAXLIGHTMAPS;k++)
1370 		{
1371 			if (tess.shader->lightmapIndex[k] >= 0)
1372 			{
1373 				tess.texCoords[ndx][k+1][0] = v[VERTEX_LM+(k*2)];
1374 				tess.texCoords[ndx][k+1][1] = v[VERTEX_LM+(k*2)+1];
1375 			}
1376 			else
1377 			{
1378 				break;
1379 			}
1380 		}
1381 		ba.ui = ComputeFinalVertexColor( (byte *)&v[VERTEX_COLOR] );
1382 		for ( j=0; j<4; j++ )
1383 			tess.vertexColors[ndx][j] = ba.b[j];
1384 		tess.vertexDlightBits[ndx] = dlightBits;
1385 	}
1386 
1387 	tess.numVertexes += surf->numPoints;
1388 }
1389 
1390 
LodErrorForVolume(vec3_t local,float radius)1391 static float LodErrorForVolume( vec3_t local, float radius ) {
1392 	vec3_t		world;
1393 	float		d;
1394 
1395 	// never let it go negative
1396 	if ( r_lodCurveError->value < 0 ) {
1397 		return 0;
1398 	}
1399 
1400 	world[0] = local[0] * backEnd.ori.axis[0][0] + local[1] * backEnd.ori.axis[1][0] +
1401 		local[2] * backEnd.ori.axis[2][0] + backEnd.ori.origin[0];
1402 	world[1] = local[0] * backEnd.ori.axis[0][1] + local[1] * backEnd.ori.axis[1][1] +
1403 		local[2] * backEnd.ori.axis[2][1] + backEnd.ori.origin[1];
1404 	world[2] = local[0] * backEnd.ori.axis[0][2] + local[1] * backEnd.ori.axis[1][2] +
1405 		local[2] * backEnd.ori.axis[2][2] + backEnd.ori.origin[2];
1406 
1407 	VectorSubtract( world, backEnd.viewParms.ori.origin, world );
1408 	d = DotProduct( world, backEnd.viewParms.ori.axis[0] );
1409 
1410 	if ( d < 0 ) {
1411 		d = -d;
1412 	}
1413 	d -= radius;
1414 	if ( d < 1 ) {
1415 		d = 1;
1416 	}
1417 
1418 	return r_lodCurveError->value / d;
1419 }
1420 
1421 /*
1422 =============
1423 RB_SurfaceGrid
1424 
1425 Just copy the grid of points and triangulate
1426 =============
1427 */
RB_SurfaceGrid(srfGridMesh_t * cv)1428 void RB_SurfaceGrid( srfGridMesh_t *cv ) {
1429 	int		i, j, k;
1430 	float	*xyz;
1431 	float	*texCoords;
1432 	float	*normal;
1433 	unsigned char *color;
1434 	drawVert_t	*dv;
1435 	int		rows, irows, vrows;
1436 	int		used;
1437 	int		widthTable[MAX_GRID_SIZE];
1438 	int		heightTable[MAX_GRID_SIZE];
1439 	float	lodError;
1440 	int		lodWidth, lodHeight;
1441 	int		numVertexes;
1442 	int		dlightBits;
1443 	int		*vDlightBits;
1444 
1445 	dlightBits = cv->dlightBits;
1446 	tess.dlightBits |= dlightBits;
1447 
1448 	// determine the allowable discrepance
1449 	lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );
1450 
1451 	// determine which rows and columns of the subdivision
1452 	// we are actually going to use
1453 	widthTable[0] = 0;
1454 	lodWidth = 1;
1455 	for ( i = 1 ; i < cv->width-1 ; i++ ) {
1456 		if ( cv->widthLodError[i] <= lodError ) {
1457 			widthTable[lodWidth] = i;
1458 			lodWidth++;
1459 		}
1460 	}
1461 	widthTable[lodWidth] = cv->width-1;
1462 	lodWidth++;
1463 
1464 	heightTable[0] = 0;
1465 	lodHeight = 1;
1466 	for ( i = 1 ; i < cv->height-1 ; i++ ) {
1467 		if ( cv->heightLodError[i] <= lodError ) {
1468 			heightTable[lodHeight] = i;
1469 			lodHeight++;
1470 		}
1471 	}
1472 	heightTable[lodHeight] = cv->height-1;
1473 	lodHeight++;
1474 
1475 
1476 	// very large grids may have more points or indexes than can be fit
1477 	// in the tess structure, so we may have to issue it in multiple passes
1478 
1479 	used = 0;
1480 	rows = 0;
1481 	while ( used < lodHeight - 1 ) {
1482 		// see how many rows of both verts and indexes we can add without overflowing
1483 		do {
1484 			vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
1485 			irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
1486 
1487 			// if we don't have enough space for at least one strip, flush the buffer
1488 			if ( vrows < 2 || irows < 1 ) {
1489 				RB_EndSurface();
1490 				RB_BeginSurface(tess.shader, tess.fogNum );
1491 			} else {
1492 				break;
1493 			}
1494 		} while ( 1 );
1495 
1496 		rows = irows;
1497 		if ( vrows < irows + 1 ) {
1498 			rows = vrows - 1;
1499 		}
1500 		if ( used + rows > lodHeight ) {
1501 			rows = lodHeight - used;
1502 		}
1503 
1504 		numVertexes = tess.numVertexes;
1505 
1506 		xyz = tess.xyz[numVertexes];
1507 		normal = tess.normal[numVertexes];
1508 		texCoords = tess.texCoords[numVertexes][0];
1509 		color = ( unsigned char * ) &tess.vertexColors[numVertexes];
1510 		vDlightBits = &tess.vertexDlightBits[numVertexes];
1511 
1512 		for ( i = 0 ; i < rows ; i++ ) {
1513 			for ( j = 0 ; j < lodWidth ; j++ ) {
1514 				dv = cv->verts + heightTable[ used + i ] * cv->width
1515 					+ widthTable[ j ];
1516 
1517 				xyz[0] = dv->xyz[0];
1518 				xyz[1] = dv->xyz[1];
1519 				xyz[2] = dv->xyz[2];
1520 				xyz += 4;
1521 
1522 				texCoords[0] = dv->st[0];
1523 				texCoords[1] = dv->st[1];
1524 
1525 				for(k=0;k<MAXLIGHTMAPS;k++)
1526 				{
1527 					texCoords[2+(k*2)]= dv->lightmap[k][0];
1528 					texCoords[2+(k*2)+1]= dv->lightmap[k][1];
1529 				}
1530 				texCoords += NUM_TEX_COORDS*2;
1531 
1532 //				if ( needsNormal )
1533 				{
1534 					normal[0] = dv->normal[0];
1535 					normal[1] = dv->normal[1];
1536 					normal[2] = dv->normal[2];
1537 				}
1538 				normal += 4;
1539 				*(unsigned *)color = ComputeFinalVertexColor((byte *)dv->color);
1540 				color += 4;
1541 				*vDlightBits++ = dlightBits;
1542 			}
1543 		}
1544 
1545 		// add the indexes
1546 		{
1547 			int		numIndexes;
1548 			int		w, h;
1549 
1550 			h = rows - 1;
1551 			w = lodWidth - 1;
1552 			numIndexes = tess.numIndexes;
1553 			for (i = 0 ; i < h ; i++) {
1554 				for (j = 0 ; j < w ; j++) {
1555 					int		v1, v2, v3, v4;
1556 
1557 					// vertex order to be reckognized as tristrips
1558 					v1 = numVertexes + i*lodWidth + j + 1;
1559 					v2 = v1 - 1;
1560 					v3 = v2 + lodWidth;
1561 					v4 = v3 + 1;
1562 
1563 					tess.indexes[numIndexes] = v2;
1564 					tess.indexes[numIndexes+1] = v3;
1565 					tess.indexes[numIndexes+2] = v1;
1566 
1567 					tess.indexes[numIndexes+3] = v1;
1568 					tess.indexes[numIndexes+4] = v3;
1569 					tess.indexes[numIndexes+5] = v4;
1570 					numIndexes += 6;
1571 				}
1572 			}
1573 
1574 			tess.numIndexes = numIndexes;
1575 		}
1576 
1577 		tess.numVertexes += rows * lodWidth;
1578 
1579 		used += rows - 1;
1580 	}
1581 }
1582 
1583 #define LATHE_SEG_STEP	10
1584 #define BEZIER_STEP		0.05f	// must be in the range of 0 to 1
1585 
1586 // FIXME: This function is horribly expensive
RB_SurfaceLathe()1587 static void RB_SurfaceLathe()
1588 {
1589 	refEntity_t *e;
1590 	vec2_t		pt, oldpt, l_oldpt;
1591 	vec2_t		pt2, oldpt2, l_oldpt2;
1592 	float		bezierStep, latheStep;
1593     float		temp, mu, mum1;
1594 	float		mum13, mu3, group1, group2;
1595 	float		s, c, d = 1.0f, pain = 0.0f;
1596 	int			i, t, vbase;
1597 
1598 	e = &backEnd.currentEntity->e;
1599 
1600 	if ( e->endTime && e->endTime > backEnd.refdef.time )
1601 	{
1602 		d = 1.0f - ( e->endTime - backEnd.refdef.time ) / 1000.0f;
1603 	}
1604 
1605 	if ( e->frame && e->frame + 1000 > backEnd.refdef.time )
1606 	{
1607 		pain = ( backEnd.refdef.time - e->frame ) / 1000.0f;
1608 //		pain *= pain;
1609 		pain = ( 1.0f - pain ) * 0.08f;
1610 	}
1611 
1612 	VectorSet2( l_oldpt, e->axis[0][0], e->axis[0][1] );
1613 
1614 	// do scalability stuff...r_lodbias 0-3
1615 	int lod = r_lodbias->integer + 1;
1616 	if ( lod > 4 )
1617 	{
1618 		lod = 4;
1619 	}
1620 	if ( lod < 1 )
1621 	{
1622 		lod = 1;
1623 	}
1624 	bezierStep = BEZIER_STEP * lod;
1625 	latheStep = LATHE_SEG_STEP * lod;
1626 
1627 	// Do bezier profile strip, then lathe this around to make a 3d model
1628 	for ( mu = 0.0f; mu <= 1.01f * d; mu += bezierStep )
1629 	{
1630 		// Four point curve
1631 		mum1	= 1 - mu;
1632 		mum13	= mum1 * mum1 * mum1;
1633 		mu3		= mu * mu * mu;
1634 		group1	= 3 * mu * mum1 * mum1;
1635 		group2	= 3 * mu * mu *mum1;
1636 
1637 		// Calc the current point on the curve
1638 		for ( i = 0; i < 2; i++ )
1639 		{
1640 			l_oldpt2[i] = mum13 * e->axis[0][i] + group1 * e->axis[1][i] + group2 * e->axis[2][i] + mu3 * e->oldorigin[i];
1641 		}
1642 
1643 		VectorSet2( oldpt, l_oldpt[0], 0 );
1644 		VectorSet2( oldpt2, l_oldpt2[0], 0 );
1645 
1646 		// lathe patch section around in a complete circle
1647 		for ( t = latheStep; t <= 360; t += latheStep )
1648 		{
1649 			VectorSet2( pt, l_oldpt[0], 0 );
1650 			VectorSet2( pt2, l_oldpt2[0], 0 );
1651 
1652 			s = sin( DEG2RAD( t ));
1653 			c = cos( DEG2RAD( t ));
1654 
1655 			// rotate lathe points
1656 //c -s 0
1657 //s  c 0
1658 //0  0 1
1659 			temp = c * pt[0] - s * pt[1];
1660 			pt[1] = s * pt[0] + c * pt[1];
1661 			pt[0] = temp;
1662 			temp = c * pt2[0] - s * pt2[1];
1663 			pt2[1] = s * pt2[0] + c * pt2[1];
1664 			pt2[0] = temp;
1665 
1666 			RB_CHECKOVERFLOW( 4, 6 );
1667 
1668 			vbase = tess.numVertexes;
1669 
1670 			// Actually generate the necessary verts
1671 			VectorSet( tess.normal[tess.numVertexes], oldpt[0], oldpt[1], l_oldpt[1] );
1672 			VectorAdd( e->origin, tess.normal[tess.numVertexes], tess.xyz[tess.numVertexes] );
1673 			VectorNormalize( tess.normal[tess.numVertexes] );
1674 			i = oldpt[0] * 0.1f + oldpt[1] * 0.1f;
1675 			tess.texCoords[tess.numVertexes][0][0] = (t-latheStep)/360.0f;
1676 			tess.texCoords[tess.numVertexes][0][1] = mu-bezierStep + cos( i + backEnd.refdef.floatTime ) * pain;
1677 			tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
1678 			tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
1679 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
1680 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1681 			tess.numVertexes++;
1682 
1683 			VectorSet( tess.normal[tess.numVertexes], oldpt2[0], oldpt2[1], l_oldpt2[1] );
1684 			VectorAdd( e->origin, tess.normal[tess.numVertexes], tess.xyz[tess.numVertexes] );
1685 			VectorNormalize( tess.normal[tess.numVertexes] );
1686 			i = oldpt2[0] * 0.1f + oldpt2[1] * 0.1f;
1687 			tess.texCoords[tess.numVertexes][0][0] = (t-latheStep) / 360.0f;
1688 			tess.texCoords[tess.numVertexes][0][1] = mu + cos( i + backEnd.refdef.floatTime ) * pain;
1689 			tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
1690 			tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
1691 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
1692 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1693 			tess.numVertexes++;
1694 
1695 			VectorSet( tess.normal[tess.numVertexes], pt[0], pt[1], l_oldpt[1] );
1696 			VectorAdd( e->origin, tess.normal[tess.numVertexes], tess.xyz[tess.numVertexes] );
1697 			VectorNormalize( tess.normal[tess.numVertexes] );
1698 			i = pt[0] * 0.1f + pt[1] * 0.1f;
1699 			tess.texCoords[tess.numVertexes][0][0] = t/360.0f;
1700 			tess.texCoords[tess.numVertexes][0][1] = mu-bezierStep + cos( i + backEnd.refdef.floatTime ) * pain;
1701 			tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
1702 			tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
1703 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
1704 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1705 			tess.numVertexes++;
1706 
1707 			VectorSet( tess.normal[tess.numVertexes], pt2[0], pt2[1], l_oldpt2[1] );
1708 			VectorAdd( e->origin, tess.normal[tess.numVertexes], tess.xyz[tess.numVertexes] );
1709 			VectorNormalize( tess.normal[tess.numVertexes] );
1710 			i = pt2[0] * 0.1f + pt2[1] * 0.1f;
1711 			tess.texCoords[tess.numVertexes][0][0] = t/360.0f;
1712 			tess.texCoords[tess.numVertexes][0][1] = mu + cos( i + backEnd.refdef.floatTime ) * pain;
1713 			tess.vertexColors[tess.numVertexes][0] = e->shaderRGBA[0];
1714 			tess.vertexColors[tess.numVertexes][1] = e->shaderRGBA[1];
1715 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[2];
1716 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1717 			tess.numVertexes++;
1718 
1719 			tess.indexes[tess.numIndexes++] = vbase;
1720 			tess.indexes[tess.numIndexes++] = vbase + 1;
1721 			tess.indexes[tess.numIndexes++] = vbase + 3;
1722 
1723 			tess.indexes[tess.numIndexes++] = vbase + 3;
1724 			tess.indexes[tess.numIndexes++] = vbase + 2;
1725 			tess.indexes[tess.numIndexes++] = vbase;
1726 
1727 			// Shuffle new points to old
1728 			VectorCopy2( pt, oldpt );
1729 			VectorCopy2( pt2, oldpt2 );
1730 		}
1731 
1732 		// shuffle lathe points
1733 		VectorCopy2( l_oldpt2, l_oldpt );
1734 	}
1735 }
1736 
1737 #define DISK_DEF	4
1738 #define TUBE_DEF	6
1739 
RB_SurfaceClouds()1740 static void RB_SurfaceClouds()
1741 {
1742 	// Disk definition
1743 	float diskStripDef[DISK_DEF] = {
1744 				0.0f,
1745 				0.4f,
1746 				0.7f,
1747 				1.0f };
1748 
1749 	float diskAlphaDef[DISK_DEF] = {
1750 				1.0f,
1751 				1.0f,
1752 				0.4f,
1753 				0.0f };
1754 
1755 	float diskCurveDef[DISK_DEF] = {
1756 				0.0f,
1757 				0.0f,
1758 				0.008f,
1759 				0.02f };
1760 
1761 	// tube definition
1762 	float tubeStripDef[TUBE_DEF] = {
1763 				0.0f,
1764 				0.05f,
1765 				0.1f,
1766 				0.5f,
1767 				0.7f,
1768 				1.0f };
1769 
1770 	float tubeAlphaDef[TUBE_DEF] = {
1771 				0.0f,
1772 				0.45f,
1773 				1.0f,
1774 				1.0f,
1775 				0.45f,
1776 				0.0f };
1777 
1778 	float tubeCurveDef[TUBE_DEF] = {
1779 				0.0f,
1780 				0.004f,
1781 				0.006f,
1782 				0.01f,
1783 				0.006f,
1784 				0.0f };
1785 
1786 	refEntity_t *e;
1787 	vec3_t		pt, oldpt;
1788 	vec3_t		pt2, oldpt2;
1789 	float		latheStep = 30.0f;
1790 	float		s, c, temp;
1791 	float		*stripDef, *alphaDef, *curveDef, ct;
1792 	int			i, t, vbase;
1793 
1794 	e = &backEnd.currentEntity->e;
1795 
1796 	// select which type we shall be doing
1797 	if ( e->renderfx & RF_GROW ) // doing tube type
1798 	{
1799 		ct = TUBE_DEF;
1800 		stripDef = tubeStripDef;
1801 		alphaDef = tubeAlphaDef;
1802 		curveDef = tubeCurveDef;
1803 		e->backlerp *= -1; // needs to be reversed
1804 	}
1805 	else
1806 	{
1807 		ct = DISK_DEF;
1808 		stripDef = diskStripDef;
1809 		alphaDef = diskAlphaDef;
1810 		curveDef = diskCurveDef;
1811 	}
1812 
1813 	// do the strip def, then lathe this around to make a 3d model
1814 	for ( i = 0; i < ct - 1; i++ )
1815 	{
1816 		VectorSet( oldpt,	(stripDef[i]	* (e->radius - e->rotation)) + e->rotation,	0, curveDef[i] * e->radius * e->backlerp );
1817 		VectorSet( oldpt2,	(stripDef[i+1]	* (e->radius - e->rotation)) + e->rotation,	0, curveDef[i+1] * e->radius * e->backlerp );
1818 
1819 		// lathe section around in a complete circle
1820 		for ( t = latheStep; t <= 360; t += latheStep )
1821 		{
1822 			// rotate every time except last seg
1823 			if ( t < 360.0f )
1824 			{
1825 				VectorCopy( oldpt, pt );
1826 				VectorCopy( oldpt2, pt2 );
1827 
1828 				s = sin( DEG2RAD( latheStep ));
1829 				c = cos( DEG2RAD( latheStep ));
1830 
1831 				// rotate lathe points
1832 				temp = c * pt[0] - s * pt[1];	// c -s 0
1833 				pt[1] = s * pt[0] + c * pt[1];	// s  c 0
1834 				pt[0] = temp;					// 0  0 1
1835 
1836 				temp = c * pt2[0] - s * pt2[1];	 // c -s 0
1837 				pt2[1] = s * pt2[0] + c * pt2[1];// s  c 0
1838 				pt2[0] = temp;					 // 0  0 1
1839 			}
1840 			else
1841 			{
1842 				// just glue directly to the def points.
1843 				VectorSet( pt,	(stripDef[i]	* (e->radius - e->rotation)) + e->rotation,	0, curveDef[i] * e->radius * e->backlerp );
1844 				VectorSet( pt2,	(stripDef[i+1]	* (e->radius - e->rotation)) + e->rotation,	0, curveDef[i+1] * e->radius * e->backlerp );
1845 			}
1846 
1847 			RB_CHECKOVERFLOW( 4, 6 );
1848 
1849 			vbase = tess.numVertexes;
1850 
1851 			// Actually generate the necessary verts
1852 			VectorAdd( e->origin, oldpt, tess.xyz[tess.numVertexes] );
1853 			tess.texCoords[tess.numVertexes][0][0] = tess.xyz[tess.numVertexes][0] * 0.1f;
1854 			tess.texCoords[tess.numVertexes][0][1] = tess.xyz[tess.numVertexes][1] * 0.1f;
1855 			tess.vertexColors[tess.numVertexes][0] =
1856 			tess.vertexColors[tess.numVertexes][1] =
1857 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[0] * alphaDef[i];
1858 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1859 			tess.numVertexes++;
1860 
1861 			VectorAdd( e->origin, oldpt2, tess.xyz[tess.numVertexes] );
1862 			tess.texCoords[tess.numVertexes][0][0] = tess.xyz[tess.numVertexes][0] * 0.1f;
1863 			tess.texCoords[tess.numVertexes][0][1] = tess.xyz[tess.numVertexes][1] * 0.1f;
1864 			tess.vertexColors[tess.numVertexes][0] =
1865 			tess.vertexColors[tess.numVertexes][1] =
1866 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[0] * alphaDef[i+1];
1867 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1868 			tess.numVertexes++;
1869 
1870 			VectorAdd( e->origin, pt, tess.xyz[tess.numVertexes] );
1871 			tess.texCoords[tess.numVertexes][0][0] = tess.xyz[tess.numVertexes][0] * 0.1f;
1872 			tess.texCoords[tess.numVertexes][0][1] = tess.xyz[tess.numVertexes][1] * 0.1f;
1873 			tess.vertexColors[tess.numVertexes][0] =
1874 			tess.vertexColors[tess.numVertexes][1] =
1875 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[0] * alphaDef[i];
1876 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1877 			tess.numVertexes++;
1878 
1879 			VectorAdd( e->origin, pt2, tess.xyz[tess.numVertexes] );
1880 			tess.texCoords[tess.numVertexes][0][0] = tess.xyz[tess.numVertexes][0] * 0.1f;
1881 			tess.texCoords[tess.numVertexes][0][1] = tess.xyz[tess.numVertexes][1] * 0.1f;
1882 			tess.vertexColors[tess.numVertexes][0] =
1883 			tess.vertexColors[tess.numVertexes][1] =
1884 			tess.vertexColors[tess.numVertexes][2] = e->shaderRGBA[0] * alphaDef[i+1];
1885 			tess.vertexColors[tess.numVertexes][3] = e->shaderRGBA[3];
1886 			tess.numVertexes++;
1887 
1888 			tess.indexes[tess.numIndexes++] = vbase;
1889 			tess.indexes[tess.numIndexes++] = vbase + 1;
1890 			tess.indexes[tess.numIndexes++] = vbase + 3;
1891 
1892 			tess.indexes[tess.numIndexes++] = vbase + 3;
1893 			tess.indexes[tess.numIndexes++] = vbase + 2;
1894 			tess.indexes[tess.numIndexes++] = vbase;
1895 
1896 			// Shuffle new points to old
1897 			VectorCopy2( pt, oldpt );
1898 			VectorCopy2( pt2, oldpt2 );
1899 		}
1900 	}
1901 }
1902 
1903 
1904 /*
1905 ===========================================================================
1906 
1907 NULL MODEL
1908 
1909 ===========================================================================
1910 */
1911 
1912 /*
1913 ===================
1914 RB_SurfaceAxis
1915 
1916 Draws x/y/z lines from the origin for orientation debugging
1917 ===================
1918 */
RB_SurfaceAxis(void)1919 static void RB_SurfaceAxis( void ) {
1920 	GL_Bind( tr.whiteImage );
1921 	GL_State( GLS_DEFAULT );
1922 	qglLineWidth( 3 );
1923 	qglBegin( GL_LINES );
1924 	qglColor3f( 1,0,0 );
1925 	qglVertex3f( 0,0,0 );
1926 	qglVertex3f( 16,0,0 );
1927 	qglColor3f( 0,1,0 );
1928 	qglVertex3f( 0,0,0 );
1929 	qglVertex3f( 0,16,0 );
1930 	qglColor3f( 0,0,1 );
1931 	qglVertex3f( 0,0,0 );
1932 	qglVertex3f( 0,0,16 );
1933 	qglEnd();
1934 	qglLineWidth( 1 );
1935 }
1936 
1937 //===========================================================================
1938 
1939 /*
1940 ====================
1941 RB_SurfaceEntity
1942 
1943 Entities that have a single procedurally generated surface
1944 ====================
1945 */
RB_SurfaceEntity(surfaceType_t * surfType)1946 void RB_SurfaceEntity( surfaceType_t *surfType ) {
1947 	switch( backEnd.currentEntity->e.reType ) {
1948 	case RT_SPRITE:
1949 		RB_SurfaceSprite();
1950 		break;
1951 	case RT_ORIENTED_QUAD:
1952 		RB_SurfaceOrientedQuad();
1953 		break;
1954 	case RT_LINE:
1955 		RB_SurfaceLine();
1956 		break;
1957 	case RT_ELECTRICITY:
1958 		RB_SurfaceElectricity();
1959 		break;
1960 	case RT_BEAM:
1961 		RB_SurfaceBeam();
1962 		break;
1963 	case RT_SABER_GLOW:
1964 		RB_SurfaceSaberGlow();
1965 		break;
1966 	case RT_CYLINDER:
1967 		RB_SurfaceCylinder();
1968 		break;
1969 	case RT_LATHE:
1970 		RB_SurfaceLathe();
1971 		break;
1972 	case RT_CLOUDS:
1973 		RB_SurfaceClouds();
1974 		break;
1975 	default:
1976 		RB_SurfaceAxis();
1977 		break;
1978 	}
1979 	return;
1980 }
1981 
RB_SurfaceBad(surfaceType_t * surfType)1982 void RB_SurfaceBad( surfaceType_t *surfType ) {
1983 	ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
1984 }
1985 
1986 
1987 /*
1988 ==================
1989 RB_TestZFlare
1990 
1991 This is called at surface tesselation time
1992 ==================
1993 */
RB_TestZFlare(vec3_t point)1994 static bool RB_TestZFlare( vec3_t point) {
1995 	int				i;
1996 	vec4_t			eye, clip, normalized, window;
1997 
1998 	// if the point is off the screen, don't bother adding it
1999 	// calculate screen coordinates and depth
2000 	R_TransformModelToClip( point, backEnd.ori.modelMatrix,
2001 		backEnd.viewParms.projectionMatrix, eye, clip );
2002 
2003 	// check to see if the point is completely off screen
2004 	for ( i = 0 ; i < 3 ; i++ ) {
2005 		if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
2006 			return qfalse;
2007 		}
2008 	}
2009 
2010 	R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
2011 
2012 	if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
2013 		|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
2014 		return qfalse;	// shouldn't happen, since we check the clip[] above, except for FP rounding
2015 	}
2016 
2017 //do test
2018 	float			depth = 0.0f;
2019 	bool			visible;
2020 	float			screenZ;
2021 
2022 	// read back the z buffer contents
2023 	if ( r_flares->integer !=1 ) {	//skipping the the z-test
2024 		return true;
2025 	}
2026 	// doing a readpixels is as good as doing a glFinish(), so
2027 	// don't bother with another sync
2028 	glState.finishCalled = qfalse;
2029 	qglReadPixels( backEnd.viewParms.viewportX + window[0],backEnd.viewParms.viewportY + window[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
2030 
2031 	screenZ = backEnd.viewParms.projectionMatrix[14] /
2032 		( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
2033 
2034 	visible = ( -eye[2] - -screenZ ) < 24;
2035 	return visible;
2036 }
2037 
RB_SurfaceFlare(srfFlare_t * surf)2038 void RB_SurfaceFlare( srfFlare_t *surf ) {
2039 	vec3_t		left, up;
2040 	float		radius;
2041 	byte		color[4];
2042 	vec3_t		dir;
2043 	vec3_t		origin;
2044 	float		d, dist;
2045 
2046 	if ( !r_flares->integer ) {
2047 		return;
2048 	}
2049 
2050 	if (!RB_TestZFlare( surf->origin ) ) {
2051 		return;
2052 	}
2053 
2054 	// calculate the xyz locations for the four corners
2055 	VectorMA( surf->origin, 3, surf->normal, origin );
2056 	float* snormal = surf->normal;
2057 
2058 	VectorSubtract( origin, backEnd.viewParms.ori.origin, dir );
2059 	dist = VectorNormalize( dir );
2060 
2061 	d = -DotProduct( dir, snormal );
2062 	if ( d < 0 ) {
2063 		d = -d;
2064 	}
2065 
2066 	// fade the intensity of the flare down as the
2067 	// light surface turns away from the viewer
2068 	color[0] = d * 255;
2069 	color[1] = d * 255;
2070 	color[2] = d * 255;
2071 	color[3] = 255;	//only gets used if the shader has cgen exact_vertex!
2072 
2073 	radius = tess.shader->portalRange ? tess.shader->portalRange: 30;
2074 	if (dist < 512.0f)
2075 	{
2076 		radius = radius * dist / 512.0f;
2077 	}
2078 	if (radius<5.0f)
2079 	{
2080 		radius = 5.0f;
2081 	}
2082 	VectorScale( backEnd.viewParms.ori.axis[1], radius, left );
2083 	VectorScale( backEnd.viewParms.ori.axis[2], radius, up );
2084 	if ( backEnd.viewParms.isMirror ) {
2085 		VectorSubtract( vec3_origin, left, left );
2086 	}
2087 
2088 	RB_AddQuadStamp( origin, left, up, color );
2089 }
2090 
2091 
RB_SurfaceDisplayList(srfDisplayList_t * surf)2092 void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
2093 	// all appropriate state must be set in RB_BeginSurface
2094 	// this isn't implemented yet...
2095 	qglCallList( surf->listNum );
2096 }
2097 
RB_SurfaceSkip(void * surf)2098 void RB_SurfaceSkip( void *surf ) {
2099 }
2100 
2101 void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
2102 	(void(*)(void*))RB_SurfaceBad,			// SF_BAD,
2103 	(void(*)(void*))RB_SurfaceSkip,			// SF_SKIP,
2104 	(void(*)(void*))RB_SurfaceFace,			// SF_FACE,
2105 	(void(*)(void*))RB_SurfaceGrid,			// SF_GRID,
2106 	(void(*)(void*))RB_SurfaceTriangles,	// SF_TRIANGLES,
2107 	(void(*)(void*))RB_SurfacePolychain,	// SF_POLY,
2108 	(void(*)(void*))RB_SurfaceMesh,			// SF_MD3,
2109 /*
2110 Ghoul2 Insert Start
2111 */
2112 
2113 	(void(*)(void*))RB_SurfaceGhoul,		// SF_MDX,
2114 /*
2115 Ghoul2 Insert End
2116 */
2117 
2118 	(void(*)(void*))RB_SurfaceFlare,		// SF_FLARE,
2119 	(void(*)(void*))RB_SurfaceEntity,		// SF_ENTITY
2120 	(void(*)(void*))RB_SurfaceDisplayList	// SF_DISPLAY_LIST
2121 };
2122