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 +