Advertisement
Guest User

Untitled

a guest
May 22nd, 2019
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.31 KB | None | 0 0
  1. #ifndef LIQUID_CELLUAR_H_
  2. #define LIQUID_CELLUAR_H_
  3.  
  4. #ifndef LC_NO_STDLIB
  5. #include <stdlib.h>
  6. #define LC_MALLOC malloc
  7. #define LC_FREE free
  8. #else
  9. #ifndef LC_MALLOC
  10. #error "No stdlib mode, but LC_MALLOC not defined"
  11. #endif
  12. #ifndef LC_FREE
  13. #error "No stdlib mode, but LC_FREE not defined"
  14. #endif
  15. #endif
  16.  
  17. #ifdef LC_STATIC
  18. #define LCDEF static
  19. #else
  20. #define LCDEF extern
  21. #endif
  22.  
  23. enum LCCellType {
  24. LC_CELL_VACUUM,
  25. LC_CELL_SOLID,
  26. };
  27.  
  28. enum LCFlowDirection {
  29. LC_TOP = 0,
  30. LC_RIGHT = 1,
  31. LC_BOTTOM = 2,
  32. LC_LEFT = 3
  33. };
  34.  
  35. typedef struct LCCell LCCell;
  36.  
  37. struct LCCell {
  38. int Type;
  39. float Liquid;
  40. int Settled;
  41. int SettleCount;
  42. int FlowDirections[4];
  43. LCCell *Neighbors[4];
  44. };
  45.  
  46. typedef struct LCWorld {
  47. // Max and min cell liquid values
  48. float MaxValue;
  49. float MinValue;
  50.  
  51. // Extra liquid a cell can store than the cell above it
  52. float MaxCompression;
  53.  
  54. // Lowest and highest amount of liquids allowed to flow per iteration
  55. float MinFlow;
  56. float MaxFlow;
  57.  
  58. // Adjusts flow speed (0.0f - 1.0f)
  59. float FlowSpeed;
  60.  
  61. // Keep track of modifications to cell liquid values
  62. float *Diffs;
  63.  
  64. LCCell *Cells;
  65. int width;
  66. int height;
  67. } LCWorld;
  68.  
  69. LCDEF void LCInit(LCWorld *world, int width, int height);
  70. LCDEF void LCClose(LCWorld *world);
  71. LCDEF void LCSimulate(LCWorld *world);
  72.  
  73. #endif // LIQUID_CELLUAR_H_
  74.  
  75.  
  76. #ifdef LIQUID_CELLUAR_IMPLEMENTATION
  77.  
  78. #ifndef LIQUID_CELLUAR_IMPLEMENTATION_SINGLE
  79. #define LIQUID_CELLUAR_IMPLEMENTATION_SINGLE
  80. #else
  81. #error "liquid_celluar header included second time"
  82. #endif // LIQUID_CELLUAR_IMPLEMENTATION_SINGLE
  83.  
  84. void LCInit(LCWorld *world, int width, int height) {
  85. if (world->Diffs) LC_FREE(world->Diffs);
  86. if (world->Cells) LC_FREE(world->Cells);
  87. world->MaxValue = 1.0;
  88. world->MinValue = 0.005;
  89. world->MaxCompression = 0.25;
  90. world->MinFlow = 0.005;
  91. world->MaxFlow = 4;
  92. world->FlowSpeed = 1;
  93. world->width = width;
  94. world->height = height;
  95. world->Diffs = LC_MALLOC(sizeof *world->Diffs * width*height);
  96. world->Cells = LC_MALLOC(sizeof *world->Cells * width*height);
  97. }
  98.  
  99. void LCClose(LCWorld *world) {
  100. if (world->Diffs) LC_FREE(world->Diffs);
  101. if (world->Cells) LC_FREE(world->Cells);
  102. world->width = 0;
  103. world->height = 0;
  104. }
  105.  
  106. #define LC_IDX(W,X,Y) ((X)*((W)->height)+(Y))
  107. #define LC_MIN(X,Y) ((X)<(Y)?(X):(Y))
  108. #define LC_MAX(X,Y) ((X)>(Y)?(X):(Y))
  109.  
  110. // Calculate how much liquid should flow to destination with pressure
  111. static float CalculateVerticalFlowValue(LCWorld *world, float remainingLiquid, LCCell *destination) {
  112. float sum = remainingLiquid + destination->Liquid;
  113. float value = 0;
  114.  
  115. if (sum <= world->MaxValue) {
  116. value = world->MaxValue;
  117. } else if (sum < 2 * world->MaxValue + world->MaxCompression) {
  118. value = (world->MaxValue * world->MaxValue + sum * world->MaxCompression) / (world->MaxValue + world->MaxCompression);
  119. } else {
  120. value = (sum + world->MaxCompression) / 2;
  121. }
  122.  
  123. return value;
  124. }
  125.  
  126. static void ResetFlowDirections(LCCell *cell) {
  127. cell->FlowDirections[LC_TOP] = 0;
  128. cell->FlowDirections[LC_RIGHT] = 0;
  129. cell->FlowDirections[LC_BOTTOM] = 0;
  130. cell->FlowDirections[LC_LEFT] = 0;
  131. }
  132.  
  133. // Force neighbors to simulate on next iteration
  134. static void UnsettleNeighbors(LCCell *cell) {
  135. if (cell->Neighbors[LC_TOP]) cell->Neighbors[LC_TOP]->Settled = 0;
  136. if (cell->Neighbors[LC_RIGHT]) cell->Neighbors[LC_RIGHT]->Settled = 0;
  137. if (cell->Neighbors[LC_BOTTOM]) cell->Neighbors[LC_BOTTOM]->Settled = 0;
  138. if (cell->Neighbors[LC_LEFT]) cell->Neighbors[LC_LEFT]->Settled = 0;
  139. }
  140.  
  141. // Run one simulation step
  142. void LCSimulate(LCWorld *world) {
  143. int width = world->width;
  144. int height = world->height;
  145. LCCell *cells = world->Cells;
  146. float flow = 0;
  147.  
  148. // Reset the diffs array
  149. for (int x = 0, index = 0; x < width; x++) {
  150. for (int y = 0; y < height; y++, index++) {
  151. world->Diffs[index] = 0;
  152. }
  153. }
  154.  
  155. // Main loop
  156. for (int x = 0, index = 0; x < width; x++) {
  157. for (int y = 0; y < height; y++, index++) {
  158.  
  159. // Get reference to Cell and reset flow
  160. LCCell *cell = cells + index;
  161. ResetFlowDirections(cell);
  162.  
  163. // Validate cell
  164. if (cell->Type == LC_CELL_SOLID) {
  165. cell->Liquid = 0;
  166. continue;
  167. }
  168. if (cell->Liquid == 0)
  169. continue;
  170. if (cell->Settled)
  171. continue;
  172. if (cell->Liquid < world->MinValue) {
  173. cell->Liquid = 0;
  174. continue;
  175. }
  176.  
  177. // Keep track of how much liquid this cell started off with
  178. float startValue = cell->Liquid;
  179. float remainingValue = cell->Liquid;
  180. flow = 0;
  181.  
  182. // Flow to bottom cell
  183. if (cell->Neighbors[LC_BOTTOM] && cell->Neighbors[LC_BOTTOM]->Type == LC_CELL_VACUUM) {
  184.  
  185. // Determine rate of flow
  186. flow = CalculateVerticalFlowValue(world, cell->Liquid, cell->Neighbors[LC_BOTTOM]) - cell->Neighbors[LC_BOTTOM]->Liquid;
  187. if (cell->Neighbors[LC_BOTTOM]->Liquid > 0 && flow > world->MinFlow)
  188. flow *= world->FlowSpeed;
  189.  
  190. // Constrain flow
  191. flow = LC_MAX(flow, 0);
  192. if (flow > LC_MIN(world->MaxFlow, cell->Liquid))
  193. flow = LC_MIN(world->MaxFlow, cell->Liquid);
  194.  
  195. // Update temp values
  196. if (flow != 0) {
  197. remainingValue -= flow;
  198. world->Diffs[index] -= flow;
  199. world->Diffs[LC_IDX(world, x, y + 1)] += flow;
  200. cell->FlowDirections[LC_BOTTOM] = 1;
  201. cell->Neighbors[LC_BOTTOM]->Settled = 0;
  202. }
  203. }
  204.  
  205. // Check to ensure we still have liquid in this cell
  206. if (remainingValue < world->MinValue) {
  207. world->Diffs[index] -= remainingValue;
  208. continue;
  209. }
  210.  
  211. // Flow to left cell
  212. if (cell->Neighbors[LC_LEFT] && cell->Neighbors[LC_LEFT]->Type == LC_CELL_VACUUM) {
  213.  
  214. // Calculate flow rate
  215. flow = (remainingValue - cell->Neighbors[LC_LEFT]->Liquid) / 4;
  216. if (flow > world->MinFlow)
  217. flow *= world->FlowSpeed;
  218.  
  219. // constrain flow
  220. flow = LC_MAX(flow, 0);
  221. if (flow > LC_MIN(world->MaxFlow, remainingValue))
  222. flow = LC_MIN(world->MaxFlow, remainingValue);
  223.  
  224. // Adjust temp values
  225. if (flow != 0) {
  226. remainingValue -= flow;
  227. world->Diffs[index] -= flow;
  228. world->Diffs[LC_IDX(world, x - 1, y)] += flow;
  229. cell->FlowDirections[LC_LEFT] = 1;
  230. cell->Neighbors[LC_LEFT]->Settled = 0;
  231. }
  232. }
  233.  
  234. // Check to ensure we still have liquid in this cell
  235. if (remainingValue < world->MinValue) {
  236. world->Diffs[index] -= remainingValue;
  237. continue;
  238. }
  239.  
  240. // Flow to right cell
  241. if (cell->Neighbors[LC_RIGHT] && cell->Neighbors[LC_RIGHT]->Type == LC_CELL_VACUUM) {
  242.  
  243. // calc flow rate
  244. flow = (remainingValue - cell->Neighbors[LC_RIGHT]->Liquid) / 3;
  245. if (flow > world->MinFlow)
  246. flow *= world->FlowSpeed;
  247.  
  248. // constrain flow
  249. flow = LC_MAX(flow, 0);
  250. if (flow > LC_MIN(world->MaxFlow, remainingValue))
  251. flow = LC_MIN(world->MaxFlow, remainingValue);
  252.  
  253. // Adjust temp values
  254. if (flow != 0) {
  255. remainingValue -= flow;
  256. world->Diffs[index] -= flow;
  257. world->Diffs[LC_IDX(world, x + 1, y)] += flow;
  258. cell->FlowDirections[LC_RIGHT] = 1;
  259. cell->Neighbors[LC_RIGHT]->Settled = 0;
  260. }
  261. }
  262.  
  263. // Check to ensure we still have liquid in this cell
  264. if (remainingValue < world->MinValue) {
  265. world->Diffs[index] -= remainingValue;
  266. continue;
  267. }
  268.  
  269. // Flow to Top cell
  270. if (cell->Neighbors[LC_TOP] && cell->Neighbors[LC_TOP]->Type == LC_CELL_VACUUM) {
  271.  
  272. flow = remainingValue - CalculateVerticalFlowValue(world, remainingValue, cell->Neighbors[LC_TOP]);
  273. if (flow > world->MinFlow)
  274. flow *= world->FlowSpeed;
  275.  
  276. // constrain flow
  277. flow = LC_MAX(flow, 0);
  278. if (flow > LC_MIN(world->MaxFlow, remainingValue))
  279. flow = LC_MIN(world->MaxFlow, remainingValue);
  280.  
  281. // Adjust values
  282. if (flow != 0) {
  283. remainingValue -= flow;
  284. world->Diffs[index] -= flow;
  285. world->Diffs[LC_IDX(world, x, y - 1)] += flow;
  286. cell->FlowDirections[LC_TOP] = 1;
  287. cell->Neighbors[LC_TOP]->Settled = 0;
  288. }
  289. }
  290.  
  291. // Check to ensure we still have liquid in this cell
  292. if (remainingValue < world->MinValue) {
  293. world->Diffs[index] -= remainingValue;
  294. continue;
  295. }
  296.  
  297. // Check if cell is settled
  298. if (startValue == remainingValue) {
  299. cell->SettleCount++;
  300. if (cell->SettleCount >= 10) {
  301. ResetFlowDirections(cell);
  302. cell->Settled = 1;
  303. }
  304. } else {
  305. UnsettleNeighbors(cell);
  306. }
  307. }
  308. }
  309.  
  310. // Update Cell values
  311. for (int x = 0, index = 0; x < width; x++) {
  312. for (int y = 0; y < height; y++, index++) {
  313. LCCell *cell = cells + index;
  314. cell->Liquid += world->Diffs[index];
  315. if (cell->Liquid < world->MinValue) {
  316. cell->Liquid = 0;
  317. cell->Settled = 0;
  318. }
  319. }
  320. }
  321. }
  322.  
  323. #undef LC_IDX
  324. #undef LC_MIN
  325. #undef LC_MAX
  326.  
  327. #endif // LIQUID_CELLUAR_IMPLEMENTATION
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement