예제 #1
0
파일: uppg21.c 프로젝트: slaeshjag/algdata
DARNIT_TILESHEET *detect_image(DARNIT_IMAGE_DATA img, int x, int y, int *piczels) {
	int minx, w, h;
	DARNIT_TILESHEET *ts;

	fill_image(img, x, y, PIXEL_SOLID, PIXEL_HIGHLIGHT);
	minx = geometrics_image(img, &w, &h);
	ts = copy_image(img, minx, y, w, h, piczels);
	fill_image(img, x, y, PIXEL_HIGHLIGHT, PIXEL_NONE);

	return ts;
}
예제 #2
0
파일: darknet.c 프로젝트: kunle12/darknet
void mkimg(char *cfgfile, char *weightfile, int h, int w, int num, char *prefix)
{
    network *net = load_network(cfgfile, weightfile, 0);
    image *ims = get_weights(net->layers[0]);
    int n = net->layers[0].n;
    int z;
    for(z = 0; z < num; ++z){
        image im = make_image(h, w, 3);
        fill_image(im, .5);
        int i;
        for(i = 0; i < 100; ++i){
            image r = copy_image(ims[rand()%n]);
            rotate_image_cw(r, rand()%4);
            random_distort_image(r, 1, 1.5, 1.5);
            int dx = rand()%(w-r.w);
            int dy = rand()%(h-r.h);
            ghost_image(r, im, dx, dy);
            free_image(r);
        }
        char buff[256];
        sprintf(buff, "%s/gen_%d", prefix, z);
        save_image(im, buff);
        free_image(im);
    }
    free_network(net);
}
예제 #3
0
int main() {
	image* img = (image*) malloc(sizeof(image));
	fill_image(img, 5, 5);
	person* p = (person*) malloc(sizeof(person));
	fill_person(p);
	img->photographer = p;
	return 0;
}
예제 #4
0
Image AlphaMask::colorImage(const Color& color) const {
	Image image(size.x, size.y);
	fill_image(image, color);
	setAlpha(image);
	return image;
}
예제 #5
0
/* Callback for resizing the verso imageview
 *
 * TODO: fold into changesize_recto
 */
void changesize_verso(GtkWidget *widget, GtkAllocation *allo, gpointer data)
{
	fill_image(verso_p, verso, allo->width, allo->height, 0);
}
예제 #6
0
/* Callback for resizing the recto imageview
 */
void changesize_recto(GtkWidget *widget, GtkAllocation *allo, gpointer data)
{
	fill_image(recto_p, recto, allo->width, allo->height, 0);
}
예제 #7
0
void interactive(image_processor p, unsigned imageWidth, unsigned imageHeight, unsigned nsSize, unsigned nsDepth) {
  image* img = image_new(imageWidth, imageHeight);
  fill_image(img, 1, 1, 1);
  
  #define WIND_COUNT 4
  wind* w[WIND_COUNT];
  vec2 wOrigin[WIND_COUNT] = {
    {0, 0},
    {imageWidth, 0},
    {0, imageHeight},
    {imageWidth, imageHeight}
  };
  float wColors[3 * WIND_COUNT] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    0, 0, 0,
  };
  for(unsigned i = 0; i < WIND_COUNT; i++) {
    w[i] = wind_new(imageWidth * imageHeight * 10 / 1000);
  }
  
  unsigned particlesToDraw = 5;
  float maxSpread = 2.5;
  float particleNoiseVelocity = 2.0;
  
  float drag = 0.99;
  
  float wAlpha = 0.125;

  //Potentials
  noise_sum* ncl = initialize_noise_sum_2d(nsSize, nsDepth);
  noise_sum_scale_in(ncl, 1.0 / (imageWidth * 4.0));
  
  vec2 gradient = {0, 0};
  
  #define GRAVITY_COUNT 16
  centered_cl orbits[ORBIT_COUNT];
  
  for(unsigned i = 0; i < ORBIT_COUNT; i++) {
    orbits[i].cx = uniformFloat(0, imageWidth);
    orbits[i].cy = uniformFloat(0, imageWidth);
    orbits[i].strength = imageWidth * imageWidth;
    if(i % 2) orbits[i].strength *= -1;
    orbits[i].denominatorSummand = (imageWidth / 4.0) * (imageWidth / 4.0);
  }
  
  //orbits[0].strength /= 4;
  orbits[0].strength *= 4;
  
  #undef POTENTIAL_COUNT
  #define POTENTIAL_COUNT (2 + GRAVITY_COUNT)
  
  float(*potentialFunctions[POTENTIAL_COUNT])(float, float, void*) = {
    noiseSumPotential, gradientPotential
  };
  
  void* pcls[POTENTIAL_COUNT] = {
    ncl, &gradient 
  };
  
  float weights[POTENTIAL_COUNT] = {
    10, 0.5,
  };
  
  for(unsigned i = 0; i < ORBIT_COUNT; i++) {
    potentialFunctions[i + 2] = distanceSquaredPotential;
    pcls[i + 2] = &orbits[i];
    weights[i + 2] = 1.0 / 2.0;
  }
  
  poly_weighted_cl pcl = { potentialFunctions, pcls, weights, POTENTIAL_COUNT };
  
  for(unsigned i = 0; !isTerminated(); i++) {
    
    processXEvents();
    
    //Update player gravity source
    
    //TODO replace the latter with the prior.
    vec2 mouse = getMousePosition();
    
    orbits[0].cx = mouse.x;
    orbits[0].cy = mouse.y;
    
    //printf("%f %f\n", mouse.x, mouse.y);
    
    if(isKeyPressed(SPACE)) {
      //Reverse polarity
      for(unsigned i = 1; i < ORBIT_COUNT; i++) {
        orbits[i].strength *= -1;
      }
      setKeyPressed(SPACE, false);
    }
    
    if(isKeyPressed(SHIFT)) {
      //Change colors.
      //TODO: use color structs..
      /*
      for(unsigned c = 0; c < C; c++) {
        color.c[c] += uniformFloatS(tracerColorChange);
        //color.c[c] *= uniformFloat(tracerColorReduction, 1);
        if(color.c[c] <= tracerColorLow) {
          if(color.c[c] < 0) {
            color.c[c] = 0;
          } else {
            color.c[c] /= tracerColorReduction;
          }
        } else if(color.c[c] >= tracerColorHigh) {
          color.c[c] *= tracerColorReduction;
        }
      }
      */
      for(unsigned i = 0; i < 3 * WIND_COUNT; i++) {
        wColors[i] += uniformFloatS(0.01);
      }
    }
    
    if(isKeyPressed('a')) {
      for(unsigned j = 0; j < WIND_COUNT; j++) {
        wind_append(w[j], mouse.x, mouse.y, 0, 0, uniformFloat(1, 2));
      }
    }
    
    //Whiten the image.
    if(i % 2 == 0) {
      if(i % 8 == 0) fill_image_a(img, 1, 1, 1, 1.0 / 64.0);
    } else {
      image_blur_fast_inplace(img, i / 2);
    }
    
    //Render the noise
    /*
    for(unsigned y = 0; y < imageHeight; y++) {
      for(unsigned x = 0; x < imageWidth; x++) {
        float intensity = noise_sum_2d(x, y, ncl);
        for(unsigned c = 0; c < C; c++) {
          *image_pixel(img, x, y, c) = intensity;
        }
      }
    }
    */
    
    for(unsigned a = 0; a < WIND_COUNT; a++) {
      wind_remove_rand(w[a], imageWidth * imageHeight / 1000);
      
      //Add wind particles.
      unsigned particlesToAdd = w[a]->maxParticles - w[a]->particles;
      for(unsigned j = 0; j < (particlesToAdd + 15) / 16; j++) {
        //float x = uniformFloat(-(int)(imageWidth / 4), 5 * imageWidth / 4);
        //float y = uniformFloat(-(int)(imageHeight / 4), 5 * imageHeight / 4);
        float x = wOrigin[a].x;
        float y = wOrigin[a].y;
        
        float dx = imageWidth / 2 - wOrigin[a].x;
        float dy = imageHeight / 2 - wOrigin[a].y;
        
        dx /= imageWidth;
        dy /= imageHeight;
        
        vec2 noise = vScale((particleNoiseVelocity), symmetricUnitBall());
        wind_append(w[a], x, y, noise.x + dx, noise.y + dy, uniformFloat(0.5, 2));
      }
      
      //Update wind.
      wind_scale_velocity(w[a], drag);
      wind_update_bound(w[a], 1.0, sumWeightedPotential, &pcl, -(imageWidth / 2.0), -(imageHeight / 2.0), 3.0 * imageWidth / 2.0, 3.0 * imageWidth / 2.0);
      
      /*
      //Perturb particle momentum just a bit.  This prevents clumping.
      for(unsigned j = 0; j < w[a]->particles; j++) {
        vec2 noise = vScale((particleNoiseVelocity / 16.0), symmetricUnitBall());
        wind_x(w[a])[j] += noise.x;
        wind_y(w[a])[j] += noise.y;
      }
      */
      
      //Draw the wind.
      //wind_draw_roffset(w[a], img,  0, 0, 0,  wAlpha * 0.5, 0, 0, 1, particlesToDraw, maxSpread);
      //wind_draw(w[a], img,  0, 0, 0,  wAlpha, 0, 0, 1);
      wind_draw_roffset(w[a], img,  wColors[a * 3 + 0], wColors[a * 3 + 1], wColors[a * 3 + 2],  wAlpha * 0.5, 0, 0, 1, particlesToDraw, maxSpread);
      wind_draw(w[a], img,  wColors[a * 3 + 0], wColors[a * 3 + 1], wColors[a * 3 + 2],  wAlpha, 0, 0, 1);
    }
    
    //Update noise.
    perturb_noise_sum(ncl, 2, 0, 1, 1.0 / 16.0, 0.25, 0.001);
    
    //Move the orbits.
    #define ORBBROWN 1
    #define ORBSHIFT 0.0001
    #define ORBKEEP 0.9999
    for(unsigned i = 1; i < ORBIT_COUNT; i++) {
      orbits[i].cx += uniformFloatS(ORBBROWN);
      orbits[i].cy += uniformFloatS(ORBBROWN);
      orbits[i].cx = ORBKEEP * orbits[i].cx + ORBSHIFT * imageWidth / 2;
      orbits[i].cy = ORBKEEP * orbits[i].cy + ORBSHIFT * imageHeight / 2;
      //Apply a repulsive force between the orbits (proportional to 1 / distance).
      for(unsigned j = i + 1; j < ORBIT_COUNT; j++) {
        float dx = orbits[i].cx - orbits[j].cx;
        float dy = orbits[i].cy - orbits[j].cy;
        float dSqr = dx * dx + dy * dy;
        float scale = imageWidth / 4; //Half the image away has effect 1.
        
        scale /= 16;
        
        orbits[i].cx += scale * dx / dSqr;
        orbits[i].cy += scale * dy / dSqr;
        orbits[j].cx -= scale * dx / dSqr;
        orbits[j].cx -= scale * dy / dSqr;
      }
    }
    
    //Perturb the gradient.
    gradient = vScale(uniformFloat(0.98, 1.0), vPlus(gradient, symmetricBall(0.01)));
    
    p(img, NULL); //Process the image (send it to the screen or to disk).
  }
}
예제 #8
0
void dust(image_processor p, unsigned imageWidth, unsigned imageHeight, unsigned frames, unsigned nsSize, unsigned nsDepth) {
  image* img = image_new(imageWidth, imageHeight);
  fill_image(img, 1, 1, 1);
  
  #define WIND_COUNT 4
  wind* w[WIND_COUNT];
  vec2 wOrigin[WIND_COUNT] = {
    {0, 0},
    {imageWidth, 0},
    {0, imageHeight},
    {imageWidth, imageHeight}
  };
  float wColors[3 * WIND_COUNT] = {
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
    0, 0, 0,
  };
  for(unsigned i = 0; i < WIND_COUNT; i++) {
    w[i] = wind_new(imageWidth * imageHeight * 10 / 1000);
  }
  
  unsigned particlesToDraw = 5;
  float maxSpread = 2.5;
  float particleNoiseVelocity = 2.0;
  
  float drag = 0.99;
  
  float wAlpha = 0.125;

  //Potentials
  noise_sum* ncl = initialize_noise_sum_2d(nsSize, nsDepth);
  noise_sum_scale_in(ncl, 1.0 / (imageWidth * 4.0));
  
  vec2 gradient = {0, 0};
  
  #define ORBIT_COUNT 16
  centered_cl orbits[ORBIT_COUNT];
  
  for(unsigned i = 0; i < ORBIT_COUNT; i++) {
    orbits[i].cx = uniformFloat(0, imageWidth);
    orbits[i].cy = uniformFloat(0, imageWidth);
    orbits[i].strength =  imageWidth * imageWidth;
    orbits[i].denominatorSummand = (imageWidth / 4.0) * (imageWidth / 4.0);
  }
  
  #undef POTENTIAL_COUNT
  #define POTENTIAL_COUNT (2 + ORBIT_COUNT)
  
  float(*potentialFunctions[POTENTIAL_COUNT])(float, float, void*) = {
    noiseSumPotential, gradientPotential
  };
  
  void* pcls[POTENTIAL_COUNT] = {
    ncl, &gradient 
  };
  
  float weights[POTENTIAL_COUNT] = {
    10, 0.5,
  };
  
  for(unsigned i = 0; i < ORBIT_COUNT; i++) {
    potentialFunctions[i + 2] = distanceSquaredPotential;
    pcls[i + 2] = &orbits[i];
    weights[i + 2] = 1.0 / 2.0;
  }
  
  
  poly_weighted_cl pcl = { potentialFunctions, pcls, weights, POTENTIAL_COUNT };
  
  
  for(unsigned i = 0; i < frames; i++) {
    //Whiten the image.
    if(i % 2 == 0) {
      if(i % 8 == 0) fill_image_a(img, 1, 1, 1, 1.0 / 64.0);
    } else {
      image_blur_fast_inplace(img, i / 2);
    }
    
    //Render the noise
    /*
    for(unsigned y = 0; y < imageHeight; y++) {
      for(unsigned x = 0; x < imageWidth; x++) {
        float intensity = noise_sum_2d(x, y, ncl);
        for(unsigned c = 0; c < C; c++) {
          *image_pixel(img, x, y, c) = intensity;
        }
      }
    }
    */
    
    for(unsigned a = 0; a < WIND_COUNT; a++) {
      wind_remove_rand(w[a], imageWidth * imageHeight / 1000);
      
      //Add wind particles.
      unsigned particlesToAdd = w[a]->maxParticles - w[a]->particles;
      for(unsigned j = 0; j < (particlesToAdd + 15) / 16; j++) {
        //float x = uniformFloat(-(int)(imageWidth / 4), 5 * imageWidth / 4);
        //float y = uniformFloat(-(int)(imageHeight / 4), 5 * imageHeight / 4);
        float x = wOrigin[a].x;
        float y = wOrigin[a].y;
        
        float dx = imageWidth / 2 - wOrigin[a].x;
        float dy = imageHeight / 2 - wOrigin[a].y;
        
        dx /= imageWidth;
        dy /= imageHeight;
        
        vec2 noise = vScale((particleNoiseVelocity), symmetricUnitBall());
        wind_append(w[a], x, y, noise.x + dx, noise.y + dy, uniformFloat(0.5, 2));
      }
      
      //Update wind.
      wind_scale_velocity(w[a], drag);
      wind_update_bound(w[a], 1.0, sumWeightedPotential, &pcl, -(imageWidth / 2.0), -(imageHeight / 2.0), 3.0 * imageWidth / 2.0, 3.0 * imageWidth / 2.0);
      
      /*
      //Perturb particle momentum just a bit.  This prevents clumping.
      for(unsigned j = 0; j < w[a]->particles; j++) {
        vec2 noise = vScale((particleNoiseVelocity / 16.0), symmetricUnitBall());
        wind_x(w[a])[j] += noise.x;
        wind_y(w[a])[j] += noise.y;
      }
      */
      
      //Draw the wind.
      //wind_draw_roffset(w[a], img,  0, 0, 0,  wAlpha * 0.5, 0, 0, 1, particlesToDraw, maxSpread);
      //wind_draw(w[a], img,  0, 0, 0,  wAlpha, 0, 0, 1);
      wind_draw_roffset(w[a], img,  wColors[a * 3 + 0], wColors[a * 3 + 1], wColors[a * 3 + 2],  wAlpha * 0.5, 0, 0, 1, particlesToDraw, maxSpread);
      wind_draw(w[a], img,  wColors[a * 3 + 0], wColors[a * 3 + 1], wColors[a * 3 + 2],  wAlpha, 0, 0, 1);
    }
    
    //Update noise.
    perturb_noise_sum(ncl, 2, 0, 1, 1.0 / 16.0, 0.25, 0.001);
    
    //Move the orbits.
    for(unsigned i = 0; i < ORBIT_COUNT; i++) {
      orbits[i].cx += uniformFloatS(8);
      orbits[i].cy += uniformFloatS(8);
      orbits[i].cx = 0.999 * orbits[i].cx + 0.001 * imageWidth / 2;
      orbits[i].cy = 0.999 * orbits[i].cy + 0.001 * imageHeight / 2;
      //Apply a repulsive force between the orbits (proportional to 1 / distance).
      for(unsigned j = i + 1; j < ORBIT_COUNT; j++) {
        float dx = orbits[i].cx - orbits[j].cx;
        float dy = orbits[i].cy - orbits[j].cy;
        float dSqr = dx * dx + dy * dy;
        float scale = imageWidth / 4; //Half the image away has effect 1.
        orbits[i].cx += scale * dx / dSqr;
        orbits[i].cy += scale * dy / dSqr;
        orbits[j].cx -= scale * dx / dSqr;
        orbits[j].cx -= scale * dy / dSqr;
      }
    }
    
    //Perturb the gradient.
    gradient = vScale(uniformFloat(0.99, 1.0), vPlus(gradient, symmetricBall(0.01)));
    
    p(img, NULL); //Process the image (send it to the screen or to disk).
  }

}
예제 #9
0
//Renders a sum curve, permuting it over time.
void curves(image_processor p, unsigned imageWidth, unsigned imageHeight, unsigned frames) {
  image* img = image_new(imageWidth, imageHeight);
  fill_image(img, 0, 0, 0);
  
  ///////////////////
  //Parameterization:
  
  float totalTime = 800;
  
  float tracerColorChange = 1.0 / 32.0;
  float tracerColorReduction = 0.95;
  
  float tracerColorLow = 0.01;
  float tracerColorHigh = 0.125;
  
  //////////
  //Tracers:
  
  weighted_sum_pcl_static* curve = randomize_weighted_static_sum(imageWidth / 2.0, imageHeight / 2.0, 4.0 * (imageWidth + imageHeight) / (2.0 * 1.5), 16);
  color color;
  randomize_color(&color, -0.125, 0.5, 1);
  
  /////////////////////
  //Run the Simulation:
      
  //Move along the curves, adding to the wind.
  
  float tStep = totalTime / frames;
  
  for(unsigned i = 0; i < frames; i++) {
    float t = tStep * i;
    //if(i % 10 == 0) {
      printf("Frame %u / %u\r", i, frames);
      fflush(stdout);
    //}
    
    //Blur and darken the existing image.
    
    if(i % 2 == 0) {
      float m = 1.0 - 128.0 / imageWidth;
      if(m < 0) m = 0;
      //Darken one color channel at a time.
      image_multiply_channel(img, (i / 2) % 3, m);
      //fill_image_a(img, 0, 0, 0, 32.0 / imageWidth);
    } else {
      image_blur_fast_inplace(img, i / 2);
    }
    
    //Render the curve
    
    //float renderSpacing = (1.0 / imageWidth) * (10.0);
    //draw_parametric_curve_uniform_time(img, draw_point_additive, parametric_curve_weighted_static_sum, 0, uniformFloat(0, 200), renderSpacing * (1 + uniformFloat(0, 1)), &color, curve);
    draw_parametric_curve_uniform_space(img, draw_point_additive, parametric_curve_weighted_static_sum, 0, t, 0.005, 1.0 + t / totalTime, 0.9, &color, curve);
    
    //Perturb the curve  
    perturb_weighted_static_sum(curve, 0.01);
    
    //Bias the curve growth upward.
    for(unsigned i = 0; i < curve->count; i++) {
      float w0 = 1.0 / curve->count; //Minimum target weight
      if(curve->weights[i] < w0) {
        curve->weights[i] *= 1.0 + (uniformFloat(0, w0 / curve->weights[i] - 1.0));
      }
      else if(curve->weights[i] < w0 * 2 / 3) {
        curve->weights[i] += uniformFloat(0, 1.0 / 256.0);
      }
    }
    
    //Perturb the colors.
    for(unsigned c = 0; c < C; c++) {
      color.c[c] += uniformFloatS(tracerColorChange);
      //color.c[c] *= uniformFloat(tracerColorReduction, 1);
      if(color.c[c] <= tracerColorLow) {
        if(color.c[c] < 0) {
          color.c[c] = 0;
        } else {
          color.c[c] /= tracerColorReduction;
        }
      } else if(color.c[c] >= tracerColorHigh) {
        color.c[c] *= tracerColorReduction;
      }
    }

    p(img, NULL); //Process the image (send it to the screen or to disk).
  }
  
  image_free(img);
}
예제 #10
0
void gravity(image_processor p, unsigned imageWidth, unsigned imageHeight, unsigned frames, unsigned nsSize, unsigned nsDepth) {
  image* img = image_new(imageWidth, imageWidth);
  fill_image(img, 0, 0, 0);
  
  //Parameterization:
  unsigned wind_count = 8; //Number of particle emmiters.
  unsigned wind_size = 1000; //Max number of particles per emitter.
  unsigned particlesPerFrame = 2000 / frames;
  if(particlesPerFrame == 0) particlesPerFrame = 1;
  
  unsigned particlesToDraw = 2;
  float maxSpread = imageWidth / 500.0;
  
  float particleNoiseVelocity = 1024.0 * imageWidth / (1000.0);
  float particleEmitterMomentumScalar = 0.5;
  
  float totalTime = TAU;
  
  float wColorRevert = 0.01; //TODO these should be exponentiated by tStep
  float wColorChange = 0.125;
  
  float wAlpha = 1.0 / 8.0; //Alpha to use for drawing the wind.
  
  unsigned tracer_count = 4; //Number of traced curves.
  float tracerColorChange = 0.125;
  float tracerColorReduction = 0.9;
  
  ////////////////////
  //Particle Emitters:
  
  wind* winds[wind_count];
  for(unsigned i = 0; i < wind_count; i++) {
    winds[i] = wind_new(wind_size);
    //wind_randomize(winds[i], imageWidth, 0, 0, imageWidth, imageWidth, VMAX, 100);
  }
  
  float windDefaultColors[wind_count * 3];
  float windColors[wind_count * 3];
  
  for(unsigned i = 0; i < wind_count; i++) {
    windDefaultColors[i * 3 + 0] = (i & 0x1) ? 3 : 0;
    windDefaultColors[i * 3 + 1] = (i & 0x2) ? 3 : 0;
    windDefaultColors[i * 3 + 2] = (i & 0x4) ? 3 : 0;
  };
  memcpy(windColors, windDefaultColors, sizeof(float) * wind_count * 3);
  
  //////////////
  //Wind Curves:
  
  //Wind curve closures (Specific type storage).
  ccl_1 pc1_cl[wind_count / 2];
  ccl_2 pc2_cl[wind_count / 2];
  
  //Parametric curve functions (Indirection layer to support generic curve types).
  vec2(*parametricCurves[wind_count])(float, void*);  
  
  //Closures for (generic) parametric curve functions
  void* cl[wind_count];
    
  //Initialize wind closures.
  for(unsigned i = 0; i < wind_count / 2; i++) {
    randomize_ccl_1(pc1_cl + i, imageWidth / 2, imageWidth / 2, imageWidth / 4);
    //Keep the amplitude low and the base high.
    pc1_cl[i].base = (pc1_cl[i].base + imageWidth / 2) / 2;
    pc1_cl[i].amplitude *= 0.5;
    pc1_cl[i].frequency = 2 + pc1_cl[i].frequency / 4;
    
    cl[i] = (void*) (pc1_cl + i);
    parametricCurves[i] = parametric_curve_1;
    
    randomize_ccl_2(pc2_cl + i, imageWidth / 2, imageWidth / 2, imageWidth / 2);
    for(unsigned j = 0; j < 4; j++) {
      pc2_cl[i].d[j] *= 1.0 / 32.0;
    }
    
    cl[i + wind_count / 2] = (void*) (pc2_cl + i);
    parametricCurves[i + wind_count / 2] = parametric_curve_2;
  }
  
  /////////////////////
  //Potential Function:
  
  noise_sum* ncl = initialize_noise_sum_2d(nsSize, nsDepth);
  noise_sum_scale_in(ncl, 1.0 / imageWidth);

  centered_cl orbitcl = { imageWidth / 2.0, imageWidth / 2.0, imageWidth * imageWidth, (imageWidth / 8.0) * (imageWidth / 8.0) };
  
  float(*potentialFunctions[POTENTIAL_COUNT])(float, float, void*) = {
    noiseSumPotential,
    distanceSquaredPotential
  };
  
  void* pcls[POTENTIAL_COUNT] = {ncl, &orbitcl};
  
  float weights[POTENTIAL_COUNT] = {
    80000000, 100000
  };
  
  poly_weighted_cl pcl = { potentialFunctions, pcls, weights, POTENTIAL_COUNT};
  
  //////////
  //Tracers:
  
  //Offsets in time
  float timeOffsets[tracer_count];
  ccl_2 tracer_cl[tracer_count];
  color tracer_color[tracer_count];
  
  memset(tracer_cl, 0, tracer_count * sizeof(ccl_2));
  memset(tracer_color, 0, tracer_count * sizeof(color));
  
  for(unsigned i = 0; i < tracer_count; i++) {
    tracer_cl[i].x0 = tracer_cl[i].y0 = -128;
    tracer_cl[i].scale = 0;
    timeOffsets[i] = 0;
    
    //Start off offscreeen.
    
    //randomize_ccl_2(tracer_cl + i, imageWidth / 2, imageWidth / 2, imageWidth / 2);
    //randomize_color(tracer_color + i, -1, 2, 1);
  }
  
  /////////////////////
  //Run the Simulation:
      
  //Move along the curves, adding to the wind.
  
  float tStep = totalTime / frames;
  float drag = powf(0.75, tStep);
  
  unsigned particleCount = 0; //Keep track of the total number of particles.
  for(unsigned i = 0; i < frames; i++) {
    float t = tStep * i;
    //if(i % 10 == 0) {
      printf("Frame %u / %u: Particles %u / %u\r", i, frames, particleCount, wind_size * wind_count);
      fflush(stdout);
    //}
    particleCount = 0;
    
    //Blur and darken the existing image.
    /*
    fill_image_a(img, 0, 0, 0, 1.0 / 32);
    image_blur_inplace(img, (i / 4) % 1);
    */
    
    if(i % 2 == 0) {
      float m = 1.0 - 64.0 / imageWidth;
      if(m < 0) m = 0;
      //Darken one color channel at a time.
      image_multiply_channel(img, (i / 2) % 3, m);
      //fill_image_a(img, 0, 0, 0, 32.0 / imageWidth);
    } else {
      image_blur_fast_inplace(img, i / 2);
    }
    
    //"Gravity Vortex": bend light inward.  (TODO move this to filters).
    /*
    for(unsigned i = 0; i < imageWidth * imageWidth / 128; i++) {
      vec2 p = symmetricBall(imageWidth / 4);
      unsigned x0 = imageWidth / 2 + (unsigned)p.x;
      unsigned y0 = imageWidth / 2 + (unsigned)p.y;
      unsigned x1 = imageWidth / 2 + (unsigned)(p.x * 1.125);
      unsigned y1 = imageWidth / 2 + (unsigned)(p.y * 1.125);
      for(unsigned c = 0; c < C; c++) {
        float* p0 = image_pixel(img, x0, y0, c);
        float* p1 = image_pixel(img, x1, y1, c);
        *p0 = (*p0 + *p1 * 0.75);
        *p1 *= 0.25;
      }
    }
    */
    
    //image_blur_fast_inplace(img, i);
    //image_blur_fast_inplace(img, i + 1);
    
    if(i % 32 == 0) {
      //Reset a curve
      unsigned idx = uniformInt(0, tracer_count);
      
      randomize_ccl_2(tracer_cl + idx, imageWidth / 2, imageWidth / 2, imageWidth / 2);
      
      for(unsigned j = 0; j < 4; j++) {
        tracer_cl[idx].d[j] *= 1.0 / 32.0;
      }
      
      
      //Randomize color.
      //randomize_color(tracer_color + idx, -0.5, 1.5, 1);
      //tracer_color[idx].a = uniformFloat(-.25, 1.5); //Negative alpha can cause some interesting effects (existing color is emphasized, new is subtracted).
      
      //Randomize color, chosen to work well with additive coloring.
      randomize_color(tracer_color + idx, -0.125, 0.5, 1);
      timeOffsets[idx] = t;
    }
    
    /*
    if(i % 64 == 0) {
      randomize_ccl_2(&ccl, imageWidth / 2, imageWidth / 2, imageWidth);
      
      for(unsigned i = 0; i < 4; i++) {
        ccl.d[i] *= 1.0 / 16.0;
      }
      
      //draw_parametric_curve_uniform_space(img, draw_circle, parametric_curve_1, 0, TAU, 0.01, 8, 0.9, &drawcl_2, &cl);
    }
    */
    
    /*
    float c2Speed = 1;
    {
      //color drawcl = {uniformFloat(0, 4), uniformFloat(0, 4), uniformFloat(0, 4), uniformFloat(1.0 / 16.0, 1)};
      
      color drawcl = {uniformFloat(-1, 2), uniformFloat(-1, 2), uniformFloat(-1, 2), uniformFloat(1.0 / 16.0, 1)};
      
      circle_cl drawcl_2 = {1, 0, 1, 0.5, 5.5};
      
      draw_parametric_curve_uniform_time(img, draw_point, parametric_curve_2, i % 64 * c2Speed, (i % 64 + 1) * c2Speed, 0.01, &drawcl, &ccl);
      
      //ccl.xS *= 0.95;
      //ccl.yS *= 0.95;
    }
    */
    
    //Render a partial curve.
    
    float tSpeed = 16.0;
    for(unsigned j = 0; j < tracer_count; j ++) {
      float renderSpacing = (1.0 / tracer_cl[j].scale) * (1.0);
      
      if(tracer_cl[j].scale < 1) continue;
      
      //Draw a partial curve
      if(j < tracer_count / 2) {
      
        float tt = (t - timeOffsets[j]) * tSpeed;
        float tt2 = (t - timeOffsets[j] + tStep) * tSpeed;
        
        //draw_parametric_curve_uniform_time(img, draw_point, parametric_curve_2, 0, uniformFloat(0, 200), 0.01, &drawcl, cl[j]);
        
        draw_parametric_curve_uniform_time(img, draw_point_additive, parametric_curve_2, tt, tt2, renderSpacing * 0.1, &tracer_color[j], &tracer_cl[j]);
        //color drawcl2 = {windColors[j * 3 + 1], windColors[j * 3 + 2], windColors[j * 3 + 0], 3};
        //draw_parametric_curve_uniform_time(img, draw_point, parametricCurves[j], 0, tt, 0.01, &drawcl2, cl[j]);
      } else {
        //Flash and permute a full curve.
        
        if(uniformInt(0, 2) == 0) {
          continue;
        }
        
        float sd = 32.0;
        float pd = TAU / 128.0;
        
        tracer_cl[j].scale *= uniformFloat((sd - 1) / sd, (sd + 1) / sd); //Should shrink slightly over time.
        tracer_cl[j].theta += uniformFloat(-pd, pd);
        
        
        float dpMax = imageWidth / 1000.0;
        vec2 dp = vScale(dpMax, symmetricUnitBall());
        tracer_cl[j].x0 += dp.x;
        tracer_cl[j].y0 += dp.y;
        
        
        float dd = 128.0;
        for(unsigned i = 0; i < PC2_SUMMANDS; i++) {
          tracer_cl[j].d[i] *= uniformFloat((dd - 1) / dd, (dd + 1) / dd);
          tracer_cl[j].f[i] *= uniformFloat((dd - 1) / dd, (dd + 1) / dd);
          tracer_cl[j].p[i] += uniformFloat(-pd, pd);
        }
        
        //draw_parametric_curve_uniform_time(img, draw_point_additive, parametric_curve_2, 0, uniformFloat(0, 200), renderSpacing * (1 + uniformFloat(0, 1)), &tracer_color[j], &tracer_cl[j]);
        
        //random_cl rcl = {3, 1, &tracer_color[j]};
        //draw_parametric_curve_uniform_space(img, draw_random_additive, parametric_curve_2, 0, uniformFloat(0, 200), 0.01, 2, 0.9, &rcl, &tracer_cl[j]);
        
        draw_parametric_curve_uniform_space(img, draw_point_additive, parametric_curve_2, 0, uniformFloat(0, 200), 0.01, 1, 0.9, &tracer_color[j], &tracer_cl[j]);
      }
    }
    
    //Permute tracer colors.
    for(unsigned i = 0; i < tracer_count; i++) {
      for(unsigned c = 0; c < C; c++) {
        tracer_color[i].c[c] += uniformFloat(-tracerColorChange, tracerColorChange);
        tracer_color[i].c[c] *= uniformFloat(tracerColorReduction, 1);
      }
      //tracer_color[i].a += uniformFloat(-tracerColorChange, tracerColorChange);
      //tracer_color[i].a *= tracerColorReduction;
    }
    
    for(unsigned i = 0; i < wind_count * 3; i++) {
      windColors[i] = windColors[i] * (1 - wColorRevert) + windDefaultColors[i] * wColorRevert + uniformFloat(-wColorChange, wColorChange);
    }
    
    for(unsigned j = 0; j < wind_count; j++) {
      //Randomly remove some particles.
      wind_remove_rand(winds[j], 512);
      //Apply a bit of drag.
      wind_scale_velocity(winds[j], drag);
      
      //Calculate the position and velocity of the emitter.
      vec2 v = parametricCurves[j](t, cl[j]);
      vec2 v2 = parametricCurves[j](t + DEPSILON, cl[j]);
      vec2 dcdt = vScale((1.0 / DEPSILON), vMinus(v2, v));
      
      for(unsigned k = 0; k < particlesPerFrame; k++) {
        vec2 noise = vScale((particleNoiseVelocity), symmetricUnitBall());
        vec2 dvdt = vPlus(vScale(particleEmitterMomentumScalar, dcdt), noise);
        
        wind_append(winds[j], v.x, v.y, dvdt.x, dvdt.y, uniformFloat(1, 2));
      }
      
      //printf("Particles: %u\n", winds[j]->particles);
      //wind_print(winds[j], stdout);
      
      //Update each particle.
      wind_update_bound(winds[j], tStep, sumWeightedPotential, &pcl, -(imageWidth / 2.0), -(imageHeight / 2.0), 3.0 * imageWidth / 2.0, 3.0 * imageWidth / 2.0);
      //wind_update(winds[j], 1.0, sumWeightedPotential, &pcl);

      //Draw the wind.
      wind_draw_roffset(winds[j], img, windColors[j * 3 + 0], windColors[j * 3 + 1], windColors[j * 3 + 2], wAlpha, 0, 0, 1, particlesToDraw, maxSpread);
      
      particleCount += winds[j]->particles;
      
      //TODO want to change the noise over time so wind does not collect in low pressure areas.
      
      //TODO render the noise function.
      
      //TODO periodically reset wind emmiters for type 2 curves.
    }
    
    p(img, NULL); //Process the image (send it to the screen or to disk).
  }
  
  
  image_free(img);
  for(unsigned i = 0; i < wind_count; i++) {
    wind_free(winds[i]);
  }
  noise_sum_free(ncl);
}