#include "ofApp.h"
 
//--------------------------------------------------------------
void ofApp::setup() {
 
	ofSetFrameRate(60);
	ofSetWindowTitle("openFrameworks");
 
	ofBackground(239);
	ofEnableDepthTest();
 
	this->frame.setMode(ofPrimitiveMode::OF_PRIMITIVE_LINES);
 
	ofFbo fbo;
	fbo.allocate(ofGetWidth(), ofGetHeight());
	fbo.begin();
	ofTranslate(ofGetWidth() * 0.5, ofGetHeight() * 0.5);
	ofClear(0);
	ofSetColor(0);
 
	ofTrueTypeFont font;
	font.loadFont("fonts/Kazesawa-Bold.ttf", 200, true, true, true);
	/* https://github.com/kazesawa/kazesawa */
 
	font.drawString("19", font.stringWidth("19") * -0.5, font.stringHeight("19") * -0.05);
	font.drawString("84", font.stringWidth("84") * -0.5, font.stringHeight("84") * 1.05);
 
	fbo.end();
 
	ofPixels pixels;
	fbo.readToPixels(pixels);
	auto span = 5;
 
	ofColor pix_color;
	for (int x = 0; x < fbo.getWidth(); x += span) {
 
		for (int y = 0; y < fbo.getHeight(); y += span) {
 
			pix_color = pixels.getColor(x, y);
			if (pix_color != ofColor(0, 0)) {
 
				for (int z = -span; z <= span; z += span) {
 
					this->location_list.push_back(glm::vec3(x - ofGetWidth() * 0.5, y - ofGetHeight() * 0.5, z));
					this->location_color_list.push_back(ofColor(39));
					this->param_list.push_back(0);
				}
			}
		}
	}
 
	for (auto& location : this->location_list) {
 
		vector<int> route_info = vector<int>();
		int index = -1;
		for (auto& other : this->location_list) {
 
			index++;
			if (location == other) { continue; }
 
			float distance = glm::distance(location, other);
			if (distance <= span) {
 
				route_info.push_back(index);
			}
		}
 
		this->route_info_list.push_back(route_info);
	}
 
	ofColor color;
	for (int i = 0; i < 250; i++) {
 
		this->index_list.push_back((int)ofRandom(this->location_list.size()));
 
		color.setHsb(ofMap(i, 0, 250, 0, 255), 150, 255);
		this->index_color_list.push_back(color);
	}
}
 
//--------------------------------------------------------------
void ofApp::update() {
 
	this->face.clear();
	this->frame.clear();
 
	for (int i = 0; i < this->index_list.size(); i++) {
 
		int next_index = this->route_info_list[this->index_list[i]][(int)ofRandom(this->route_info_list[this->index_list[i]].size())];
		for (int k = 0; k < this->route_info_list[this->index_list[i]].size(); k++) {
 
			if (this->param_list[next_index] <= 0) {
 
				this->param_list[next_index] = 30;
				this->location_color_list[next_index] = this->index_color_list[i];
				this->index_list[i] = next_index;
				break;
			}
		}
	}
 
	for (int i = 0; i < this->location_list.size(); i++) {
 
		if (this->param_list[i] > 0) {
 
			this->setBoxToMesh(this->face, this->frame, this->location_list[i], 5, this->location_color_list[i]);
		}
 
		if (this->param_list[i] > 0) { this->param_list[i] -= 1; }
	}
}
 
//--------------------------------------------------------------
void ofApp::draw() {
 
	this->cam.begin();
	ofRotateX(180);
 
	ofSetColor(39);
	this->face.draw();
 
	ofSetColor(239);
	this->frame.drawWireframe();
 
	this->cam.end();
}
 
//--------------------------------------------------------------
void ofApp::setBoxToMesh(ofMesh& face_target, ofMesh& frame_target, glm::vec3 location, float size, ofColor color) {
 
	this->setBoxToMesh(face_target, frame_target, location, size, size, size, color);
}
 
//--------------------------------------------------------------
void ofApp::setBoxToMesh(ofMesh& face_target, ofMesh& frame_target, glm::vec3 location, float height, float width, float depth, ofColor color) {
 
	int face_index = face_target.getNumVertices();
	int frame_index = frame_target.getNumVertices();
 
	face_target.addVertex(location + glm::vec3(width * -0.5 * 0.99, height * 0.5 * 0.99, depth * -0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * 0.5 * 0.99, height * 0.5 * 0.99, depth * -0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * 0.5 * 0.99, height * 0.5 * 0.99, depth * 0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * -0.5 * 0.99, height * 0.5 * 0.99, depth * 0.5 * 0.99));
 
	face_target.addVertex(location + glm::vec3(width * -0.5 * 0.99, height * -0.5 * 0.99, depth * -0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * 0.5 * 0.99, height * -0.5 * 0.99, depth * -0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * 0.5 * 0.99, height * -0.5 * 0.99, depth * 0.5 * 0.99));
	face_target.addVertex(location + glm::vec3(width * -0.5 * 0.99, height * -0.5 * 0.99, depth * 0.5 * 0.99));
 
	face_target.addIndex(face_index + 0); face_target.addIndex(face_index + 1); face_target.addIndex(face_index + 2);
	face_target.addIndex(face_index + 0); face_target.addIndex(face_index + 2); face_target.addIndex(face_index + 3);
 
	face_target.addIndex(face_index + 4); face_target.addIndex(face_index + 5); face_target.addIndex(face_index + 6);
	face_target.addIndex(face_index + 4); face_target.addIndex(face_index + 6); face_target.addIndex(face_index + 7);
 
	face_target.addIndex(face_index + 0); face_target.addIndex(face_index + 4); face_target.addIndex(face_index + 1);
	face_target.addIndex(face_index + 4); face_target.addIndex(face_index + 5); face_target.addIndex(face_index + 1);
 
	face_target.addIndex(face_index + 1); face_target.addIndex(face_index + 5); face_target.addIndex(face_index + 6);
	face_target.addIndex(face_index + 6); face_target.addIndex(face_index + 2); face_target.addIndex(face_index + 1);
 
	face_target.addIndex(face_index + 2); face_target.addIndex(face_index + 6); face_target.addIndex(face_index + 7);
	face_target.addIndex(face_index + 7); face_target.addIndex(face_index + 3); face_target.addIndex(face_index + 2);
 
	face_target.addIndex(face_index + 3); face_target.addIndex(face_index + 7); face_target.addIndex(face_index + 4);
	face_target.addIndex(face_index + 4); face_target.addIndex(face_index + 0); face_target.addIndex(face_index + 3);
 
	frame_target.addVertex(location + glm::vec3(width * -0.5, height * 0.5, depth * -0.5));
	frame_target.addVertex(location + glm::vec3(width * 0.5, height * 0.5, depth * -0.5));
	frame_target.addVertex(location + glm::vec3(width * 0.5, height * 0.5, depth * 0.5));
	frame_target.addVertex(location + glm::vec3(width * -0.5, height * 0.5, depth * 0.5));
 
	frame_target.addVertex(location + glm::vec3(width * -0.5, height * -0.5, depth * -0.5));
	frame_target.addVertex(location + glm::vec3(width * 0.5, height * -0.5, depth * -0.5));
	frame_target.addVertex(location + glm::vec3(width * 0.5, height * -0.5, depth * 0.5));
	frame_target.addVertex(location + glm::vec3(width * -0.5, height * -0.5, depth * 0.5));
 
	frame_target.addIndex(frame_index + 0); frame_target.addIndex(frame_index + 1);
	frame_target.addIndex(frame_index + 1); frame_target.addIndex(frame_index + 2);
	frame_target.addIndex(frame_index + 2); frame_target.addIndex(frame_index + 3);
	frame_target.addIndex(frame_index + 3); frame_target.addIndex(frame_index + 0);
 
	frame_target.addIndex(frame_index + 4); frame_target.addIndex(frame_index + 5);
	frame_target.addIndex(frame_index + 5); frame_target.addIndex(frame_index + 6);
	frame_target.addIndex(frame_index + 6); frame_target.addIndex(frame_index + 7);
	frame_target.addIndex(frame_index + 7); frame_target.addIndex(frame_index + 4);
 
	frame_target.addIndex(frame_index + 0); frame_target.addIndex(frame_index + 4);
	frame_target.addIndex(frame_index + 1); frame_target.addIndex(frame_index + 5);
	frame_target.addIndex(frame_index + 2); frame_target.addIndex(frame_index + 6);
	frame_target.addIndex(frame_index + 3); frame_target.addIndex(frame_index + 7);
 
	for (int i = 0; i < 8; i++) {
 
		face_target.addColor(color);
		frame_target.addColor(ofColor(39));
	}
}
 
//--------------------------------------------------------------
int main() {
 
	ofSetupOpenGL(720, 720, OF_WINDOW);
	ofRunApp(new ofApp());
}