PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/r_explosion.c

https://gitlab.com/xonotic/darkplaces
C | 285 lines | 224 code | 25 blank | 36 comment | 28 complexity | d4fb68fa51992d023eb0722284a5b023 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 1996-1997 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. #include "quakedef.h"
  16. #include "cl_collision.h"
  17. #ifdef MAX_EXPLOSIONS
  18. #define EXPLOSIONGRID 8
  19. #define EXPLOSIONVERTS ((EXPLOSIONGRID+1)*(EXPLOSIONGRID+1))
  20. #define EXPLOSIONTRIS (EXPLOSIONGRID*EXPLOSIONGRID*2)
  21. static int numexplosions = 0;
  22. static float explosiontexcoord2f[EXPLOSIONVERTS][2];
  23. static unsigned short explosiontris[EXPLOSIONTRIS][3];
  24. static int explosionnoiseindex[EXPLOSIONVERTS];
  25. static vec3_t explosionpoint[EXPLOSIONVERTS];
  26. typedef struct explosion_s
  27. {
  28. float starttime;
  29. float endtime;
  30. float time;
  31. float alpha;
  32. float fade;
  33. vec3_t origin;
  34. vec3_t vert[EXPLOSIONVERTS];
  35. vec3_t vertvel[EXPLOSIONVERTS];
  36. qboolean clipping;
  37. }
  38. explosion_t;
  39. static explosion_t explosion[MAX_EXPLOSIONS];
  40. static rtexture_t *explosiontexture;
  41. //static rtexture_t *explosiontexturefog;
  42. static rtexturepool_t *explosiontexturepool;
  43. #endif
  44. cvar_t r_explosionclip = {CVAR_SAVE, "r_explosionclip", "1", "enables collision detection for explosion shell (so that it flattens against walls and floors)"};
  45. #ifdef MAX_EXPLOSIONS
  46. static cvar_t r_drawexplosions = {0, "r_drawexplosions", "1", "enables rendering of explosion shells (see also cl_particles_explosions_shell)"};
  47. //extern qboolean r_loadfog;
  48. static void r_explosion_start(void)
  49. {
  50. int x, y;
  51. static unsigned char noise1[128][128], noise2[128][128], noise3[128][128], data[128][128][4];
  52. explosiontexturepool = R_AllocTexturePool();
  53. explosiontexture = NULL;
  54. //explosiontexturefog = NULL;
  55. fractalnoise(&noise1[0][0], 128, 32);
  56. fractalnoise(&noise2[0][0], 128, 4);
  57. fractalnoise(&noise3[0][0], 128, 4);
  58. for (y = 0;y < 128;y++)
  59. {
  60. for (x = 0;x < 128;x++)
  61. {
  62. int j, r, g, b, a;
  63. j = (noise1[y][x] * noise2[y][x]) * 3 / 256 - 128;
  64. r = (j * 512) / 256;
  65. g = (j * 256) / 256;
  66. b = (j * 128) / 256;
  67. a = noise3[y][x] * 3 - 128;
  68. data[y][x][2] = bound(0, r, 255);
  69. data[y][x][1] = bound(0, g, 255);
  70. data[y][x][0] = bound(0, b, 255);
  71. data[y][x][3] = bound(0, a, 255);
  72. }
  73. }
  74. explosiontexture = R_LoadTexture2D(explosiontexturepool, "explosiontexture", 128, 128, &data[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
  75. // if (r_loadfog)
  76. // {
  77. // for (y = 0;y < 128;y++)
  78. // for (x = 0;x < 128;x++)
  79. // data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
  80. // explosiontexturefog = R_LoadTexture2D(explosiontexturepool, "explosiontexture_fog", 128, 128, &data[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
  81. // }
  82. // note that explosions survive the restart
  83. }
  84. static void r_explosion_shutdown(void)
  85. {
  86. R_FreeTexturePool(&explosiontexturepool);
  87. }
  88. static void r_explosion_newmap(void)
  89. {
  90. numexplosions = 0;
  91. memset(explosion, 0, sizeof(explosion));
  92. }
  93. static int R_ExplosionVert(int column, int row)
  94. {
  95. int i;
  96. float yaw, pitch;
  97. // top and bottom rows are all one position...
  98. if (row == 0 || row == EXPLOSIONGRID)
  99. column = 0;
  100. i = row * (EXPLOSIONGRID + 1) + column;
  101. yaw = ((double) column / EXPLOSIONGRID) * M_PI * 2;
  102. pitch = (((double) row / EXPLOSIONGRID) - 0.5) * M_PI;
  103. explosionpoint[i][0] = cos(yaw) * cos(pitch);
  104. explosionpoint[i][1] = sin(yaw) * cos(pitch);
  105. explosionpoint[i][2] = 1 * -sin(pitch);
  106. explosiontexcoord2f[i][0] = (float) column / (float) EXPLOSIONGRID;
  107. explosiontexcoord2f[i][1] = (float) row / (float) EXPLOSIONGRID;
  108. explosionnoiseindex[i] = (row % EXPLOSIONGRID) * EXPLOSIONGRID + (column % EXPLOSIONGRID);
  109. return i;
  110. }
  111. #endif
  112. void R_Explosion_Init(void)
  113. {
  114. #ifdef MAX_EXPLOSIONS
  115. int i, x, y;
  116. i = 0;
  117. for (y = 0;y < EXPLOSIONGRID;y++)
  118. {
  119. for (x = 0;x < EXPLOSIONGRID;x++)
  120. {
  121. explosiontris[i][0] = R_ExplosionVert(x , y );
  122. explosiontris[i][1] = R_ExplosionVert(x + 1, y );
  123. explosiontris[i][2] = R_ExplosionVert(x , y + 1);
  124. i++;
  125. explosiontris[i][0] = R_ExplosionVert(x + 1, y );
  126. explosiontris[i][1] = R_ExplosionVert(x + 1, y + 1);
  127. explosiontris[i][2] = R_ExplosionVert(x , y + 1);
  128. i++;
  129. }
  130. }
  131. #endif
  132. Cvar_RegisterVariable(&r_explosionclip);
  133. #ifdef MAX_EXPLOSIONS
  134. Cvar_RegisterVariable(&r_drawexplosions);
  135. R_RegisterModule("R_Explosions", r_explosion_start, r_explosion_shutdown, r_explosion_newmap, NULL, NULL);
  136. #endif
  137. }
  138. void R_NewExplosion(const vec3_t org)
  139. {
  140. #ifdef MAX_EXPLOSIONS
  141. int i, j;
  142. float dist, n;
  143. explosion_t *e;
  144. trace_t trace;
  145. unsigned char noise[EXPLOSIONGRID*EXPLOSIONGRID];
  146. fractalnoisequick(noise, EXPLOSIONGRID, 4); // adjust noise grid size according to explosion
  147. for (i = 0, e = explosion;i < MAX_EXPLOSIONS;i++, e++)
  148. {
  149. if (!e->alpha)
  150. {
  151. numexplosions = max(numexplosions, i + 1);
  152. e->starttime = cl.time;
  153. e->endtime = cl.time + cl_explosions_lifetime.value;
  154. e->time = e->starttime;
  155. e->alpha = cl_explosions_alpha_start.value;
  156. e->fade = (cl_explosions_alpha_start.value - cl_explosions_alpha_end.value) / cl_explosions_lifetime.value;
  157. e->clipping = r_explosionclip.integer != 0;
  158. VectorCopy(org, e->origin);
  159. for (j = 0;j < EXPLOSIONVERTS;j++)
  160. {
  161. // calculate start origin and velocity
  162. n = noise[explosionnoiseindex[j]] * (1.0f / 255.0f) + 0.5;
  163. dist = n * cl_explosions_size_start.value;
  164. VectorMA(e->origin, dist, explosionpoint[j], e->vert[j]);
  165. dist = n * (cl_explosions_size_end.value - cl_explosions_size_start.value) / cl_explosions_lifetime.value;
  166. VectorScale(explosionpoint[j], dist, e->vertvel[j]);
  167. // clip start origin
  168. if (e->clipping)
  169. {
  170. trace = CL_TraceLine(e->origin, e->vert[j], MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false);
  171. VectorCopy(trace.endpos, e->vert[i]);
  172. }
  173. }
  174. break;
  175. }
  176. }
  177. #endif
  178. }
  179. #ifdef MAX_EXPLOSIONS
  180. static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
  181. {
  182. int surfacelistindex = 0;
  183. const int numtriangles = EXPLOSIONTRIS, numverts = EXPLOSIONVERTS;
  184. GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
  185. GL_DepthMask(false);
  186. GL_DepthRange(0, 1);
  187. GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
  188. GL_DepthTest(true);
  189. GL_CullFace(r_refdef.view.cullface_back);
  190. R_EntityMatrix(&identitymatrix);
  191. // R_Mesh_ResetTextureState();
  192. R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false, false, false);
  193. for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
  194. {
  195. const explosion_t *e = explosion + surfacelist[surfacelistindex];
  196. // FIXME: this can't properly handle r_refdef.view.colorscale > 1
  197. GL_Color(e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, 1);
  198. R_Mesh_PrepareVertices_Generic_Arrays(numverts, e->vert[0], NULL, explosiontexcoord2f[0]);
  199. R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, NULL, 0, explosiontris[0], NULL, 0);
  200. }
  201. }
  202. static void R_MoveExplosion(explosion_t *e)
  203. {
  204. int i;
  205. float dot, end[3], frametime;
  206. trace_t trace;
  207. frametime = cl.time - e->time;
  208. e->time = cl.time;
  209. e->alpha = e->alpha - (e->fade * frametime);
  210. if (e->alpha < 0 || cl.time > e->endtime)
  211. {
  212. e->alpha = 0;
  213. return;
  214. }
  215. for (i = 0;i < EXPLOSIONVERTS;i++)
  216. {
  217. if (e->vertvel[i][0] || e->vertvel[i][1] || e->vertvel[i][2])
  218. {
  219. VectorMA(e->vert[i], frametime, e->vertvel[i], end);
  220. if (e->clipping)
  221. {
  222. trace = CL_TraceLine(e->vert[i], end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false);
  223. if (trace.fraction < 1)
  224. {
  225. // clip velocity against the wall
  226. dot = -DotProduct(e->vertvel[i], trace.plane.normal);
  227. VectorMA(e->vertvel[i], dot, trace.plane.normal, e->vertvel[i]);
  228. }
  229. VectorCopy(trace.endpos, e->vert[i]);
  230. }
  231. else
  232. VectorCopy(end, e->vert[i]);
  233. }
  234. }
  235. }
  236. #endif
  237. void R_DrawExplosions(void)
  238. {
  239. #ifdef MAX_EXPLOSIONS
  240. int i;
  241. if (!r_drawexplosions.integer)
  242. return;
  243. for (i = 0;i < numexplosions;i++)
  244. {
  245. if (explosion[i].alpha)
  246. {
  247. R_MoveExplosion(&explosion[i]);
  248. if (explosion[i].alpha)
  249. R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, explosion[i].origin, R_DrawExplosion_TransparentCallback, NULL, i, NULL);
  250. }
  251. }
  252. while (numexplosions > 0 && explosion[i-1].alpha <= 0)
  253. numexplosions--;
  254. #endif
  255. }