winlivebg_test1

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