]> git.lizzy.rs Git - dragonblocks3d.git/blob - src/dragonblocks/mesh.cpp
Multithreading
[dragonblocks3d.git] / src / dragonblocks / mesh.cpp
1 #include <stdexcept>
2 #include <cstdlib>
3 #include <cstring>
4 #include <glm/gtc/matrix_transform.hpp>
5 #include <glm/gtc/constants.hpp>
6 #include "gldebug.hpp"
7 #include "mesh.hpp"
8 #include "scene.hpp"
9 #include "shader_program.hpp"
10
11 using namespace std;
12 using namespace glm;
13 using namespace dragonblocks;
14
15 double Mesh::Effect::grow_time = 0.25;  // s
16 double Mesh::Effect::flyin_time = 0.4;  // s
17 double Mesh::Effect::flyin_offset = 20; // m
18 double Mesh::Effect::rotate_speed = 1;  // turns/s
19
20 mat4 Mesh::Effect::getModelMatrix(double dtime, vec3 pos, vec3 size, vec3 rotation_axis, float rotation_angle)
21 {
22         mat4 trans = mat4(1.0);
23
24         if (type == Mesh::Effect::Type::NONE)
25                 goto finish;
26
27         if (expires) {
28                 time_left -= dtime;
29                 if (time_left < 0) {
30                         type = Mesh::Effect::Type::NONE;
31                         if (on_finish) {
32                                 (*on_finish)(extra_data);
33                         }
34                         goto finish;
35                 }
36         }       
37
38         switch (type) {
39                 case Mesh::Effect::Type::FLYIN:
40                 pos.y -= Mesh::Effect::flyin_offset * time_left / Mesh::Effect::flyin_time;
41                 break;
42                 
43                 case Mesh::Effect::Type::GROW:
44                 size *= 1 - time_left / Mesh::Effect::grow_time;
45                 break;
46                 
47                 case Mesh::Effect::Type::ROTATE:
48                 rotation_angle += glfwGetTime() * Mesh::Effect::rotate_speed * pi<float>() * 2;
49         }
50
51         finish:
52         
53         trans = translate(trans, pos);
54         trans = rotate(trans, rotation_angle, rotation_axis);
55         trans = scale(trans, size);
56         
57         return trans;
58 }
59
60 Mesh::Effect::Effect(Mesh::Effect::Type t, void (*o)(void *), void *e) : type(t), on_finish(o), extra_data(e)
61 {
62         switch(type) {
63                 case Mesh::Effect::Type::FLYIN:
64                 expires = true;
65                 time_left = Mesh::Effect::flyin_time;
66                 break;
67                 
68                 case Mesh::Effect::Type::GROW:
69                 expires = true;
70                 time_left = Mesh::Effect::grow_time;
71                 break;
72                 
73                 case Mesh::Effect::Type::ROTATE:
74                 expires = false;
75         }
76 }
77
78 void Mesh::vertexConfig(const GLvoid *v, GLsizei s)
79 {
80         if (vertices_changed || configured)
81                 throw runtime_error("Attempt to configure Mesh that is already configured");
82         vertices = malloc(s);
83         memcpy(vertices, v, s);
84         vertices_size = s;
85         vertices_changed = true;
86 }
87
88 void Mesh::render(double dtime, ShaderProgram *shader_program)
89 {
90         if (vertices_changed) {
91                 runVertexConfig();
92         }
93                 
94         if (! configured)
95                 return;
96
97         shader_program->use(); CHECKERR
98         
99         mat4 model_matrix = effect.getModelMatrix(dtime, pos, size, rotation_axis, rotation_angle); CHECKERR
100         
101         shader_program->set("model", model_matrix); CHECKERR
102         
103         glBindVertexArray(VAO); CHECKERR
104         for (int i = 0; i < textures.size(); i++) {
105                 textures[i].bind(); CHECKERR
106                 glDrawArrays(GL_TRIANGLES, i * vertices_per_texture, vertices_per_texture); CHECKERR
107         }
108         glBindVertexArray(0); CHECKERR
109         glBindTexture(GL_TEXTURE_2D, 0); CHECKERR
110 }
111
112 void Mesh::reset()
113 {
114         removeFromScene();
115         pos = vec3(0.0);
116         size = vec3(1.0);
117         rotation_axis = vec3(0.0, 1.0, 0.0);
118         vertices_per_texture = 0;
119         textures = {};
120         rotation_angle = 0;
121         if (VAO) {
122                 glDeleteVertexArrays(1, &VAO); CHECKERR
123         }
124         if (VBO) {
125                 glDeleteBuffers(1, &VAO); CHECKERR
126         }
127         vertices_changed = false;
128         if (vertices) {
129                 free(vertices);
130         }
131         vertices = NULL;
132         configured = false;
133 }
134
135 void Mesh::addToScene()
136 {
137         scene->add(this);
138 }
139
140 void Mesh::removeFromScene()
141 {
142         scene->remove(this);
143 }
144
145 Mesh::Mesh(Scene *s): scene(s)
146 {
147         reset();
148 }
149
150 void Mesh::runVertexConfig()
151 {               
152         if (! vertices || vertices_size == 0)
153                 throw runtime_error("Invalid Mesh configuration");
154         
155         glGenVertexArrays(1, &VAO); CHECKERR
156         glGenBuffers(1, &VBO); CHECKERR
157         
158         glBindVertexArray(VAO); CHECKERR
159         glBindBuffer(GL_ARRAY_BUFFER, VBO); CHECKERR
160                 
161         glBufferData(GL_ARRAY_BUFFER, vertices_size, vertices, GL_STATIC_DRAW); CHECKERR
162         
163         GLsizei stride = 5 * sizeof(GLfloat); CHECKERR
164         
165         glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, (GLvoid *)(0 * sizeof(GLfloat))); CHECKERR
166         glEnableVertexAttribArray(0); CHECKERR
167         glVertexAttribPointer(1, 2, GL_FLOAT, false, stride, (GLvoid *)(3 * sizeof(GLfloat))); CHECKERR
168         glEnableVertexAttribArray(1); CHECKERR
169         
170         glBindBuffer(GL_ARRAY_BUFFER, 0); CHECKERR
171         glBindVertexArray(0); CHECKERR
172         
173         free(vertices);
174         vertices = NULL;
175         vertices_changed = false;
176         configured = true;
177 }