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