Advertisement
Guest User

envfx_bubbles.c

a guest
Apr 1st, 2019
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.12 KB | None | 0 0
  1. #include <ultra64.h>
  2.  
  3. #include "sm64.h"
  4. #include "display.h"
  5. #include "memory.h"
  6. #include "ingame_menu.h"
  7. #include "envfx_snow.h"
  8. #include "envfx_bubbles.h"
  9. #include "engine/surface_collision.h"
  10. #include "engine/math_util.h"
  11. #include "engine/behavior_script.h"
  12. #include "audio/interface_2.h"
  13. #include "obj_behaviors.h"
  14.  
  15. /** This file implements environment effects that are not snow:
  16. * Flowers (unused), lava bubbles and jetsream/whirlpool bubbles.
  17. * Refer to 'envfx_snow.c' for more info about environment effects.
  18. * Note that the term 'bubbles' is used as a collective name for
  19. * effects in this file even though flowers aren't bubbles. For the
  20. * sake of concise naming, flowers fall under bubbles.
  21. */
  22.  
  23. s16 gEnvFxBubbleConfig[10];
  24. static Gfx *sGfxCursor; // points to end of display list for bubble particles
  25. static s32 sBubbleParticleCount;
  26. static s32 sBubbleParticleMaxCount;
  27.  
  28. UNUSED s32 D_80330690 = 0;
  29. UNUSED s32 D_80330694 = 0;
  30.  
  31. /// Template for a bubble particle triangle
  32. Vtx_t gBubbleTempVtx[3] =
  33. {
  34. {
  35. {0, 0, 0},
  36. 0,
  37. {1544, 964},
  38. {0xFF, 0xFF, 0xFF, 0xFF}
  39. },
  40. {
  41. {0, 0, 0},
  42. 0,
  43. {522, -568},
  44. {0xFF, 0xFF, 0xFF, 0xFF}
  45. },
  46. {
  47. {0, 0, 0},
  48. 0,
  49. {-498, 964},
  50. {0xFF, 0xFF, 0xFF, 0xFF}
  51. },
  52. };
  53.  
  54. extern void *flower_bubbles_textures_ptr_0B002008;
  55. extern void *lava_bubble_ptr_0B006020;
  56. extern void *bubble_ptr_0B006848;
  57. extern void *tiny_bubble_dl_0B006AB0;
  58. extern void *tiny_bubble_dl_0B006D38;
  59. extern void *tiny_bubble_dl_0B006D68;
  60.  
  61. /** Check whether the particle with the given index is
  62. * laterally within distance of point (x, z). Used to
  63. * kill flower and bubble particles.
  64. */
  65. s32 particle_is_laterally_close(s32 index, s32 x, s32 z, s32 distance) {
  66. s32 xPos = (gEnvFxBuffer + index)->xPos;
  67. s32 zPos = (gEnvFxBuffer + index)->zPos;
  68.  
  69. if (sqr(xPos - x) + sqr(zPos - z) > sqr(distance))
  70. return 0;
  71.  
  72. return 1;
  73. }
  74.  
  75. /** Generate a uniform random number in range [-2000, -1000[ or [1000, 2000[
  76. * Used to position flower particles
  77. */
  78. s32 random_flower_offset() {
  79. s32 result = RandomFloat() * 2000.0f - 1000.0f;
  80. if (result < 0 )
  81. result -= 1000;
  82. else
  83. result += 1000;
  84.  
  85. return result;
  86. }
  87.  
  88. /** Update flower particles. Flowers are scattered randomly in front of the
  89. * camera, and can land on any ground
  90. */
  91. void envfx_update_flower(Vec3s centerPos) {
  92. s32 i;
  93. f32 *floorPlane; // Unused, but contains normal and offset of floor triangle
  94. s32 timer = gGlobalTimer;
  95.  
  96. s16 centerX = centerPos[0];
  97. UNUSED s16 centerY = centerPos[1];
  98. s16 centerZ = centerPos[2];
  99.  
  100. for (i = 0; i < sBubbleParticleMaxCount; i++) {
  101. (gEnvFxBuffer + i)->isAlive = particle_is_laterally_close(i, centerX, centerZ, 3000);
  102. if ((gEnvFxBuffer + i)->isAlive == 0) {
  103. (gEnvFxBuffer + i)->xPos = random_flower_offset() + centerX;
  104. (gEnvFxBuffer + i)->zPos = random_flower_offset() + centerZ;
  105. (gEnvFxBuffer + i)->yPos = func_803814B8((gEnvFxBuffer + i)->xPos, 10000.0f, (gEnvFxBuffer + i)->zPos, &floorPlane);
  106. (gEnvFxBuffer + i)->isAlive = 1;
  107. (gEnvFxBuffer + i)->animFrame = RandomFloat() * 5.0f;
  108. } else if ((timer & 0x03) == 0) {
  109. (gEnvFxBuffer + i)->animFrame += 1;
  110. if ((gEnvFxBuffer + i)->animFrame > 5)
  111. (gEnvFxBuffer + i)->animFrame = 0;
  112. }
  113. }
  114. }
  115.  
  116. /** Update the position of a lava bubble to be somewhere around centerPos
  117. * Uses find_floor to find the height of lava, if no floor or a non-lava
  118. * floor is found the bubble y is set to -10000, which is why you can see
  119. * occasional lava bubbles far below the course in Lethal Lava Land.
  120. * In the second Bowser fight arena, the visual lava is above the lava
  121. * floor so lava-bubbles are not normally visible, only if you bring the
  122. * camera below the lava plane.
  123. */
  124. void envfx_set_lava_bubble_position(s32 index, Vec3s centerPos) {
  125. struct Surface *surface;
  126. s16 floorY;
  127. s16 centerX, centerY, centerZ;
  128.  
  129. centerX = centerPos[0];
  130. centerY = centerPos[1];
  131. centerZ = centerPos[2];
  132.  
  133. (gEnvFxBuffer + index)->xPos = RandomFloat() * 6000.0f - 3000.0f + centerX;
  134. (gEnvFxBuffer + index)->zPos = RandomFloat() * 6000.0f - 3000.0f + centerZ;
  135.  
  136. if ((gEnvFxBuffer + index)->xPos > 8000)
  137. (gEnvFxBuffer + index)->xPos = 16000 - (gEnvFxBuffer + index)->xPos;
  138. if ((gEnvFxBuffer + index)->xPos < -8000)
  139. (gEnvFxBuffer + index)->xPos = -16000 - (gEnvFxBuffer + index)->xPos;
  140.  
  141. if ((gEnvFxBuffer + index)->zPos > 8000)
  142. (gEnvFxBuffer + index)->zPos = 16000 - (gEnvFxBuffer + index)->zPos;
  143. if ((gEnvFxBuffer + index)->zPos < -8000)
  144. (gEnvFxBuffer + index)->zPos = -16000 - (gEnvFxBuffer + index)->zPos;
  145.  
  146. floorY = find_floor((gEnvFxBuffer + index)->xPos, centerY + 500, (gEnvFxBuffer + index)->zPos, &surface);
  147. if (surface == NULL) {
  148. (gEnvFxBuffer + index)->yPos = -10000;
  149. return;
  150. }
  151.  
  152. if (surface->type == SURFACE_LAVA) {
  153. (gEnvFxBuffer + index)->yPos = floorY;
  154. }
  155. else {
  156. (gEnvFxBuffer + index)->yPos = -10000;
  157. }
  158. }
  159.  
  160. /** Update lava bubble animation and give the bubble a new position if the
  161. * animation is over.
  162. */
  163. void envfx_update_lava(Vec3s centerPos) {
  164. s32 i;
  165. s32 timer = gGlobalTimer;
  166. s8 chance;
  167. UNUSED s16 centerX, centerY, centerZ;
  168.  
  169. centerX = centerPos[0];
  170. centerY = centerPos[1];
  171. centerZ = centerPos[2];
  172.  
  173. for (i = 0; i < sBubbleParticleMaxCount; i++) {
  174. if ((gEnvFxBuffer + i)->isAlive == 0) {
  175. envfx_set_lava_bubble_position(i, centerPos);
  176. (gEnvFxBuffer + i)->isAlive = 1;
  177. }
  178. else if ((timer & 0x01) == 0) {
  179. (gEnvFxBuffer + i)->animFrame += 1;
  180. if ((gEnvFxBuffer + i)->animFrame > 8) {
  181. (gEnvFxBuffer + i)->isAlive = 0;
  182. (gEnvFxBuffer + i)->animFrame = 0;
  183. }
  184. }
  185. }
  186.  
  187. if ((chance = (s32)(RandomFloat() * 16.0f)) == 8)
  188. SetSound(0x300D0081, D_803320E0);
  189. }
  190.  
  191. /** Rotate the input x, y and z around the rotation origin of the whirlpool
  192. * according to the pitch and yaw of the whirlpool.
  193. */
  194. void envfx_rotate_around_whirlpool(s32 *x, s32 *y, s32 *z) {
  195. s32 vecX = *x - gEnvFxBubbleConfig[ENVFX_STATE_DEST_X];
  196. s32 vecY = *y - gEnvFxBubbleConfig[ENVFX_STATE_DEST_Y];
  197. s32 vecZ = *z - gEnvFxBubbleConfig[ENVFX_STATE_DEST_Z];
  198. f32 cosPitch = coss(gEnvFxBubbleConfig[ENVFX_STATE_PITCH]);
  199. f32 sinPitch = sins(gEnvFxBubbleConfig[ENVFX_STATE_PITCH]);
  200. f32 cosMYaw = coss(-gEnvFxBubbleConfig[ENVFX_STATE_YAW]);
  201. f32 sinMYaw = sins(-gEnvFxBubbleConfig[ENVFX_STATE_YAW]);
  202.  
  203. f32 rotatedX = vecX * cosMYaw - sinMYaw * cosPitch * vecY - sinPitch * sinMYaw * vecZ;
  204. f32 rotatedY = vecX * sinMYaw + cosPitch * cosMYaw * vecY - sinPitch * cosMYaw * vecZ;
  205. f32 rotatedZ = vecY * sinPitch + cosPitch * vecZ;
  206.  
  207. *x = gEnvFxBubbleConfig[ENVFX_STATE_DEST_X] + (s32)rotatedX;
  208. *y = gEnvFxBubbleConfig[ENVFX_STATE_DEST_Y] + (s32)rotatedY;
  209. *z = gEnvFxBubbleConfig[ENVFX_STATE_DEST_Z] + (s32)rotatedZ;
  210. }
  211.  
  212. /** Check whether a whirlpool bubble is alive. A bubble respawns when it is too
  213. * low or close to the center.
  214. */
  215. s32 envfx_is_whirlpool_bubble_alive(s32 index) {
  216. s32 UNUSED sp4;
  217.  
  218. if ((gEnvFxBuffer + index)->bubbleY < gEnvFxBubbleConfig[ENVFX_STATE_DEST_Y] - 100)
  219. return 0;
  220.  
  221. if ((gEnvFxBuffer + index)->angleAndDist[1] < 10)
  222. return 0;
  223.  
  224. return 1;
  225. }
  226.  
  227. /** Update whirlpool particles. Whirlpool particles start high and far from
  228. * the center and get sucked into the sink in a spiraling motion.
  229. */
  230. void envfx_update_whirlpool(void) {
  231. s32 i;
  232.  
  233. for (i = 0; i < sBubbleParticleMaxCount; i++) {
  234. (gEnvFxBuffer + i)->isAlive = envfx_is_whirlpool_bubble_alive(i);
  235. if ((gEnvFxBuffer + i)->isAlive == 0) {
  236. (gEnvFxBuffer + i)->angleAndDist[1] = RandomFloat() * 1000.0f;
  237. (gEnvFxBuffer + i)->angleAndDist[0] = RandomFloat() * 65536.0f;
  238. (gEnvFxBuffer + i)->xPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_X] + sins((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  239. (gEnvFxBuffer + i)->zPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z] + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  240. (gEnvFxBuffer + i)->bubbleY = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (RandomFloat() * 100.0f - 50.0f);
  241. (gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY;
  242. (gEnvFxBuffer + i)->unusedBubbleVar = 0;
  243. (gEnvFxBuffer + i)->isAlive = 1;
  244.  
  245. envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos, &(gEnvFxBuffer + i)->zPos);
  246. }
  247. else {
  248. (gEnvFxBuffer + i)->angleAndDist[1] -= 40;
  249. (gEnvFxBuffer + i)->angleAndDist[0] += (s16) (3000 - (gEnvFxBuffer + i)->angleAndDist[1] * 2) + 0x400;
  250. (gEnvFxBuffer + i)->xPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_X] + sins((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  251. (gEnvFxBuffer + i)->zPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z] + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  252. (gEnvFxBuffer + i)->bubbleY -= -((s16)(gEnvFxBuffer + i)->angleAndDist[1] / 100) + 40;
  253. (gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY;
  254.  
  255. envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos, &(gEnvFxBuffer + i)->zPos);
  256. }
  257. }
  258. }
  259.  
  260. /** Check whether a jetstream bubble should respawn. Happens if it is laterally
  261. * 1000 units away from the source or 1500 units above it.
  262. */
  263. s32 envfx_is_jestream_bubble_alive(s32 index) {
  264. UNUSED s32 unk;
  265.  
  266. if (!particle_is_laterally_close(index, gEnvFxBubbleConfig[ENVFX_STATE_SRC_X], gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z], 1000)
  267. || gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + 1500 < (gEnvFxBuffer + index)->yPos)
  268. return 0;
  269.  
  270. return 1;
  271. }
  272.  
  273. /** Update the positions of jestream bubble particles.
  274. * They move up and outwards.
  275. */
  276. void envfx_update_jetstream(void) {
  277. s32 i;
  278.  
  279. for (i = 0; i < sBubbleParticleMaxCount; i++) {
  280. (gEnvFxBuffer + i)->isAlive = envfx_is_jestream_bubble_alive(i);
  281. if ((gEnvFxBuffer + i)->isAlive == 0) {
  282. (gEnvFxBuffer + i)->angleAndDist[1] = RandomFloat() * 300.0f;
  283. (gEnvFxBuffer + i)->angleAndDist[0] = RandomU16();
  284. (gEnvFxBuffer + i)->xPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_X] + sins((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  285. (gEnvFxBuffer + i)->zPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z] + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
  286. (gEnvFxBuffer + i)->yPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (RandomFloat() * 400.0f - 200.0f);
  287. }
  288. else {
  289. (gEnvFxBuffer + i)->angleAndDist[1] += 10;
  290. (gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f;
  291. (gEnvFxBuffer + i)->zPos += coss((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f;
  292. (gEnvFxBuffer + i)->yPos -= ((gEnvFxBuffer + i)->angleAndDist[1] / 30) - 50;
  293. }
  294. }
  295. }
  296.  
  297. /** Initialize bubble (or flower) effect by allocating a buffer to store
  298. * the state of each particle and setting the initial and max count.
  299. * Analogous to init_snow_particles, but for bubbles.
  300. */
  301. s32 envfx_init_bubble(s32 mode) {
  302. s32 i;
  303.  
  304. switch (mode) {
  305. case ENVFX_MODE_NONE:
  306. return 0;
  307.  
  308. case ENVFX_FLOWERS:
  309. sBubbleParticleCount = 30;
  310. sBubbleParticleMaxCount = 30;
  311. break;
  312.  
  313. case ENVFX_LAVA_BUBBLES:
  314. sBubbleParticleCount = 15;
  315. sBubbleParticleMaxCount = 15;
  316. break;
  317.  
  318. case ENVFX_WHIRLPOOL_BUBBLES:
  319. sBubbleParticleCount = 60;
  320. break;
  321.  
  322. case ENVFX_JETSTREAM_BUBBLES:
  323. sBubbleParticleCount = 60;
  324. break;
  325. }
  326.  
  327. gEnvFxBuffer = (struct EnvFxParticle *)mem_pool_alloc(D_8033A124, sBubbleParticleCount * sizeof(struct EnvFxParticle));
  328. if (!gEnvFxBuffer)
  329. return 0;
  330.  
  331. bzero(gEnvFxBuffer, sBubbleParticleCount * sizeof(struct EnvFxParticle));
  332. bzero(gEnvFxBubbleConfig, sizeof(gEnvFxBubbleConfig));
  333.  
  334. if (mode == ENVFX_LAVA_BUBBLES) {
  335. //! Dead code
  336. if (0) { }
  337.  
  338. for (i = 0; i < sBubbleParticleCount; i++) {
  339. (gEnvFxBuffer + i)->animFrame = RandomFloat() * 7.0f;
  340. }
  341.  
  342. if (0) { }
  343. }
  344.  
  345. gEnvFxMode = mode;
  346. return 1;
  347. }
  348.  
  349. /** Update particles depending on mode.
  350. * Also sets the given vertices to the correct shape for each mode,
  351. * though they are not being rotated yet.
  352. */
  353. void envfx_bubbles_update_switch(s32 mode, Vec3s camTo, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) {
  354. switch(mode) {
  355. case ENVFX_FLOWERS:
  356. envfx_update_flower(camTo);
  357. vertex1[0] = 50;
  358. vertex1[1] = 0;
  359. vertex1[2] = 0;
  360. vertex2[0] = 0;
  361. vertex2[1] = 75;
  362. vertex2[2] = 0;
  363. vertex3[0] = -50;
  364. vertex3[1] = 0;
  365. vertex3[2] = 0;
  366. break;
  367.  
  368. case ENVFX_LAVA_BUBBLES:
  369. envfx_update_lava(camTo);
  370. vertex1[0] = 100;
  371. vertex1[1] = 0;
  372. vertex1[2] = 0;
  373. vertex2[0] = 0;
  374. vertex2[1] = 150;
  375. vertex2[2] = 0;
  376. vertex3[0] = -100;
  377. vertex3[1] = 0;
  378. vertex3[2] = 0;
  379. break;
  380.  
  381. case ENVFX_WHIRLPOOL_BUBBLES:
  382. envfx_update_whirlpool();
  383. vertex1[0] = 40;
  384. vertex1[1] = 0;
  385. vertex1[2] = 0;
  386. vertex2[0] = 0;
  387. vertex2[1] = 60;
  388. vertex2[2] = 0;
  389. vertex3[0] = -40;
  390. vertex3[1] = 0;
  391. vertex3[2] = 0;
  392. break;
  393.  
  394. case ENVFX_JETSTREAM_BUBBLES:
  395. envfx_update_jetstream();
  396. vertex1[0] = 40;
  397. vertex1[1] = 0;
  398. vertex1[2] = 0;
  399. vertex2[0] = 0;
  400. vertex2[1] = 60;
  401. vertex2[2] = 0;
  402. vertex3[0] = -40;
  403. vertex3[1] = 0;
  404. vertex3[2] = 0;
  405. break;
  406. }
  407. }
  408.  
  409. /** Append 15 vertices to 'gfx', which is enough for 5 bubbles starting at
  410. * 'index'. The 3 input vertices represent the roated triangle around (0,0,0)
  411. * that will be translated to bubble positions to draw the bubble image
  412. */
  413. void append_bubble_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, Vtx *template) {
  414. s32 i = 0;
  415. Vtx *vertBuf = (Vtx *)alloc_display_list(15 * sizeof(Vtx));
  416.  
  417. if (vertBuf == NULL)
  418. return;
  419.  
  420. for (i = 0; i < 15; i += 3) {
  421. vertBuf[i] = template[0];
  422. vertBuf[i].v.ob[0] = vertex1[0] + (gEnvFxBuffer + (index + i / 3))->xPos;
  423. vertBuf[i].v.ob[1] = vertex1[1] + (gEnvFxBuffer + (index + i / 3))->yPos;
  424. vertBuf[i].v.ob[2] = vertex1[2] + (gEnvFxBuffer + (index + i / 3))->zPos;
  425.  
  426. vertBuf[i + 1] = template[1];
  427. vertBuf[i + 1].v.ob[0] = vertex2[0] + (gEnvFxBuffer + (index + i / 3))->xPos;
  428. vertBuf[i + 1].v.ob[1] = vertex2[1] + (gEnvFxBuffer + (index + i / 3))->yPos;
  429. vertBuf[i + 1].v.ob[2] = vertex2[2] + (gEnvFxBuffer + (index + i / 3))->zPos;
  430.  
  431. vertBuf[i + 2] = template[2];
  432. vertBuf[i + 2].v.ob[0] = vertex3[0] + (gEnvFxBuffer + (index + i / 3))->xPos;
  433. vertBuf[i + 2].v.ob[1] = vertex3[1] + (gEnvFxBuffer + (index + i / 3))->yPos;
  434. vertBuf[i + 2].v.ob[2] = vertex3[2] + (gEnvFxBuffer + (index + i / 3))->zPos;
  435. }
  436.  
  437. gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0);
  438. }
  439.  
  440. /** Appends to the enfvx display list a command setting the appropriate texture
  441. * for a specific particle. The display list is not passed as parameter but uses
  442. * the global sGfxCursor instead.
  443. */
  444. void envfx_set_bubble_texture(s32 mode, s16 index) {
  445. void **imageArr;
  446. s16 frame = (gEnvFxBuffer + index)->animFrame;
  447.  
  448. switch(mode) {
  449. case ENVFX_FLOWERS:
  450. imageArr = (void **)segmented_to_virtual(&flower_bubbles_textures_ptr_0B002008);
  451. frame = (gEnvFxBuffer + index)->animFrame;
  452. break;
  453.  
  454. case ENVFX_LAVA_BUBBLES:
  455. imageArr = (void **)segmented_to_virtual(&lava_bubble_ptr_0B006020);
  456. frame = (gEnvFxBuffer + index)->animFrame;
  457. break;
  458.  
  459. case ENVFX_WHIRLPOOL_BUBBLES:
  460. case ENVFX_JETSTREAM_BUBBLES:
  461. imageArr = (void **)segmented_to_virtual(&bubble_ptr_0B006848);
  462. frame = 0;
  463. break;
  464. }
  465.  
  466. gDPSetTextureImage(sGfxCursor++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, *(imageArr + frame));
  467. gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D68);
  468. }
  469.  
  470. /** Updates the bubble particle positions, then generates and returns a display
  471. * list drawing them.
  472. */
  473. Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFrom, Vec3s camTo) {
  474. s32 i;
  475. s16 radius, pitch, yaw;
  476.  
  477. Vec3s vertex1;
  478. Vec3s vertex2;
  479. Vec3s vertex3;
  480.  
  481. Gfx *gfxStart;
  482.  
  483. gfxStart = (Gfx *)alloc_display_list(((sBubbleParticleMaxCount / 5) * 10 + sBubbleParticleMaxCount + 3) * sizeof(Gfx));
  484. if (gfxStart == NULL)
  485. return NULL;
  486.  
  487. sGfxCursor = gfxStart;
  488.  
  489. orbit_from_positions(camTo, camFrom, &radius, &pitch, &yaw);
  490. envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3);
  491. rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw);
  492.  
  493. gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D38);
  494.  
  495. for (i = 0; i < sBubbleParticleMaxCount; i += 5) {
  496. gDPPipeSync(sGfxCursor++);
  497. envfx_set_bubble_texture(mode, i);
  498. append_bubble_vertex_buffer(sGfxCursor++, i, vertex1, vertex2, vertex3, (Vtx *)gBubbleTempVtx);
  499. gSP1Triangle(sGfxCursor++, 0, 1, 2, 0);
  500. gSP1Triangle(sGfxCursor++, 3, 4, 5, 0);
  501. gSP1Triangle(sGfxCursor++, 6, 7, 8, 0);
  502. gSP1Triangle(sGfxCursor++, 9, 10, 11, 0);
  503. gSP1Triangle(sGfxCursor++, 12, 13, 14, 0);
  504. }
  505.  
  506. gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006AB0);
  507. gSPEndDisplayList(sGfxCursor++);
  508.  
  509. return gfxStart;
  510. }
  511.  
  512. /** Set the maximum particle count from the gEnvFxBubbleConfig variable,
  513. * which is set by the whirlpool or jetstream behavior.
  514. */
  515. void envfx_set_max_bubble_particles(s32 mode) {
  516. switch (mode) {
  517. case ENVFX_WHIRLPOOL_BUBBLES:
  518. sBubbleParticleMaxCount = gEnvFxBubbleConfig[ENVFX_STATE_PARTICLECOUNT];
  519. break;
  520. case ENVFX_JETSTREAM_BUBBLES:
  521. sBubbleParticleMaxCount = gEnvFxBubbleConfig[ENVFX_STATE_PARTICLECOUNT];
  522. break;
  523. }
  524. }
  525.  
  526. /** Update bubble-like environment effects. Assumes the mode is larger than 10,
  527. * lower modes are snow effects which are updated in a different function.
  528. * Returns a display list drawing the particles.
  529. */
  530. Gfx *envfx_update_bubbles(s32 mode, Vec3s marioPos, Vec3s camTo, Vec3s camFrom) {
  531. Gfx *gfx;
  532.  
  533. if (gEnvFxMode == 0 && !envfx_init_bubble(mode))
  534. return NULL;
  535.  
  536. envfx_set_max_bubble_particles(mode);
  537.  
  538. if (sBubbleParticleMaxCount == 0)
  539. return NULL;
  540.  
  541. switch (mode) {
  542. case ENVFX_FLOWERS:
  543. gfx = envfx_update_bubble_particles(ENVFX_FLOWERS, marioPos, camFrom, camTo);
  544. break;
  545.  
  546. case ENVFX_LAVA_BUBBLES:
  547. gfx = envfx_update_bubble_particles(ENVFX_LAVA_BUBBLES, marioPos, camFrom, camTo);
  548. break;
  549.  
  550. case ENVFX_WHIRLPOOL_BUBBLES:
  551. gfx = envfx_update_bubble_particles(ENVFX_WHIRLPOOL_BUBBLES, marioPos, camFrom, camTo);
  552. break;
  553.  
  554. case ENVFX_JETSTREAM_BUBBLES:
  555. gfx = envfx_update_bubble_particles(ENVFX_JETSTREAM_BUBBLES, marioPos, camFrom, camTo);
  556. break;
  557.  
  558. default:
  559. return NULL;
  560. }
  561.  
  562. return gfx;
  563. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement