struct glpal_ctx *pal_init_glsl(GLboolean float_packed_pixels) {CHECK_GL_ERR; printf("Compiling pallet shader:\n"); GLint prog = 0; if(!float_packed_pixels) prog = compile_program(vtx_shader, pal_frag_shader); else prog = compile_program(vtx_shader, pal_frag_mix); if(!prog) return NULL; glUseProgramObjectARB(prog); glUniform1iARB(glGetUniformLocationARB(prog, "src"), 0); glUniform1iARB(glGetUniformLocationARB(prog, "pal"), 1); glBindAttribLocationARB(prog, 0, "vertex"); glUseProgramObjectARB(0); printf("Pallet shader compiled\n"); struct priv_ctx *priv = malloc(sizeof(*priv)); priv->pubctx.render = render; priv->pubctx.step = pal_step; priv->pubctx.start_switch = start_switch; priv->pubctx.changing = changing; priv->pal = pal_ctx_new(0); priv->prog = prog; priv->cnt = 0; glGenTextures(2, &priv->tex); glBindTexture(GL_TEXTURE_1D, priv->tex[0]); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, pal_ctx_get_active(priv->pal)); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_1D, priv->tex[1]); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, pal_ctx_get_active(priv->pal)); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_1D, 0); CHECK_GL_ERR; return (struct glpal_ctx *)priv; }
static void render(struct glpal_ctx *ctx, GLuint draw_tex) {DEBUG_CHECK_GL_ERR; static const float verts[] = { 0, 0 , -1, -1, 1, 0 , 1, -1, 0, 1 , -1, 1, 1, 1 , 1, 1 }; struct priv_ctx *priv = (struct priv_ctx *)ctx; glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glUseProgramObjectARB(priv->prog); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, draw_tex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_1D, priv->tex[priv->cnt]); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, pal_ctx_get_active(priv->pal)); priv->cnt = (priv->cnt+1)%2; glBindTexture(GL_TEXTURE_1D, priv->tex[priv->cnt]); glEnableVertexAttribArrayARB(0); glVertexAttribPointerARB(0, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, verts); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glUseProgramObjectARB(0); glDisableVertexAttribArrayARB(0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_1D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glPopClientAttrib(); DEBUG_CHECK_GL_ERR; }
// TODO: need a "now" take it as an argument void simple_soft_render(struct simple_soft_ctx *ctx, Pixbuf *out, int64_t now, int64_t tick0) { ctx->m = (ctx->m+1)&0x1; if(tick0+(ctx->maxfrms*1000)/ctx->maxsrc_rate - now > 1000/ctx->maxsrc_rate) { maxsrc_update(ctx->maxsrc, ctx->prev_buf, ctx->nr_samp/2); ctx->maxfrms++; } if(!ctx->rational_julia) { ctx->map_func(ctx->map_surf[ctx->m], ctx->map_surf[(ctx->m+1)&0x1], ctx->im_w, ctx->im_h, ctx->pd); maxblend(ctx->map_surf[ctx->m], maxsrc_get(ctx->maxsrc), ctx->im_w, ctx->im_h); } if(ctx->rational_julia) { maxblend(ctx->map_surf[(ctx->m+1)&0x1], maxsrc_get(ctx->maxsrc), ctx->im_w, ctx->im_h); ctx->map_func(ctx->map_surf[ctx->m], ctx->map_surf[(ctx->m+1)&0x1], ctx->im_w, ctx->im_h, ctx->pd); } // rather than just audio clock if((now - ctx->lastpalstep)*256/1024 >= 1) { // want pallet switch to take ~2 seconds pal_ctx_step(ctx->pal_ctx, IMIN((now - ctx->lastpalstep)*256/1024, 32)); ctx->lastpalstep = now; } pallet_blit_Pixbuf(out, ctx->map_surf[ctx->m], ctx->im_w, ctx->im_h, pal_ctx_get_active(ctx->pal_ctx)); //pallet_blit_Pixbuf(out, maxsrc_get(ctx->maxsrc), ctx->im_w, ctx->im_h, pal_ctx_get_active(ctx->pal_ctx)); int newbeat = beat_ctx_count(ctx->beat); if(newbeat != ctx->beats) pal_ctx_start_switch(ctx->pal_ctx, newbeat); if(newbeat != ctx->beats && now - ctx->last_beat_time > 1000) { ctx->last_beat_time = now; update_points(ctx->pd, (now - tick0), 1); } else update_points(ctx->pd, (now - tick0), 0); ctx->beats = newbeat; }
int main(int argc, char **argv) { optproc(argc, argv, &opts); if(audio_init(&opts) < 0) exit(1); SDL_Surface *screen = sdl_setup(&opts, IM_SIZE); im_w = screen->w - screen->w%16; im_h = screen->h - screen->h%16; printf("running with %dx%d bufs\n", im_w, im_h); if(strcmp(opts.map_name, "rational") == 0) { map_func = soft_map_rational_interp; if(opts.quality >= 1) map_func = soft_map_rational; } else if(strcmp(opts.map_name, "butterfly") == 0) { // map_func = soft_map_butterfly_interp; // if(opts.quality >= 1) map_func = soft_map_butterfly; } else if(opts.quality >= 1) map_func = soft_map; maxsrc = maxsrc_new(im_w, im_h); struct pal_ctx *pal_ctx = pal_ctx_new(screen->format->BitsPerPixel == 8); uint16_t *map_surf[3]; void *map_surf_mem = aligned_alloc(64, 3 * im_w * im_h * sizeof(uint16_t)); for(int i=0; i<3; i++) map_surf[i] = map_surf_mem + i * im_w * im_h * sizeof(uint16_t); memset(map_surf_mem, 0, 3 * im_w * im_h * sizeof(uint16_t)); tribuf *map_tb = tribuf_new((void **)map_surf, 1); int beats = 0; int frmcnt = 0; int lastdrawn=0; SDL_Thread *map_thread = SDL_CreateThread((void *)&run_map_thread, map_tb); SDL_Delay(100); uint32_t frametimes[FPS_HIST_LEN]; for(int i=1; i<FPS_HIST_LEN; i++) frametimes[i] = 0; uint32_t totframetime = frametimes[0] = MIN(1000/opts.draw_rate, 1); Uint32 tick0 = SDL_GetTicks(); Uint32 lastpalstep, lastupdate, fps_oldtime; fps_oldtime = lastpalstep = lastupdate = tick0; SDL_Event event; while(SDL_PollEvent(&event) >= 0) { if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { break; } else if(tribuf_check_fresh(map_tb)) { Uint32 now = SDL_GetTicks(); if(now - lastpalstep >= 2048/256) { // want pallet switch to take ~2 seconds pal_ctx_step(pal_ctx, IMIN((now - lastpalstep)*256/2048, 64)); lastpalstep = now; } pallet_blit_SDL(screen, tribuf_get_read(map_tb), im_w, im_h, pal_ctx_get_active(pal_ctx)); tribuf_finish_read(map_tb); char buf[64]; sprintf(buf,"%6.1f FPS %6.1f UPS %6.1f", map_fps, FPS_HIST_LEN*1000.0f/totframetime, maxfrms*1000.0f/(now-tick0)); DrawText(screen, buf); SDL_Flip(screen); int newbeat = beat_get_count(); if(newbeat != beats) pal_ctx_start_switch(pal_ctx, newbeat); beats = newbeat; now = SDL_GetTicks(); int delay = (tick0 + frmcnt*1000/opts.draw_rate) - now; if(delay > 0) SDL_Delay(delay); totframetime -= frametimes[frmcnt%FPS_HIST_LEN]; totframetime += (frametimes[frmcnt%FPS_HIST_LEN] = now - fps_oldtime); fps_oldtime = now; frmcnt++; } else { SDL_Delay(1000/opts.draw_rate/2); // wait half a frame and hope we get a new buffer } } running = 0; int status; SDL_WaitThread(map_thread, &status); aligned_free(map_surf_mem); audio_shutdown(); SDL_Quit(); return 0; }