#include #include #include #include #include #include "../common/shader_utils.h" #include "res_texture.c" GLuint program; GLint attribute_coord2d; GLint uniform_offset_x; GLint uniform_scale_x; GLint uniform_sprite; GLuint texture_id; GLint uniform_mytexture; float offset_x = 0.0; float scale_x = 1.0; int mode = 0; struct point { GLfloat x; GLfloat y; }; GLuint vbo; int init_resources() { program = create_program("graph.v.glsl", "graph.f.glsl"); if (program == 0) return 0; attribute_coord2d = get_attrib(program, "coord2d"); uniform_offset_x = get_uniform(program, "offset_x"); uniform_scale_x = get_uniform(program, "scale_x"); uniform_sprite = get_uniform(program, "sprite"); uniform_mytexture = get_uniform(program, "mytexture"); if (attribute_coord2d == -1 || uniform_offset_x == -1 || uniform_scale_x == -1 || uniform_sprite == -1 || uniform_mytexture == -1) return 0; /* Enable blending */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* Enable point sprites (not necessary for true OpenGL ES 2.0) */ #ifndef GL_ES_VERSION_2_0 glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif /* Upload the texture for our point sprites */ glActiveTexture(GL_TEXTURE0); glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res_texture.width, res_texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, res_texture.pixel_data); // Create the vertex buffer object glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); // Create our own temporary buffer point graph[2000]; // Fill it in just like an array for (int i = 0; i < 2000; i++) { float x = (i - 1000.0) / 100.0; graph[i].x = x; graph[i].y = sin(x * 10.0) / (1.0 + x * x); } // Tell OpenGL to copy our array to the buffer object glBufferData(GL_ARRAY_BUFFER, sizeof graph, graph, GL_STATIC_DRAW); return 1; } void free_resources() { glDeleteProgram(program); } void display() { glUseProgram(program); glUniform1i(uniform_mytexture, 0); glUniform1f(uniform_offset_x, offset_x); glUniform1f(uniform_scale_x, scale_x); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); /* Draw using the vertices in our vertex buffer object */ glBindBuffer(GL_ARRAY_BUFFER, vbo); glEnableVertexAttribArray(attribute_coord2d); glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0); /* Push each element in buffer_vertices to the vertex shader */ switch (mode) { case 0: glUniform1f(uniform_sprite, 0); glDrawArrays(GL_LINE_STRIP, 0, 2000); break; case 1: glUniform1f(uniform_sprite, 1); glDrawArrays(GL_POINTS, 0, 2000); break; case 2: glUniform1f(uniform_sprite, res_texture.width); glDrawArrays(GL_POINTS, 0, 2000); break; } } void keyDown(SDL_KeyboardEvent *ev) { switch (ev->keysym.scancode) { case SDL_SCANCODE_F1: mode = 0; printf("Now drawing using lines.\n"); break; case SDL_SCANCODE_F2: mode = 1; printf("Now drawing using points.\n"); break; case SDL_SCANCODE_F3: mode = 2; printf("Now drawing using point sprites.\n"); break; case SDL_SCANCODE_LEFT: offset_x -= 0.1; break; case SDL_SCANCODE_RIGHT: offset_x += 0.1; break; case SDL_SCANCODE_UP: scale_x *= 1.5; break; case SDL_SCANCODE_DOWN: scale_x /= 1.5; break; case SDL_SCANCODE_HOME: offset_x = 0.0; scale_x = 1.0; break; default: break; } } void windowEvent(SDL_WindowEvent *ev) { switch(ev->event) { case SDL_WINDOWEVENT_SIZE_CHANGED: glViewport(0, 0, ev->data1, ev->data2); break; default: break; } } void mainLoop(SDL_Window *window) { while (true) { display(); SDL_GL_SwapWindow(window); bool redraw = false; while (!redraw) { SDL_Event ev; if (!SDL_WaitEvent(&ev)) return; switch (ev.type) { case SDL_QUIT: return; case SDL_KEYDOWN: keyDown(&ev.key); redraw = true; break; case SDL_WINDOWEVENT: windowEvent(&ev.window); redraw = true; break; default: break; } } } } int main(int argc, char *argv[]) { SDL_Init(SDL_INIT_VIDEO); SDL_Window *window = SDL_CreateWindow("My Graph", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window); GLenum glew_status = glewInit(); if (GLEW_OK != glew_status) { fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); return 1; } if (!GLEW_VERSION_2_0) { fprintf(stderr, "No support for OpenGL 2.0 found\n"); return 1; } GLfloat range[2]; glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range); if (range[1] < res_texture.width) fprintf(stderr, "WARNING: point sprite range (%f, %f) too small\n", range[0], range[1]); printf("Use left/right to move horizontally.\n"); printf("Use up/down to change the horizontal scale.\n"); printf("Press home to reset the position and scale.\n"); printf("Press F1 to draw lines.\n"); printf("Press F2 to draw points.\n"); printf("Press F3 to draw point sprites.\n"); if (!init_resources()) return EXIT_FAILURE; mainLoop(window); free_resources(); SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); SDL_Quit(); return EXIT_SUCCESS; }