chip8

A simple C CHIP8 VM.
git clone git://git.vgx.fr/chip8
Log | Files | Refs | README

media-glfw.c (6489B)


      1 #include <assert.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 
      5 #define GLFW_INCLUDE_ES2
      6 #include <GLFW/glfw3.h>
      7 
      8 #define MA_NO_DECODING
      9 #define MINIAUDIO_IMPLEMENTATION
     10 #include "ext/miniaudio.h"
     11 
     12 #include "media.h"
     13 
     14 #define PIXEL_RADIUS 16
     15 
     16 #define SCREEN_WIDTH (64*PIXEL_RADIUS)
     17 #define SCREEN_HEIGHT (32*PIXEL_RADIUS)
     18 
     19 #define WINDOW_NAME "CHIP-8 emulator"
     20 
     21 #define NUM_PIXELS (32*64)
     22 
     23 #define SOUND_DEV_FREQ 48000
     24 #define SOUND_DEV_FORMAT ma_format_f32
     25 #define SOUND_DEV_CHANNELS 1
     26 
     27 #define BUZZER_WAVE_TYPE ma_waveform_type_sawtooth
     28 #define BUZZER_FREQ 440
     29 #define BUZZER_VOL .05
     30 
     31 unsigned char pixels[NUM_PIXELS];
     32 
     33 GLFWwindow *window;
     34 
     35 const float vertices[] = {
     36 	-1.0f, -1.0f,
     37 	-1.0f, +1.0f,
     38 	+1.0f, -1.0f,
     39 	+1.0f, +1.0f,
     40 };
     41 
     42 const char *v_shader_src =
     43 "#version 100\n"
     44 "in vec2 coords;\n"
     45 "varying vec2 tex_coords;\n"
     46 "void main(){\n"
     47 "	gl_Position = vec4(coords.x, coords.y, 0.0, 1.0);\n"
     48 "	tex_coords.x = (1.0 + coords.x)/2.0;\n"
     49 "	tex_coords.y = (1.0 - coords.y)/2.0;\n"
     50 "}";
     51 
     52 const char *f_shader_src =
     53 "#version 100\n"
     54 "in lowp vec2 tex_coords;\n"
     55 "uniform sampler2D tex;\n"
     56 "void main(){\n"
     57 "	gl_FragColor = vec4(vec3(texture2D(tex, tex_coords).a), 1.0);\n"
     58 "}";
     59 
     60 
     61 unsigned short input;
     62 
     63 
     64 /* sound state*/
     65 ma_waveform wave;
     66 ma_device device;
     67 
     68 /*
     69 ┌───┬───┬───┬───┐
     70 │ 1 │ 2 │ 3 │ C │
     71 ├───┼───┼───┼───┤
     72 │ 4 │ 5 │ 6 │ D │
     73 ├───┼───┼───┼───┤
     74 │ 7 │ 8 │ 9 │ E │
     75 ├───┼───┼───┼───┤
     76 │ A │ 0 │ B │ F │
     77 └───┴───┴───┴───┘
     78 */
     79 
     80 int keys[16] = {
     81 	GLFW_KEY_V,
     82 	GLFW_KEY_3, GLFW_KEY_4, GLFW_KEY_5,
     83 	GLFW_KEY_E, GLFW_KEY_R, GLFW_KEY_T,
     84 	GLFW_KEY_D, GLFW_KEY_F, GLFW_KEY_G,
     85 	GLFW_KEY_C, GLFW_KEY_B,
     86 	GLFW_KEY_6, GLFW_KEY_Y, GLFW_KEY_H, GLFW_KEY_N
     87 };
     88 
     89 static void buzzer_callback(ma_device *d, void *out, const void *in, ma_uint32 frame){
     90 	(void)in; (void)d;
     91 	ma_waveform_read_pcm_frames(&wave, out, frame);
     92 }
     93 
     94 static void key_callback(GLFWwindow* window, int key, int s, int action, int m){
     95 	(void) s, (void)m, (void) window;
     96 	for (int i=0 ; i<16 ; i++) {
     97 		if (key == keys[i]){
     98 			if (action == GLFW_PRESS)
     99 				input |= 1<<i;
    100 			else if (action == GLFW_RELEASE)
    101 				input ^= 1<<i;
    102 		}
    103 	}
    104 }
    105 
    106 void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    107 	(void) window;
    108 	glViewport(0, 0, width, height);
    109 }
    110 
    111 static void check_shader_log(unsigned shader){
    112 	int success;
    113 	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    114 	if (!success){
    115 		char log[512];
    116 		glGetShaderInfoLog(shader, 512, NULL, log);
    117 		puts("Shader compile log:");
    118 		puts(log);
    119 	}
    120 }
    121 
    122 static void setup_shaders(void){
    123 	/* Create vertex shader */
    124 	unsigned v_shader = glCreateShader(GL_VERTEX_SHADER);
    125 	glShaderSource(v_shader, 1, &v_shader_src, NULL);
    126 	glCompileShader(v_shader);
    127 	check_shader_log(v_shader);
    128 
    129 	/* Create fragment shader */
    130 	unsigned f_shader = glCreateShader(GL_FRAGMENT_SHADER);
    131 	glShaderSource(f_shader, 1, &f_shader_src, NULL);
    132 	glCompileShader(f_shader);
    133 	check_shader_log(f_shader);
    134 
    135 	/* Create shader program */
    136 	unsigned program = glCreateProgram();
    137 	glAttachShader(program, v_shader);
    138 	glAttachShader(program, f_shader);
    139 	glLinkProgram(program);
    140 	glUseProgram(program);
    141 
    142 	/* Remove shaders */
    143 	glDeleteShader(v_shader);
    144 	glDeleteShader(f_shader);
    145 
    146 	/* Create vertex buffer */
    147 	unsigned VBO;
    148 	glGenBuffers(1, &VBO);
    149 	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    150 	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    151 
    152 	/* Setup vertex input array */
    153 	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    154 	glEnableVertexAttribArray(0);
    155 }
    156 
    157 static void setup_texture(void){
    158 	unsigned texture;
    159 	glGenTextures(1, &texture);
    160 	glBindTexture(GL_TEXTURE_2D, texture);
    161 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    162 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    163 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    164 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    165 	glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 64, 32, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
    166 }
    167 
    168 static void init_graphics(void){
    169 	/* Init GLFW */
    170 	glfwInit();
    171 	glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
    172 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    173 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    174 
    175 	window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME, NULL, NULL);
    176 	glfwMakeContextCurrent(window);
    177 
    178 	glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    179 	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    180 
    181 	glfwSwapInterval(1);
    182 
    183 	/* Init OpenGL */
    184 	setup_shaders();
    185 	setup_texture();
    186 	
    187 	glClear(GL_COLOR_BUFFER_BIT);
    188 }
    189 
    190 static void init_audio(void){
    191 	ma_waveform_config wave_config = ma_waveform_config_init(
    192 			SOUND_DEV_FORMAT, SOUND_DEV_CHANNELS, SOUND_DEV_FREQ,
    193 			BUZZER_WAVE_TYPE, BUZZER_VOL, BUZZER_FREQ);
    194 
    195 	ma_waveform_init(&wave_config, &wave);
    196 
    197 	ma_device_config device_config = ma_device_config_init(ma_device_type_playback);
    198 
    199 	device_config.playback.format   = SOUND_DEV_FORMAT;
    200 	device_config.playback.channels = SOUND_DEV_CHANNELS;
    201 	device_config.sampleRate        = SOUND_DEV_FREQ;
    202 	device_config.dataCallback      = buzzer_callback;
    203 
    204 	ma_device_init(NULL, &device_config, &device);
    205 	ma_device_start(&device);
    206 
    207 	ma_device_set_master_volume(&device, 0);
    208 }
    209 
    210 int m_init(int argc, char **argv){
    211 	(void)argc, (void)argv;
    212 	/*TODO: check every init */
    213 
    214 	init_graphics();
    215 
    216 	init_audio();
    217 
    218 	glfwSetKeyCallback(window, key_callback);
    219 
    220 	return 0;
    221 }
    222 
    223 void m_quit(void){
    224 	glfwDestroyWindow(window);
    225 
    226 	glfwTerminate();
    227 
    228 	ma_device_uninit(&device);
    229 }
    230 
    231 unsigned short get_input(unsigned short old_input){
    232 	(void) old_input;
    233 	if (glfwWindowShouldClose(window))
    234 		return -1;
    235 
    236 	return input;
    237 }
    238 unsigned short wait_input(unsigned short input){
    239 	int new_input;
    240 	
    241 	while((new_input = get_input(input)) == input)
    242 		frame();
    243 
    244 	return new_input;
    245 }
    246 
    247 void clear_screen(void){
    248 	memset(pixels,0,NUM_PIXELS);
    249 	glClear(GL_COLOR_BUFFER_BIT);
    250 }
    251 
    252 void draw(int x, int y, int value){
    253 	assert(0<=x && x<64);
    254 	assert(0<=y && y<32);
    255 
    256 	pixels[y*64+x] = value ? 255 : 0;
    257 }
    258 
    259 void frame(void){
    260 	glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 64, 32, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
    261 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    262 
    263 	glfwSwapBuffers(window);
    264 	glfwPollEvents();
    265 }
    266 
    267 void set_buzzer_state(int state){
    268 	static int old_state = 0;
    269 	if(state != old_state){
    270 		ma_device_set_master_volume(&device, state);
    271 		old_state = state;
    272 	}
    273 }