main.c (12276B)


      1 #include <epoxy/gl.h>
      2 #include <GLES3/gl3.h>
      3 #include <GLFW/glfw3.h>
      4 
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <math.h>
      9 #include <fcntl.h>
     10 #include <unistd.h>
     11 #include <sys/wait.h>
     12 
     13 #include <arpa/inet.h>
     14 
     15 #include "util.h"
     16 #include "config.h"
     17 
     18 /* Private definitions */
     19 typedef struct {
     20     float x;
     21     float y;
     22     float scale;
     23 } scout_instance_card_t;
     24 
     25 typedef struct {
     26     float x;
     27     float y;
     28 } scout_camera_t;
     29 
     30 /* Misc. globals */
     31 const char *title = "SCOUT";
     32 scout_cfg_t cfg = DEFAULT_CFG;
     33 
     34 scout_camera_t camera = {
     35     .x = 0.0f,
     36     .y = 0.0f
     37 };
     38 
     39 /* Card data */
     40 unsigned int num_cards = 0;
     41 unsigned int max_cards = 0;
     42 unsigned int current_card = 0;
     43 scout_card_t *cards;
     44 unsigned int *card_textures;
     45 float *card_ratios;
     46 float *card_offsets;
     47 
     48 /* Actions */
     49 int change_card = 0;
     50 int launch_card = 0;
     51 
     52 /* OpenGL variables */
     53 unsigned int vertex_shader;
     54 unsigned int fragment_shader;
     55 int scale_uniform;
     56 int trans_uniform;
     57 int camera_uniform;
     58 int texture_uniform;
     59 
     60 /* Load all shaders from file */
     61 void load_shaders()
     62 {
     63     const char *path;
     64     if (!(path = getenv("SCOUT_SHADER_PATH")))
     65 	path = SHADER_PATH;
     66 
     67     int dir_fd = open(path, O_RDONLY | O_DIRECTORY);
     68     if (dir_fd < 0) {
     69 	fprintf(stderr, "Unable to open shader path \"%s\"\n", path);
     70 	return;
     71     }
     72 
     73     int vert_fd = openat(dir_fd, "vert.glsl", O_RDONLY);
     74     if (vert_fd < 0) {
     75 	fprintf(stderr, "Unable to open vertex shader\n");
     76 	return;
     77     }
     78 
     79     int frag_fd = openat(dir_fd, "frag.glsl", O_RDONLY);
     80     if (frag_fd < 0) {
     81 	fprintf(stderr, "Unable to open fragment shader\n");
     82 	return;
     83     }
     84 
     85     int success;
     86 
     87     const char *vert_source = fdreadfile(vert_fd);
     88 
     89     vertex_shader = glCreateShader(GL_VERTEX_SHADER);
     90     glShaderSource(vertex_shader, 1, &vert_source, NULL);
     91     glCompileShader(vertex_shader);
     92 
     93     glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
     94     if (!success) {
     95 	fprintf(stderr, "Failed to compile vertex shader!\n");
     96 	return;
     97     }
     98 
     99     const char *frag_source = fdreadfile(frag_fd);
    100 
    101     fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    102     glShaderSource(fragment_shader, 1, &frag_source, NULL);
    103     glCompileShader(fragment_shader);
    104 
    105     glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
    106     if (!success) {
    107 	fprintf(stderr, "Failed to compile fragment shader!\n");
    108 	return;
    109     }
    110 
    111     fprintf(stderr, "Compiled shaders\n");
    112 }
    113 
    114 /* GLFW Callbacks */
    115 void error_callback(int error, const char *description)
    116 {
    117     fprintf(stderr, "GLFW Error: %s\n", description);
    118 }
    119 
    120 void framebuffer_size_callback(GLFWwindow *window, int width, int height)
    121 {
    122     glViewport(0, 0, width, height);
    123     /* Apply aspect ratio */
    124     float ratio = (float) width / (float) height;
    125     fprintf(stderr, "Resized: %i x %i, max %f\n", width, height, ratio);
    126     glUniform2f(scale_uniform, ratio, 1.0f);
    127 }
    128 
    129 /* TODO: Proper input management */
    130 void key_callback(GLFWwindow *window, int key, int scancode, int action,
    131 		  int mods)
    132 {
    133     if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) {
    134 	change_card = 1;
    135 	return;
    136     }
    137     if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) {
    138 	change_card = -1;
    139 	return;
    140     }
    141     if (key == GLFW_KEY_ENTER && action == GLFW_PRESS) {
    142 	launch_card = 1;
    143 	return;
    144     }
    145 }
    146 
    147 void joystick_callback(int jid, int event)
    148 {
    149     if (!glfwJoystickIsGamepad(jid))
    150 	return;
    151 
    152     if (event == GLFW_CONNECTED) {
    153 	fprintf(stderr, "Connected %d\n", jid);
    154     } else if (event == GLFW_DISCONNECTED) {
    155 	fprintf(stderr, "Disconnected %d\n", jid);
    156     }
    157 }
    158 
    159 int main()
    160 {
    161     /* Initialize GLFW */
    162     glfwSetErrorCallback(error_callback);
    163 
    164     if (!glfwInit()) {
    165 	printf("Failed to initialize GLFW!\n");
    166 	return -1;
    167     }
    168 
    169     glfwSetJoystickCallback(joystick_callback);
    170 
    171     /* Load configuration */
    172     load_config(&cfg, &num_cards, &cards);
    173     fprintf(stderr, "Loaded %d cards\n", num_cards);
    174 
    175 
    176     /* Window creation */
    177     GLFWwindow *window = glfwCreateWindow(640, 480, title, NULL, NULL);
    178     if (!window) {
    179 	printf("Failed to create GLFW window!\n");
    180 	glfwTerminate();
    181 	return -1;
    182     }
    183     glfwMakeContextCurrent(window);
    184 
    185     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    186     glfwSetKeyCallback(window, key_callback);
    187 
    188     /* Controller setup */
    189     for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) {
    190 	if (glfwJoystickPresent(i) && glfwJoystickIsGamepad(i)) {
    191 	    fprintf(stderr, "Controller %d available\n", i);
    192 	}
    193     }
    194 
    195     /* Set up shaders */
    196     load_shaders();
    197 
    198     unsigned int shader_program = glCreateProgram();
    199 
    200     glAttachShader(shader_program, vertex_shader);
    201     glAttachShader(shader_program, fragment_shader);
    202     glLinkProgram(shader_program);
    203 
    204     glDeleteShader(vertex_shader);
    205     glDeleteShader(fragment_shader);
    206 
    207     /* Uniforms */
    208     scale_uniform = glGetUniformLocation(shader_program, "scale");
    209     trans_uniform = glGetUniformLocation(shader_program, "trans");
    210     camera_uniform = glGetUniformLocation(shader_program, "camera");
    211 
    212     texture_uniform = glGetUniformLocation(shader_program, "texture1");
    213 
    214     /* Set up vertex data and configure vertex attributes */
    215     float vertices[] = {
    216 	0.5f, 0.5f, 1.0f, 0.0f,
    217 	0.5f, -0.5f, 1.0f, 1.0f,
    218 	-0.5f, -0.5f, 0.0f, 1.0f,
    219 	-0.5f, 0.5f, 0.0f, 0.0f
    220     };
    221     unsigned int indices[] = {
    222 	0, 1, 2,
    223 	2, 3, 0
    224     };
    225 
    226     /* Create vertex arrays, buffers, etc. */
    227     unsigned int VBO, EBO, VAO;
    228     glGenVertexArrays(1, &VAO);
    229     glGenBuffers(1, &VBO);
    230     glGenBuffers(1, &EBO);
    231 
    232     glBindVertexArray(VAO);
    233 
    234     glBindBuffer(GL_ARRAY_BUFFER, VBO);
    235     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
    236 		 GL_STATIC_DRAW);
    237     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    238     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
    239 		 GL_STATIC_DRAW);
    240 
    241     /* Vertex coordinates */
    242     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
    243 			  (void *) 0);
    244     glEnableVertexAttribArray(0);
    245     /* Texture coordinates */
    246     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
    247 			  (void *) (2 * sizeof(float)));
    248     glEnableVertexAttribArray(1);
    249 
    250     /* Create cards */
    251     card_ratios = malloc(num_cards * sizeof(float));
    252     card_offsets = malloc(num_cards * sizeof(float));
    253     card_textures = malloc(num_cards * sizeof(unsigned int));
    254     glGenTextures(num_cards, card_textures);
    255 
    256     for (unsigned int i = 0; i < num_cards; i++) {
    257 	printf("  %s\n", cards[i].title);
    258 	
    259 	if (*cards[i].image_path != 0) {
    260     	    /* Decode image */
    261     	    int img_fd = open(cards[i].image_path, O_RDONLY);
    262     	    if (img_fd < 0) {
    263                 continue;
    264     	    }
    265 
    266     	    unsigned int hdr[4];
    267     	    read(img_fd, hdr, 16);
    268 
    269     	    if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1) != 0)
    270         	continue;
    271     	    
    272     	    unsigned int width = ntohl(hdr[2]);
    273     	    unsigned int height = ntohl(hdr[3]);
    274     	    size_t size = width * height * 8;
    275     	    unsigned char *data = malloc(size);
    276     	    read(img_fd, data, size);
    277 
    278     	    close(img_fd);
    279 
    280     	    /* Create OpenGL texture */
    281     	    glBindTexture(GL_TEXTURE_2D, card_textures[i]);
    282     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    283     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    284     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    285     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    286     	    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT, data);
    287 
    288             /* The texture is on GPU so we can release the decoded data. */
    289     	    free(data);
    290 
    291     	    /* Calculate the vertical scale of the image */
    292     	    card_ratios[i] =  (float) height / (float) width;
    293 	} else {
    294     	    /* This is really ugly but that's also kinda the point... */
    295     	    const unsigned char blah[16] = { 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff }; 
    296 
    297     	    /* Create OpenGL texture */
    298     	    glBindTexture(GL_TEXTURE_2D, card_textures[i]);
    299     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    300     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    301     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    302     	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    303     	    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, blah);
    304     	    
    305     	    /* TODO: Use default image */
    306     	    card_ratios[i] = 1.0f;
    307 	}
    308     }
    309 
    310     /* Main loop */
    311     float counter = 0.0f;
    312     float time = 0.0f;
    313     float lastCheck = 0.0f;
    314     float fps = 0.0f;
    315 
    316     float dt = 0.0f;
    317 
    318     GLFWgamepadstate state;
    319     float move_cooldown_left = 0.0f;
    320     float move_cooldown_right = 0.0f;
    321     int down = 0;
    322 
    323     /* Set background color */
    324     glClearColor(cfg.bg.r, cfg.bg.g, cfg.bg.b, 1.0f);
    325 
    326     while (!glfwWindowShouldClose(window)) {
    327 	/* Game Logic */
    328 	lastCheck = time;
    329 	time = glfwGetTime();
    330 	dt = time - lastCheck;
    331 
    332 	/* Controller setup */
    333 	for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) {
    334 	    if (!glfwJoystickIsGamepad(i))
    335 		continue;
    336 
    337 	    glfwGetGamepadState(i, &state);
    338 	    
    339             /* Avoid repeating inputs */
    340 	    if (state.buttons[GLFW_GAMEPAD_BUTTON_A]) {
    341     	        if (down != 1) {
    342 	     	    launch_card = 1;
    343 		    down = 1;
    344     	        }
    345 	    } else {
    346     	        down = 0;
    347 	    }
    348 
    349 	    if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT]
    350 		|| state.axes[GLFW_GAMEPAD_AXIS_LEFT_X] > 0.01f) {
    351 		if (move_cooldown_left <= 0.0f) {
    352 		    change_card = 1;
    353 		    move_cooldown_left = 0.2f;
    354 		}
    355 	    } else {
    356 		move_cooldown_left = 0.0f;
    357 	    }
    358 
    359 	    if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]
    360 		|| state.axes[GLFW_GAMEPAD_AXIS_LEFT_X] < -0.01f) {
    361 		if (move_cooldown_right <= 0.0f) {
    362 		    change_card = -1;
    363 		    move_cooldown_right = 0.2f;
    364 		}
    365 	    } else {
    366 		move_cooldown_right = 0.0f;
    367 	    }
    368 	}
    369 
    370 	move_cooldown_left -= dt;
    371 	move_cooldown_right -= dt;
    372 
    373 	/* Handle card change */
    374         if (change_card != 0) {
    375 	    if (change_card < 0 && current_card > 0) {
    376 		current_card--;
    377 	    } else if (change_card > 0 && current_card < num_cards - 1) {
    378 		current_card++;
    379 	    }
    380 
    381 	    change_card = 0;
    382 	}
    383 
    384 	/* Animate cards */
    385 	for (int i = 0; i < num_cards; i++) {
    386             if (i == current_card)
    387                 card_offsets[i] = exp_decay(card_offsets[i], 1.0f, 16.0f, dt);
    388             else
    389                 card_offsets[i] = exp_decay(card_offsets[i], 0.0f, 16.0f, dt);
    390 	}
    391 
    392 	/* Smooth camera */
    393 	camera.x = exp_decay(camera.x, (float) current_card, 8.0f, dt);
    394 
    395 	/* Handle launching card */
    396 	if (launch_card) {
    397 	    pid_t pid = fork();
    398 
    399 	    if (pid == 0) {
    400 		char *const argv[] = {
    401 		    "sh",
    402 		    "-c",
    403 		    cards[current_card].command,
    404 		    NULL
    405 		};
    406 
    407 		execv("/bin/sh", argv);
    408 
    409 		printf("Error...");
    410 		_exit(127);
    411 	    } else if (pid > 0) {
    412 		printf("Launched %s\n", cards[current_card].title);
    413 	    } else {
    414 		printf("Error launching\n");
    415 	    }
    416 
    417 	    launch_card = 0;
    418 
    419 	    /* TODO: Monitor child process */
    420 	}
    421 
    422 	/* Calculate FPS */
    423 	counter += 1.0f;
    424 
    425 	if (time - lastCheck >= 1.0f) {
    426 	    fps = counter / (time - lastCheck);
    427 	    //fprintf(stderr, "%.2f FPS\n", fps);
    428 	    counter = 0.0f;
    429 	    lastCheck = time;
    430 	}
    431 
    432 	/* Clear screen */
    433 	glClear(GL_COLOR_BUFFER_BIT);
    434 	
    435 
    436         /* Render */
    437 	glUseProgram(shader_program);
    438 	
    439         /* Update camera */
    440 	glUniform2f(camera_uniform, camera.x, camera.y);
    441 
    442         /* Bind mesh */
    443      	glBindVertexArray(VAO);
    444 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    445 
    446      	for (int i = (current_card <= 2 ? 0 : current_card - 2); i < MIN(current_card + 3, num_cards); i++) {
    447 	    glActiveTexture(GL_TEXTURE0);
    448             glBindTexture(GL_TEXTURE_2D, card_textures[i]);
    449 
    450             glUniform4f(trans_uniform, (float) i * 1.0f, card_ratios[i] * -0.5f * (1.0f - card_offsets[i]), card_ratios[i], 0.8f + card_offsets[i] * 0.2f);
    451 
    452 	    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    453      	}
    454 
    455 	glfwSwapBuffers(window);
    456 	glfwPollEvents();
    457     }
    458 
    459     fprintf(stderr, "Closing\n");
    460 
    461     /* De-allocate GL resources when no longer needed */
    462     glDeleteVertexArrays(1, &VAO);
    463     glDeleteBuffers(1, &VBO);
    464     glDeleteBuffers(1, &EBO);
    465     glDeleteProgram(shader_program);
    466 
    467     /* TODO: Dealloc configuration */
    468     free(card_ratios);
    469     free(card_offsets);
    470     free(card_textures);
    471 
    472     glfwTerminate();
    473 }