1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // cg_view.c
22 //
23
24 #include "cg_local.h"
25
26 /*
27 =======================================================================
28
29 SCREEN SIZE
30
31 =======================================================================
32 */
33
34 /*
35 ==============
36 V_TileClear
37 ==============
38 */
V_TileRect(int x,int y,int w,int h)39 static void V_TileRect (int x, int y, int w, int h)
40 {
41 if (w == 0 || h == 0)
42 return; // Prevents div by zero (should never happen)
43
44 if (cgMedia.tileBackShader)
45 cgi.R_DrawPic (cgMedia.tileBackShader, 0,
46 (float)x, (float)y, (float)w, (float)h,
47 x/64.0f, y/64.0f, (x+w)/64.0f, (y+h)/64.0f, Q_colorWhite);
48 else
49 CG_DrawFill ((float)x, (float)y, (float)w, (float)h, Q_colorBlack);
50 }
V_TileClear(void)51 static void V_TileClear (void)
52 {
53 int top, bottom, left, right;
54
55 if (viewsize->intVal >= 100)
56 return; // Full screen rendering
57
58 top = cg.refDef.y;
59 bottom = top + cg.refDef.height-1;
60 left = cg.refDef.x;
61 right = left + cg.refDef.width-1;
62
63 // Clear above view screen
64 V_TileRect (0, 0, cg.refConfig.vidWidth, top);
65
66 // Clear below view screen
67 V_TileRect (0, bottom, cg.refConfig.vidWidth, cg.refConfig.vidHeight - bottom);
68
69 // Clear left of view screen
70 V_TileRect (0, top, left, bottom - top + 1);
71
72 // Clear right of view screen
73 V_TileRect (right, top, cg.refConfig.vidWidth - right, bottom - top + 1);
74 }
75
76
77 /*
78 =================
79 V_CalcVrect
80
81 Sets the coordinates of the rendered window
82 =================
83 */
V_CalcVrect(void)84 static void V_CalcVrect (void)
85 {
86 int size;
87
88 // Bound viewsize
89 if (viewsize->intVal < 40)
90 cgi.Cvar_SetValue ("viewsize", 40, qTrue);
91 if (viewsize->intVal > 100)
92 cgi.Cvar_SetValue ("viewsize", 100, qTrue);
93
94 size = viewsize->intVal;
95
96 cg.refDef.width = cg.refConfig.vidWidth*size/100;
97 cg.refDef.width &= ~7;
98
99 cg.refDef.height = cg.refConfig.vidHeight*size/100;
100 cg.refDef.height &= ~1;
101
102 cg.refDef.x = (cg.refConfig.vidWidth - cg.refDef.width)/2;
103 cg.refDef.y = (cg.refConfig.vidHeight - cg.refDef.height)/2;
104
105 // Clear the background
106 V_TileClear ();
107 }
108
109
110 /*
111 =================
112 V_SizeUp_f
113 =================
114 */
V_SizeUp_f(void)115 static void V_SizeUp_f (void)
116 {
117 cgi.Cvar_SetValue ("viewsize", viewsize->intVal + 10.0f, qTrue);
118 }
119
120
121 /*
122 =================
123 V_SizeDown_f
124 =================
125 */
V_SizeDown_f(void)126 static void V_SizeDown_f (void)
127 {
128 cgi.Cvar_SetValue ("viewsize", viewsize->intVal - 10.0f, qTrue);
129 }
130
131 /*
132 =======================================================================
133
134 VIEW RENDERING
135
136 =======================================================================
137 */
138
139 /*
140 ================
141 V_TestParticles
142 ================
143 */
144 static cgParticle_t v_testParticleList[PT_PICTOTAL];
V_TestParticles(void)145 static void V_TestParticles (void)
146 {
147 int i;
148 float d, r, u;
149 vec3_t origin;
150 float scale;
151 bvec4_t outColor;
152 cgParticle_t *p;
153
154 cgi.R_ClearScene ();
155 Vec4Set (outColor, 255, 255, 255, 255);
156 scale = 1;
157
158 for (p=&v_testParticleList[0], i=0 ; i<PT_PICTOTAL ; i++, p++) {
159 d = i*0.5f;
160 r = 3*((i&7)-3.5f);
161 u = 3*(((i>>3)&7)-3.5f);
162
163 // Center
164 origin[0] = cg.refDef.viewOrigin[0] + cg.refDef.viewAxis[0][0]*d - cg.refDef.viewAxis[1][0]*r + cg.refDef.viewAxis[2][0]*u;
165 origin[1] = cg.refDef.viewOrigin[1] + cg.refDef.viewAxis[0][1]*d - cg.refDef.viewAxis[1][1]*r + cg.refDef.viewAxis[2][1]*u;
166 origin[2] = cg.refDef.viewOrigin[2] + cg.refDef.viewAxis[0][2]*d - cg.refDef.viewAxis[1][2]*r + cg.refDef.viewAxis[2][2]*u;
167
168 // Top left
169 *(int *)v_testParticleList[i].outColor[0] = *(int *)outColor;
170 Vec2Set (v_testParticleList[i].outCoords[0], 0, 0);
171 Vec3Set (v_testParticleList[i].outVertices[0], origin[0] + cg.refDef.viewAxis[2][0]*scale + cg.refDef.viewAxis[1][0]*scale,
172 origin[1] + cg.refDef.viewAxis[2][1]*scale + cg.refDef.viewAxis[1][1]*scale,
173 origin[2] + cg.refDef.viewAxis[2][2]*scale + cg.refDef.viewAxis[1][2]*scale);
174
175 // Bottom left
176 *(int *)v_testParticleList[i].outColor[0] = *(int *)outColor;
177 Vec2Set (v_testParticleList[i].outCoords[1], 0, 1);
178 Vec3Set (v_testParticleList[i].outVertices[1], origin[0] - cg.refDef.viewAxis[2][0]*scale + cg.refDef.viewAxis[1][0]*scale,
179 origin[1] - cg.refDef.viewAxis[2][1]*scale + cg.refDef.viewAxis[1][1]*scale,
180 origin[2] - cg.refDef.viewAxis[2][2]*scale + cg.refDef.viewAxis[1][2]*scale);
181
182 // Bottom right
183 *(int *)v_testParticleList[i].outColor[0] = *(int *)outColor;
184 Vec2Set (v_testParticleList[i].outCoords[2], 1, 1);
185 Vec3Set (v_testParticleList[i].outVertices[2], origin[0] - cg.refDef.viewAxis[2][0]*scale - cg.refDef.viewAxis[1][0]*scale,
186 origin[1] - cg.refDef.viewAxis[2][1]*scale - cg.refDef.viewAxis[1][1]*scale,
187 origin[2] - cg.refDef.viewAxis[2][2]*scale - cg.refDef.viewAxis[1][2]*scale);
188
189 // Top right
190 *(int *)v_testParticleList[i].outColor[0] = *(int *)outColor;
191 Vec2Set (v_testParticleList[i].outCoords[3], 1, 0);
192 Vec3Set (v_testParticleList[i].outVertices[3], origin[0] + cg.refDef.viewAxis[2][0]*scale - cg.refDef.viewAxis[1][0]*scale,
193 origin[1] + cg.refDef.viewAxis[2][1]*scale - cg.refDef.viewAxis[1][1]*scale,
194 origin[2] + cg.refDef.viewAxis[2][2]*scale - cg.refDef.viewAxis[1][2]*scale);
195
196 // Render it
197 p->outPoly.numVerts = 4;
198 p->outPoly.colors = v_testParticleList[i].outColor;
199 p->outPoly.texCoords = v_testParticleList[i].outCoords;
200 p->outPoly.vertices = v_testParticleList[i].outVertices;
201 p->outPoly.shader = cgMedia.particleTable[i % PT_PICTOTAL];
202 p->outPoly.shaderTime = 0;
203
204 cgi.R_AddPoly (&p->outPoly);
205 }
206 }
207
208
209 /*
210 ================
211 V_TestEntities
212 ================
213 */
V_TestEntities(void)214 static void V_TestEntities (void)
215 {
216 int i, j;
217 float f, r;
218 refEntity_t ent;
219
220 cgi.R_ClearScene ();
221 for (i=0 ; i<32 ; i++) {
222 r = 64 * ((i%4) - 1.5f);
223 f = 64 * (i/40.f) + 128;
224
225 for (j=0 ; j<3 ; j++) {
226 ent.origin[j] = cg.refDef.viewOrigin[j] + cg.refDef.viewAxis[0][j]*f - cg.refDef.viewAxis[1][j]*r;
227 ent.oldOrigin[j] = ent.origin[j];
228 }
229
230 Matrix3_Identity (ent.axis);
231
232 ent.model = cg.baseClientInfo.model;
233 ent.skin = cg.baseClientInfo.skin;
234 ent.skinNum = 0;
235
236 ent.flags = 0;
237 ent.scale = 1;
238 Vec4Set (ent.color, 255, 255, 255, 255);
239
240 ent.backLerp = 0;
241 ent.frame = 0;
242 ent.oldFrame = 0;
243
244 cgi.R_AddEntity (&ent);
245 }
246 }
247
248
249 /*
250 ================
251 V_TestLights
252 ================
253 */
V_TestLights(void)254 static void V_TestLights (void)
255 {
256 int i;
257 float f, r;
258 vec3_t origin;
259 float red, green, blue;
260
261 for (i=0 ; i<32 ; i++) {
262 r = 64 * ((i%4) - 1.5f);
263 f = 64 * (i/40.f) + 128;
264
265 origin[0] = cg.refDef.viewOrigin[0] + cg.refDef.viewAxis[0][0]*f - cg.refDef.viewAxis[1][0]*r;
266 origin[1] = cg.refDef.viewOrigin[1] + cg.refDef.viewAxis[0][1]*f - cg.refDef.viewAxis[1][1]*r;
267 origin[2] = cg.refDef.viewOrigin[2] + cg.refDef.viewAxis[0][2]*f - cg.refDef.viewAxis[1][2]*r;
268
269 red = (float)(((i%6)+1) & 1);
270 green = (float)((((i%6)+1) & 2)>>1);
271 blue = (float)((((i%6)+1) & 4)>>2);
272
273 cgi.R_AddLight (origin, 200, red, green, blue);
274 }
275 }
276
277 // ====================================================================
278
279 /*
280 ===============
281 V_CalcThirdPersonView
282 ===============
283 */
ClipCam(vec3_t start,vec3_t end,vec3_t newPos)284 static void ClipCam (vec3_t start, vec3_t end, vec3_t newPos)
285 {
286 trace_t tr;
287 vec3_t mins, maxs;
288
289 Vec3Set (mins, -5, -5, -5);
290 Vec3Set (maxs, 5, 5, 5);
291
292 CG_PMTrace (&tr, start, mins, maxs, end, qTrue);
293
294 newPos[0] = tr.endPos[0];
295 newPos[1] = tr.endPos[1];
296 newPos[2] = tr.endPos[2];
297 }
V_CalcThirdPersonView(void)298 static void V_CalcThirdPersonView (void)
299 {
300 vec3_t end, camPosition;
301 vec3_t dir, newAngles;
302 float upDist, backDist, angle;
303
304 // Set the camera angle
305 if (cg_thirdPersonAngle->modified) {
306 cg_thirdPersonAngle->modified = qFalse;
307
308 if (cg_thirdPersonAngle->floatVal < 0.0f)
309 cgi.Cvar_SetValue ("cg_thirdPersonAngle", 0.0f, qTrue);
310 }
311
312 // Set the camera distance
313 if (cg_thirdPersonDist->modified) {
314 cg_thirdPersonDist->modified = qFalse;
315
316 if (cg_thirdPersonDist->floatVal < 1.0f)
317 cgi.Cvar_SetValue ("cg_thirdPersonDist", 1.0f, qTrue);
318 }
319
320 // Trig stuff
321 angle = M_PI * (cg_thirdPersonAngle->floatVal / 180.0f);
322 upDist = cg_thirdPersonDist->floatVal * sin (angle);
323 backDist = cg_thirdPersonDist->floatVal * cos (angle);
324
325 // Move up
326 Vec3MA (cg.refDef.viewOrigin, -backDist, cg.refDef.viewAxis[0], end);
327 Vec3MA (end, upDist, cg.refDef.viewAxis[2], end);
328
329 // Clip
330 ClipCam (cg.refDef.viewOrigin, end, camPosition);
331
332 // Adjust player transparency
333 cg.cameraTrans = Vec3DistFast (cg.refDef.viewOrigin, camPosition);
334 if (cg.cameraTrans < cg_thirdPersonDist->floatVal) {
335 cg.cameraTrans = (cg.cameraTrans / cg_thirdPersonDist->floatVal) * 255;
336
337 if (cg.cameraTrans == 0)
338 return;
339 else if (cg.cameraTrans > 245)
340 cg.cameraTrans = 245;
341 }
342 else {
343 cg.cameraTrans = 255;
344 }
345
346 // Clip and adjust aim
347 if (cg_thirdPersonClip->intVal) {
348 Vec3MA (cg.refDef.viewOrigin, 8192, cg.refDef.viewAxis[0], dir);
349 ClipCam (cg.refDef.viewOrigin, dir, newAngles);
350
351 Vec3Subtract (newAngles, camPosition, dir);
352 VectorNormalizef (dir, dir);
353 VecToAngles (dir, newAngles);
354
355 // Apply
356 Vec3Copy (newAngles, cg.refDef.viewAngles);
357 Angles_Matrix3 (cg.refDef.viewAngles, cg.refDef.viewAxis);
358 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
359 }
360
361 Vec3Copy (camPosition, cg.refDef.viewOrigin);
362 }
363
364
365 /*
366 ===============
367 V_CalcViewValues
368
369 Sets cg.refDef view values
370 ===============
371 */
V_CalcViewValues(void)372 static void V_CalcViewValues (void)
373 {
374 playerStateNew_t *ps, *ops;
375 cgEntity_t *ent;
376 int i;
377
378 // Set cg.lerpFrac
379 if (cgi.Cvar_GetIntegerValue ("timedemo"))
380 cg.lerpFrac = 1.0f;
381 else
382 cg.lerpFrac = 1.0f - (cg.frame.serverTime - cg.refreshTime)*0.01f;
383
384 // Find the previous frame to interpolate from
385 ps = &cg.frame.playerState;
386 if (cg.oldFrame.serverFrame != cg.frame.serverFrame-1 || !cg.oldFrame.valid)
387 ops = &cg.frame.playerState; // previous frame was dropped or invalid
388 else
389 ops = &cg.oldFrame.playerState;
390
391 // See if the player entity was teleported this frame
392 if (fabs (ops->pMove.origin[0] - ps->pMove.origin[0]) > 256*8
393 || abs (ops->pMove.origin[1] - ps->pMove.origin[1]) > 256*8
394 || abs (ops->pMove.origin[2] - ps->pMove.origin[2]) > 256*8)
395 ops = ps; // don't interpolate
396
397 ent = &cg_entityList[cg.playerNum+1];
398
399 // Calculate the origin
400 if (cl_predict->intVal && !(cg.frame.playerState.pMove.pmFlags & PMF_NO_PREDICTION)) {
401 // Use predicted values
402 uint32 delta;
403 float backLerp;
404
405 backLerp = 1.0f - cg.lerpFrac;
406 for (i=0 ; i<3 ; i++) {
407 cg.refDef.viewOrigin[i] = cg.predicted.origin[i] + ops->viewOffset[i]
408 + cg.lerpFrac*(ps->viewOffset[i] - ops->viewOffset[i])
409 - backLerp*cg.predicted.error[i];
410 }
411
412 // Smooth out stair climbing
413 delta = cg.realTime - cg.predicted.stepTime;
414 if (delta < 150)
415 cg.refDef.viewOrigin[2] -= cg.predicted.step * (150 - delta) / 150;
416 }
417 else {
418 // Just use interpolated values
419 for (i=0 ; i<3 ; i++) {
420 cg.refDef.viewOrigin[i] = ops->pMove.origin[i]*(1.0f/8.0f) + ops->viewOffset[i]
421 + cg.lerpFrac*(ps->pMove.origin[i]*(1.0f/8.0f) + ps->viewOffset[i]
422 - (ops->pMove.origin[i]*(1.0f/8.0f) + ops->viewOffset[i]));
423 }
424 }
425
426 // If not running a demo or on a locked frame, add the local angle movement
427 if (cg.frame.playerState.pMove.pmType < PMT_DEAD && !cg.attractLoop) {
428 // Use predicted values
429 Vec3Copy (cg.predicted.angles, cg.refDef.viewAngles);
430 }
431 else {
432 // Just use interpolated values
433 if (cg.frame.playerState.pMove.pmType >= PMT_DEAD && ops->pMove.pmType < PMT_DEAD) {
434 cg.refDef.viewAngles[0] = LerpAngle (cg.predicted.angles[0], ps->viewAngles[0], cg.lerpFrac);
435 cg.refDef.viewAngles[1] = LerpAngle (cg.predicted.angles[1], ps->viewAngles[1], cg.lerpFrac);
436 cg.refDef.viewAngles[2] = LerpAngle (cg.predicted.angles[2], ps->viewAngles[2], cg.lerpFrac);
437 }
438 else {
439 cg.refDef.viewAngles[0] = LerpAngle (ops->viewAngles[0], ps->viewAngles[0], cg.lerpFrac);
440 cg.refDef.viewAngles[1] = LerpAngle (ops->viewAngles[1], ps->viewAngles[1], cg.lerpFrac);
441 cg.refDef.viewAngles[2] = LerpAngle (ops->viewAngles[2], ps->viewAngles[2], cg.lerpFrac);
442 }
443 }
444
445 // Add kick angles
446 cg.refDef.viewAngles[0] += LerpAngle (ops->kickAngles[0], ps->kickAngles[0], cg.lerpFrac);
447 cg.refDef.viewAngles[1] += LerpAngle (ops->kickAngles[1], ps->kickAngles[1], cg.lerpFrac);
448 cg.refDef.viewAngles[2] += LerpAngle (ops->kickAngles[2], ps->kickAngles[2], cg.lerpFrac);
449
450 // Calculate direction vectors
451 Angles_Matrix3 (cg.refDef.viewAngles, cg.refDef.viewAxis);
452 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
453
454 // Interpolate field of view
455 cg.refDef.fovX = ops->fov + cg.lerpFrac * (ps->fov - ops->fov);
456
457 // Don't interpolate blend color
458 Vec4Copy (ps->viewBlend, cg.viewBlend);
459
460 // Offset if in third person
461 if (cg.thirdPerson)
462 V_CalcThirdPersonView ();
463 }
464
465
466 /*
467 ==================
468 V_RenderView
469 ==================
470 */
471 #define FRAMETIME_MAX 0.5
V_RenderView(int realTime,float netFrameTime,float refreshFrameTime,float stereoSeparation,qBool refreshPrepped)472 void V_RenderView (int realTime, float netFrameTime, float refreshFrameTime, float stereoSeparation, qBool refreshPrepped)
473 {
474 // Check cvar sanity
475 CG_UpdateCvars ();
476
477 // Calculate screen dimensions and clear the background
478 V_CalcVrect ();
479
480 // Set time
481 cg.realTime = realTime;
482
483 cg.netFrameTime = netFrameTime;
484 cg.netTime += netFrameTime * 1000.0f;
485 cg.refreshFrameTime = refreshFrameTime;
486 cg.refreshTime += refreshFrameTime * 1000.0f;
487
488 // Clamp time
489 cg.netTime = clamp (cg.netTime, cg.frame.serverTime - 100, cg.frame.serverTime);
490 if (cg.netFrameTime > FRAMETIME_MAX)
491 cg.netFrameTime = FRAMETIME_MAX;
492
493 cg.refreshTime = clamp (cg.refreshTime, cg.frame.serverTime - 100, cg.frame.serverTime);
494 if (cg.refreshFrameTime > FRAMETIME_MAX)
495 cg.refreshFrameTime = FRAMETIME_MAX;
496
497 // Only update time if we're not rendering the scene
498 if (!cg.forceRefDef && (cg.mapLoading || !cg.frame.valid || cgi.Com_ClientState () != CA_ACTIVE || !refreshPrepped)) {
499 // Render the menu
500 switch (cgi.Com_ClientState ()) {
501 case CA_DISCONNECTED:
502 if (cgi.Key_GetDest () == KD_GAME)
503 CG_DrawConnectScreen ();
504 UI_Refresh (qTrue);
505 break;
506
507 case CA_CONNECTING:
508 case CA_CONNECTED:
509 case CA_ACTIVE:
510 CG_DrawConnectScreen ();
511 UI_Refresh (qFalse);
512 break;
513 }
514
515 return;
516 }
517
518 // Predict all unacknowledged movements
519 CG_PredictMovement ();
520
521 // Watch for gender bending if desired
522 CG_FixUpGender ();
523
524 // Run light styles
525 CG_RunLightStyles ();
526
527 // An invalid frame will just use the exact previous refdef
528 // We can't use the old frame if the video mode has changed, though
529 if (cg.frame.valid && (cg.forceRefDef || !cgi.Cvar_GetIntegerValue ("paused"))) {
530 cg.forceRefDef = qFalse;
531
532 cgi.R_ClearScene ();
533
534 // Calculate the view values
535 V_CalcViewValues ();
536
537 // Add in entities and effects
538 CG_AddEntities ();
539
540 // Testing testing...
541 if (cl_testblend->intVal) {
542 cg.viewBlend[0] = 1.0f;
543 cg.viewBlend[1] = 0.5f;
544 cg.viewBlend[2] = 0.25f;
545 cg.viewBlend[3] = 0.5f;
546 }
547 if (cl_testentities->intVal)
548 V_TestEntities ();
549 if (cl_testlights->intVal)
550 V_TestLights ();
551 if (cl_testparticles->intVal)
552 V_TestParticles ();
553
554 // Offset the viewOrigin if we're using stereo separation
555 if (stereoSeparation != 0)
556 Vec3MA (cg.refDef.viewOrigin, stereoSeparation, cg.refDef.rightVec, cg.refDef.viewOrigin);
557
558 // Never let it sit exactly on a node line, because a water plane
559 // can dissapear when viewed with the eye exactly on it. the server
560 // protocol only specifies to 1/8 pixel, so add 1/16 in each axis
561 cg.refDef.viewOrigin[0] += (1.0f/16.0f);
562 cg.refDef.viewOrigin[1] += (1.0f/16.0f);
563 cg.refDef.viewOrigin[2] += (1.0f/16.0f);
564
565 cg.refDef.velocity[0] = cg.predicted.velocity[0];
566 cg.refDef.velocity[1] = cg.predicted.velocity[1];
567 cg.refDef.velocity[2] = cg.predicted.velocity[2];
568
569 cg.refDef.fovY = Q_CalcFovY (cg.refDef.fovX, (float)cg.refDef.width, (float)cg.refDef.height);
570
571 cg.refDef.time = cg.refreshTime * 0.001f;
572
573 cg.refDef.areaChanged = cg.frame.areaChanged;
574 cg.refDef.areaBits = cg.frame.areaBits;
575
576 cg.refDef.rdFlags = cg.frame.playerState.rdFlags;
577 }
578
579 // Render the frame
580 cgi.R_RenderScene (&cg.refDef);
581
582 // Update orientation for sound subsystem
583 cgi.Snd_Update (&cg.refDef);
584
585 // Run subsystems
586 CG_RunDLights ();
587
588 // Render screen stuff
589 SCR_Draw ();
590
591 // Increment frame counter
592 cg.frameCount++;
593 }
594
595 /*
596 =======================================================================
597
598 CONSOLE FUNCTIONS
599
600 =======================================================================
601 */
602
603 /*
604 =============
605 V_Viewpos_f
606 =============
607 */
V_Viewpos_f(void)608 static void V_Viewpos_f (void)
609 {
610 Com_Printf (0, "(x%i y%i z%i) : yaw%i\n",
611 (int)cg.refDef.viewOrigin[0],
612 (int)cg.refDef.viewOrigin[1],
613 (int)cg.refDef.viewOrigin[2],
614 (int)cg.refDef.viewAngles[YAW]);
615 }
616
617
618 /*
619 ================
620 V_Benchmark_f
621 ================
622 */
V_Benchmark_f(void)623 static void V_Benchmark_f (void)
624 {
625 int i, j, times;
626 int start;
627 float time, timeinc;
628 float result;
629 refDef_t refDef;
630
631 memset (&refDef, 0, sizeof (refDef_t));
632
633 refDef.width = cg.refConfig.vidWidth;
634 refDef.height = cg.refConfig.vidHeight;
635 refDef.fovX = 90;
636 refDef.fovY = Q_CalcFovY (refDef.fovX, refDef.width, refDef.height);
637 Vec3MA (cg.frame.playerState.viewOffset, (1.0f/8.0f), cg.frame.playerState.pMove.origin, refDef.viewOrigin);
638
639 if (cgi.Cmd_Argc () >= 2)
640 times = atoi (cgi.Cmd_Argv (1));
641 else
642 times = 10;
643
644 for (j=0, result=0, timeinc=0 ; j<times ; j++) {
645 start = cgi.Sys_Milliseconds ();
646
647 if (cgi.Cmd_Argc () >= 3) {
648 // Run without page flipping
649 cgi.R_BeginFrame (0);
650 for (i=0 ; i<128 ; i++) {
651 refDef.viewAngles[1] = i/128.0*360.0;
652 Angles_Matrix3 (refDef.viewAngles, refDef.viewAxis);
653 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
654
655 cgi.R_RenderScene (&refDef);
656 }
657 cgi.R_EndFrame ();
658 }
659 else {
660 for (i=0 ; i<128 ; i++) {
661 refDef.viewAngles[1] = i/128.0*360.0;
662 Angles_Matrix3 (refDef.viewAngles, refDef.viewAxis);
663 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
664
665 cgi.R_BeginFrame (0);
666 cgi.R_RenderScene (&refDef);
667 cgi.R_EndFrame ();
668 }
669 }
670
671 time = (cgi.Sys_Milliseconds () - start) / 1000.0;
672 timeinc += time;
673 result += 128.0 / time;
674 }
675
676 Com_Printf (0, "%f secs, %f fps total\n", timeinc, result/times);
677 }
678
679
680 /*
681 ================
682 V_TimeRefresh_f
683 ================
684 */
V_TimeRefresh_f(void)685 static void V_TimeRefresh_f (void)
686 {
687 int i, start;
688 float time;
689 refDef_t refDef;
690
691 start = cgi.Sys_Milliseconds ();
692
693 memset (&refDef, 0, sizeof (refDef_t));
694
695 refDef.width = cg.refConfig.vidWidth;
696 refDef.height = cg.refConfig.vidHeight;
697 refDef.fovX = 90;
698 refDef.fovY = Q_CalcFovY (refDef.fovX, refDef.width, refDef.height);
699 Vec3MA (cg.frame.playerState.viewOffset, (1.0f/8.0f), cg.frame.playerState.pMove.origin, refDef.viewOrigin);
700
701 if (cgi.Cmd_Argc () == 2) {
702 // Run without page flipping
703 cgi.R_BeginFrame (0);
704 for (i=0 ; i<128 ; i++) {
705 refDef.viewAngles[1] = i/128.0*360.0;
706 Angles_Matrix3 (refDef.viewAngles, refDef.viewAxis);
707 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
708
709 cgi.R_RenderScene (&refDef);
710 }
711 cgi.R_EndFrame ();
712 }
713 else {
714 for (i=0 ; i<128 ; i++) {
715 refDef.viewAngles[1] = i/128.0*360.0;
716 Angles_Matrix3 (refDef.viewAngles, refDef.viewAxis);
717 Vec3Negate (cg.refDef.viewAxis[1], cg.refDef.rightVec);
718
719 cgi.R_BeginFrame (0);
720 cgi.R_RenderScene (&refDef);
721 cgi.R_EndFrame ();
722 }
723 }
724
725 time = (cgi.Sys_Milliseconds () - start) / 1000.0;
726 Com_Printf (0, "%f seconds (%f fps)\n", time, 128/time);
727 }
728
729 /*
730 =======================================================================
731
732 INIT / SHUTDOWN
733
734 =======================================================================
735 */
736
737 static void *cmd_sizeUp;
738 static void *cmd_sizeDown;
739 static void *cmd_viewPos;
740 static void *cmd_benchMark;
741 static void *cmd_timeRefresh;
742
743 /*
744 =============
745 V_Register
746 =============
747 */
V_Register(void)748 void V_Register (void)
749 {
750 cmd_sizeUp = cgi.Cmd_AddCommand ("sizeup", V_SizeUp_f, "Increases viewport size");
751 cmd_sizeDown = cgi.Cmd_AddCommand ("sizedown", V_SizeDown_f, "Decreases viewport size");
752
753 cmd_viewPos = cgi.Cmd_AddCommand ("viewpos", V_Viewpos_f, "Prints view position and yaw");
754
755 cmd_benchMark = cgi.Cmd_AddCommand ("benchmark", V_Benchmark_f, "Multiple speed tests for one scene");
756 cmd_timeRefresh = cgi.Cmd_AddCommand ("timerefresh", V_TimeRefresh_f, "Prints framerate of current scene");
757 }
758
759
760 /*
761 =============
762 V_Unregister
763 =============
764 */
V_Unregister(void)765 void V_Unregister (void)
766 {
767 cgi.Cmd_RemoveCommand ("sizeup", cmd_sizeUp);
768 cgi.Cmd_RemoveCommand ("sizedown", cmd_sizeDown);
769
770 cgi.Cmd_RemoveCommand ("viewpos", cmd_viewPos);
771
772 cgi.Cmd_RemoveCommand ("benchmark", cmd_benchMark);
773 cgi.Cmd_RemoveCommand ("timerefresh", cmd_timeRefresh);
774 }
775