winlivebg_test1
diff src/colcycle.c @ 2:a9025f31ae2d
sortof works, testing with colcycle hack
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 28 Oct 2019 16:07:25 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/colcycle.c Mon Oct 28 16:07:25 2019 +0200 1.3 @@ -0,0 +1,405 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <assert.h> 1.8 +#include <windows.h> 1.9 +#include <GL/gl.h> 1.10 +#include "glext.h" 1.11 +#include "wglext.h" 1.12 +#include "app.h" 1.13 + 1.14 +static void draw_screen(long time_msec); 1.15 +static unsigned int create_program(const char *vsdr, const char *psdr); 1.16 +static unsigned int create_shader(unsigned int type, const char *sdr); 1.17 +static unsigned int next_pow2(unsigned int x); 1.18 +static int enable_vsync(void); 1.19 +static int init_glext(void); 1.20 +static void calc_image_proj(float img_aspect, float *xform); 1.21 + 1.22 +extern int scr_width, scr_height; 1.23 + 1.24 +PFNWGLSWAPINTERVALEXTPROC wgl_swap_interval; 1.25 + 1.26 +/* multitexture */ 1.27 +PFNGLACTIVETEXTUREPROC gl_active_texture; 1.28 + 1.29 +/* shader API entry points */ 1.30 +PFNGLCREATEPROGRAMPROC gl_create_program; 1.31 +PFNGLDELETEPROGRAMPROC gl_delete_program; 1.32 +PFNGLCREATESHADERPROC gl_create_shader; 1.33 +PFNGLDELETESHADERPROC gl_delete_shader; 1.34 +PFNGLSHADERSOURCEPROC gl_shader_source; 1.35 +PFNGLCOMPILESHADERPROC gl_compile_shader; 1.36 +PFNGLGETSHADERIVPROC gl_get_shaderiv; 1.37 +PFNGLGETSHADERINFOLOGPROC gl_get_shader_info_log; 1.38 +PFNGLATTACHSHADERPROC gl_attach_shader; 1.39 +PFNGLLINKPROGRAMPROC gl_link_program; 1.40 +PFNGLGETPROGRAMIVPROC gl_get_programiv; 1.41 +PFNGLGETPROGRAMINFOLOGPROC gl_get_program_info_log; 1.42 +PFNGLUSEPROGRAMPROC gl_use_program; 1.43 +PFNGLGETUNIFORMLOCATIONPROC gl_get_uniform_location; 1.44 +PFNGLUNIFORM1IPROC gl_uniform1i; 1.45 +PFNGLUNIFORM2FPROC gl_uniform2f; 1.46 +PFNGLUNIFORMMATRIX4FVPROC gl_uniform_matrix4fv; 1.47 + 1.48 +enum { FIT_FULL, FIT_CROP, FIT_STRETCH }; 1.49 +static int fit_mode = FIT_FULL; 1.50 +static float crop_zoom = 1.0f; 1.51 +static float crop_dir[] = {0.0f, 0.0f}; 1.52 + 1.53 +static int tex_xsz, tex_ysz; 1.54 +static unsigned int img_tex, pal_tex, prog; 1.55 +static unsigned char pal[256 * 3]; 1.56 +static int pal_valid; 1.57 + 1.58 +static const char *vsdr = 1.59 + "uniform mat4 xform;\n" 1.60 + "uniform vec2 uvscale;\n" 1.61 + "varying vec2 uv;\n" 1.62 + "void main()\n" 1.63 + "{\n" 1.64 + "\tgl_Position = xform * gl_Vertex;\n" 1.65 + "\tuv = (gl_Vertex.xy * vec2(0.5, -0.5) + 0.5) * uvscale;\n" 1.66 + "}\n"; 1.67 + 1.68 +static const char *psdr = 1.69 + "uniform sampler2D img_tex;\n" 1.70 + "uniform sampler1D pal_tex;\n" 1.71 + "varying vec2 uv;\n" 1.72 + "void main()\n" 1.73 + "{\n" 1.74 + "\tfloat cidx = texture2D(img_tex, uv).x;\n" 1.75 + "\tvec3 color = texture1D(pal_tex, cidx).xyz;\n" 1.76 + "\tgl_FragColor.xyz = color;\n" 1.77 + "\tgl_FragColor.a = 1.0;\n" 1.78 + "}\n"; 1.79 + 1.80 +static int xform_loc, uvscale_loc; 1.81 + 1.82 +void resize(int xsz, int ysz) 1.83 +{ 1.84 + if(xsz == fbwidth && ysz == fbheight) return; 1.85 + 1.86 + fbwidth = xsz; 1.87 + fbheight = ysz; 1.88 + 1.89 + tex_xsz = next_pow2(fbwidth); 1.90 + tex_ysz = next_pow2(fbheight); 1.91 + 1.92 + glBindTexture(GL_TEXTURE_2D, img_tex); 1.93 + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); 1.94 +} 1.95 + 1.96 + 1.97 +void set_palette(int idx, int r, int g, int b) 1.98 +{ 1.99 + unsigned char *pptr = pal + idx * 3; 1.100 + pptr[0] = r; 1.101 + pptr[1] = g; 1.102 + pptr[2] = b; 1.103 + pal_valid = 0; 1.104 +} 1.105 + 1.106 +void colcycle_init(void) 1.107 +{ 1.108 + int loc; 1.109 + char *argv[] = {"colcycle", "foo.lbm", 0}; 1.110 + 1.111 + init_glext(); 1.112 + 1.113 + fbwidth = 640; 1.114 + fbheight = 480; 1.115 + fbpixels = malloc(fbwidth * fbheight); 1.116 + 1.117 + colc_init(2, argv); 1.118 + 1.119 + tex_xsz = next_pow2(fbwidth); 1.120 + tex_ysz = next_pow2(fbheight); 1.121 + 1.122 + glGenTextures(1, &img_tex); 1.123 + glBindTexture(GL_TEXTURE_2D, img_tex); 1.124 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1.125 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1.126 + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); 1.127 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels); 1.128 + 1.129 + glGenTextures(1, &pal_tex); 1.130 + glBindTexture(GL_TEXTURE_1D, pal_tex); 1.131 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1.132 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1.133 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1.134 + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pal); 1.135 + 1.136 + if((prog = create_program(vsdr, psdr))) { 1.137 + gl_use_program(prog); 1.138 + if((loc = gl_get_uniform_location(prog, "img_tex")) >= 0) { 1.139 + gl_uniform1i(loc, 0); 1.140 + } 1.141 + if((loc = gl_get_uniform_location(prog, "pal_tex")) >= 0) { 1.142 + gl_uniform1i(loc, 1); 1.143 + } 1.144 + if((uvscale_loc = gl_get_uniform_location(prog, "uvscale")) >= 0) { 1.145 + gl_uniform2f(uvscale_loc, (float)fbwidth / (float)tex_xsz, (float)fbheight / (float)tex_ysz); 1.146 + } 1.147 + xform_loc = gl_get_uniform_location(prog, "xform"); 1.148 + } 1.149 + gl_use_program(0); 1.150 + 1.151 + if(enable_vsync() == -1) { 1.152 + fprintf(stderr, "failed to enable vsync\n"); 1.153 + } 1.154 +} 1.155 + 1.156 +void colcycle_cleanup(void) 1.157 +{ 1.158 + colc_cleanup(); 1.159 +} 1.160 + 1.161 +void colcycle_draw(long time_msec) 1.162 +{ 1.163 + float xform[16]; 1.164 + 1.165 + glClearColor(0, 0, 0, 1); 1.166 + glClear(GL_COLOR_BUFFER_BIT); 1.167 + 1.168 + glViewport(0, 0, scr_width, scr_height); 1.169 + 1.170 + calc_image_proj((float)fbwidth / (float)fbheight, xform); 1.171 + 1.172 + gl_use_program(prog); 1.173 + if(xform_loc >= 0) { 1.174 + gl_uniform_matrix4fv(xform_loc, 1, GL_FALSE, xform); 1.175 + } 1.176 + 1.177 + draw_screen(time_msec); 1.178 +} 1.179 + 1.180 +static void draw_screen(long time_msec) 1.181 +{ 1.182 + *(uint32_t*)fbpixels = 0xbadf00d; 1.183 + colc_draw(time_msec); 1.184 + 1.185 + if(*(uint32_t*)fbpixels != 0xbadf00d) { 1.186 + /* update texture data if the framebuffer changed */ 1.187 + glBindTexture(GL_TEXTURE_2D, img_tex); 1.188 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels); 1.189 + } 1.190 + if(!pal_valid) { 1.191 + /* update the palette texture */ 1.192 + glBindTexture(GL_TEXTURE_1D, pal_tex); 1.193 + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGB, GL_UNSIGNED_BYTE, pal); 1.194 + pal_valid = 1; 1.195 + } 1.196 + 1.197 + gl_active_texture(GL_TEXTURE0); 1.198 + glBindTexture(GL_TEXTURE_2D, img_tex); 1.199 + gl_active_texture(GL_TEXTURE1); 1.200 + glBindTexture(GL_TEXTURE_1D, pal_tex); 1.201 + gl_active_texture(GL_TEXTURE0); 1.202 + 1.203 + glBegin(GL_QUADS); 1.204 + glVertex2f(-1, -1); 1.205 + glVertex2f(1, -1); 1.206 + glVertex2f(1, 1); 1.207 + glVertex2f(-1, 1); 1.208 + glEnd(); 1.209 + 1.210 + assert(glGetError() == GL_NO_ERROR); 1.211 +} 1.212 + 1.213 +static unsigned int create_program(const char *vsdr, const char *psdr) 1.214 +{ 1.215 + unsigned int vs, ps, prog; 1.216 + int status, info_len; 1.217 + 1.218 + if(!(vs = create_shader(GL_VERTEX_SHADER, vsdr))) { 1.219 + return 0; 1.220 + } 1.221 + if(!(ps = create_shader(GL_FRAGMENT_SHADER, psdr))) { 1.222 + gl_delete_shader(vs); 1.223 + return 0; 1.224 + } 1.225 + 1.226 + prog = gl_create_program(); 1.227 + gl_attach_shader(prog, vs); 1.228 + gl_attach_shader(prog, ps); 1.229 + gl_link_program(prog); 1.230 + 1.231 + gl_get_programiv(prog, GL_LINK_STATUS, &status); 1.232 + if(!status) { 1.233 + fprintf(stderr, "failed to link shader program\n"); 1.234 + gl_delete_program(prog); 1.235 + prog = 0; 1.236 + } 1.237 + 1.238 + gl_get_programiv(prog, GL_INFO_LOG_LENGTH, &info_len); 1.239 + if(info_len) { 1.240 + char *buf = alloca(info_len + 1); 1.241 + gl_get_program_info_log(prog, info_len, 0, buf); 1.242 + buf[info_len] = 0; 1.243 + if(buf[0]) { 1.244 + fprintf(stderr, "linker output:\n%s\n", buf); 1.245 + } 1.246 + } 1.247 + 1.248 + if(!status) { 1.249 + gl_delete_program(prog); 1.250 + prog = 0; 1.251 + } 1.252 + return prog; 1.253 +} 1.254 + 1.255 +static unsigned int create_shader(unsigned int type, const char *src) 1.256 +{ 1.257 + unsigned int sdr; 1.258 + int status, info_len; 1.259 + 1.260 + sdr = gl_create_shader(type); 1.261 + gl_shader_source(sdr, 1, &src, 0); 1.262 + gl_compile_shader(sdr); 1.263 + 1.264 + gl_get_shaderiv(sdr, GL_COMPILE_STATUS, &status); 1.265 + if(!status) { 1.266 + fprintf(stderr, "failed to compile %s shader\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel"); 1.267 + } 1.268 + 1.269 + gl_get_shaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 1.270 + if(info_len) { 1.271 + char *buf = alloca(info_len + 1); 1.272 + gl_get_shader_info_log(sdr, info_len, 0, buf); 1.273 + buf[info_len] = 0; 1.274 + if(buf[0]) { 1.275 + fprintf(stderr, "compiler output:\n%s\n", buf); 1.276 + } 1.277 + } 1.278 + 1.279 + if(!status) { 1.280 + gl_delete_shader(sdr); 1.281 + sdr = 0; 1.282 + } 1.283 + return sdr; 1.284 +} 1.285 + 1.286 +static unsigned int next_pow2(unsigned int x) 1.287 +{ 1.288 + --x; 1.289 + x |= x >> 1; 1.290 + x |= x >> 2; 1.291 + x |= x >> 4; 1.292 + x |= x >> 8; 1.293 + x |= x >> 16; 1.294 + return x + 1; 1.295 +} 1.296 + 1.297 +static int enable_vsync(void) 1.298 +{ 1.299 + if(wgl_swap_interval) { 1.300 + wgl_swap_interval(1); 1.301 + } 1.302 + return -1; 1.303 +} 1.304 + 1.305 +static int init_glext(void) 1.306 +{ 1.307 + static int init_done; 1.308 + const char *extstr; 1.309 + PFNWGLGETEXTENSIONSSTRINGEXTPROC wgl_get_extstr_ext; 1.310 + 1.311 + if(init_done) return 0; 1.312 + init_done = 1; 1.313 + 1.314 + /* WGL extensions */ 1.315 + if((wgl_get_extstr_ext = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"))) { 1.316 + if(!(extstr = wgl_get_extstr_ext())) { 1.317 + fprintf(stderr, "failed to retrieve WGL extensions string\n"); 1.318 + return -1; 1.319 + } 1.320 + } else { 1.321 + fprintf(stderr, "wglGetExtensionsString not found\n"); 1.322 + return -1; 1.323 + } 1.324 + if(strstr(extstr, "WGL_EXT_swap_control")) { 1.325 + wgl_swap_interval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); 1.326 + } 1.327 + 1.328 + /* OpenGL extensions */ 1.329 + if(!(extstr = (const char*)glGetString(GL_EXTENSIONS))) { 1.330 + fprintf(stderr, "failed to retrieve GL extensions string\n"); 1.331 + return -1; 1.332 + } 1.333 + /* proceed to ignore the extensions string and just attempt to load entry points, 1.334 + * because we want to use the GL2.0 style of the API, instead of the clunkier ARB one 1.335 + */ 1.336 + if(!(gl_create_program = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))) { 1.337 + fprintf(stderr, "failed to find the OpenGL shader API entry points\n"); 1.338 + return -1; 1.339 + } 1.340 + /* assume everything else is there if glCreateProgram is there */ 1.341 + gl_delete_program = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram"); 1.342 + gl_create_shader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"); 1.343 + gl_delete_shader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader"); 1.344 + gl_shader_source = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"); 1.345 + gl_compile_shader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"); 1.346 + gl_get_shaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"); 1.347 + gl_get_shader_info_log = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog"); 1.348 + gl_attach_shader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"); 1.349 + gl_link_program = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"); 1.350 + gl_get_programiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv"); 1.351 + gl_get_program_info_log = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog"); 1.352 + gl_use_program = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"); 1.353 + gl_get_uniform_location = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation"); 1.354 + gl_uniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i"); 1.355 + gl_uniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f"); 1.356 + gl_uniform_matrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv"); 1.357 + 1.358 + if(!(gl_active_texture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture"))) { 1.359 + fprintf(stderr, "failed to find the multitexturing entry points\n"); 1.360 + return -1; 1.361 + } 1.362 + 1.363 + return 0; 1.364 +} 1.365 + 1.366 +static void calc_image_proj(float img_aspect, float *xform) 1.367 +{ 1.368 + static const float ident[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.369 + float vpscale; 1.370 + float aspect = (float)scr_width / (float)scr_height; 1.371 + 1.372 + memcpy(xform, ident, sizeof ident); 1.373 + 1.374 + if(fit_mode != FIT_STRETCH) { 1.375 + if(aspect > img_aspect) { 1.376 + vpscale = xform[0] = img_aspect / aspect; 1.377 + xform[5] = 1.0f; 1.378 + } else { 1.379 + vpscale = xform[5] = aspect / img_aspect; 1.380 + xform[0] = 1.0f; 1.381 + } 1.382 + 1.383 + if(fit_mode == FIT_CROP) { 1.384 + float cropscale, maxpan, tx, ty; 1.385 + 1.386 + cropscale = 1.0f / vpscale; 1.387 + cropscale = 1.0f + (cropscale - 1.0f) * crop_zoom; 1.388 + maxpan = cropscale - 1.0f; 1.389 + 1.390 + xform[0] *= cropscale; 1.391 + xform[5] *= cropscale; 1.392 + 1.393 + if(aspect > img_aspect) { 1.394 + tx = 0.0f; 1.395 + ty = -crop_dir[1] * maxpan; 1.396 + } else { 1.397 + tx = -crop_dir[0] * maxpan; 1.398 + ty = 0.0f; 1.399 + } 1.400 + 1.401 + xform[12] = tx; 1.402 + xform[13] = ty; 1.403 + } else { 1.404 + xform[12] = xform[13] = 0.0f; 1.405 + } 1.406 + } 1.407 +} 1.408 +