/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;
}