aboutsummaryrefslogtreecommitdiff
path: root/src/boid.cc
blob: 9eeea41700e10cd450116653783e7b6327efb3cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "main_window.hh"

#include <QVector3D>
#include <QRandomGenerator>


struct Fish {
	QVector3D pos;
	QVector3D vel;
	float size;
	float dist = 10;
	float sqdist;

	OpenGLMesh mesh;

	Fish(QVector3D pos, OpenGLMesh mesh)
		:pos(pos),
		 sqdist(dist * dist),
		 mesh(mesh) {}

	void step() {
		pos += vel;
		mesh.mat.setToIdentity();
		QMatrix4x4 rot;
		rot.lookAt(pos, vel, {0, 1, 0});
		mesh.mat.translate(pos);
		// mesh.mat = rot * mesh.mat;
	}

	bool in_neighborhood(const QVector3D &p) const {
		return (p - pos).lengthSquared() < sqdist;
	}
};


struct Banc {
	QVector<Fish> fishes;

	Banc() {}

	Banc(size_t nfishes) {
		OpenGLMesh fish_mesh = OpenGLMesh({
				0, .1, 0,
				-.0866, -.05, 0,
				.0866, -.05, 0,
			});
		QRandomGenerator *rng = QRandomGenerator::global();
		for (size_t i = 0; i < nfishes; i++) {
			Fish fish({
					(float) (rng->generateDouble() * 3 - 1.5),
					(float) (rng->generateDouble() * 3 - 1.5),
					(float) (rng->generateDouble() * 3 - 1.5)
				}, fish_mesh);
			fishes.append(fish);
		}
	}

	void step() {
		QVector<Fish> neighbors;
		for (Fish &fish : fishes) {
			QVector3D neighbors_cog;
			QVector3D neighbors_vel;
			size_t nneighbors = 0;
			for (Fish &fish_b : fishes) {
				if (fish_b.in_neighborhood(fish.pos)) {
					nneighbors++;
					neighbors_cog += fish_b.pos;
					neighbors_vel += fish_b.vel;
				}
			}
			neighbors_cog /= nneighbors;
			neighbors_vel /= nneighbors;
			QVector3D v1 = -(fish.pos - neighbors_cog);
			QVector3D v2 = fish.vel - neighbors_vel;
			QVector3D v3 = neighbors_cog - fish.pos;
			QVector3D v = 1.5 * v1 + v2 + v3;
			float L = .001;
			fish.vel = (1-L) * fish.vel + L * v;
			fish.step();
		}
	}
};


Banc banc;

void MainWindow::init() {
	banc = Banc(10);
	for (Fish &fish : banc.fishes) {
		glw.meshes.append(&fish.mesh);
	}
}


void MainWindow::step() {
	banc.step();
	OpenGLWidget::instance->update();
}


void OpenGLWidget::paintGL() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	for (const Fish &fish : banc.fishes) {
		glUniformMatrix4fv(model_attr, 1, GL_FALSE, fish.mesh.mat.data());
		glBindVertexArray(fish.mesh.vao);
		glDrawArrays(GL_TRIANGLES, 0, fish.mesh.nverts);
	}
}