180 lines
4.3 KiB
C
180 lines
4.3 KiB
C
|
#include "shadermeh.h"
|
||
|
|
||
|
static GLfloat vertex_buffer[] = {
|
||
|
-1.0f, -1.0f, 0.0f, /* lower left corner */
|
||
|
1.0f, 1.0f, 1.0f,
|
||
|
|
||
|
+1.0f, -1.0f, 0.0f, /* lower right corner */
|
||
|
1.0f, 1.0f, 1.0f,
|
||
|
|
||
|
-1.0f, 1.0f, 0.0f, /* uper left corner */
|
||
|
1.0f, 1.0f, 1.0f,
|
||
|
|
||
|
+1.0f, +1.0f, 0.0f, /* upper right corner */
|
||
|
1.0f, 1.0f, 1.0f,
|
||
|
};
|
||
|
|
||
|
static double diff_timespec(const struct timespec *time1,
|
||
|
const struct timespec *time0)
|
||
|
{
|
||
|
return (time1->tv_sec - time0->tv_sec)
|
||
|
+ (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
|
||
|
}
|
||
|
|
||
|
static const struct option long_opts[] = {
|
||
|
{ "width", required_argument, NULL, 'w' },
|
||
|
{ "height", required_argument, NULL, 'h' },
|
||
|
{ "shader", required_argument, NULL, 's' },
|
||
|
{ NULL, 0, NULL, 0 },
|
||
|
};
|
||
|
|
||
|
static const char *short_opts = "w:h:s:";
|
||
|
|
||
|
static const char *usage_str =
|
||
|
"shadermeh OPTIONS...\n"
|
||
|
"\n"
|
||
|
"Possible options:\n"
|
||
|
"\n"
|
||
|
" --width, -w <pixels>\n"
|
||
|
" --height, -h <pixels>\n"
|
||
|
"\n"
|
||
|
" --shader, -s <shader file>\n"
|
||
|
"\n";
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
GLuint u_iResolution, u_iTime, u_iTimeDelta, u_iFrame;
|
||
|
struct timespec start, frame_start, frame_end;
|
||
|
unsigned int width, height, iFrame = 0;
|
||
|
const char *shader_file = NULL;
|
||
|
GLint major, minor, prog;
|
||
|
float iTime, iTimeDelta;
|
||
|
GLuint vao, vbo;
|
||
|
window *wnd;
|
||
|
int i;
|
||
|
|
||
|
/******************** parse options ************************/
|
||
|
width = 800;
|
||
|
height = 450;
|
||
|
|
||
|
for (;;) {
|
||
|
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
|
||
|
if (i == -1)
|
||
|
break;
|
||
|
|
||
|
switch (i) {
|
||
|
case 'w':
|
||
|
width = strtol(optarg, NULL, 10);
|
||
|
break;
|
||
|
case 'h':
|
||
|
height = strtol(optarg, NULL, 10);
|
||
|
break;
|
||
|
case 's':
|
||
|
shader_file = optarg;
|
||
|
break;
|
||
|
default:
|
||
|
fputs(usage_str, stderr);
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!shader_file) {
|
||
|
fputs(usage_str, stderr);
|
||
|
fputs("No shader file specified!\n", stderr);
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
/********** create window and make context current **********/
|
||
|
wnd = window_create(width, height, "shader meh...");
|
||
|
|
||
|
if (!wnd) {
|
||
|
fputs("failed to create window", stderr);
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
window_make_current(wnd);
|
||
|
window_set_vsync(wnd, 1);
|
||
|
|
||
|
/******************** load entry points ********************/
|
||
|
glewExperimental = GL_TRUE;
|
||
|
|
||
|
if (glewInit() != GLEW_OK) {
|
||
|
fputs("glewInit() error", stderr);
|
||
|
window_destroy(wnd);
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||
|
printf("OpenGL version %d.%d\n", major, minor);
|
||
|
|
||
|
/******************** initialization ********************/
|
||
|
glViewport(0, 0, width, height);
|
||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||
|
|
||
|
/* vertex buffer object & vertex array object */
|
||
|
glGenVertexArrays(1, &vao);
|
||
|
glBindVertexArray(vao);
|
||
|
|
||
|
glGenBuffers(1, &vbo);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||
|
|
||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer),
|
||
|
vertex_buffer, GL_STATIC_DRAW);
|
||
|
|
||
|
glEnableVertexAttribArray(0);
|
||
|
glEnableVertexAttribArray(1);
|
||
|
|
||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
|
||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6,
|
||
|
(GLvoid *)(3 * sizeof(GLfloat)));
|
||
|
|
||
|
/* shader */
|
||
|
prog = shader_program_load(shader_file);
|
||
|
|
||
|
if (!shader_program_get_build_status(prog)) {
|
||
|
shader_program_print_info_log(prog);
|
||
|
}
|
||
|
|
||
|
glUseProgram(prog);
|
||
|
|
||
|
/* uniforms */
|
||
|
u_iResolution = glGetUniformLocation(prog, "iResolution");
|
||
|
u_iTime = glGetUniformLocation(prog, "iTime");
|
||
|
u_iTimeDelta = glGetUniformLocation(prog, "iTimeDelta");
|
||
|
u_iFrame = glGetUniformLocation(prog, "iFrame;");
|
||
|
|
||
|
glUniform3f(u_iResolution, width, height, 0.0f);
|
||
|
|
||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
||
|
|
||
|
/******************** drawing loop ********************/
|
||
|
while (window_handle_events()) {
|
||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_start);
|
||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||
|
window_swap_buffers(wnd);
|
||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_end);
|
||
|
|
||
|
iFrame += 1;
|
||
|
iTimeDelta = diff_timespec(&frame_end, &frame_start);
|
||
|
iTime = diff_timespec(&frame_end, &start);
|
||
|
|
||
|
glUniform1f(u_iTimeDelta, iTimeDelta);
|
||
|
glUniform1f(u_iTime, iTime);
|
||
|
glUniform1ui(u_iFrame, iFrame);
|
||
|
}
|
||
|
|
||
|
/******************** cleanup ********************/
|
||
|
glUseProgram(0);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
glDeleteBuffers(1, &vbo);
|
||
|
glBindVertexArray(0);
|
||
|
glDeleteVertexArrays(1, &vao);
|
||
|
glDeleteProgram(prog);
|
||
|
|
||
|
window_make_current(NULL);
|
||
|
window_destroy(wnd);
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|