byte fb_init_int(uint *fbo, uint *fbtex, uint *rbo, byte linear) { uint status; glGenFramebuffers(1, fbo); glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glGenTextures(1, fbtex); glBindTexture(GL_TEXTURE_2D, *fbtex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *fbtex, 0); if(rbo) { glGenRenderbuffers(1, rbo); glBindRenderbuffer(GL_RENDERBUFFER, *rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 16, 16); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *rbo); } if((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { loge(LOG_GFX, STR_FBO_INCOMPLETE, *fbo, status); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteTextures(1, fbtex); glDeleteFramebuffers(1, fbo); if(rbo) { glDeleteRenderbuffers(1, rbo); } return 0; } glBindFramebuffer(GL_FRAMEBUFFER, 0); gdr.fb_mem += 16 * 16 * 4; gdr.fb_peak = gdr.fb_mem > gdr.fb_peak ? gdr.fb_mem : gdr.fb_peak; return 1; } byte fb_init_sys(uint *fbo, uint *fbtex) { if(fb_init_int(fbo, fbtex, NULL, 0)) { logd(LOG_GFX, STR_FBO_ADDED, *fbo, *fbtex); gdr.fb_loaded += 1; return 1; } return 0; } fbo_t *fb_init(uint *fbo, uint *fbtex, uint *rbo, window_t *resize, byte linear) { fbo_t *bind; if(!fb_init_int(fbo, fbtex, rbo, linear)) return NULL; sys_assert(bind = (fbo_t*)tbl_push(&gdr.framebufs)); bind->fbo = fbo; bind->tex = fbtex; bind->rbo = rbo; bind->resize = resize; bind->linear = linear; bind->xsize = 0; bind->ysize = 0; gdr.fb_loaded += 1; if(rbo) logd(LOG_GFX, STR_FBO_ADDED_RBO, *fbo, *fbtex, *rbo); else logd(LOG_GFX, STR_FBO_ADDED, *fbo, *fbtex); return bind; } void fb_resize_int(uint fbtex, int px, int py, int x, int y) { gdr.fb_mem -= px * py * 4; glBindTexture(GL_TEXTURE_2D, fbtex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); gdr.fb_mem += x * y * 4; gdr.fb_peak = gdr.fb_mem > gdr.fb_peak ? gdr.fb_mem : gdr.fb_peak; } byte fb_resize(fbo_t *buf, window_t *resize) { if(!(buf->resize) || (buf->resize != resize)) return 0; glBindTexture(GL_TEXTURE_2D, *(buf->tex)); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resize->fb_x, resize->fb_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if(buf->rbo) { glBindRenderbuffer(GL_RENDERBUFFER, *(buf->rbo)); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, resize->fb_x, resize->fb_y); } gdr.fb_mem -= buf->xsize * buf->ysize * 4; gdr.fb_mem += (buf->xsize = resize->fb_x) * (buf->ysize = resize->fb_y) * 4; gdr.fb_peak = gdr.fb_mem > gdr.fb_peak ? gdr.fb_mem : gdr.fb_peak; return 1; } int fb_reconfig(window_t *resize) { int done = 0; ulong iter = 0; fbo_t *buf; while(buf = tbl_iter(&gdr.framebufs, &iter)) { done += (int)fb_resize(buf, resize); } // logd(LOG_GFX, STR_FBO_RESIZE, done); return done; } void fb_size_int(uint tex, uint rbo, int x, int y) { glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if(rbo) { glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, x, y); } } byte fb_size(fbo_t *buf, int x, int y) { fb_size_int(*(buf->tex), buf->rbo ? *(buf->rbo) : 0, x, y); gdr.fb_mem -= buf->xsize * buf->ysize * 4; gdr.fb_mem += (buf->xsize = x) * (buf->ysize = y) * 4; gdr.fb_peak = gdr.fb_mem > gdr.fb_peak ? gdr.fb_mem : gdr.fb_peak; } void fb_delete(uint *fbo, uint *fbtex) { if(*fbo) { glDeleteTextures(1, fbtex); glDeleteFramebuffers(1, fbo); logd(LOG_GFX, STR_FBO_DELETED, *fbo, *fbtex); *fbo = 0; *fbtex = 0; gdr.fb_loaded -= 1; } } byte fb_unload(fbo_t *buf) { if(!(*(buf->fbo))) { return 0; } glDeleteTextures(1, buf->tex); glDeleteFramebuffers(1, buf->fbo); if(buf->rbo) { glDeleteRenderbuffers(1, buf->rbo); logd(LOG_GFX, STR_FBO_DELETED_RBO, *(buf->fbo), *(buf->tex), *(buf->rbo)); *(buf->rbo) = 0; } else { logd(LOG_GFX, STR_FBO_DELETED, *(buf->fbo), *(buf->tex)); } *(buf->fbo) = 0; *(buf->tex) = 0; gdr.fb_loaded -= 1; return 1; } void fb_remove(fbo_t *buf) { if(fb_unload(buf)) { tbl_pop(&gdr.framebufs, buf); } } int fb_clear() { return tbl_clear_func(&gdr.framebufs, (clear_func*)fb_unload); }