winlivebg_test1

view 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 source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <windows.h>
6 #include <GL/gl.h>
7 #include "glext.h"
8 #include "wglext.h"
9 #include "app.h"
11 static void draw_screen(long time_msec);
12 static unsigned int create_program(const char *vsdr, const char *psdr);
13 static unsigned int create_shader(unsigned int type, const char *sdr);
14 static unsigned int next_pow2(unsigned int x);
15 static int enable_vsync(void);
16 static int init_glext(void);
17 static void calc_image_proj(float img_aspect, float *xform);
19 extern int scr_width, scr_height;
21 PFNWGLSWAPINTERVALEXTPROC wgl_swap_interval;
23 /* multitexture */
24 PFNGLACTIVETEXTUREPROC gl_active_texture;
26 /* shader API entry points */
27 PFNGLCREATEPROGRAMPROC gl_create_program;
28 PFNGLDELETEPROGRAMPROC gl_delete_program;
29 PFNGLCREATESHADERPROC gl_create_shader;
30 PFNGLDELETESHADERPROC gl_delete_shader;
31 PFNGLSHADERSOURCEPROC gl_shader_source;
32 PFNGLCOMPILESHADERPROC gl_compile_shader;
33 PFNGLGETSHADERIVPROC gl_get_shaderiv;
34 PFNGLGETSHADERINFOLOGPROC gl_get_shader_info_log;
35 PFNGLATTACHSHADERPROC gl_attach_shader;
36 PFNGLLINKPROGRAMPROC gl_link_program;
37 PFNGLGETPROGRAMIVPROC gl_get_programiv;
38 PFNGLGETPROGRAMINFOLOGPROC gl_get_program_info_log;
39 PFNGLUSEPROGRAMPROC gl_use_program;
40 PFNGLGETUNIFORMLOCATIONPROC gl_get_uniform_location;
41 PFNGLUNIFORM1IPROC gl_uniform1i;
42 PFNGLUNIFORM2FPROC gl_uniform2f;
43 PFNGLUNIFORMMATRIX4FVPROC gl_uniform_matrix4fv;
45 enum { FIT_FULL, FIT_CROP, FIT_STRETCH };
46 static int fit_mode = FIT_FULL;
47 static float crop_zoom = 1.0f;
48 static float crop_dir[] = {0.0f, 0.0f};
50 static int tex_xsz, tex_ysz;
51 static unsigned int img_tex, pal_tex, prog;
52 static unsigned char pal[256 * 3];
53 static int pal_valid;
55 static const char *vsdr =
56 "uniform mat4 xform;\n"
57 "uniform vec2 uvscale;\n"
58 "varying vec2 uv;\n"
59 "void main()\n"
60 "{\n"
61 "\tgl_Position = xform * gl_Vertex;\n"
62 "\tuv = (gl_Vertex.xy * vec2(0.5, -0.5) + 0.5) * uvscale;\n"
63 "}\n";
65 static const char *psdr =
66 "uniform sampler2D img_tex;\n"
67 "uniform sampler1D pal_tex;\n"
68 "varying vec2 uv;\n"
69 "void main()\n"
70 "{\n"
71 "\tfloat cidx = texture2D(img_tex, uv).x;\n"
72 "\tvec3 color = texture1D(pal_tex, cidx).xyz;\n"
73 "\tgl_FragColor.xyz = color;\n"
74 "\tgl_FragColor.a = 1.0;\n"
75 "}\n";
77 static int xform_loc, uvscale_loc;
79 void resize(int xsz, int ysz)
80 {
81 if(xsz == fbwidth && ysz == fbheight) return;
83 fbwidth = xsz;
84 fbheight = ysz;
86 tex_xsz = next_pow2(fbwidth);
87 tex_ysz = next_pow2(fbheight);
89 glBindTexture(GL_TEXTURE_2D, img_tex);
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
91 }
94 void set_palette(int idx, int r, int g, int b)
95 {
96 unsigned char *pptr = pal + idx * 3;
97 pptr[0] = r;
98 pptr[1] = g;
99 pptr[2] = b;
100 pal_valid = 0;
101 }
103 void colcycle_init(void)
104 {
105 int loc;
106 char *argv[] = {"colcycle", "foo.lbm", 0};
108 init_glext();
110 fbwidth = 640;
111 fbheight = 480;
112 fbpixels = malloc(fbwidth * fbheight);
114 colc_init(2, argv);
116 tex_xsz = next_pow2(fbwidth);
117 tex_ysz = next_pow2(fbheight);
119 glGenTextures(1, &img_tex);
120 glBindTexture(GL_TEXTURE_2D, img_tex);
121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
123 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
124 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels);
126 glGenTextures(1, &pal_tex);
127 glBindTexture(GL_TEXTURE_1D, pal_tex);
128 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
129 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
130 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pal);
133 if((prog = create_program(vsdr, psdr))) {
134 gl_use_program(prog);
135 if((loc = gl_get_uniform_location(prog, "img_tex")) >= 0) {
136 gl_uniform1i(loc, 0);
137 }
138 if((loc = gl_get_uniform_location(prog, "pal_tex")) >= 0) {
139 gl_uniform1i(loc, 1);
140 }
141 if((uvscale_loc = gl_get_uniform_location(prog, "uvscale")) >= 0) {
142 gl_uniform2f(uvscale_loc, (float)fbwidth / (float)tex_xsz, (float)fbheight / (float)tex_ysz);
143 }
144 xform_loc = gl_get_uniform_location(prog, "xform");
145 }
146 gl_use_program(0);
148 if(enable_vsync() == -1) {
149 fprintf(stderr, "failed to enable vsync\n");
150 }
151 }
153 void colcycle_cleanup(void)
154 {
155 colc_cleanup();
156 }
158 void colcycle_draw(long time_msec)
159 {
160 float xform[16];
162 glClearColor(0, 0, 0, 1);
163 glClear(GL_COLOR_BUFFER_BIT);
165 glViewport(0, 0, scr_width, scr_height);
167 calc_image_proj((float)fbwidth / (float)fbheight, xform);
169 gl_use_program(prog);
170 if(xform_loc >= 0) {
171 gl_uniform_matrix4fv(xform_loc, 1, GL_FALSE, xform);
172 }
174 draw_screen(time_msec);
175 }
177 static void draw_screen(long time_msec)
178 {
179 *(uint32_t*)fbpixels = 0xbadf00d;
180 colc_draw(time_msec);
182 if(*(uint32_t*)fbpixels != 0xbadf00d) {
183 /* update texture data if the framebuffer changed */
184 glBindTexture(GL_TEXTURE_2D, img_tex);
185 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels);
186 }
187 if(!pal_valid) {
188 /* update the palette texture */
189 glBindTexture(GL_TEXTURE_1D, pal_tex);
190 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGB, GL_UNSIGNED_BYTE, pal);
191 pal_valid = 1;
192 }
194 gl_active_texture(GL_TEXTURE0);
195 glBindTexture(GL_TEXTURE_2D, img_tex);
196 gl_active_texture(GL_TEXTURE1);
197 glBindTexture(GL_TEXTURE_1D, pal_tex);
198 gl_active_texture(GL_TEXTURE0);
200 glBegin(GL_QUADS);
201 glVertex2f(-1, -1);
202 glVertex2f(1, -1);
203 glVertex2f(1, 1);
204 glVertex2f(-1, 1);
205 glEnd();
207 assert(glGetError() == GL_NO_ERROR);
208 }
210 static unsigned int create_program(const char *vsdr, const char *psdr)
211 {
212 unsigned int vs, ps, prog;
213 int status, info_len;
215 if(!(vs = create_shader(GL_VERTEX_SHADER, vsdr))) {
216 return 0;
217 }
218 if(!(ps = create_shader(GL_FRAGMENT_SHADER, psdr))) {
219 gl_delete_shader(vs);
220 return 0;
221 }
223 prog = gl_create_program();
224 gl_attach_shader(prog, vs);
225 gl_attach_shader(prog, ps);
226 gl_link_program(prog);
228 gl_get_programiv(prog, GL_LINK_STATUS, &status);
229 if(!status) {
230 fprintf(stderr, "failed to link shader program\n");
231 gl_delete_program(prog);
232 prog = 0;
233 }
235 gl_get_programiv(prog, GL_INFO_LOG_LENGTH, &info_len);
236 if(info_len) {
237 char *buf = alloca(info_len + 1);
238 gl_get_program_info_log(prog, info_len, 0, buf);
239 buf[info_len] = 0;
240 if(buf[0]) {
241 fprintf(stderr, "linker output:\n%s\n", buf);
242 }
243 }
245 if(!status) {
246 gl_delete_program(prog);
247 prog = 0;
248 }
249 return prog;
250 }
252 static unsigned int create_shader(unsigned int type, const char *src)
253 {
254 unsigned int sdr;
255 int status, info_len;
257 sdr = gl_create_shader(type);
258 gl_shader_source(sdr, 1, &src, 0);
259 gl_compile_shader(sdr);
261 gl_get_shaderiv(sdr, GL_COMPILE_STATUS, &status);
262 if(!status) {
263 fprintf(stderr, "failed to compile %s shader\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel");
264 }
266 gl_get_shaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
267 if(info_len) {
268 char *buf = alloca(info_len + 1);
269 gl_get_shader_info_log(sdr, info_len, 0, buf);
270 buf[info_len] = 0;
271 if(buf[0]) {
272 fprintf(stderr, "compiler output:\n%s\n", buf);
273 }
274 }
276 if(!status) {
277 gl_delete_shader(sdr);
278 sdr = 0;
279 }
280 return sdr;
281 }
283 static unsigned int next_pow2(unsigned int x)
284 {
285 --x;
286 x |= x >> 1;
287 x |= x >> 2;
288 x |= x >> 4;
289 x |= x >> 8;
290 x |= x >> 16;
291 return x + 1;
292 }
294 static int enable_vsync(void)
295 {
296 if(wgl_swap_interval) {
297 wgl_swap_interval(1);
298 }
299 return -1;
300 }
302 static int init_glext(void)
303 {
304 static int init_done;
305 const char *extstr;
306 PFNWGLGETEXTENSIONSSTRINGEXTPROC wgl_get_extstr_ext;
308 if(init_done) return 0;
309 init_done = 1;
311 /* WGL extensions */
312 if((wgl_get_extstr_ext = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"))) {
313 if(!(extstr = wgl_get_extstr_ext())) {
314 fprintf(stderr, "failed to retrieve WGL extensions string\n");
315 return -1;
316 }
317 } else {
318 fprintf(stderr, "wglGetExtensionsString not found\n");
319 return -1;
320 }
321 if(strstr(extstr, "WGL_EXT_swap_control")) {
322 wgl_swap_interval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
323 }
325 /* OpenGL extensions */
326 if(!(extstr = (const char*)glGetString(GL_EXTENSIONS))) {
327 fprintf(stderr, "failed to retrieve GL extensions string\n");
328 return -1;
329 }
330 /* proceed to ignore the extensions string and just attempt to load entry points,
331 * because we want to use the GL2.0 style of the API, instead of the clunkier ARB one
332 */
333 if(!(gl_create_program = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))) {
334 fprintf(stderr, "failed to find the OpenGL shader API entry points\n");
335 return -1;
336 }
337 /* assume everything else is there if glCreateProgram is there */
338 gl_delete_program = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
339 gl_create_shader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
340 gl_delete_shader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
341 gl_shader_source = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
342 gl_compile_shader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
343 gl_get_shaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
344 gl_get_shader_info_log = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
345 gl_attach_shader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
346 gl_link_program = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
347 gl_get_programiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
348 gl_get_program_info_log = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
349 gl_use_program = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
350 gl_get_uniform_location = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
351 gl_uniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
352 gl_uniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f");
353 gl_uniform_matrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv");
355 if(!(gl_active_texture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture"))) {
356 fprintf(stderr, "failed to find the multitexturing entry points\n");
357 return -1;
358 }
360 return 0;
361 }
363 static void calc_image_proj(float img_aspect, float *xform)
364 {
365 static const float ident[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
366 float vpscale;
367 float aspect = (float)scr_width / (float)scr_height;
369 memcpy(xform, ident, sizeof ident);
371 if(fit_mode != FIT_STRETCH) {
372 if(aspect > img_aspect) {
373 vpscale = xform[0] = img_aspect / aspect;
374 xform[5] = 1.0f;
375 } else {
376 vpscale = xform[5] = aspect / img_aspect;
377 xform[0] = 1.0f;
378 }
380 if(fit_mode == FIT_CROP) {
381 float cropscale, maxpan, tx, ty;
383 cropscale = 1.0f / vpscale;
384 cropscale = 1.0f + (cropscale - 1.0f) * crop_zoom;
385 maxpan = cropscale - 1.0f;
387 xform[0] *= cropscale;
388 xform[5] *= cropscale;
390 if(aspect > img_aspect) {
391 tx = 0.0f;
392 ty = -crop_dir[1] * maxpan;
393 } else {
394 tx = -crop_dir[0] * maxpan;
395 ty = 0.0f;
396 }
398 xform[12] = tx;
399 xform[13] = ty;
400 } else {
401 xform[12] = xform[13] = 0.0f;
402 }
403 }
404 }