/src/swarm.cpp
#include <stdio.h>
#include <math.h>
#include <GLES/gl.h>
#include "SDL.h"
#include "PDL.h"
#include "Pixel.h"
#define NPIXELS 2500
#define SCREENW 320
#define SCREENH 480
SDL_Surface* screen; // Screen surface
Uint16 mx, my;
Pixel** pixels;
GLfloat* vertices;
#ifdef WIN32
extern "C"
#endif
GL_API int GL_APIENTRY _dgles_load_library(void *, void *(*)(void *, const char *));
static void *proc_loader(void *h, const char *name)
{
(void) h;
return SDL_GL_GetProcAddress(name);
}
void init() {
// Set up OpenGL
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0.0f, (float)screen->w, (float)screen->h, 0.0f, -1.0f, 1.0f);
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
// Initialize vertices
vertices = new GLfloat[NPIXELS * 6];
memset(vertices, 0, sizeof(GLfloat) * NPIXELS * 6);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
// Center cursor
mx = screen->w / 2;
my = screen->h / 2;
// Initialize pixel objects
pixels = new Pixel*[NPIXELS];
for (int x = 0; x < NPIXELS; x++) {
pixels[x] = new Pixel(screen);
}
}
void pushPixels(int pushX, int pushY) {
// Apply force to each pixel outwards from the mouse
for (int i = 0; i < NPIXELS; i++) {
// Get the direction
float dx = pixels[i]->x - pushX;
float dy = pixels[i]->y - pushY;
float mag = sqrtf(dx*dx + dy*dy);
dx /= mag;
dy /= mag;
// Apply force.
pixels[i]->accel(dx * 10.0, dy * 10.0);
}
}
void engine() {
// Clear the canvas
glClear(GL_COLOR_BUFFER_BIT);
// Update cursor
vertices[0] = mx - 5;
vertices[1] = my - 5;
vertices[3] = mx + 5;
vertices[4] = my - 5;
vertices[6] = mx + 5;
vertices[7] = my + 5;
vertices[9] = mx - 5;
vertices[10] = my + 5;
glDrawArrays(GL_LINE_LOOP, 0, 4);
// Update all pixel objects
for (int i = 0; i < NPIXELS; i++) {
// Get distance
float dx = mx - pixels[i]->x;
float dy = my - pixels[i]->y;
float d = sqrtf(dx*dx + dy*dy);
// Apply acceleration to pixels towards the mouse cursor
float ax = dx / 50.0;
float ay = dy / 50.0;
// Apply a drag proportional to the distance from the cursor
if (d > 25.0) {
ax += -pixels[i]->vx * (d - 25.0) / 1000.0;
ay += -pixels[i]->vy * (d - 25.0) / 1000.0;
}
// And a "chaotic" acceleration inversely proportional
// to the distance from the cursor
ax += ((rand() / (float)RAND_MAX) * 40.0 - 20.0) / d;
ay += ((rand() / (float)RAND_MAX) * 40.0 - 20.0) / d;
pixels[i]->accel(ax,ay);
pixels[i]->update();
pixels[i]->draw(&vertices[i*6]);
}
glDrawArrays(GL_LINES, 0, NPIXELS * 2);
}
int main(int argc, char** argv)
{
// Initialize the SDL library with the Video subsystem
SDL_Init(SDL_INIT_VIDEO);
// start the PDL library
PDL_Init(0);
// Tell it to use OpenGL ES version 1.1
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
// Set the video mode to full screen with OpenGL-ES support
screen = SDL_SetVideoMode(SCREENW, SCREENH, 0, SDL_OPENGL);
if (!screen) {
printf("Could not initialize video!\n");
exit(1);
}
printf("width: %d, height, %d\n", screen->w, screen->h);
printf("Starting up with %d pixels\n", NPIXELS);
#if WIN32
// Load the desktop OpenGL-ES emulation library
_dgles_load_library(NULL, proc_loader);
#endif
init();
// Event descriptor
SDL_Event Event;
int app_is_active = 1;
Uint32 last = SDL_GetTicks();
int fps_counter = 0;
do {
// Process the events
if (!app_is_active)
SDL_WaitEvent(NULL);
while (SDL_PollEvent(&Event)) {
switch (Event.type) {
case SDL_MOUSEMOTION:
mx = Event.motion.x;
my = Event.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
pushPixels(Event.button.x, Event.button.y);
case SDL_ACTIVEEVENT:
if (Event.active.state == SDL_APPACTIVE)
app_is_active = Event.active.gain;
break;
default:
break;
}
}
engine();
glFlush();
SDL_GL_SwapBuffers();
// Calculate FPS
fps_counter++;
Uint32 now = SDL_GetTicks();
if (now - last > 1000) {
printf("%d FPS\n", fps_counter);
fps_counter = 0;
last = now;
}
} while (Event.type != SDL_QUIT);
// We exit anytime we get a request to quit the app
// Cleanup
PDL_Quit();
SDL_Quit();
return 0;
}