#include "ofApp.h"
 
//--------------------------------------------------------------
void ofApp::setup() {
 
	ofSetFrameRate(60);
	ofSetWindowTitle("openframeworks");
 
	ofBackground(0);
	ofEnableDepthTest();
 
	for (auto v = 0; v < 360; v += 5) {
 
		for (auto u = 0; u < 360; u += 8) {
	
			this->location_list.push_back(this->make_point(200, 50, u, v));
			this->height_list.push_back(0);
		}
	}
 
	this->frame_mesh.setMode(ofPrimitiveMode::OF_PRIMITIVE_LINES);
}
 
//--------------------------------------------------------------
void ofApp::update() {
 
	ofSeedRandom(39);
 
	this->face_mesh.clear();
	this->frame_mesh.clear();
 
	auto R = 200;
	auto r = 50;
	auto v_span = 5;
	auto u_span = 8;
 
	for (int k = 0; k < 2; k++) {
 
		auto location = this->make_point(200, 50, ofMap(ofNoise(ofRandom(1000), ofGetFrameNum() * 0.015), 0, 1, 0, 360), ofMap(ofNoise(ofRandom(1000), ofGetFrameNum() * 0.015), 0, 1, 0, 360));
 
		for (int i = 0; i < this->height_list.size(); i++) {
 
			auto distance = glm::distance(location, this->location_list[i]);
 
			if (distance < 40) {
 
				this->height_list[i] < 100 ? this->height_list[i] += ofMap(distance, 0, 40, 30, 1) : 100;
			}
			else {
 
				this->height_list[i] > 0 ? this->height_list[i] -= 1 : 0;
			}
		}
	}
 
	int index = 0;
	for (auto v = 0; v < 360; v += v_span) {
 
		for (auto u = 0; u < 360; u += u_span) {
 
			auto noise_seed = this->make_point(R, r, u + u_span * 0.5, v + v_span * 0.5);
			auto noise_value = ofNoise(glm::vec4(noise_seed, ofGetFrameNum() * 0.01));
			auto height = this->height_list[index++];
 
			vector<glm::vec3> vertices;
			vertices.push_back(this->make_point(R, r, u, v));
			vertices.push_back(this->make_point(R, r, u + u_span, v));
			vertices.push_back(this->make_point(R, r, u + u_span, v + v_span));
			vertices.push_back(this->make_point(R, r, u, v + v_span));
			vertices.push_back(this->make_point(R, r + height, u, v));
			vertices.push_back(this->make_point(R, r + height, u + u_span, v));
			vertices.push_back(this->make_point(R, r + height, u + u_span, v + v_span));
			vertices.push_back(this->make_point(R, r + height, u, v + v_span));
 
			int index = this->face_mesh.getNumVertices();
			this->face_mesh.addVertices(vertices);
			this->frame_mesh.addVertices(vertices);
 
			// Face Index
 
			this->face_mesh.addIndex(index + 0); this->face_mesh.addIndex(index + 1); this->face_mesh.addIndex(index + 2);
			this->face_mesh.addIndex(index + 0); this->face_mesh.addIndex(index + 2); this->face_mesh.addIndex(index + 3);
 
			this->face_mesh.addIndex(index + 4); this->face_mesh.addIndex(index + 5); this->face_mesh.addIndex(index + 6);
			this->face_mesh.addIndex(index + 4); this->face_mesh.addIndex(index + 6); this->face_mesh.addIndex(index + 7);
 
			this->face_mesh.addIndex(index + 0); this->face_mesh.addIndex(index + 4); this->face_mesh.addIndex(index + 5);
			this->face_mesh.addIndex(index + 0); this->face_mesh.addIndex(index + 5); this->face_mesh.addIndex(index + 1);
 
			this->face_mesh.addIndex(index + 1); this->face_mesh.addIndex(index + 5); this->face_mesh.addIndex(index + 6);
			this->face_mesh.addIndex(index + 1); this->face_mesh.addIndex(index + 6); this->face_mesh.addIndex(index + 2);
 
			this->face_mesh.addIndex(index + 2); this->face_mesh.addIndex(index + 6); this->face_mesh.addIndex(index + 7);
			this->face_mesh.addIndex(index + 2); this->face_mesh.addIndex(index + 7); this->face_mesh.addIndex(index + 3);
 
			this->face_mesh.addIndex(index + 3); this->face_mesh.addIndex(index + 7); this->face_mesh.addIndex(index + 4);
			this->face_mesh.addIndex(index + 3); this->face_mesh.addIndex(index + 4); this->face_mesh.addIndex(index + 0);
 
			// Frame Index
 
			this->frame_mesh.addIndex(index + 0); this->frame_mesh.addIndex(index + 1);
			this->frame_mesh.addIndex(index + 1); this->frame_mesh.addIndex(index + 2);
			this->frame_mesh.addIndex(index + 2); this->frame_mesh.addIndex(index + 3);
			this->frame_mesh.addIndex(index + 3); this->frame_mesh.addIndex(index + 0);
 
			this->frame_mesh.addIndex(index + 4); this->frame_mesh.addIndex(index + 5);
			this->frame_mesh.addIndex(index + 5); this->frame_mesh.addIndex(index + 6);
			this->frame_mesh.addIndex(index + 6); this->frame_mesh.addIndex(index + 7);
			this->frame_mesh.addIndex(index + 7); this->frame_mesh.addIndex(index + 4);
 
			this->frame_mesh.addIndex(index + 0); this->frame_mesh.addIndex(index + 4);
			this->frame_mesh.addIndex(index + 1); this->frame_mesh.addIndex(index + 5);
			this->frame_mesh.addIndex(index + 2); this->frame_mesh.addIndex(index + 6);
			this->frame_mesh.addIndex(index + 3); this->frame_mesh.addIndex(index + 7);
		}
	}
}
 
//--------------------------------------------------------------
void ofApp::draw() {
 
	this->cam.begin();
	ofRotateY(ofGetFrameNum() * 0.6666666666666666);
 
	ofSetColor(0);
	this->face_mesh.drawFaces();
 
	ofSetColor(255);
	this->frame_mesh.drawWireframe();
 
	this->cam.end();
}
 
//--------------------------------------------------------------
glm::vec3 ofApp::make_point(float R, float r, float u, float v) {
 
	// 数学デッサン教室 描いて楽しむ数学たち P.31
 
	u *= DEG_TO_RAD;
	v *= DEG_TO_RAD;
 
	auto x = (R + r * cos(u)) * cos(v);
	auto y = (R + r * cos(u)) * sin(v);
	auto z = r * sin(u);
 
	return glm::vec3(x, y, z);
}
 
//--------------------------------------------------------------
int main() {
 
	ofSetupOpenGL(720, 720, OF_WINDOW);
	ofRunApp(new ofApp());
}