cl_view.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // cl_view.c -- player rendering positioning
  16. #include "client.h"
  17. //=============
  18. //
  19. // development tools for weapons
  20. //
  21. int gun_frame;
  22. struct model_s *gun_model;
  23. //=============
  24. cvar_t *crosshair;
  25. cvar_t *cl_testparticles;
  26. cvar_t *cl_testentities;
  27. cvar_t *cl_testlights;
  28. cvar_t *cl_testblend;
  29. cvar_t *cl_stats;
  30. int r_numdlights;
  31. dlight_t r_dlights[MAX_DLIGHTS];
  32. int r_numentities;
  33. entity_t r_entities[MAX_ENTITIES];
  34. int r_numparticles;
  35. particle_t r_particles[MAX_PARTICLES];
  36. lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
  37. char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
  38. int num_cl_weaponmodels;
  39. /*
  40. ====================
  41. V_ClearScene
  42. Specifies the model that will be used as the world
  43. ====================
  44. */
  45. void V_ClearScene (void)
  46. {
  47. r_numdlights = 0;
  48. r_numentities = 0;
  49. r_numparticles = 0;
  50. }
  51. /*
  52. =====================
  53. V_AddEntity
  54. =====================
  55. */
  56. void V_AddEntity (entity_t *ent)
  57. {
  58. if (r_numentities >= MAX_ENTITIES)
  59. return;
  60. r_entities[r_numentities++] = *ent;
  61. }
  62. /*
  63. =====================
  64. V_AddParticle
  65. =====================
  66. */
  67. void V_AddParticle (vec3_t org, int color, float alpha)
  68. {
  69. particle_t *p;
  70. if (r_numparticles >= MAX_PARTICLES)
  71. return;
  72. p = &r_particles[r_numparticles++];
  73. VectorCopy (org, p->origin);
  74. p->color = color;
  75. p->alpha = alpha;
  76. }
  77. /*
  78. =====================
  79. V_AddLight
  80. =====================
  81. */
  82. void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
  83. {
  84. dlight_t *dl;
  85. if (r_numdlights >= MAX_DLIGHTS)
  86. return;
  87. dl = &r_dlights[r_numdlights++];
  88. VectorCopy (org, dl->origin);
  89. dl->intensity = intensity;
  90. dl->color[0] = r;
  91. dl->color[1] = g;
  92. dl->color[2] = b;
  93. }
  94. /*
  95. =====================
  96. V_AddLightStyle
  97. =====================
  98. */
  99. void V_AddLightStyle (int style, float r, float g, float b)
  100. {
  101. lightstyle_t *ls;
  102. if (style < 0 || style > MAX_LIGHTSTYLES)
  103. Com_Error (ERR_DROP, "Bad light style %i", style);
  104. ls = &r_lightstyles[style];
  105. ls->white = r+g+b;
  106. ls->rgb[0] = r;
  107. ls->rgb[1] = g;
  108. ls->rgb[2] = b;
  109. }
  110. /*
  111. ================
  112. V_TestParticles
  113. If cl_testparticles is set, create 4096 particles in the view
  114. ================
  115. */
  116. void V_TestParticles (void)
  117. {
  118. particle_t *p;
  119. int i, j;
  120. float d, r, u;
  121. r_numparticles = MAX_PARTICLES;
  122. for (i=0 ; i<r_numparticles ; i++)
  123. {
  124. d = i*0.25;
  125. r = 4*((i&7)-3.5);
  126. u = 4*(((i>>3)&7)-3.5);
  127. p = &r_particles[i];
  128. for (j=0 ; j<3 ; j++)
  129. p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
  130. cl.v_right[j]*r + cl.v_up[j]*u;
  131. p->color = 8;
  132. p->alpha = cl_testparticles->value;
  133. }
  134. }
  135. /*
  136. ================
  137. V_TestEntities
  138. If cl_testentities is set, create 32 player models
  139. ================
  140. */
  141. void V_TestEntities (void)
  142. {
  143. int i, j;
  144. float f, r;
  145. entity_t *ent;
  146. r_numentities = 32;
  147. memset (r_entities, 0, sizeof(r_entities));
  148. for (i=0 ; i<r_numentities ; i++)
  149. {
  150. ent = &r_entities[i];
  151. r = 64 * ( (i%4) - 1.5 );
  152. f = 64 * (i/4) + 128;
  153. for (j=0 ; j<3 ; j++)
  154. ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
  155. cl.v_right[j]*r;
  156. ent->model = cl.baseclientinfo.model;
  157. ent->skin = cl.baseclientinfo.skin;
  158. }
  159. }
  160. /*
  161. ================
  162. V_TestLights
  163. If cl_testlights is set, create 32 lights models
  164. ================
  165. */
  166. void V_TestLights (void)
  167. {
  168. int i, j;
  169. float f, r;
  170. dlight_t *dl;
  171. r_numdlights = 32;
  172. memset (r_dlights, 0, sizeof(r_dlights));
  173. for (i=0 ; i<r_numdlights ; i++)
  174. {
  175. dl = &r_dlights[i];
  176. r = 64 * ( (i%4) - 1.5 );
  177. f = 64 * (i/4) + 128;
  178. for (j=0 ; j<3 ; j++)
  179. dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
  180. cl.v_right[j]*r;
  181. dl->color[0] = ((i%6)+1) & 1;
  182. dl->color[1] = (((i%6)+1) & 2)>>1;
  183. dl->color[2] = (((i%6)+1) & 4)>>2;
  184. dl->intensity = 200;
  185. }
  186. }
  187. //===================================================================
  188. /*
  189. =================
  190. CL_PrepRefresh
  191. Call before entering a new level, or after changing dlls
  192. =================
  193. */
  194. void CL_PrepRefresh (void)
  195. {
  196. char mapname[32];
  197. int i;
  198. char name[MAX_QPATH];
  199. float rotate;
  200. vec3_t axis;
  201. if (!cl.configstrings[CS_MODELS+1][0])
  202. return; // no map loaded
  203. SCR_AddDirtyPoint (0, 0);
  204. SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
  205. // let the render dll load the map
  206. strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
  207. mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
  208. // register models, pics, and skins
  209. Com_Printf ("Map: %s\r", mapname);
  210. SCR_UpdateScreen ();
  211. re.BeginRegistration (mapname);
  212. Com_Printf (" \r");
  213. // precache status bar pics
  214. Com_Printf ("pics\r");
  215. SCR_UpdateScreen ();
  216. SCR_TouchPics ();
  217. Com_Printf (" \r");
  218. CL_RegisterTEntModels ();
  219. num_cl_weaponmodels = 1;
  220. strcpy(cl_weaponmodels[0], "weapon.md2");
  221. for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
  222. {
  223. strcpy (name, cl.configstrings[CS_MODELS+i]);
  224. name[37] = 0; // never go beyond one line
  225. if (name[0] != '*')
  226. Com_Printf ("%s\r", name);
  227. SCR_UpdateScreen ();
  228. Sys_SendKeyEvents (); // pump message loop
  229. if (name[0] == '#')
  230. {
  231. // special player weapon model
  232. if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
  233. {
  234. strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
  235. sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
  236. num_cl_weaponmodels++;
  237. }
  238. }
  239. else
  240. {
  241. cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
  242. if (name[0] == '*')
  243. cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
  244. else
  245. cl.model_clip[i] = NULL;
  246. }
  247. if (name[0] != '*')
  248. Com_Printf (" \r");
  249. }
  250. Com_Printf ("images\r", i);
  251. SCR_UpdateScreen ();
  252. for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
  253. {
  254. cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
  255. Sys_SendKeyEvents (); // pump message loop
  256. }
  257. Com_Printf (" \r");
  258. for (i=0 ; i<MAX_CLIENTS ; i++)
  259. {
  260. if (!cl.configstrings[CS_PLAYERSKINS+i][0])
  261. continue;
  262. Com_Printf ("client %i\r", i);
  263. SCR_UpdateScreen ();
  264. Sys_SendKeyEvents (); // pump message loop
  265. CL_ParseClientinfo (i);
  266. Com_Printf (" \r");
  267. }
  268. CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
  269. // set sky textures and speed
  270. Com_Printf ("sky\r", i);
  271. SCR_UpdateScreen ();
  272. rotate = atof (cl.configstrings[CS_SKYROTATE]);
  273. sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
  274. &axis[0], &axis[1], &axis[2]);
  275. re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
  276. Com_Printf (" \r");
  277. // the renderer can now free unneeded stuff
  278. re.EndRegistration ();
  279. // clear any lines of console text
  280. Con_ClearNotify ();
  281. SCR_UpdateScreen ();
  282. cl.refresh_prepped = true;
  283. cl.force_refdef = true; // make sure we have a valid refdef
  284. // start the cd track
  285. CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
  286. }
  287. /*
  288. ====================
  289. CalcFov
  290. ====================
  291. */
  292. float CalcFov (float fov_x, float width, float height)
  293. {
  294. float a;
  295. float x;
  296. if (fov_x < 1 || fov_x > 179)
  297. Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
  298. x = width/tan(fov_x/360*M_PI);
  299. a = atan (height/x);
  300. a = a*360/M_PI;
  301. return a;
  302. }
  303. //============================================================================
  304. // gun frame debugging functions
  305. void V_Gun_Next_f (void)
  306. {
  307. gun_frame++;
  308. Com_Printf ("frame %i\n", gun_frame);
  309. }
  310. void V_Gun_Prev_f (void)
  311. {
  312. gun_frame--;
  313. if (gun_frame < 0)
  314. gun_frame = 0;
  315. Com_Printf ("frame %i\n", gun_frame);
  316. }
  317. void V_Gun_Model_f (void)
  318. {
  319. char name[MAX_QPATH];
  320. if (Cmd_Argc() != 2)
  321. {
  322. gun_model = NULL;
  323. return;
  324. }
  325. Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
  326. gun_model = re.RegisterModel (name);
  327. }
  328. //============================================================================
  329. /*
  330. =================
  331. SCR_DrawCrosshair
  332. =================
  333. */
  334. void SCR_DrawCrosshair (void)
  335. {
  336. if (!crosshair->value)
  337. return;
  338. if (crosshair->modified)
  339. {
  340. crosshair->modified = false;
  341. SCR_TouchPics ();
  342. }
  343. if (!crosshair_pic[0])
  344. return;
  345. re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
  346. , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
  347. }
  348. /*
  349. ==================
  350. V_RenderView
  351. ==================
  352. */
  353. void V_RenderView( float stereo_separation )
  354. {
  355. extern int entitycmpfnc( const entity_t *, const entity_t * );
  356. if (cls.state != ca_active)
  357. return;
  358. if (!cl.refresh_prepped)
  359. return; // still loading
  360. if (cl_timedemo->value)
  361. {
  362. if (!cl.timedemo_start)
  363. cl.timedemo_start = Sys_Milliseconds ();
  364. cl.timedemo_frames++;
  365. }
  366. // an invalid frame will just use the exact previous refdef
  367. // we can't use the old frame if the video mode has changed, though...
  368. if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
  369. {
  370. cl.force_refdef = false;
  371. V_ClearScene ();
  372. // build a refresh entity list and calc cl.sim*
  373. // this also calls CL_CalcViewValues which loads
  374. // v_forward, etc.
  375. CL_AddEntities ();
  376. if (cl_testparticles->value)
  377. V_TestParticles ();
  378. if (cl_testentities->value)
  379. V_TestEntities ();
  380. if (cl_testlights->value)
  381. V_TestLights ();
  382. if (cl_testblend->value)
  383. {
  384. cl.refdef.blend[0] = 1;
  385. cl.refdef.blend[1] = 0.5;
  386. cl.refdef.blend[2] = 0.25;
  387. cl.refdef.blend[3] = 0.5;
  388. }
  389. // offset vieworg appropriately if we're doing stereo separation
  390. if ( stereo_separation != 0 )
  391. {
  392. vec3_t tmp;
  393. VectorScale( cl.v_right, stereo_separation, tmp );
  394. VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
  395. }
  396. // never let it sit exactly on a node line, because a water plane can
  397. // dissapear when viewed with the eye exactly on it.
  398. // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
  399. cl.refdef.vieworg[0] += 1.0/16;
  400. cl.refdef.vieworg[1] += 1.0/16;
  401. cl.refdef.vieworg[2] += 1.0/16;
  402. cl.refdef.x = scr_vrect.x;
  403. cl.refdef.y = scr_vrect.y;
  404. cl.refdef.width = scr_vrect.width;
  405. cl.refdef.height = scr_vrect.height;
  406. cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
  407. cl.refdef.time = cl.time*0.001;
  408. cl.refdef.areabits = cl.frame.areabits;
  409. if (!cl_add_entities->value)
  410. r_numentities = 0;
  411. if (!cl_add_particles->value)
  412. r_numparticles = 0;
  413. if (!cl_add_lights->value)
  414. r_numdlights = 0;
  415. if (!cl_add_blend->value)
  416. {
  417. VectorClear (cl.refdef.blend);
  418. }
  419. cl.refdef.num_entities = r_numentities;
  420. cl.refdef.entities = r_entities;
  421. cl.refdef.num_particles = r_numparticles;
  422. cl.refdef.particles = r_particles;
  423. cl.refdef.num_dlights = r_numdlights;
  424. cl.refdef.dlights = r_dlights;
  425. cl.refdef.lightstyles = r_lightstyles;
  426. cl.refdef.rdflags = cl.frame.playerstate.rdflags;
  427. // sort entities for better cache locality
  428. qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
  429. }
  430. re.RenderFrame (&cl.refdef);
  431. if (cl_stats->value)
  432. Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
  433. if ( log_stats->value && ( log_stats_file != 0 ) )
  434. fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
  435. SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
  436. SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
  437. scr_vrect.y+scr_vrect.height-1);
  438. SCR_DrawCrosshair ();
  439. }
  440. /*
  441. =============
  442. V_Viewpos_f
  443. =============
  444. */
  445. void V_Viewpos_f (void)
  446. {
  447. Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
  448. (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
  449. (int)cl.refdef.viewangles[YAW]);
  450. }
  451. /*
  452. =============
  453. V_Init
  454. =============
  455. */
  456. void V_Init (void)
  457. {
  458. Cmd_AddCommand ("gun_next", V_Gun_Next_f);
  459. Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
  460. Cmd_AddCommand ("gun_model", V_Gun_Model_f);
  461. Cmd_AddCommand ("viewpos", V_Viewpos_f);
  462. crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
  463. cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
  464. cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
  465. cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
  466. cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
  467. cl_stats = Cvar_Get ("cl_stats", "0", 0);
  468. }