8 #include <GLFW/glfw3.h>
11 #define error(...) {fprintf(stderr, __VA_ARGS__); abort();}
13 #define UNUSED(x) (void)(x)
15 #define VERTSHDSRC_COMMON "" \
16 "uniform float screenRatio;" \
17 "vec2 nodePosNDC(vec2 p)" \
19 " return (p * 2 - vec2(1.0)) * vec2(1.0, -1.0);" \
21 "vec2 scalePercent(vec2 p, float perc)" \
23 " return p * vec2(1.0, screenRatio) / 100 * perc;" \
26 #define VERTSHDSRC_NODES "#version 330 core\n" \
27 "layout(location = 0) in vec2 vertexCoord;" \
28 "uniform vec2 nodePos;" \
29 "uniform bool nodeSelected;" \
33 " vec2 pos = nodePosNDC(nodePos) + scalePercent(vertexCoord, nodeSelected ? 7.5 : 5.0);" \
34 " gl_Position = vec4(pos, 0.0, 1.0);" \
38 #define FRAGSHDSRC_NODES "#version 330 core\n" \
39 "uniform bool nodeSelected;" \
42 " gl_FragColor = vec4(nodeSelected ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0), 1.0);" \
45 #define VERTSHDSRC_WAYS "#version 330 core\n" \
46 "layout(location = 0) in vec2 vertexCoord;" \
47 "out float progress;" \
48 "uniform vec2 wayPos;" \
49 "uniform float wayLength;" \
54 " progress = (vertexCoord.x + 0.5) * wayLength;" \
55 " vec2 w = normalize(way);" \
56 " vec2 pos = nodePosNDC(wayPos) + mat2(w.x, -w.y, w.y, w.x) * ((vertexCoord * vec2(wayLength * 2, 0.0125)) * vec2(1.0, screenRatio));" \
57 " gl_Position = vec4(pos, 0.0, 1.0);" \
60 #define FRAGSHDSRC_WAYS "#version 330 core\n" \
61 "in float progress;" \
62 "uniform float wayProgress;" \
63 "uniform float wayLength;" \
66 " vec3 color = vec3(1.0, 0.0, 0.0);" \
67 " if (wayProgress > 0.0 && wayProgress >= progress || wayProgress < 0.0 && (wayLength + wayProgress) <= progress)" \
68 " color = vec3(0.0, 0.0, 1.0);" \
69 " gl_FragColor = vec4(color, 1.0);" \
74 } screenBounds, screenBoundsNormalized;
97 typedef struct Node Node;
98 typedef struct Way Way;
100 Node *nodelist = NULL;
103 Node *selected_node = NULL;
105 scwaypoint *currentwp = NULL;
106 float currentprog = 0.0;
107 bool unselect = false;
109 GLuint screenRatio_nodes_loc, nodePos_loc, nodeSelected_loc, screenRatio_ways_loc, wayPos_loc, wayLength_loc, way_loc, wayProgress_loc;
110 GLuint nodes_shaders, ways_shaders;
112 Node *createNode(float x, float y)
114 Node *node = malloc(sizeof(Node));
117 node->selected = false;
118 node->scnod = scnodalloc(node);
120 for (Node *nptr = nodelist; nptr != NULL; nptr = nptr->next) {
121 if (nptr->next == NULL) {
122 return nptr->next = node;
125 return nodelist = node;
128 Way *connectNodes(Node *from, Node *to)
130 if (scisconnected(from->scnod, to->scnod))
132 Way *way = malloc(sizeof(Way));
133 way->posx = (from->x + to->x) / 2;
134 way->posy = (from->y + to->y) / 2;
135 way->vecx = to->x - from->x;
136 way->vecy = to->y - from->y;
139 float len = sqrt(way->vecx * way->vecx + way->vecy * way->vecy);
140 way->scway_1 = scaddway(from->scnod, to->scnod, len, way);
141 way->scway_2 = scaddway(to->scnod, from->scnod, len, way);
143 for (Way *wptr = waylist; wptr != NULL; wptr = wptr->next) {
144 if (wptr->next == NULL) {
145 return wptr->next = way;
148 return waylist = way;
151 Node *getNodeAtPos(float x, float y)
155 for (Node *nptr = nodelist; nptr != NULL; nptr = nptr->next) {
157 dx = (nptr->x - x) * screenBoundsNormalized.width;
158 dy = (nptr->y - y) * screenBoundsNormalized.height;
159 float d = sqrt(dx * dx + dy * dy);
160 if (d > (nptr->selected ? 7.5f : 5.0f) / 100.0f / 4.0f)
162 if (node == NULL || d < distance) {
172 return currentwp != NULL && currentwp->way != NULL ? (Way *)currentwp->way->dat : NULL;
175 Node *getActiveNode()
177 return currentwp != NULL ? (Node *)currentwp->nod->dat : NULL;
183 scdestroypath(currentwp);
187 void findPathStep(double dtime)
189 if (currentwp == NULL)
191 Node *active_node = getActiveNode();
192 active_node->selected = true;
193 Way *active_way = getActiveWay();
198 Node *to = (Node *)active_way->scway_1->lto->dat;
199 float len = active_way->scway_1->len;
201 if (active_node == to)
203 currentprog += dtime * fac * 0.25;
204 if (currentprog * fac > len) {
205 active_way->done = true;
206 currentwp = currentwp->nxt;
211 void findPathStart(Node *from, Node *to)
213 currentwp = scout(from->scnod, to->scnod, NULL);
214 if (currentwp == NULL)
219 GLuint createShaderProgram(const char *vsrc, const char *fsrc)
223 char buffer[1024] = {0};
225 id = glCreateProgram();
228 vsh = glCreateShader(GL_VERTEX_SHADER);
229 glShaderSource(vsh, 1, &vsrc, NULL);
230 glCompileShader(vsh);
231 glGetShaderiv(vsh, GL_COMPILE_STATUS, &success);
233 glGetShaderInfoLog(vsh, 1024, NULL, buffer);
234 error("Failed to compile vertex shader: %s\n", buffer);
236 glAttachShader(id, vsh);
240 fsh = glCreateShader(GL_FRAGMENT_SHADER);
241 glShaderSource(fsh, 1, &fsrc, NULL);
242 glCompileShader(fsh);
243 glGetShaderiv(fsh, GL_COMPILE_STATUS, &success);
245 glGetShaderInfoLog(fsh, 1024, NULL, buffer);
246 error("Failed to compile fragment shader: %s\n", buffer);
248 glAttachShader(id, fsh);
252 glGetProgramiv(id, GL_LINK_STATUS, &success);
254 glGetProgramInfoLog(id, 1024, NULL, buffer);
255 error("Failed to link shader program: %s\n", buffer);
264 GLuint makeMesh(const GLfloat *vertices, GLsizei vertices_count, const GLuint *indices, GLsizei indices_count)
266 GLuint VAO, VBO, EBO;
268 glGenVertexArrays(1, &VAO);
269 glGenBuffers(1, &VBO);
270 glGenBuffers(1, &EBO);
272 glBindVertexArray(VAO);
273 glBindBuffer(GL_ARRAY_BUFFER, VBO);
274 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
276 glBufferData(GL_ARRAY_BUFFER, vertices_count * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
277 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(GLuint), indices, GL_STATIC_DRAW);
279 glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * sizeof(GLfloat), 0);
280 glEnableVertexAttribArray(0);
282 glBindVertexArray(0);
283 glBindBuffer(GL_ARRAY_BUFFER, 0);
284 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
289 void framebuffer_size_callback(GLFWwindow *window, int width, int height)
292 glViewport(0, 0, width, height);
293 screenBounds.width = width;
294 screenBounds.height = height;
295 float len = sqrt(width * width + height * height);
296 screenBoundsNormalized.width = (float)width / len;
297 screenBoundsNormalized.height = (float)height / len;
298 glProgramUniform1f(nodes_shaders, screenRatio_nodes_loc, (float)width / (float)height);
299 glProgramUniform1f(ways_shaders, screenRatio_ways_loc, (float)width / (float)height);
302 void mouse_button_callback(GLFWwindow *window, int button, int action, int mods)
306 if (action != GLFW_RELEASE || currentwp != NULL)
309 for (Way *wptr = waylist; wptr != NULL; wptr = wptr->next)
311 for (Node *nptr = nodelist; nptr != NULL; nptr = nptr->next)
312 nptr->selected = false;
315 float x = cursorPos.x / screenBounds.width;
316 float y = cursorPos.y / screenBounds.height;
317 Node *nod = getNodeAtPos(x, y);
321 case GLFW_MOUSE_BUTTON_LEFT:
322 connectNodes(selected_node, nod);
324 case GLFW_MOUSE_BUTTON_RIGHT:
325 findPathStart(selected_node, nod);
328 selected_node->selected = false;
329 selected_node = NULL;
333 selected_node->selected = true;
340 void cursor_pos_callback(GLFWwindow *window, double x, double y)
350 error("Failed to initialize GLFW\n");
351 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
352 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
353 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
355 GLFWwindow *window = glfwCreateWindow(10, 10, "libscout Example", NULL, NULL);
358 error("Failed to create GLFW window\n");
360 glfwMakeContextCurrent(window);
361 glfwSetFramebufferSizeCallback(window, &framebuffer_size_callback);
362 glfwSetCursorPosCallback(window, &cursor_pos_callback);
363 glfwSetMouseButtonCallback(window, &mouse_button_callback);
364 glfwSetWindowSize(window, 750, 500);
366 GLenum glew_init_err = glewInit();
367 if (glew_init_err != GLEW_OK)
368 error("Failed to initalize GLEW\n");
370 float degtorad = M_PI / 180.0f;
372 GLfloat circle_vertices[361][2];
373 GLuint circle_indices[360][3];
375 circle_vertices[360][0] = 0;
376 circle_vertices[360][1] = 0;
378 for (int deg = 0; deg < 360; deg++) {
379 float rad = (float)deg * degtorad;
380 circle_vertices[deg][0] = cos(rad) * 0.5;
381 circle_vertices[deg][1] = sin(rad) * 0.5;
383 int nextdeg = deg + 1;
385 circle_indices[deg][0] = 360;
386 circle_indices[deg][1] = deg;
387 circle_indices[deg][2] = nextdeg < 360 ? nextdeg : 0;
390 GLsizei circle_vertices_count = 361 * 2;
392 GLsizei circle_indices_count = 360 * 3;
394 GLfloat square_vertices[4][2] = {
401 GLsizei square_vertices_count = 4 * 2;
403 GLuint square_indices[2][3] = {
408 GLsizei square_indices_count = 2 * 3;
410 GLuint nodes_VAO, ways_VAO;
412 nodes_VAO = makeMesh(circle_vertices[0], circle_vertices_count, circle_indices[0], circle_indices_count);
413 ways_VAO = makeMesh(square_vertices[0], square_vertices_count, square_indices[0], square_indices_count);
415 nodes_shaders = createShaderProgram(VERTSHDSRC_NODES, FRAGSHDSRC_NODES);
416 ways_shaders = createShaderProgram(VERTSHDSRC_WAYS, FRAGSHDSRC_WAYS);
418 screenRatio_nodes_loc = glGetUniformLocation(nodes_shaders, "screenRatio");
419 nodePos_loc = glGetUniformLocation(nodes_shaders, "nodePos");
420 nodeSelected_loc = glGetUniformLocation(nodes_shaders, "nodeSelected");
422 screenRatio_ways_loc = glGetUniformLocation(ways_shaders, "screenRatio");
423 wayPos_loc = glGetUniformLocation(ways_shaders, "wayPos");
424 wayLength_loc = glGetUniformLocation(ways_shaders, "wayLength");
425 way_loc = glGetUniformLocation(ways_shaders, "way");
426 wayProgress_loc = glGetUniformLocation(ways_shaders, "wayProgress");
428 double last_time = glfwGetTime();
430 while (! glfwWindowShouldClose(window)) {
431 double dtime = glfwGetTime() - last_time;
432 last_time = glfwGetTime();
436 glClearColor(1.0, 1.0, 1.0, 1.0);
437 glClear(GL_COLOR_BUFFER_BIT);
439 glUseProgram(ways_shaders);
440 glBindVertexArray(ways_VAO);
441 Way *active_way = getActiveWay();
442 for (Way *way = waylist; way != NULL; way = way->next) {
443 float progress = 0.0;
444 float len = way->scway_1->len;
445 if (way == active_way)
446 progress = currentprog;
449 glUniform1f(wayProgress_loc, progress);
450 glUniform1f(wayLength_loc, len);
451 glUniform2f(wayPos_loc, way->posx, way->posy);
452 glUniform2f(way_loc, way->vecx, way->vecy);
453 glDrawElements(GL_TRIANGLES, square_indices_count, GL_UNSIGNED_INT, 0);
456 glUseProgram(nodes_shaders);
457 glBindVertexArray(nodes_VAO);
458 for (Node *node = nodelist; node != NULL; node = node->next) {
459 glUniform2f(nodePos_loc, node->x, node->y);
460 glUniform1i(nodeSelected_loc, node->selected);
461 glDrawElements(GL_TRIANGLES, circle_indices_count, GL_UNSIGNED_INT, 0);
464 glBindVertexArray(0);
466 glfwSwapBuffers(window);