Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Basic example of using primitive restart
/*
---------------------------------------------------------------
oooo
'888
oooo d8b .ooooo. oooo ooo 888 oooo oooo
'888""8P d88' '88b '88b..8P' 888 '888 '888
888 888 888 Y888' 888 888 888
888 888 888 .o8"'88b 888 888 888
d888b 'Y8bod8P' o88' 888o o888o 'V88V"V8P'
www.roxlu.com
www.twitter.com/roxlu
---------------------------------------------------------------
PRIMITIVE RESTART
==================
This is a quick experiment that shows how to use primitive restart. Primitive
restart allows you to flag an index of a element buffer as "special". Every
time GL reads this value from the index buffer it will start a new primitive.
This is nice, because this allows you to use one array-buffer and one
element-buffer to draw separate GL_LINE_STRIPS or GL_TRIANGLE_STRIPS for
example. You can even use glDrawArrays() and "restart" every N-th draw vertex
(not showing here).
*/
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <vector>
void button_callback(GLFWwindow* win, int bt, int action, int mods);
void cursor_callback(GLFWwindow* win, double x, double y);
void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods);
void char_callback(GLFWwindow* win, unsigned int key);
void error_callback(int err, const char* desc);
void resize_callback(GLFWwindow* window, int width, int height);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
/* -------------------------------------------- */
int win_w = 1280;
int win_h = 720;
struct vertex {
float x;
float y;
};
/* -------------------------------------------- */
int main() {
glfwSetErrorCallback(error_callback);
if(!glfwInit()) {
printf("Error: cannot setup glfw.\n");
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* win = NULL;
int w = win_w;
int h = win_h;
win = glfwCreateWindow(w, h, "Primitive restart v1.0", NULL, NULL);
if(!win) {
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetFramebufferSizeCallback(win, resize_callback);
glfwSetKeyCallback(win, key_callback);
glfwSetCharCallback(win, char_callback);
glfwSetCursorPosCallback(win, cursor_callback);
glfwSetMouseButtonCallback(win, button_callback);
glfwSetScrollCallback(win, scroll_callback);
glfwMakeContextCurrent(win);
glfwSwapInterval(1);
if (!gladLoadGL()) {
printf("Cannot load GL.\n");
exit(1);
}
// ----------------------------------------------------------------
// THIS IS WHERE YOU START CALLING OPENGL FUNCTIONS, NOT EARLIER!!
// ----------------------------------------------------------------
/* Fill our vertex and index buffers. 0xFFFF is our primitive restart value. */
int num_particles = 3;
int num_points = 40;
std::vector<int> indices;
std::vector<vertex> vertices;
for (int i = 0; i < num_particles; ++i) {
for (int j = 0; j < num_points; ++j) {
indices.push_back(vertices.size());
vertices.push_back(vertex{100 + i * 10.0f, 100 + j * 5.0f});
}
indices.push_back(0xFFFF);
}
GLuint rib_vbo = 0;
glGenBuffers(1, &rib_vbo);
glBindBuffer(GL_ARRAY_BUFFER, rib_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0].x, GL_STATIC_DRAW);
GLuint rib_ebo = 0;
glGenBuffers(1, &rib_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rib_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices.size(), &indices[0], GL_STATIC_DRAW);
/* Create the VAO that we use when drawing. */
GLuint rib_vao = 0;
glGenVertexArrays(1, &rib_vao);
glBindVertexArray(rib_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rib_ebo);
glBindBuffer(GL_ARRAY_BUFFER, rib_vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0);
/* ==================================================== */
/* DRAW SHADER */
/* ==================================================== */
const char* dvss = ""
"#version 330\n"
"uniform mat4 u_pm;\n"
"layout (location = 0) in vec2 a_pos;\n"
"void main() {\n"
" gl_Position = u_pm * vec4(a_pos, 0.0, 1.0);\n"
"}";
GLuint draw_vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(draw_vs, 1, (const char**)&dvss, NULL);
glCompileShader(draw_vs);
const char* dfss = ""
"#version 330\n"
"uniform vec3 u_color;\n"
"layout (location = 0) out vec4 fragcolor;\n"
"void main() {\n"
" fragcolor = vec4(u_color, 1.0);\n"
"}";
GLuint draw_fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(draw_fs, 1, (const char**)&dfss, NULL);
glCompileShader(draw_fs);
GLuint draw_prog = glCreateProgram();
glAttachShader(draw_prog, draw_vs);
glAttachShader(draw_prog, draw_fs);
glLinkProgram(draw_prog);
float pm[16] = { 0.0f };
pm[0] = 2.0 / win_w;
pm[5] = 2.0f / -win_h;
pm[10] = -1.0f;
pm[12] = -1.0;
pm[13] = 1.0f;
pm[15] = 1.0f;
GLint u_pm = glGetUniformLocation(draw_prog, "u_pm");
GLint u_color = glGetUniformLocation(draw_prog, "u_color");
glUseProgram(draw_prog);
glUniformMatrix4fv(u_pm, 1, GL_FALSE, pm);
glUniform3f(u_color, 1.0f, 1.0f, 1.0f);
/* ==================================================== */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
while(!glfwWindowShouldClose(win)) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, w, h);
glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*
This is where we enable primitive restart; Note that we have one draw call
but we're drawing multiple separate GL_LINE_STRIPs.
*/
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(0xFFFF);
glUseProgram(draw_prog);
glBindVertexArray(rib_vao);
glDrawElements(GL_LINE_STRIP, indices.size(), GL_UNSIGNED_INT, (GLvoid*)0);
glfwSwapBuffers(win);
glfwPollEvents();
}
glfwTerminate();
return EXIT_SUCCESS;
}
void char_callback(GLFWwindow* win, unsigned int key) {
}
void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods) {
if (GLFW_RELEASE == action) {
return;
}
switch(key) {
case GLFW_KEY_SPACE: {
break;
}
case GLFW_KEY_ESCAPE: {
glfwSetWindowShouldClose(win, GL_TRUE);
break;
}
};
}
void resize_callback(GLFWwindow* window, int width, int height) {
}
void cursor_callback(GLFWwindow* win, double x, double y) {
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
}
void button_callback(GLFWwindow* win, int bt, int action, int mods) {
double mx = 0.0;
double my = 0.0;
glfwGetCursorPos(win, &mx, &my);
if (GLFW_PRESS == action) {
}
else if (GLFW_RELEASE == action) {
}
}
void error_callback(int err, const char* desc) {
printf("GLFW error: %s (%d)\n", desc, err);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.