Advertisement
Kitomas

metaball demo

May 23rd, 2025
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.86 KB | None | 0 0
  1. #include <public_stuff.hpp>
  2. #include <math.h>
  3.  
  4.  
  5.  
  6. #define METABALL_THRESHHOLD 75.0f
  7. #define METABALL_SPEED 500.0f
  8. #define METABALL_COUNT 400
  9.  
  10.  
  11.  
  12.  
  13.  
  14. struct Metaball {
  15.   f32 x, y, m;
  16.   f32 velX, velY;
  17. };
  18.  
  19. static Metaball metaballs[METABALL_COUNT];
  20.  
  21.  
  22.  
  23. static void reset_metaballs(){
  24.   #define MBCOUNT_FRACT(x,y) ((f32)METABALL_COUNT*((f32)(x)/(y)))
  25.   for(int i=0; i<METABALL_COUNT; ++i){
  26.     metaballs[i].x    = frandf()*CANVAS_W;
  27.     metaballs[i].y    = frandf()*CANVAS_H;
  28.     metaballs[i].m    = frandf()*MBCOUNT_FRACT(3.0f,4) + MBCOUNT_FRACT(1.0f,4);
  29.     metaballs[i].velX = frandf2()*METABALL_SPEED;
  30.     metaballs[i].velY = frandf2()*METABALL_SPEED;
  31.  
  32.   }
  33.  
  34. }
  35.  
  36.  
  37.  
  38. static inline f32 distancef(f32 x0, f32 y0,
  39.                             f32 x1, f32 y1, f32 m)
  40. {
  41.   x0 -= x1;
  42.   y0 -= y1;
  43.   const f32 result = sqrtf(x0*x0+y0*y0);
  44.  
  45.   return m / (result*result);
  46.  
  47. }
  48.  
  49. static inline Color8 sum_metaballs(f32 x, f32 y){
  50.   // Note: convert to f64 if too many rounding errors start happening
  51.   f32 sum = 0.0f;
  52.  
  53.   for(int i=0; i<METABALL_COUNT; ++i)
  54.     sum += distancef(x, y, metaballs[i].x, metaballs[i].y, metaballs[i].m);
  55.  
  56.   // Monochromatic
  57.   //return 255 * (sum < METABALL_THRESHHOLD);
  58.  
  59.   // Balls of light
  60.   //#define GRAY(u) MIN(16*(s32)( (u)*16.0f + 0.5f ), 255)
  61.   //return GRAY(MIN(sum/METABALL_THRESHHOLD, 1.0f));
  62.  
  63.   // Black-and-white trippy look
  64.   //#define GRAY(u) (16*(s32)( (u)*16.0f + 0.5f ))
  65.   //return GRAY(sum/METABALL_THRESHHOLD);
  66.  
  67.   // Normal trippy look
  68.   return 255 * (sum/METABALL_THRESHHOLD);
  69.  
  70. }
  71.  
  72. static void render_metaballs(){
  73.   for(PixelCoords i=0; i.v<(CANVAS_W*CANVAS_H); ++i.v)
  74.     //pixels[i.v] = sum_metaballs((f32)i.x, (f32)i.y);
  75.     pixels[i.v] = sum_metaballs((f32)(i.v&255), (f32)(i.v>>8));
  76.  
  77. }
  78.  
  79.  
  80.  
  81. static void animate_metaballs(){
  82.   #define OPTIMAL_FRAME (1000.0/62.5) // 16ms
  83.   #define COEFFICIENT_DIV (1.0/OPTIMAL_FRAME)
  84.  
  85.   #define LASTTIME_START 0xFFFFFFFFFFFFFFFF // = 2^64 - 1
  86.   static u64 timeLast = LASTTIME_START;
  87.  
  88.   const u64 timeThis = timeGetPerfCounter();
  89.   if(timeLast == LASTTIME_START) timeLast = timeThis;
  90.  
  91.   // Note: convert to f64 if too many rounding errors start happening
  92.   const f32 timeDelta = (f32)(timeThis-timeLast)/timeGetPerfFreq();
  93.   timeLast = timeThis;
  94.  
  95.  
  96.  
  97.   for(int i=0; i<METABALL_COUNT; ++i){
  98.     // Note: convert to f64 if too many rounding errors start happening
  99.     const f32 coefficient = timeDelta*COEFFICIENT_DIV;
  100.     Metaball& metaball = metaballs[i];
  101.  
  102.     metaball.x += metaball.velX*coefficient;
  103.     metaball.y += metaball.velY*coefficient;
  104.  
  105.     if(metaball.x<0 || metaball.x>=CANVAS_W){
  106.       metaball.velX = -metaball.velX;
  107.       metaball.x = CLAMP(metaball.x, 0, CANVAS_W-1);
  108.     }
  109.  
  110.     if(metaball.y<0 || metaball.y>=CANVAS_H){
  111.       metaball.velY = -metaball.velY;
  112.       metaball.y = CLAMP(metaball.y, 0, CANVAS_H-1);
  113.     }
  114.  
  115.   }
  116.  
  117. }
  118.  
  119.  
  120.  
  121.  
  122.  
  123. int user_main(int argc, char** argv){
  124.   #define GAMMA 0.45
  125.   for(int i=0; i<256; ++i){
  126.     u8 gray = u8(  255 * pow((f64)i/255, 1.0/(GAMMA))  );
  127.     Color24 color(gray, gray, gray);
  128.     update_palette(&color, i, 1);
  129.   }
  130.  
  131.   //_lbl_start:
  132.   reset_metaballs();
  133.  
  134.  
  135.  
  136.   while(!win_closed){
  137.     //Handle events
  138.  
  139.     Event evt;
  140.  
  141.     while(pollEvent(&evt))
  142.     switch(evt.type){
  143.       case EVENT_QUIT: return 0; // No break needed
  144.       //case EVENT_KEY_DOWN: goto _lbl_start;
  145.       default:;
  146.     }
  147.  
  148.  
  149.  
  150.     // Draw stuff
  151.  
  152.     u64 timeStart = timeGetPerfCounter();
  153.  
  154.     // (No need to call canvas_clear(); this overwrites all pixels anyway!)
  155.     render_metaballs();
  156.     canvas_present(true);
  157.     animate_metaballs();
  158.  
  159.     u64 timeEnd = timeGetPerfCounter();
  160.     f64 timeDelta = (f64)(timeEnd-timeStart)/timeGetPerfFreq();
  161.  
  162.     // Waits for about 16ms to approximate 60fps
  163.     timeDelta = (0.016-timeDelta);
  164.     timeSleep(  (u32)MAX(1, (s32)(1000.0*timeDelta + 0.5))  );
  165.  
  166.   }
  167.  
  168.  
  169.  
  170.   return 0;
  171.  
  172. }
  173.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement