void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) { EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, attachments = 0x%0.8p)", target, numAttachments, attachments); Context *context = GetValidGlobalContext(); if (context) { if (!context->getExtensions().discardFramebuffer) { context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return; } if (!ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments)) { return; } Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); ASSERT(framebuffer); // The specification isn't clear what should be done when the framebuffer isn't complete. // We leave it up to the framebuffer implementation to decide what to do. Error error = framebuffer->discard(numAttachments, attachments); if (error.isError()) { context->recordError(error); return; } } }
void SceneContext::render(Framebuffer& fb, const Rect& rect) { // Render all buffers // FIXME: Render all to pbuffer for later combining of them if (impl->use_cliprect) { fb.push_cliprect(impl->cliprect); impl->color.render(fb, rect); fb.pop_cliprect(); } else { impl->color.render(fb, rect); } #if 0 { // lightmap support impl->light.render(impl->canvas.get_gc()); impl->canvas.sync_surface(); //impl->lightmap.set_blend_func(blend_src_alpha, blend_one); impl->lightmap.set_blend_func(blend_dest_color, blend_zero); //GL_DST_COLOR, GL_ZERO impl->lightmap.set_scale(SCALE_FACTOR, SCALE_FACTOR); impl->lightmap.draw(); impl->canvas.get_gc()->clear(); } #endif impl->highlight.render(fb, rect); }
void Context::releaseSurface() { Framebuffer *defaultFBO = mFramebufferMap[0]; defaultFBO->resetAttachment(GL_BACK); defaultFBO->resetAttachment(GL_DEPTH); defaultFBO->resetAttachment(GL_STENCIL); }
ImageWrapper& ImageWrapper::operator=(const ImageWrapper& rhs) { clear(); if (rhs.m_source == NONE) { return *this; } else if(rhs.getFbo()) { // Copy the FBO m_source = FBO; Framebuffer* rhsFBO = rhs.getFbo(); m_fbo = std::make_shared<Framebuffer>(rhsFBO->size()); Framebuffer::blitFramebuffer(*m_fbo, *rhsFBO); m_size = rhs.size(); } else { // Create an image m_source = IMAGE; m_image = std::make_shared<Image>(rhs.getImage().clone()); m_size = rhs.size(); } return *this; }
void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data) { EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", x, y, width, height, format, type, bufSize, data); Context *context = GetValidGlobalContext(); if (context) { if (width < 0 || height < 0 || bufSize < 0) { context->recordError(Error(GL_INVALID_VALUE)); return; } if (!ValidateReadPixelsParameters(context, x, y, width, height, format, type, &bufSize, data)) { return; } Framebuffer *framebufferObject = context->getState().getReadFramebuffer(); ASSERT(framebufferObject); Rectangle area(x, y, width, height); Error error = framebufferObject->readPixels(context, area, format, type, data); if (error.isError()) { context->recordError(error); return; } } }
static void make_fb() { // tcol is a 2D RGB texsize x texsize texture // RGB is a constant that represents 8-bit RGB texture // See the definition of TexFormat enum in texture.h for other values allowed. // Stencil may require new hardware/drivers to work properly. tcol = new Texture(RGB,texsize,texsize); // tdepth is a depth texture, i.e. it stores depth values as the values of texels. tdepth = new Texture(Depth,texsize,texsize); // allocate new Framebuffer fb = new Framebuffer; // attach color and depth textures to it; the tcol texture will play the role of color // buffer and tdepth - of the depth buffer. fb->attachColor(tcol); fb->attachDepth(tdepth); // Print out the status of the frame buffer. In particular, if the textures are of // wrong type/format, the framebuffer will not be `complete', i.e. suitable for // rendering into it. If this is the case, you should get a message complaining // about it in the terminal. For example, it is wrong to use a color texture as // the depth texture or the other way around. The restrictions are mostly common // sense. See specification for more details. fb->printLog(); }
void State::detachRenderbuffer(GLuint renderbuffer) { // [OpenGL ES 2.0.24] section 4.4 page 109: // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer // had been executed with the target RENDERBUFFER and name of zero. if (mRenderbuffer.id() == renderbuffer) { mRenderbuffer.set(NULL); } // [OpenGL ES 2.0.24] section 4.4 page 111: // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment // point to which this image was attached in the currently bound framebuffer. Framebuffer *readFramebuffer = mReadFramebuffer; Framebuffer *drawFramebuffer = mDrawFramebuffer; if (readFramebuffer) { readFramebuffer->detachRenderbuffer(renderbuffer); } if (drawFramebuffer && drawFramebuffer != readFramebuffer) { drawFramebuffer->detachRenderbuffer(renderbuffer); } }
void Renderbuffer::blit(Framebuffer& target_fbo) { blit(target_fbo, 0, 0, m_width, m_height, 0, 0, target_fbo.get_width(), target_fbo.get_height()); }
void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); Context *context = GetValidGlobalContext(); if (context) { if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter, true)) { return; } Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); ASSERT(readFramebuffer); Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); ASSERT(drawFramebuffer); Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); Error error = drawFramebuffer->blit(context->getState(), srcArea, dstArea, mask, filter, readFramebuffer); if (error.isError()) { context->recordError(error); return; } } }
void DrawingContext::render(Framebuffer& fb, const Rect& parent_rect) { Rect this_rect(Math::max(rect.left + parent_rect.left, parent_rect.left), Math::max(rect.top + parent_rect.top, parent_rect.top), Math::min(rect.right + parent_rect.left, parent_rect.right), Math::min(rect.bottom + parent_rect.top, parent_rect.bottom)); if (do_clipping) fb.push_cliprect(this_rect); std::stable_sort(drawingrequests.begin(), drawingrequests.end(), DrawingRequestsSorter()); if (0) { std::cout << "<<<<<<<<<<<<<<" << std::endl; for(DrawingRequests::iterator i = drawingrequests.begin(); i != drawingrequests.end(); ++i) std::cout << (*i)->get_z_pos() << std::endl; std::cout << ">>>>>>>>>>>>>>" << std::endl; } for(DrawingRequests::iterator i = drawingrequests.begin(); i != drawingrequests.end(); ++i) { //std::cout << this << ": " << (*i)->get_z_pos() << std::endl; (*i)->render(fb, this_rect); // FIXME: Should we clip size against parent rect? } if (do_clipping) fb.pop_cliprect(); }
bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) { if (!context->getQueryParameterInfo(pname, nativeType, numParams)) { return gl::error(GL_INVALID_ENUM, false); } if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) { unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); if (colorAttachment >= context->getMaximumRenderTargets()) { return gl::error(GL_INVALID_OPERATION, false); } } switch (pname) { case GL_TEXTURE_BINDING_2D: case GL_TEXTURE_BINDING_CUBE_MAP: case GL_TEXTURE_BINDING_3D: case GL_TEXTURE_BINDING_2D_ARRAY: if (context->getActiveSampler() >= context->getMaximumCombinedTextureImageUnits()) { return gl::error(GL_INVALID_OPERATION, false); } break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: case GL_IMPLEMENTATION_COLOR_READ_FORMAT: { Framebuffer *framebuffer = context->getReadFramebuffer(); ASSERT(framebuffer); if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) { return gl::error(GL_INVALID_OPERATION, false); } Renderbuffer *renderbuffer = framebuffer->getReadColorbuffer(); if (!renderbuffer) { return gl::error(GL_INVALID_OPERATION, false); } } break; default: break; } // pname is valid, but there are no parameters to return if (numParams == 0) { return false; } return true; }
void render(Framebuffer& fb) { if (m_push) { fb.push_cliprect(m_rect); } else { fb.pop_cliprect(); } }
void Renderer::render (Framebuffer& buf, size_t) { const auto& camera = m_scene.camera (); for (size_t x = 0; x < buf.width (); ++ x) { for (size_t y = 0; y < buf.height (); ++ y) { const auto dx = rng () - 0.5; const auto dy = rng () - 0.5; const auto ray = camera.spawnRay (x + dx, y + dy); buf.addColour (x, y, render (ray)); } } }
inline void storeFramebuffer(int resultIndex, const FilePath& pngDir, const FilePath& exrDir, const FilePath& baseName, float gamma, const Framebuffer& framebuffer) { // Create output directories in case they don't exist createDirectory(pngDir.str()); createDirectory(exrDir.str()); // Path of primary output image files FilePath pngFile = pngDir + baseName.addExt(".png"); FilePath exrFile = exrDir + baseName.addExt(".exr"); // Make a copy of the image Image copy = framebuffer.getChannel(0); // Store the EXR image "as is" storeEXRImage(exrFile.str(), copy); // Post-process copy of image and store PNG file copy.flipY(); copy.divideByAlpha(); copy.applyGamma(gamma); storeImage(pngFile.str(), copy); // Store complete framebuffer as a single EXR multi layer image auto exrFramebufferFilePath = exrDir + baseName.addExt(".bnzframebuffer.exr"); storeEXRFramebuffer(exrFramebufferFilePath.str(), framebuffer); // Store complete framebuffer as PNG indivual files in a dediacted subdirectory auto pngFramebufferDirPath = pngDir + "framebuffers/"; createDirectory(pngFramebufferDirPath.str()); if(resultIndex >= 0) { pngFramebufferDirPath = pngFramebufferDirPath + toString3(resultIndex); // Split different results of the same batch in different subdirectories } createDirectory(pngFramebufferDirPath.str()); // Store each channel of the framebuffer for(auto i = 0u; i < framebuffer.getChannelCount(); ++i) { auto name = framebuffer.getChannelName(i); // Prefix by the index of the channel FilePath pngFile = pngFramebufferDirPath + FilePath(toString3(i)).addExt("_" + name + ".png"); auto copy = framebuffer.getChannel(i); copy.flipY(); copy.divideByAlpha(); copy.applyGamma(gamma); storeImage(pngFile.str(), copy); } }
bool set() { if(!color || !depth) return false; if(!fakeTargetActive || !SHARE_BUFFERS) { fakeTargetActive = true; // FIXME? fbo->activate(); if(!fbo->validate()) { fbo->disable(); return false; } /* not required because opengl can't clear just part of buffer // unless using scissor // which is a horrible hack D3DRECT rc = { 0 }; rc.x2 = BUFFER_WIDTH * 2; rc.y2 = BUFFER_HEIGHT * 2; */ // because on opengl scissor test affects clear // but on direct3d not glDisable(GL_SCISSOR_TEST); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); // Black, no alpha test //hr = device.Clear(1, &rc, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xFF000000, 1.0f, 0); // Black, alpha test //hr = device.Clear(1, &rc, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, 1.0f, 0); // White, no alpha test //hr = device.Clear(1, &rc, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xFFFFFFFF, 1.0f, 0); // White, alpha tested (Normal) glClearColor(1.0f, 1.0f, 1.0f, 0.0f); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } glViewport(pos.x * BUFFER_WIDTH, pos.y * BUFFER_HEIGHT, BUFFER_WIDTH, BUFFER_HEIGHT); return true; }
int main(void) { Framebuffer fb; fb.drawRectangle(2,2,125,61); fb.drawRectangle(6,6,12,12,1); fb.show(); // Invert uses direct hardware commands // So no need to send the framebuffer again // => no need to fb.show(); fb.invert(1); return 0; }
void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs) { EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); Context *context = GetValidGlobalContext(); if (context) { if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers) { context->recordError(Error(GL_INVALID_VALUE)); return; } ASSERT(context->getState().getDrawFramebuffer()); if (context->getState().getDrawFramebuffer()->id() == 0) { if (n != 1) { context->recordError(Error(GL_INVALID_OPERATION)); return; } if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) { context->recordError(Error(GL_INVALID_OPERATION)); return; } } else { for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) { const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment) { context->recordError(Error(GL_INVALID_OPERATION)); return; } } } Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); ASSERT(framebuffer); framebuffer->setDrawBuffers(n, bufs); } }
void Update(double time) { gl.Viewport(size, size); fbo.Bind(Framebuffer::Target::Draw); Framebuffer::AttachColorTexture( Framebuffer::Target::Draw, 1, holder.CurrentHeightMap(), 0 ); Context::ColorBuffer draw_buffs[2] = { FramebufferColorAttachment::_0, FramebufferColorAttachment::_1 }; gl.DrawBuffers(draw_buffs); prog.Use(); prog.hmap_1.Set(holder.HMapUnit1()); prog.hmap_2.Set(holder.HMapUnit2()); prog.time.Set(time); screen.Use(); gl.Disable(Capability::DepthTest); screen.Draw(); gl.Enable(Capability::DepthTest); holder.Swap(); }
void Renderbuffer::blit(Framebuffer& target_fbo, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, GLbitfield mask, GLenum filter) { // mask // The bitwise OR of the flags indicating which buffers are to be // copied. The allowed flags are GL_COLOR_BUFFER_BIT, // GL_DEPTH_BUFFER_BIT and GL_STENCIL_BUFFER_BIT. // filter // Specifies the interpolation to be applied if the image is // stretched. Must be GL_NEAREST or GL_LINEAR. // http://www.opengl.org/registry/specs/EXT/framebuffer_blit.txt // http://www.opengl.org/wiki/GLAPI/glBlitFramebuffer assert_gl("enter: BlitFramebuffer"); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target_fbo.get_id()); assert_gl("enter: BlitFramebuffer1"); glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); glReadBuffer(GL_COLOR_ATTACHMENT0); assert_gl("enter: BlitFramebuffer2"); glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); assert_gl("done: BlitFramebuffer"); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); }
void ImageWrapper::setFbo(const Framebuffer& fbo) { clear(); m_fbo = std::make_shared<Framebuffer>(fbo); m_source = FBO; m_size = fbo.size(); }
void RenderFrameShadowMap( const Vec3f& light_position, const Mat4f& torus_matrix, const Mat4f& light_proj_matrix ) { frame_shadow_fbo.Bind(Framebuffer::Target::Draw); gl.Viewport(shadow_tex_side, shadow_tex_side); gl.ClearDepthBuffer(1.0f); gl.CullFace(Face::Back); transf_prog.camera_matrix.Set(light_proj_matrix); transf_prog.camera_position.Set(light_position); // Render the torus' frame transf_prog.model_matrix.Set(torus_matrix); shadow_pp.Bind(); gl.Enable(Capability::PolygonOffsetFill); torus.Draw( [](GLuint phase) -> bool { return (phase <= 3); } ); gl.Disable(Capability::PolygonOffsetFill); }
void removeLabel(string province, string population){ // Remove old province char* provinsi_label = new char[province.size() + 1]; std::copy(province.begin(), province.end(), provinsi_label); provinsi_label[province.size()] = '\0'; // don't forget the terminating 0 framebuffer.DrawString(provinsi_label, 10, framebuffer.height - 40, 1, DEFAULT); delete[] provinsi_label; char* populasi_label = new char[population.size() + 1]; std::copy(population.begin(), population.end(), populasi_label); populasi_label[population.size()] = '\0'; // don't forget the terminating 0 framebuffer.DrawString(populasi_label, 10, framebuffer.height - 25, 1, DEFAULT); delete[] populasi_label; }
void RenderGlassShadowMap( const Vec3f& light_position, const Vec3f& torus_center, const Mat4f& torus_matrix, const Mat4f& light_proj_matrix ) { glass_shadow_fbo.Bind(Framebuffer::Target::Draw); gl.Viewport(shadow_tex_side, shadow_tex_side); const GLfloat clear_color[4] = {1.0f, 1.0f, 1.0f, 0.0f}; gl.ClearColorBuffer(0, clear_color); transf_prog.camera_matrix.Set(light_proj_matrix); transf_prog.camera_position.Set(light_position); transf_prog.light_proj_matrix.Set(light_proj_matrix); transf_prog.light_position.Set(light_position); // Render the torus' frame transf_prog.model_matrix.Set(torus_matrix); // setup the view clipping plane Planef clip_plane = Planef::FromPointAndNormal( torus_center, Normalized(light_position-torus_center) ); transf_prog.clip_plane.Set(clip_plane.Equation()); light_pp.Bind(); light_prog.color = Vec3f(0.6f, 0.4f, 0.1f); gl.Disable(Capability::DepthTest); gl.Enable(Functionality::ClipDistance, 0); gl.Enable(Capability::Blend); for(int c=0; c!=2; ++c) { transf_prog.clip_direction.Set((c == 0)?1:-1); for(int p=3; p>=0; --p) { if(p % 2 == 0) gl.CullFace(Face::Front); else gl.CullFace(Face::Back); torus.Draw( [&p](GLuint phase) -> bool { if(p == 0 || p == 3) { return (phase == 4); } else return (phase > 4); } ); } } gl.Disable(Capability::Blend); gl.Disable(Functionality::ClipDistance, 0); gl.Enable(Capability::DepthTest); }
void Update(void) { gl.Viewport(size, size); fbo.Bind(Framebuffer::Target::Draw); Framebuffer::AttachColorTexture( Framebuffer::Target::Draw, 1, holder.CurrentHeightMap(), 0 ); Context::ColorBuffer draw_buffs[2] = { FramebufferColorAttachment::_0, FramebufferColorAttachment::_1 }; gl.DrawBuffers(draw_buffs); prog.Use(); prog.tex_1.Set(holder.TexUnit1()); prog.tex_2.Set(holder.TexUnit2()); prog.new_drop.Set(std::rand()%size, std::rand()%size); vao.Bind(); gl.DrawArrays(PrimitiveType::Points, 0, 1); holder.Swap(); }
void Context::makeCurrent(egl::Surface *surface) { ASSERT(surface != nullptr); if (!mHasBeenCurrent) { initRendererString(); initExtensionStrings(); mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); mHasBeenCurrent = true; } // Update default framebuffer Framebuffer *defaultFBO = mFramebufferMap[0]; GLenum drawBufferState = GL_BACK; defaultFBO->setDrawBuffers(1, &drawBufferState); defaultFBO->setReadBuffer(GL_BACK); const FramebufferAttachment *backAttachment = defaultFBO->getAttachment(GL_BACK); if (backAttachment && backAttachment->getSurface() == surface) { // FBO already initialized to the surface. return; } const egl::Config *config = surface->getConfig(); defaultFBO->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex::MakeInvalid(), surface); if (config->depthSize > 0) { defaultFBO->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex::MakeInvalid(), surface); } else { defaultFBO->resetAttachment(GL_DEPTH); } if (config->stencilSize > 0) { defaultFBO->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex::MakeInvalid(), surface); } else { defaultFBO->resetAttachment(GL_STENCIL); } }
void render(Framebuffer& fb, const Rect& rect) { if (filled) { fb.fill_rect(Rect(Vector2i(d_rect.left + rect.left, d_rect.top + rect.top), d_rect.get_size()), color); } else { fb.draw_rect(Rect(Vector2i(d_rect.left + rect.left, d_rect.top + rect.top), d_rect.get_size()), color); } }
Framebuffer *RegisterFramebuffer(IO::Framebuffer *source) { Framebuffer *framebuffer = _framebufferMap->GetObjectForKey<Framebuffer>(source); if(framebuffer) return framebuffer; size_t index = (_framebufferCounter ++); framebuffer = Framebuffer::Alloc()->Init(index, source); if(framebuffer) { _framebufferMap->SetObjectForKey(framebuffer, source); framebuffer->Release(); } return framebuffer; }
void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs) { EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); Context *context = GetValidGlobalContext(); if (context) { if (!ValidateDrawBuffers(context, n, bufs)) { return; } Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); ASSERT(framebuffer); framebuffer->setDrawBuffers(n, bufs); } }
void SpriteImpl::render(int x, int y, Framebuffer& fb) { fb.draw_surface(framebuffer_surface, Rect(frame_pos + Vector2i(frame_size.width * (frame%array.width), frame_size.height * (frame/array.width)), frame_size), Vector2i(x - offset.x, y - offset.y)); }
void Render(double time) { auto camera = CamMatrixf::Roll(Degrees(SineWave(time / 11.0)*7+SineWave(time/13.0)*5))* CamMatrixf::Orbiting( Vec3f(), 40.0f, Degrees(SineWave(time / 11.0)*10+CosineWave(time/19.0)*10-90), Degrees(SineWave(time / 17.0)*10+SineWave(time/13.0)*10) ); auto mm_identity = ModelMatrixf(); auto mm_rotation = ModelMatrixf::RotationZ(FullCircles(time / 7.0)); Uniform<Mat4f>* model_matrix = nullptr; GLuint drawing_fan = fan_index; auto drawing_driver = [ &model_matrix, &mm_identity, &mm_rotation, &drawing_fan ](GLuint phase) -> bool { if(phase == drawing_fan) model_matrix->Set(mm_rotation); else model_matrix->Set(mm_identity); return true; }; // render the light mask light_fbo.Bind(Framebuffer::Target::Draw); gl.Clear().ColorBuffer().DepthBuffer(); mask_vao.Bind(); mask_prog.Use(); mask_prog.camera_matrix.Set(camera); model_matrix = &mask_prog.model_matrix; meshes.Draw(drawing_driver); // render the final image DefaultFramebuffer().Bind(Framebuffer::Target::Draw); gl.Clear().ColorBuffer().DepthBuffer(); draw_vao.Bind(); draw_prog.Use(); Vec4f lsp = projection * camera * Vec4f(light_position, 1.0); draw_prog.light_screen_pos = lsp.xyz()/lsp.w(); draw_prog.camera_matrix.Set(camera); model_matrix = &draw_prog.model_matrix; meshes.Draw(drawing_driver); }