+ if (phases.size() > 1) {
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ check_error();
+ }
+
+ for (unsigned phase = 0; phase < phases.size(); ++phase) {
+ // Set up inputs and outputs for this phase.
+ if (phase == 0) {
+ // First phase reads from the input texture (which is already bound).
+ } else {
+ glBindTexture(GL_TEXTURE_2D, temp_textures[(phase + 1) % 2]);
+ check_error();
+ }
+ if (phases[phase].input_needs_mipmaps) {
+ glGenerateMipmap(GL_TEXTURE_2D);
+ check_error();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ check_error();
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ check_error();
+ }
+
+ if (phase == phases.size() - 1) {
+ // Last phase goes directly to the screen.
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ check_error();
+ } else {
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ temp_textures[phase % 2],
+ 0);
+ }
+
+ // We have baked an upside-down transform into the quad coordinates,
+ // since the typical graphics program will have the origin at the upper-left,
+ // while OpenGL uses lower-left. In the next ones, however, the origin
+ // is all right, and we need to reverse that.
+ if (phase == 1) {
+ glTranslatef(0.0f, 1.0f, 0.0f);
+ glScalef(1.0f, -1.0f, 1.0f);
+ }