Advertisement
Guest User

Untitled

a guest
Feb 24th, 2025
1,643
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 28.96 KB | Source Code | 0 0
  1. #include <SDL2/SDL.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5. #include <time.h>  // For random seed
  6.  
  7. #define WIDTH 800
  8. #define HEIGHT 800
  9. #define SCALE 4  // Size of fluid cells
  10. #define IX(x, y) ((x) + (y) * N)
  11. #define SWAP(x0, x) {float *tmp = x0; x0 = x; x = tmp;}
  12.  
  13. // Simulation parameters
  14. #define N (WIDTH / SCALE)
  15. #define SIZE (N * N)
  16. #define ITER 8        // Reduced iterations for stability
  17. #define DIFFUSION 0.00001  // Lower diffusion
  18. #define VISCOSITY 0.00001  // Lower viscosity
  19. #define DT 0.02       // Much smaller time step for stability
  20. #define FORCE 200.0   // Much lower force to prevent instability
  21. #define VORTICITY 2.0  // Much lower vorticity
  22. #define COLORFUL 1     // Enable colorful dye
  23. #define CONTINUOUS_SOURCE 1  // Add continuous source
  24.  
  25. // Utility function to check for NaN
  26. #define CHECK_NAN(x) \
  27.     if (isnan(x)) { \
  28.         printf("NaN detected! Fixing...\n"); \
  29.         x = 0.0f; \
  30.     }
  31.  
  32. // Fluid cell data
  33. typedef struct {
  34.     float *density;
  35.     float *density_prev;
  36.    
  37.     float *u;
  38.     float *v;
  39.     float *u_prev;
  40.     float *v_prev;
  41.    
  42.     // For color dye
  43.     float *r;
  44.     float *g;
  45.     float *b;
  46.     float *r_prev;
  47.     float *g_prev;
  48.     float *b_prev;
  49. } fluid_grid;
  50.  
  51. // Function prototypes
  52. void fluid_step(fluid_grid *grid);
  53. void add_density(fluid_grid *grid, int x, int y, float amount, int color);
  54. void add_velocity(fluid_grid *grid, int x, int y, float amount_x, float amount_y);
  55. void diffuse(int b, float *x, float *x0, float diff, float dt);
  56. void project(float *u, float *v, float *p, float *div);
  57. void advect(int b, float *d, float *d0, float *u, float *v, float dt);
  58. void render(SDL_Renderer *renderer, fluid_grid *grid);
  59. void set_boundaries(int b, float *x);
  60. void vorticity_confinement(fluid_grid *grid);
  61.  
  62. // Main function
  63. int main(int argc, char *argv[]) {
  64.     // Initialize SDL
  65.     if (SDL_Init(SDL_INIT_VIDEO) != 0) {
  66.         printf("SDL_Init Error: %s\n", SDL_GetError());
  67.         return 1;
  68.     }
  69.    
  70.     SDL_Window *window = SDL_CreateWindow("Fluid Simulation",
  71.                                           SDL_WINDOWPOS_CENTERED,
  72.                                           SDL_WINDOWPOS_CENTERED,
  73.                                           WIDTH, HEIGHT,
  74.                                           SDL_WINDOW_SHOWN);
  75.     if (window == NULL) {
  76.         printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
  77.         SDL_Quit();
  78.         return 1;
  79.     }
  80.    
  81.     SDL_Renderer *renderer = SDL_CreateRenderer(window, -1,
  82.                                                SDL_RENDERER_ACCELERATED |
  83.                                                SDL_RENDERER_PRESENTVSYNC);
  84.     if (renderer == NULL) {
  85.         SDL_DestroyWindow(window);
  86.         printf("SDL_CreateRenderer Error: %s\n", SDL_GetError());
  87.         SDL_Quit();
  88.         return 1;
  89.     }
  90.    
  91.     printf("Simulation started. Window size: %d x %d, Grid size: %d x %d\n", WIDTH, HEIGHT, N, N);
  92.    
  93.     // Create fluid grid
  94.     fluid_grid grid;
  95.     grid.density = calloc(SIZE, sizeof(float));
  96.     grid.density_prev = calloc(SIZE, sizeof(float));
  97.     grid.u = calloc(SIZE, sizeof(float));
  98.     grid.v = calloc(SIZE, sizeof(float));
  99.     grid.u_prev = calloc(SIZE, sizeof(float));
  100.     grid.v_prev = calloc(SIZE, sizeof(float));
  101.    
  102.     // For colorful dye
  103.     grid.r = calloc(SIZE, sizeof(float));
  104.     grid.g = calloc(SIZE, sizeof(float));
  105.     grid.b = calloc(SIZE, sizeof(float));
  106.     grid.r_prev = calloc(SIZE, sizeof(float));
  107.     grid.g_prev = calloc(SIZE, sizeof(float));
  108.     grid.b_prev = calloc(SIZE, sizeof(float));
  109.    
  110.     // Add some initial fluid to make things visible right away
  111.     srand(time(NULL));  // Initialize random seed
  112.    
  113.     printf("Adding initial fluid...\n");
  114.    
  115.     // Create a strong vortex in the center
  116.     int cx = N/2;
  117.     int cy = N/2;
  118.    
  119.     // Add a central density blob
  120.     for (int i = cx-10; i <= cx+10; i++) {
  121.         for (int j = cy-10; j <= cy+10; j++) {
  122.             if (i >= 0 && i < N && j >= 0 && j < N) {
  123.                 float dist = sqrtf((i-cx)*(i-cx) + (j-cy)*(j-cy));
  124.                 if (dist < 10) {
  125.                     float amount = 20 * (1 - dist/10);  // Reduced amount
  126.                     add_density(&grid, i, j, amount, 1);
  127.                    
  128.                     // Add vivid colors
  129.                     grid.r[IX(i, j)] = 50 + rand() % 50;  // Lower values
  130.                     grid.g[IX(i, j)] = 50 + rand() % 50;
  131.                     grid.b[IX(i, j)] = 50 + rand() % 50;
  132.                    
  133.                     // Create swirling velocity - much lower values
  134.                     float angle = atan2f(j-cy, i-cx);
  135.                     float speed = 20 * (1 - dist/10);  // Much smaller velocity
  136.                     add_velocity(&grid, i, j, -speed * sinf(angle), speed * cosf(angle));
  137.                 }
  138.             }
  139.         }
  140.     }
  141.    
  142.     // Add some random splotches too
  143.     for (int n = 0; n < 5; n++) {  // Fewer splotches
  144.         int x = N/4 + rand() % (N/2);
  145.         int y = N/4 + rand() % (N/2);
  146.        
  147.         for (int i = x-3; i <= x+3; i++) {  // Smaller radius
  148.             for (int j = y-3; j <= y+3; j++) {
  149.                 if (i >= 0 && i < N && j >= 0 && j < N) {
  150.                     float dist = sqrtf((i-x)*(i-x) + (j-y)*(j-y));
  151.                     if (dist < 3) {
  152.                         add_density(&grid, i, j, 10 * (1 - dist/3), 1);  // Lower density
  153.                         grid.r[IX(i, j)] = 20 + rand() % 30;  // Lower colors
  154.                         grid.g[IX(i, j)] = 20 + rand() % 30;
  155.                         grid.b[IX(i, j)] = 20 + rand() % 30;
  156.                     }
  157.                 }
  158.             }
  159.         }
  160.     }
  161.    
  162.     printf("Initial fluid added.\n");
  163.    
  164.     // Mouse state
  165.     int mouse_x = 0, mouse_y = 0;
  166.     int prev_mouse_x = 0, prev_mouse_y = 0;
  167.     int mouse_down = 0;
  168.     int right_mouse_down = 0;
  169.    
  170.     // Main loop
  171.     int quit = 0;
  172.     int frame_count = 0;
  173.     while (!quit) {
  174.         SDL_Event event;
  175.         while (SDL_PollEvent(&event)) {
  176.             switch (event.type) {
  177.                 case SDL_QUIT:
  178.                     quit = 1;
  179.                     break;
  180.                    
  181.                 case SDL_MOUSEMOTION:
  182.                     mouse_x = event.motion.x / SCALE;
  183.                     mouse_y = event.motion.y / SCALE;
  184.                     break;
  185.                    
  186.                 case SDL_MOUSEBUTTONDOWN:
  187.                     if (event.button.button == SDL_BUTTON_LEFT) {
  188.                         mouse_down = 1;
  189.                         prev_mouse_x = mouse_x;
  190.                         prev_mouse_y = mouse_y;
  191.                     } else if (event.button.button == SDL_BUTTON_RIGHT) {
  192.                         right_mouse_down = 1;
  193.                     }
  194.                     break;
  195.                    
  196.                 case SDL_MOUSEBUTTONUP:
  197.                     if (event.button.button == SDL_BUTTON_LEFT) {
  198.                         mouse_down = 0;
  199.                     } else if (event.button.button == SDL_BUTTON_RIGHT) {
  200.                         right_mouse_down = 0;
  201.                     }
  202.                     break;
  203.             }
  204.         }
  205.        
  206.         // Add velocity with mouse drag
  207.         if (mouse_down) {
  208.             float dx = mouse_x - prev_mouse_x;
  209.             float dy = mouse_y - prev_mouse_y;
  210.            
  211.             if (dx != 0 || dy != 0) {
  212.                 add_velocity(&grid, mouse_x, mouse_y, dx * FORCE, dy * FORCE);
  213.             }
  214.            
  215.             // Cycle through colors based on frame count for fun visual effect
  216.             if (COLORFUL) {
  217.                 float r = 0.5f + 0.5f * sin(0.01f * frame_count);
  218.                 float g = 0.5f + 0.5f * sin(0.01f * frame_count + 2.0f);
  219.                 float b = 0.5f + 0.5f * sin(0.01f * frame_count + 4.0f);
  220.                
  221.                 add_density(&grid, mouse_x, mouse_y, 100, 1);
  222.                 grid.r[IX(mouse_x, mouse_y)] += 100 * r;
  223.                 grid.g[IX(mouse_x, mouse_y)] += 100 * g;
  224.                 grid.b[IX(mouse_x, mouse_y)] += 100 * b;
  225.             } else {
  226.                 add_density(&grid, mouse_x, mouse_y, 100, 0);
  227.             }
  228.         }
  229.        
  230.         // Add density with right mouse button
  231.         if (right_mouse_down) {
  232.             add_density(&grid, mouse_x, mouse_y, 200, 1);
  233.            
  234.             // Create a little vortex
  235.             for (int i = -3; i <= 3; i++) {
  236.                 for (int j = -3; j <= 3; j++) {
  237.                     int x = mouse_x + i;
  238.                     int y = mouse_y + j;
  239.                    
  240.                     if (x >= 1 && x < N-1 && y >= 1 && y < N-1) {
  241.                         // Create a swirling effect around the cursor
  242.                         float dx = i;
  243.                         float dy = j;
  244.                         float dist = sqrt(dx*dx + dy*dy);
  245.                        
  246.                         if (dist > 0) {
  247.                             // Perpendicular vector for swirling
  248.                             float vx = -dy / dist * 50;
  249.                             float vy = dx / dist * 50;
  250.                            
  251.                             add_velocity(&grid, x, y, vx, vy);
  252.                         }
  253.                     }
  254.                 }
  255.             }
  256.         }
  257.        
  258.         // Update fluid simulation
  259.         fluid_step(&grid);
  260.        
  261.         // Render to screen
  262.         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  263.         SDL_RenderClear(renderer);
  264.         render(renderer, &grid);
  265.         SDL_RenderPresent(renderer);
  266.        
  267.         // Store prev mouse position
  268.         prev_mouse_x = mouse_x;
  269.         prev_mouse_y = mouse_y;
  270.        
  271.         frame_count++;
  272.     }
  273.    
  274.     // Clean up
  275.     free(grid.density);
  276.     free(grid.density_prev);
  277.     free(grid.u);
  278.     free(grid.v);
  279.     free(grid.u_prev);
  280.     free(grid.v_prev);
  281.     free(grid.r);
  282.     free(grid.g);
  283.     free(grid.b);
  284.     free(grid.r_prev);
  285.     free(grid.g_prev);
  286.     free(grid.b_prev);
  287.    
  288.     SDL_DestroyRenderer(renderer);
  289.     SDL_DestroyWindow(window);
  290.     SDL_Quit();
  291.    
  292.     return 0;
  293. }
  294.  
  295. // Update fluid simulation for one time step
  296. void fluid_step(fluid_grid *grid) {
  297.     // Add continuous source in the center to keep the simulation active
  298.     if (CONTINUOUS_SOURCE) {
  299.         static int frame = 0;
  300.         frame++;
  301.        
  302.         // Center of the grid
  303.         int cx = N/2;
  304.         int cy = N/2;
  305.        
  306.         // Add a pulsing source with changing colors
  307.         float strength = 5.0f + 3.0f * sin(frame * 0.05f);  // Much lower strength
  308.        
  309.         // Vary the position slightly for more interesting effects
  310.         int x = cx + 2 * sin(frame * 0.02f);  // Smaller offset
  311.         int y = cy + 2 * cos(frame * 0.03f);
  312.        
  313.         if (frame % 5 == 0) {  // Only add every few frames to avoid overwhelming
  314.             add_density(grid, x, y, strength, 1);
  315.             grid->r[IX(x, y)] += 20 * (0.5f + 0.5f * sin(frame * 0.01f));  // Lower color values
  316.             grid->g[IX(x, y)] += 20 * (0.5f + 0.5f * sin(frame * 0.01f + 2.0f));
  317.             grid->b[IX(x, y)] += 20 * (0.5f + 0.5f * sin(frame * 0.01f + 4.0f));
  318.            
  319.             // Add some swirling velocity too - much lower values
  320.             float angle = frame * 0.01f;
  321.             add_velocity(grid, x, y, 5 * cos(angle), 5 * sin(angle));  // Much smaller velocity
  322.         }
  323.     }
  324.    
  325.     // Check grid for NaN or extreme values before processing
  326.     for (int i = 0; i < SIZE; i++) {
  327.         CHECK_NAN(grid->u[i]);
  328.         CHECK_NAN(grid->v[i]);
  329.         CHECK_NAN(grid->density[i]);
  330.         CHECK_NAN(grid->r[i]);
  331.         CHECK_NAN(grid->g[i]);
  332.         CHECK_NAN(grid->b[i]);
  333.        
  334.         // Clamp extreme values
  335.         if (fabs(grid->u[i]) > 100.0f) grid->u[i] = grid->u[i] > 0 ? 100.0f : -100.0f;
  336.         if (fabs(grid->v[i]) > 100.0f) grid->v[i] = grid->v[i] > 0 ? 100.0f : -100.0f;
  337.         if (grid->density[i] > 100.0f) grid->density[i] = 100.0f;
  338.         if (grid->r[i] > 100.0f) grid->r[i] = 100.0f;
  339.         if (grid->g[i] > 100.0f) grid->g[i] = 100.0f;
  340.         if (grid->b[i] > 100.0f) grid->b[i] = 100.0f;
  341.     }
  342.    
  343.     // Diffuse velocities
  344.     diffuse(1, grid->u_prev, grid->u, VISCOSITY, DT);
  345.     diffuse(2, grid->v_prev, grid->v, VISCOSITY, DT);
  346.    
  347.     // Project to enforce incompressibility
  348.     project(grid->u_prev, grid->v_prev, grid->u, grid->v);
  349.    
  350.     // Advect velocities
  351.     advect(1, grid->u, grid->u_prev, grid->u_prev, grid->v_prev, DT);
  352.     advect(2, grid->v, grid->v_prev, grid->u_prev, grid->v_prev, DT);
  353.    
  354.     // Project again
  355.     project(grid->u, grid->v, grid->u_prev, grid->v_prev);
  356.    
  357.     // Add vorticity confinement
  358.     vorticity_confinement(grid);
  359.    
  360.     // Diffuse and advect density
  361.     diffuse(0, grid->density_prev, grid->density, DIFFUSION, DT);
  362.     advect(0, grid->density, grid->density_prev, grid->u, grid->v, DT);
  363.    
  364.     // For colorful dye
  365.     if (COLORFUL) {
  366.         diffuse(0, grid->r_prev, grid->r, DIFFUSION, DT);
  367.         diffuse(0, grid->g_prev, grid->g, DIFFUSION, DT);
  368.         diffuse(0, grid->b_prev, grid->b, DIFFUSION, DT);
  369.        
  370.         advect(0, grid->r, grid->r_prev, grid->u, grid->v, DT);
  371.         advect(0, grid->g, grid->g_prev, grid->u, grid->v, DT);
  372.         advect(0, grid->b, grid->b_prev, grid->u, grid->v, DT);
  373.     }
  374.    
  375.     // Debug - Print max values for first 10 frames
  376.     static int debug_frame = 0;
  377.     if (debug_frame < 10) {
  378.         float max_d = 0, max_u = 0, max_v = 0;
  379.         float sum_d = 0;
  380.         for (int i = 0; i < SIZE; i++) {
  381.             sum_d += grid->density[i];
  382.             max_d = fmaxf(max_d, grid->density[i]);
  383.             max_u = fmaxf(max_u, fabsf(grid->u[i]));
  384.             max_v = fmaxf(max_v, fabsf(grid->v[i]));
  385.            
  386.             // Check for NaN and fix if needed
  387.             CHECK_NAN(grid->density[i]);
  388.             CHECK_NAN(grid->u[i]);
  389.             CHECK_NAN(grid->v[i]);
  390.             CHECK_NAN(grid->r[i]);
  391.             CHECK_NAN(grid->g[i]);
  392.             CHECK_NAN(grid->b[i]);
  393.         }
  394.        
  395.         if (isnan(sum_d)) {
  396.             printf("ERROR: NaN detected in density sum! Fixing the grid...\n");
  397.             // Reset the grid to fix NaN values
  398.             for (int i = 0; i < SIZE; i++) {
  399.                 if (isnan(grid->density[i])) grid->density[i] = 0.0f;
  400.                 if (isnan(grid->u[i])) grid->u[i] = 0.0f;
  401.                 if (isnan(grid->v[i])) grid->v[i] = 0.0f;
  402.                 if (isnan(grid->r[i])) grid->r[i] = 0.0f;
  403.                 if (isnan(grid->g[i])) grid->g[i] = 0.0f;
  404.                 if (isnan(grid->b[i])) grid->b[i] = 0.0f;
  405.             }
  406.         }
  407.        
  408.         printf("Frame %d: max_density=%.2f, sum_density=%.2f, max_u=%.2f, max_v=%.2f\n",
  409.                debug_frame, max_d, sum_d, max_u, max_v);
  410.         debug_frame++;
  411.     }
  412. }
  413.  
  414. // Add density to a specific cell with optional color
  415. void add_density(fluid_grid *grid, int x, int y, float amount, int color) {
  416.     if (x < 1 || x > N-2 || y < 1 || y > N-2) return;
  417.    
  418.     // Clamp density to avoid extreme values
  419.     if (amount > 100.0f) amount = 100.0f;
  420.    
  421.     int index = IX(x, y);
  422.     grid->density[index] += amount;
  423.    
  424.     // Check for NaN
  425.     CHECK_NAN(grid->density[index]);
  426.    
  427.     // Add density to surrounding cells for a smoother effect - only add half as much
  428.     grid->density[IX(x+1, y)] += amount * 0.3f;
  429.     grid->density[IX(x-1, y)] += amount * 0.3f;
  430.     grid->density[IX(x, y+1)] += amount * 0.3f;
  431.     grid->density[IX(x, y-1)] += amount * 0.3f;
  432.    
  433.     // For color dye
  434.     if (color && COLORFUL) {
  435.         // More controlled colors
  436.         float r_amount = amount * ((float)rand() / RAND_MAX);
  437.         float g_amount = amount * ((float)rand() / RAND_MAX);
  438.         float b_amount = amount * ((float)rand() / RAND_MAX);
  439.        
  440.         // Clamp to reasonable values
  441.         if (r_amount > 100.0f) r_amount = 100.0f;
  442.         if (g_amount > 100.0f) g_amount = 100.0f;
  443.         if (b_amount > 100.0f) b_amount = 100.0f;
  444.        
  445.         grid->r[index] += r_amount;
  446.         grid->g[index] += g_amount;
  447.         grid->b[index] += b_amount;
  448.        
  449.         // Check for NaN
  450.         CHECK_NAN(grid->r[index]);
  451.         CHECK_NAN(grid->g[index]);
  452.         CHECK_NAN(grid->b[index]);
  453.     }
  454. }
  455.  
  456. // Add velocity to a specific cell
  457. void add_velocity(fluid_grid *grid, int x, int y, float amount_x, float amount_y) {
  458.     if (x < 1 || x > N-2 || y < 1 || y > N-2) return;
  459.    
  460.     // Clamp velocity to avoid extreme values
  461.     if (amount_x > 50.0f) amount_x = 50.0f;
  462.     if (amount_x < -50.0f) amount_x = -50.0f;
  463.     if (amount_y > 50.0f) amount_y = 50.0f;
  464.     if (amount_y < -50.0f) amount_y = -50.0f;
  465.    
  466.     int index = IX(x, y);
  467.     grid->u[index] += amount_x;
  468.     grid->v[index] += amount_y;
  469.    
  470.     // Check for NaN
  471.     CHECK_NAN(grid->u[index]);
  472.     CHECK_NAN(grid->v[index]);
  473.    
  474.     // Add velocity to surrounding cells for a smoother effect - less spread
  475.     grid->u[IX(x+1, y)] += amount_x * 0.25f;
  476.     grid->u[IX(x-1, y)] += amount_x * 0.25f;
  477.     grid->u[IX(x, y+1)] += amount_x * 0.25f;
  478.     grid->u[IX(x, y-1)] += amount_x * 0.25f;
  479.    
  480.     grid->v[IX(x+1, y)] += amount_y * 0.25f;
  481.     grid->v[IX(x-1, y)] += amount_y * 0.25f;
  482.     grid->v[IX(x, y+1)] += amount_y * 0.25f;
  483.     grid->v[IX(x, y-1)] += amount_y * 0.25f;
  484. }
  485.  
  486. // Diffusion step
  487. void diffuse(int b, float *x, float *x0, float diff, float dt) {
  488.     float a = dt * diff * (N - 2) * (N - 2);
  489.    
  490.     for (int k = 0; k < ITER; k++) {
  491.         for (int i = 1; i < N - 1; i++) {
  492.             for (int j = 1; j < N - 1; j++) {
  493.                 x[IX(i, j)] = (x0[IX(i, j)] + a * (
  494.                     x[IX(i+1, j)] + x[IX(i-1, j)] +
  495.                     x[IX(i, j+1)] + x[IX(i, j-1)]
  496.                 )) / (1 + 4 * a);
  497.                
  498.                 // Prevent extreme values that can cause instability
  499.                 if (x[IX(i, j)] > 100.0f) x[IX(i, j)] = 100.0f;
  500.                 if (x[IX(i, j)] < -100.0f) x[IX(i, j)] = -100.0f;
  501.                
  502.                 // Check for NaN
  503.                 CHECK_NAN(x[IX(i, j)]);
  504.             }
  505.         }
  506.         set_boundaries(b, x);
  507.     }
  508.    
  509.     // Debug first few diffusions
  510.     static int diffuse_count = 0;
  511.     if (diffuse_count < 5) {
  512.         float sum = 0, max_val = 0;
  513.         for (int i = 0; i < SIZE; i++) {
  514.             sum += fabsf(x[i]);
  515.             max_val = fmaxf(max_val, fabsf(x[i]));
  516.            
  517.             // Check for NaN
  518.             CHECK_NAN(x[i]);
  519.         }
  520.         printf("Diffuse %d (type %d): sum=%.2f, max=%.2f\n",
  521.                diffuse_count, b, sum, max_val);
  522.         diffuse_count++;
  523.     }
  524. }
  525.  
  526. // Project step (enforce incompressibility)
  527. void project(float *u, float *v, float *p, float *div) {
  528.     float h = 1.0f / N;
  529.    
  530.     // Calculate divergence
  531.     for (int i = 1; i < N - 1; i++) {
  532.         for (int j = 1; j < N - 1; j++) {
  533.             div[IX(i, j)] = -0.5f * h * (
  534.                 u[IX(i+1, j)] - u[IX(i-1, j)] +
  535.                 v[IX(i, j+1)] - v[IX(i, j-1)]
  536.             );
  537.             p[IX(i, j)] = 0;
  538.            
  539.             // Check for NaN
  540.             CHECK_NAN(div[IX(i, j)]);
  541.            
  542.             // Clamp divergence to avoid instability
  543.             if (div[IX(i, j)] > 100.0f) div[IX(i, j)] = 100.0f;
  544.             if (div[IX(i, j)] < -100.0f) div[IX(i, j)] = -100.0f;
  545.         }
  546.     }
  547.     set_boundaries(0, div);
  548.     set_boundaries(0, p);
  549.    
  550.     // Solve pressure
  551.     for (int k = 0; k < ITER; k++) {
  552.         for (int i = 1; i < N - 1; i++) {
  553.             for (int j = 1; j < N - 1; j++) {
  554.                 p[IX(i, j)] = (div[IX(i, j)] + (
  555.                     p[IX(i+1, j)] + p[IX(i-1, j)] +
  556.                     p[IX(i, j+1)] + p[IX(i, j-1)]
  557.                 )) / 4;
  558.                
  559.                 // Check for NaN
  560.                 CHECK_NAN(p[IX(i, j)]);
  561.                
  562.                 // Clamp pressure to avoid instability
  563.                 if (p[IX(i, j)] > 100.0f) p[IX(i, j)] = 100.0f;
  564.                 if (p[IX(i, j)] < -100.0f) p[IX(i, j)] = -100.0f;
  565.             }
  566.         }
  567.         set_boundaries(0, p);
  568.     }
  569.    
  570.     // Apply pressure gradient
  571.     for (int i = 1; i < N - 1; i++) {
  572.         for (int j = 1; j < N - 1; j++) {
  573.             u[IX(i, j)] -= 0.5f * (p[IX(i+1, j)] - p[IX(i-1, j)]) / h;
  574.             v[IX(i, j)] -= 0.5f * (p[IX(i, j+1)] - p[IX(i, j-1)]) / h;
  575.            
  576.             // Check for NaN
  577.             CHECK_NAN(u[IX(i, j)]);
  578.             CHECK_NAN(v[IX(i, j)]);
  579.            
  580.             // Clamp velocities to avoid instability
  581.             if (u[IX(i, j)] > 100.0f) u[IX(i, j)] = 100.0f;
  582.             if (u[IX(i, j)] < -100.0f) u[IX(i, j)] = -100.0f;
  583.             if (v[IX(i, j)] > 100.0f) v[IX(i, j)] = 100.0f;
  584.             if (v[IX(i, j)] < -100.0f) v[IX(i, j)] = -100.0f;
  585.         }
  586.     }
  587.     set_boundaries(1, u);
  588.     set_boundaries(2, v);
  589.    
  590.     // Debug - Check for NaN anywhere in the grid
  591.     for (int i = 0; i < SIZE; i++) {
  592.         CHECK_NAN(u[i]);
  593.         CHECK_NAN(v[i]);
  594.         CHECK_NAN(p[i]);
  595.         CHECK_NAN(div[i]);
  596.     }
  597. }
  598.  
  599. // Advection step (semi-Lagrangian)
  600. void advect(int b, float *d, float *d0, float *u, float *v, float dt) {
  601.     float dt0 = dt * (N - 2);
  602.    
  603.     // Apply a tiny constant force to keep things moving
  604.     static int advect_count = 0;
  605.    
  606.     for (int i = 1; i < N - 1; i++) {
  607.         for (int j = 1; j < N - 1; j++) {
  608.             // Trace particle back
  609.             float x = i - dt0 * u[IX(i, j)];
  610.             float y = j - dt0 * v[IX(i, j)];
  611.            
  612.             // Clamp to grid
  613.             if (x < 0.5f) x = 0.5f;
  614.             if (x > N - 1.5f) x = N - 1.5f;
  615.             if (y < 0.5f) y = 0.5f;
  616.             if (y > N - 1.5f) y = N - 1.5f;
  617.            
  618.             // Bilinear interpolation
  619.             int i0 = (int)x;
  620.             int i1 = i0 + 1;
  621.             int j0 = (int)y;
  622.             int j1 = j0 + 1;
  623.            
  624.             float s1 = x - i0;
  625.             float s0 = 1 - s1;
  626.             float t1 = y - j0;
  627.             float t0 = 1 - t1;
  628.            
  629.             // Check for invalid indices
  630.             if (i0 < 0) i0 = 0; if (i0 >= N) i0 = N-1;
  631.             if (i1 < 0) i1 = 0; if (i1 >= N) i1 = N-1;
  632.             if (j0 < 0) j0 = 0; if (j0 >= N) j0 = N-1;
  633.             if (j1 < 0) j1 = 0; if (j1 >= N) j1 = N-1;
  634.            
  635.             d[IX(i, j)] =
  636.                 s0 * (t0 * d0[IX(i0, j0)] + t1 * d0[IX(i0, j1)]) +
  637.                 s1 * (t0 * d0[IX(i1, j0)] + t1 * d0[IX(i1, j1)]);
  638.            
  639.             // Check for NaN
  640.             CHECK_NAN(d[IX(i, j)]);
  641.            
  642.             // Prevent too much dissipation for density
  643.             if (b == 0 && d[IX(i, j)] > 0.01f) {
  644.                 // Apply a little damping but not too much
  645.                 d[IX(i, j)] *= 0.998f;
  646.                
  647.                 // Ensure a minimum density if there was some density before
  648.                 if (d[IX(i, j)] < 0.1f && d0[IX(i, j)] > 0.1f) {
  649.                     d[IX(i, j)] = 0.1f;
  650.                 }
  651.             }
  652.            
  653.             // Clamp values to prevent instability
  654.             if (d[IX(i, j)] > 100.0f) d[IX(i, j)] = 100.0f;
  655.             if (b != 0 && d[IX(i, j)] < -100.0f) d[IX(i, j)] = -100.0f;
  656.         }
  657.     }
  658.    
  659.     // Debug for first few advections
  660.     if (advect_count < 5) {
  661.         float sum = 0, max_val = 0;
  662.         for (int i = 0; i < SIZE; i++) {
  663.             sum += fabsf(d[i]);
  664.             max_val = fmaxf(max_val, fabsf(d[i]));
  665.            
  666.             // Check for NaN
  667.             CHECK_NAN(d[i]);
  668.         }
  669.         printf("Advect %d (type %d): sum=%.2f, max=%.2f\n",
  670.                advect_count, b, sum, max_val);
  671.         advect_count++;
  672.     }
  673.    
  674.     set_boundaries(b, d);
  675. }
  676.  
  677. // Render the fluid simulation
  678. void render(SDL_Renderer *renderer, fluid_grid *grid) {
  679.     static int frame_counter = 0;
  680.     frame_counter++;
  681.    
  682.     // Always print for the first 10 frames
  683.     if (frame_counter <= 10 || frame_counter % 100 == 0) {
  684.         // Debug: Print max density value to check if we have any density at all
  685.         float max_density = 0;
  686.         float sum_density = 0;
  687.         for (int i = 0; i < N; i++) {
  688.             for (int j = 0; j < N; j++) {
  689.                 max_density = fmaxf(max_density, grid->density[IX(i, j)]);
  690.                 sum_density += grid->density[IX(i, j)];
  691.             }
  692.         }
  693.         printf("Frame %d: Max density = %.2f, Sum density = %.2f\n",
  694.                frame_counter, max_density, sum_density);
  695.     }
  696.    
  697.     // First clear with a very dark blue background to show grid boundaries
  698.     SDL_SetRenderDrawColor(renderer, 0, 0, 20, 255);
  699.     SDL_RenderClear(renderer);
  700.    
  701.     // Count how many cells have visible content
  702.     int visible_cells = 0;
  703.    
  704.     for (int i = 0; i < N; i++) {
  705.         for (int j = 0; j < N; j++) {
  706.             int idx = IX(i, j);
  707.             float d = grid->density[idx];
  708.            
  709.             // Skip cells with basically no density - optimization
  710.             if (d < 0.01f) continue;
  711.            
  712.             // Make small density values more visible (logarithmic scaling)
  713.             d = 80.0f * log(1.0f + d * 0.2f);
  714.            
  715.             if (d > 255) d = 255;
  716.            
  717.             visible_cells++;
  718.            
  719.             Uint8 r, g, b;
  720.            
  721.             if (COLORFUL) {
  722.                 float r_val = grid->r[idx];
  723.                 float g_val = grid->g[idx];
  724.                 float b_val = grid->b[idx];
  725.                
  726.                 // Ensure colors are visible even with low density
  727.                 float brightness = fmaxf(30.0f, d);
  728.                
  729.                 // Normalize colors
  730.                 float max_color = fmaxf(r_val, fmaxf(g_val, b_val));
  731.                 if (max_color < 0.01f) {
  732.                     // If no color, use white dye
  733.                     r = g = b = (Uint8)brightness;
  734.                 } else {
  735.                     // Normalize and apply brightness
  736.                     r = (Uint8)(brightness * r_val / max_color);
  737.                     g = (Uint8)(brightness * g_val / max_color);
  738.                     b = (Uint8)(brightness * b_val / max_color);
  739.                 }
  740.                
  741.                 // Ensure some minimum color to make it visible
  742.                 r = fmaxf(r, 20);
  743.                 g = fmaxf(g, 20);
  744.                 b = fmaxf(b, 20);
  745.             } else {
  746.                 r = g = b = (Uint8)d;
  747.             }
  748.            
  749.             SDL_SetRenderDrawColor(renderer, r, g, b, 255);
  750.             SDL_Rect rect = {i * SCALE, j * SCALE, SCALE, SCALE};
  751.             SDL_RenderFillRect(renderer, &rect);
  752.         }
  753.     }
  754.    
  755.     // Debug output for first 10 frames
  756.     if (frame_counter <= 10) {
  757.         printf("Frame %d: %d visible cells (%.1f%% of grid)\n",
  758.                frame_counter, visible_cells, 100.0f * visible_cells / SIZE);
  759.     }
  760. }
  761.  
  762. // Set boundary conditions
  763. void set_boundaries(int b, float *x) {
  764.     // Edges
  765.     for (int i = 1; i < N - 1; i++) {
  766.         x[IX(i, 0)] = b == 2 ? -x[IX(i, 1)] : x[IX(i, 1)];
  767.         x[IX(i, N-1)] = b == 2 ? -x[IX(i, N-2)] : x[IX(i, N-2)];
  768.     }
  769.    
  770.     for (int j = 1; j < N - 1; j++) {
  771.         x[IX(0, j)] = b == 1 ? -x[IX(1, j)] : x[IX(1, j)];
  772.         x[IX(N-1, j)] = b == 1 ? -x[IX(N-2, j)] : x[IX(N-2, j)];
  773.     }
  774.    
  775.     // Corners
  776.     x[IX(0, 0)] = 0.5f * (x[IX(1, 0)] + x[IX(0, 1)]);
  777.     x[IX(0, N-1)] = 0.5f * (x[IX(1, N-1)] + x[IX(0, N-2)]);
  778.     x[IX(N-1, 0)] = 0.5f * (x[IX(N-2, 0)] + x[IX(N-1, 1)]);
  779.     x[IX(N-1, N-1)] = 0.5f * (x[IX(N-2, N-1)] + x[IX(N-1, N-2)]);
  780.    
  781.     // Debug boundary check - Print max values every 500 frames
  782.     static int counter = 0;
  783.     if (++counter % 500 == 0) {
  784.         float max_val = 0.0f;
  785.         for (int i = 0; i < N; i++) {
  786.             for (int j = 0; j < N; j++) {
  787.                 max_val = fmaxf(max_val, fabsf(x[IX(i, j)]));
  788.             }
  789.         }
  790.         printf("Max value in grid (type %d): %.2f\n", b, max_val);
  791.     }
  792. }
  793.  
  794. // Vorticity confinement to make the fluid more swirly
  795. void vorticity_confinement(fluid_grid *grid) {
  796.     float *curl = (float *)malloc(SIZE * sizeof(float));
  797.    
  798.     // Calculate curl (vorticity)
  799.     for (int i = 1; i < N - 1; i++) {
  800.         for (int j = 1; j < N - 1; j++) {
  801.             float du_dy = (grid->u[IX(i, j+1)] - grid->u[IX(i, j-1)]) * 0.5f;
  802.             float dv_dx = (grid->v[IX(i+1, j)] - grid->v[IX(i-1, j)]) * 0.5f;
  803.            
  804.             curl[IX(i, j)] = du_dy - dv_dx;
  805.         }
  806.     }
  807.    
  808.     // Calculate vorticity force
  809.     for (int i = 1; i < N - 1; i++) {
  810.         for (int j = 1; j < N - 1; j++) {
  811.             float curl_ij = curl[IX(i, j)];
  812.            
  813.             // Find magnitude of curl gradient
  814.             float dx = fabs(curl[IX(i+1, j)]) - fabs(curl[IX(i-1, j)]);
  815.             float dy = fabs(curl[IX(i, j+1)]) - fabs(curl[IX(i, j-1)]);
  816.            
  817.             float grad_mag = sqrt(dx*dx + dy*dy) + 1e-5f;
  818.             dx /= grad_mag;
  819.             dy /= grad_mag;
  820.            
  821.             // Apply force
  822.             grid->u[IX(i, j)] += VORTICITY * dy * curl_ij * DT;
  823.             grid->v[IX(i, j)] -= VORTICITY * dx * curl_ij * DT;
  824.         }
  825.     }
  826.    
  827.     free(curl);
  828. }
  829.  
Tags: Claude
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement