glGetIntegerv(GL_MAX_CLIP_PLANES, reinterpret_cast<int *>(&max_clip_planes));
glGetIntegerv(GL_MAX_SAMPLES, reinterpret_cast<int *>(&max_samples));
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<int *>(&uniform_buffer_alignment));
+ glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, reinterpret_cast<int *>(&max_color_attachments));
}
const Limits &Limits::get_global()
unsigned max_clip_planes;
unsigned max_samples;
unsigned uniform_buffer_alignment;
+ unsigned max_color_attachments;
Limits();
height = view[3];
}
-Framebuffer::Framebuffer():
- width(0),
- height(0),
- status(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
- dirty(0)
+Framebuffer::Framebuffer()
+{
+ init();
+}
+
+Framebuffer::Framebuffer(FrameAttachment fa)
+{
+ init();
+ set_format(fa);
+}
+
+Framebuffer::Framebuffer(const FrameFormat &f)
+{
+ init();
+ set_format(f);
+}
+
+void Framebuffer::init()
{
static Require _req(EXT_framebuffer_object);
+ width = 0;
+ height = 0;
+ status = FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ dirty = 0;
+
if(ARB_direct_state_access)
glCreateFramebuffers(1, &id);
else
glDeleteFramebuffers(1, &id);
}
+void Framebuffer::set_format(const FrameFormat &fmt)
+{
+ if(!format.empty())
+ throw invalid_operation("Framebuffer::set_format");
+ if(fmt.empty())
+ throw invalid_argument("Framebuffer::set_format");
+
+ format = fmt;
+ attachments.resize(format.size());
+}
+
void Framebuffer::update() const
{
vector<GLenum> color_bufs;
- color_bufs.reserve(attachments.size());
- for(unsigned i=0; i<attachments.size(); ++i)
+ color_bufs.reserve(format.size());
+ unsigned i = 0;
+ for(const UInt16 *j=format.begin(); j!=format.end(); ++j, ++i)
{
- const Attachment &attch = attachments[i];
+ GLenum gl_attach_point = get_gl_attachment(static_cast<FrameAttachment>(*j));
if(dirty&(1<<i))
{
+ const Attachment &attch = attachments[i];
if(attch.tex)
{
GLenum type = attch.tex->get_target();
if(ARB_direct_state_access)
{
if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
- glNamedFramebufferTexture(id, attch.attachment, attch.tex->get_id(), attch.level);
+ glNamedFramebufferTexture(id, gl_attach_point, attch.tex->get_id(), attch.level);
else
- glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer);
+ glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer);
}
else if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE)
- glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level);
else if(attch.layer<0)
- glFramebufferTexture(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level);
+ glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level);
else if(type==GL_TEXTURE_2D_ARRAY)
- glFramebufferTextureLayer(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level, attch.layer);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer);
else if(type==GL_TEXTURE_3D)
- glFramebufferTexture3D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level, attch.layer);
+ glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level, attch.layer);
else if(type==GL_TEXTURE_CUBE_MAP)
- glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level);
}
else if(ARB_direct_state_access)
- glNamedFramebufferTexture(id, attch.attachment, 0, 0);
+ glNamedFramebufferTexture(id, gl_attach_point, 0, 0);
else
- glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, GL_TEXTURE_2D, 0, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
}
- if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
- color_bufs.push_back(attch.attachment);
+ if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
+ color_bufs.push_back(gl_attach_point);
}
if(color_bufs.size()>1)
}
break;
}
-}
-unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch)
-{
- for(unsigned i=0; i<attachments.size(); ++i)
- if(attachments[i].attachment==attch)
- return i;
- attachments.push_back(Attachment(attch));
- return attachments.size()-1;
}
-void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer)
+void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer, unsigned samples)
{
- if(!id)
+ if(format.empty() || !id)
throw invalid_operation("Framebuffer::attach");
- unsigned i = get_attachment_index(attch);
- attachments[i].set(tex, level, layer);
- dirty |= 1<<i;
- check_size();
+ if((format.get_samples()>1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples))
+ throw incompatible_data("Framebuffer::attach");
+
+ unsigned i = 0;
+ for(const UInt16 *j=format.begin(); j!=format.end(); ++j, ++i)
+ if(*j==attch)
+ {
+ attachments[i].set(tex, level, layer);
+ dirty |= 1<<i;
+ check_size();
+ return;
+ }
+
+ throw incompatible_data("Framebuffer::attach");
}
-void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level)
{
tex.allocate(level);
- set_attachment(attch, tex, level, 0);
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0);
}
-void Framebuffer::attach(FramebufferAttachment attch, Texture2DMultisample &tex)
+void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex)
{
- set_attachment(attch, tex, 0, 0);
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, 0, tex.get_samples());
}
-void Framebuffer::attach(FramebufferAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
{
tex.allocate(level);
- set_attachment(attch, tex, level, layer);
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0);
}
-void Framebuffer::attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
{
tex.allocate(level);
- set_attachment(attch, tex, level, TextureCube::get_face_index(face));
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, TextureCube::get_face_index(face), 0);
}
-void Framebuffer::attach_layered(FramebufferAttachment attch, Texture3D &tex, unsigned level)
+void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level)
{
static Require _req(ARB_geometry_shader4);
tex.allocate(level);
- set_attachment(attch, tex, level, -1);
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
}
-void Framebuffer::attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level)
+void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level)
{
static Require _req(ARB_geometry_shader4);
tex.allocate(level);
- set_attachment(attch, tex, level, -1);
+ set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
}
-void Framebuffer::detach(FramebufferAttachment attch)
+void Framebuffer::detach(FrameAttachment attch)
{
if(!id)
throw invalid_operation("Framebuffer::detach");
- unsigned i = get_attachment_index(attch);
- attachments[i].clear();
- dirty |= 1<<i;
- check_size();
+ int i = format.index(attch);
+ if(i>=0)
+ {
+ attachments[i].clear();
+ dirty |= 1<<i;
+ check_size();
+ }
}
void Framebuffer::resize(const WindowView &view)
}
-Framebuffer::Attachment::Attachment(FramebufferAttachment a):
- attachment(a),
+Framebuffer::Attachment::Attachment():
tex(0),
level(0),
layer(0)
#define MSP_GL_FRAMEBUFFER_H_
#include <vector>
+#include "frameformat.h"
#include "gl.h"
#include "texturecube.h"
#include <msp/gl/extensions/arb_geometry_shader4.h>
class Texture3D;
class WindowView;
-enum FramebufferAttachment
-{
- COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0,
- COLOR_ATTACHMENT1 = GL_COLOR_ATTACHMENT1,
- COLOR_ATTACHMENT2 = GL_COLOR_ATTACHMENT2,
- COLOR_ATTACHMENT3 = GL_COLOR_ATTACHMENT3,
- DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT,
- STENCIL_ATTACHMENT = GL_STENCIL_ATTACHMENT
-};
-
enum FramebufferStatus
{
FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
private:
struct Attachment
{
- FramebufferAttachment attachment;
Texture *tex;
unsigned level;
int layer;
- Attachment(FramebufferAttachment);
+ Attachment();
void set(Texture &, unsigned, int);
void clear();
};
unsigned id;
+ FrameFormat format;
std::vector<Attachment> attachments;
unsigned width;
unsigned height;
Framebuffer(unsigned);
public:
+ /** Creates an empty framebuffer. Format must be set before textures can
+ be attached. */
Framebuffer();
+
+ /** Creates a framebuffer and sets its format to a single attachment. */
+ Framebuffer(FrameAttachment);
+
+ /** Creates a framebuffer and sets its format. */
+ Framebuffer(const FrameFormat &);
+
+private:
+ void init();
+public:
~Framebuffer();
+ /** Sets the format of the framebuffer. Once the format is set, it can't
+ be changed. */
+ void set_format(const FrameFormat &);
+
+ const FrameFormat &get_format() const { return format; }
+
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
private:
void update() const;
void check_size();
- unsigned get_attachment_index(FramebufferAttachment);
- void set_attachment(FramebufferAttachment, Texture &, unsigned, int);
+ void set_attachment(FrameAttachment, Texture &, unsigned, int, unsigned);
public:
- void attach(FramebufferAttachment attch, Texture2D &tex, unsigned level = 0);
- void attach(FramebufferAttachment attch, Texture2DMultisample &tex);
- void attach(FramebufferAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0);
- void attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0);
- void attach_layered(FramebufferAttachment attch, Texture3D &tex, unsigned level = 0);
- void attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level = 0);
- void detach(FramebufferAttachment attch);
+
+ /** Attaches a texture to the framebuffer. Only the attachment point
+ portion of attch is considered; pixel format is ignored. The framebuffer
+ must have a format and the format of the texture must match that defined
+ in the framebuffer for this attachment point. */
+ void attach(FrameAttachment attch, Texture2D &tex, unsigned level = 0);
+
+ void attach(FrameAttachment attch, Texture2DMultisample &tex);
+ void attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0);
+ void attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0);
+ void attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level = 0);
+ void attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level = 0);
+ void detach(FrameAttachment attch);
void resize(const WindowView &);
--- /dev/null
+#include "deviceinfo.h"
+#include "error.h"
+#include "frameformat.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+FrameFormat::FrameFormat():
+ count(0),
+ samples(1)
+{ }
+
+FrameFormat::FrameFormat(FrameAttachment fa):
+ count(1),
+ samples(1)
+{
+ attachments[0] = fa;
+}
+
+FrameFormat FrameFormat::operator,(FrameAttachment fa) const
+{
+ if(count>=MAX_ATTACHMENTS)
+ throw invalid_operation("FrameFormat::operator,");
+
+ FrameFormat result = *this;
+ result.attachments[result.count++] = fa;
+
+ return result;
+}
+
+FrameFormat FrameFormat::operator,(PixelFormat pf) const
+{
+ if(!count)
+ throw invalid_operation("FrameFormat::operator,");
+
+ FrameFormat r = *this;
+ UInt16 &fa = r.attachments[r.count-1];
+ fa = make_typed_attachment(static_cast<FrameAttachment>(fa), pf);
+
+ return r;
+}
+
+FrameFormat FrameFormat::operator,(unsigned index) const
+{
+ if(!count)
+ throw invalid_operation("FrameFormat::operator,");
+
+ FrameFormat r = *this;
+ UInt16 &fa = r.attachments[r.count-1];
+ fa = make_indexed_attachment(static_cast<FrameAttachment>(fa), index);
+
+ return r;
+}
+
+FrameFormat &FrameFormat::set_samples(unsigned s)
+{
+ samples = s;
+ return *this;
+}
+
+int FrameFormat::index(FrameAttachment fa) const
+{
+ for(unsigned i=0; i<count; ++i)
+ if(get_attach_point(attachments[i])==get_attach_point(fa))
+ return i;
+ return -1;
+}
+
+
+FrameAttachment make_typed_attachment(FrameAttachment fa, PixelFormat pf)
+{
+ PixelComponents comp = get_components(pf);
+ if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+ {
+ if(comp!=DEPTH_COMPONENT)
+ throw invalid_argument("make_typed_attachment");
+ }
+ else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+ {
+ if(comp!=STENCIL_INDEX)
+ throw invalid_argument("make_typed_attachment");
+ }
+ else
+ {
+ if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
+ throw invalid_argument("make_typed_attachment");
+ }
+
+ DataType type = get_component_type(pf);
+ return static_cast<FrameAttachment>((fa&0xFC00) | (is_float(type)*0x80) | get_type_size(type)<<4 | get_component_count(comp));
+}
+
+FrameAttachment make_indexed_attachment(FrameAttachment fa, unsigned i)
+{
+ if(get_attach_point(fa)==get_attach_point(COLOR_ATTACHMENT))
+ {
+ if(i>61)
+ throw out_of_range("make_indexed_attachment");
+ return static_cast<FrameAttachment>(fa+(i<<10));
+ }
+ else
+ throw invalid_argument("make_indexed_attachment");
+}
+
+PixelFormat get_attachment_pixelformat(UInt16 fa)
+{
+ PixelComponents comp;
+ if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+ comp = DEPTH_COMPONENT;
+ else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+ comp = STENCIL_INDEX;
+ else
+ comp = static_cast<PixelComponents>(fa&7);
+
+ DataType type;
+ if(fa&0x80)
+ type = static_cast<DataType>((fa&0x70)>>4 | 0x300);
+ else
+ type = static_cast<DataType>((fa&0x70)>>4);
+
+ return make_pixelformat(comp, type);
+}
+
+GLenum get_gl_attachment(FrameAttachment fa)
+{
+ if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+ return GL_DEPTH_ATTACHMENT;
+ else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+ return GL_STENCIL_ATTACHMENT;
+ else
+ return GL_COLOR_ATTACHMENT0+get_attach_point(fa);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_FRAMEFORMAT_H_
+#define MSP_GL_FRAMEFORMAT_H_
+
+#include <msp/core/inttypes.h>
+#include "pixelformat.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+Describes a single attachment of a framebuffer. The values are bitfields laid
+as follows:
+
+nnnn nn__ fsss _ccc
+ │ │ │ └╴Number of components
+ │ │ └─────╴Size of one component
+ │ └────────╴Floating-point flag
+ └────────────╴Attachment index
+
+This information is presented for internal documentation purposes only; it is
+inadvisable for programs to rely on it.
+*/
+enum FrameAttachment
+{
+ COLOR_ATTACHMENT = 0x0014,
+ DEPTH_ATTACHMENT = 0xF8C1,
+ STENCIL_ATTACHMENT = 0xFC11
+};
+
+/**
+Describes the complete format of a framebuffer. It can hold multiple
+attachments (currently up to seven) as well as a sample count.
+*/
+class FrameFormat
+{
+private:
+ enum { MAX_ATTACHMENTS = 7 };
+
+ UInt8 count;
+ UInt8 samples;
+ UInt16 attachments[MAX_ATTACHMENTS];
+
+public:
+ FrameFormat();
+ FrameFormat(FrameAttachment);
+
+ FrameFormat operator,(FrameAttachment) const;
+ FrameFormat operator,(PixelFormat) const;
+ FrameFormat operator,(unsigned) const;
+
+ FrameFormat &set_samples(unsigned);
+ unsigned get_samples() const { return samples; }
+
+ unsigned size() const { return count; }
+ bool empty() const { return !count; }
+ const UInt16 *begin() const { return attachments; }
+ const UInt16 *end() const { return attachments+count; }
+ int index(FrameAttachment) const;
+};
+
+inline FrameFormat operator,(FrameAttachment fa1, FrameAttachment fa2)
+{ return (FrameFormat(fa1), fa2); }
+
+FrameAttachment make_typed_attachment(FrameAttachment, PixelFormat);
+
+inline FrameAttachment operator,(FrameAttachment fa, PixelFormat pf)
+{ return make_typed_attachment(fa, pf); }
+
+FrameAttachment make_indexed_attachment(FrameAttachment, unsigned);
+
+inline FrameAttachment operator,(FrameAttachment fa, unsigned i)
+{ return make_indexed_attachment(fa, i); }
+
+inline unsigned get_attach_point(UInt16 fa)
+{ return fa>>10; }
+
+PixelFormat get_attachment_pixelformat(UInt16);
+
+GLenum get_gl_attachment(FrameAttachment);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
void set_parameter_i(GLenum, int) const;
public:
+ PixelFormat get_format() const { return format; }
+
static bool can_generate_mipmap();
void generate_mipmap();
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
+ unsigned get_samples() const { return samples; }
virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; }
virtual UInt64 get_data_size() const;
AmbientOcclusion::AmbientOcclusion(unsigned w, unsigned h, float):
rotate_lookup(get_or_create_rotate_lookup()),
- occlude_target(w, h, (RENDER_COLOR,R8)),
+ occlude_target(w, h, (COLOR_ATTACHMENT,R8)),
occlude_shader(Resources::get_global().get<Program>("_ambientocclusion_occlude.glsl.shader")),
combine_shader(Resources::get_global().get<Program>("_ambientocclusion_combine.glsl.shader")),
quad(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
Renderer::Push push(renderer);
renderer.set_texture("source", &color, &nearest_clamp_sampler);
renderer.set_texture("depth", &depth, &nearest_clamp_sampler);
- renderer.set_texture("occlusion", &occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler);
+ renderer.set_texture("occlusion", &occlude_target.get_target_texture(COLOR_ATTACHMENT), &linear_sampler);
renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler);
renderer.set_shader_program(&occlude_shader, &shdata);
blur_shdata[1].uniform("delta", 0.0f, 1.0f/h);
for(unsigned i=0; i<2; ++i)
- target[i] = new RenderTarget(w, h, (RENDER_COLOR,RGB16F));
+ target[i] = new RenderTarget(w, h, (COLOR_ATTACHMENT,RGB16F));
set_radius(2.0f);
set_strength(0.2f);
{
Renderer::Push push2(renderer);
renderer.set_framebuffer(&target[i]->get_framebuffer());
- renderer.set_texture("source", (i ? &target[0]->get_target_texture(RENDER_COLOR) : &src), &nearest_sampler);
+ renderer.set_texture("source", (i ? &target[0]->get_target_texture(COLOR_ATTACHMENT) : &src), &nearest_sampler);
renderer.add_shader_data(blur_shdata[i]);
quad.draw(renderer);
}
renderer.set_texture("source", &src, &nearest_sampler);
- renderer.set_texture("blurred", &target[1]->get_target_texture(RENDER_COLOR), &linear_sampler);
+ renderer.set_texture("blurred", &target[1]->get_target_texture(COLOR_ATTACHMENT), &linear_sampler);
renderer.set_shader_program(&combine_shader);
quad.draw(renderer);
}
for(unsigned i=0; i<6; ++i)
{
TextureCubeFace face = TextureCube::enumerate_faces(i);
- faces[i].fbo.attach(COLOR_ATTACHMENT0, env_tex, face, 0);
+ faces[i].fbo.set_format((COLOR_ATTACHMENT,f, DEPTH_ATTACHMENT,DEPTH_COMPONENT32F));
+ faces[i].fbo.attach(COLOR_ATTACHMENT, env_tex, face, 0);
faces[i].fbo.attach(DEPTH_ATTACHMENT, depth_buf);
faces[i].camera.set_look_direction(TextureCube::get_face_direction(face));
faces[i].camera.set_up_direction(TextureCube::get_t_direction(face));
}
irradiance.storage(f, size/4, 1);
- irradiance_fbo.attach_layered(COLOR_ATTACHMENT0, irradiance);
+ irradiance_fbo.set_format((COLOR_ATTACHMENT,f));
+ irradiance_fbo.attach_layered(COLOR_ATTACHMENT, irradiance);
if(l>1)
{
specular_fbos.resize(l-1);
for(unsigned i=1; i<l; ++i)
- specular_fbos[i-1].attach_layered(COLOR_ATTACHMENT0, env_tex, i);
+ {
+ specular_fbos[i-1].set_format((COLOR_ATTACHMENT,f));
+ specular_fbos[i-1].attach_layered(COLOR_ATTACHMENT, env_tex, i);
+ }
LinAl::Matrix<float, 3, 3> face_matrices[6];
for(unsigned i=0; i<6; ++i)
rendered = false;
depth_buf.storage(DEPTH_COMPONENT32F, size, size, 1);
+ fbo.set_format((DEPTH_ATTACHMENT,DEPTH_COMPONENT32F));
fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
depth_test.enabled = true;
Sky::Sky(Renderable &r, Light &s):
Effect(r),
sun(s),
- transmittance_lookup(128, 64, (RENDER_COLOR, RGB16F)),
+ transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)),
transmittance_shprog(Resources::get_global().get<Program>("_sky_transmittance.glsl.shader")),
transmittance_lookup_dirty(true),
- distant(256, 128, (RENDER_COLOR, RGB16F)),
+ distant(256, 128, (COLOR_ATTACHMENT,RGB16F)),
distant_shprog(Resources::get_global().get<Program>("_sky_distant.glsl.shader")),
fullscreen_mesh(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
backdrop_shprog(Resources::get_global().get<Program>("_sky_backdrop.glsl.shader")),
shdata.uniform("roughness", 0.0f);
const Mesh &mesh = resources.get<Mesh>("_fullscreen_quad.mesh");
- Framebuffer fresnel_lookup_fbo;
- fresnel_lookup_fbo.attach(COLOR_ATTACHMENT0, *fresnel_lookup);
+ Framebuffer fresnel_lookup_fbo((COLOR_ATTACHMENT,RG8));
+ fresnel_lookup_fbo.attach(COLOR_ATTACHMENT, *fresnel_lookup);
Renderer renderer;
renderer.set_framebuffer(&fresnel_lookup_fbo);
renderer.set_shader_program(&shprog, &shdata);
namespace Msp {
namespace GL {
-RenderTargetFormat::RenderTargetFormat():
- count(0)
-{ }
-
-RenderTargetFormat::RenderTargetFormat(RenderOutput o):
- count(1)
-{
- outputs[0] = o;
-}
-
-RenderTargetFormat RenderTargetFormat::operator,(RenderOutput o) const
+RenderTarget::RenderTarget(unsigned w, unsigned h, const FrameFormat &f):
+ width(w),
+ height(h),
+ fbo(f)
{
- if(count>=MAX_OUTPUTS)
- throw invalid_operation("RenderTargetFormat::operator,");
-
- RenderTargetFormat result = *this;
- result.outputs[result.count++] = o;
-
- return result;
-}
-
-RenderTargetFormat RenderTargetFormat::operator,(PixelFormat f) const
-{
- if(!count)
- throw invalid_operation("RenderTargetFormat::operator,");
-
- PixelComponents comp = get_components(f);
- DataType type = get_component_type(f);
- unsigned size = 0;
- unsigned char out = outputs[count-1];
- if(get_output_type(out)>=get_output_type(RENDER_DEPTH))
+ textures.reserve(f.size());
+ unsigned samples = f.get_samples();
+ for(const UInt16 *i=f.begin(); i!=f.end(); ++i)
{
- if(comp!=DEPTH_COMPONENT)
- throw invalid_argument("RenderTargetFormat::operator,");
- switch(type)
- {
- case UNSIGNED_SHORT: size = 0; break;
- case UNSIGNED_INT: size = 2; break;
- case FLOAT: size = 3; break;
- default: throw invalid_argument("RenderTargetFormat::operator,");
- }
- }
- else
- {
- if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
- throw invalid_argument("RenderTargetformat::operator,");
- switch(type)
- {
- case UNSIGNED_BYTE: size = 0; break;
- case HALF_FLOAT: size = 2; break;
- case FLOAT: size = 3; break;
- default: throw invalid_argument("RenderTargetFormat::operator,");
- }
- }
-
- out = (out&~15) | (size<<2) | (get_component_count(f)-1);
- RenderTargetFormat result = *this;
- result.outputs[result.count-1] = out;
-
- return result;
-}
-
-int RenderTargetFormat::index(RenderOutput o) const
-{
- unsigned type = get_output_type(o);
- unsigned i = 0;
- for(const unsigned char *j=begin(); j!=end(); ++j, ++i)
- if(get_output_type(*j)==type)
- return i;
- return -1;
-}
-
-
-PixelFormat get_output_pixelformat(unsigned char o)
-{
- PixelComponents comp;
- DataType type;
- if(get_output_type(o)>=get_output_type(RENDER_DEPTH))
- {
- static DataType types[4] = { UNSIGNED_SHORT, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT };
- comp = DEPTH_COMPONENT;
- type = types[(o>>2)&3];
- }
- else
- {
- static PixelComponents components[4] = { RED, RG, RGB, RGBA };
- static DataType types[4] = { UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT };
- comp = components[o&3];
- type = types[(o>>2)&3];
- }
-
- return make_pixelformat(comp, type);
-}
-
-
-RenderTarget::RenderTarget(unsigned w, unsigned h, RenderOutput o)
-{
- init(w, h, 0, o);
-}
-
-RenderTarget::RenderTarget(unsigned w, unsigned h, const RenderTargetFormat &f)
-{
- init(w, h, 0, f);
-}
-
-RenderTarget::RenderTarget(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
-{
- init(w, h, s, f);
-}
-
-void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
-{
- width = w;
- height = h;
- samples = s;
- format = f;
-
- for(const unsigned char *i=format.begin(); i!=format.end(); ++i)
- {
- unsigned type = get_output_type(*i);
- FramebufferAttachment att;
- if(type>=get_output_type(RENDER_DEPTH))
- att = DEPTH_ATTACHMENT;
- else
- att = static_cast<FramebufferAttachment>(COLOR_ATTACHMENT0+type);
-
- PixelFormat pf = get_output_pixelformat(*i);
+ FrameAttachment fa = static_cast<FrameAttachment>(*i);
+ PixelFormat pf = get_attachment_pixelformat(*i);
- if(samples)
+ if(samples>1)
{
Texture2DMultisample *tex2d_ms = new Texture2DMultisample;
tex2d_ms->storage(pf, width, height, samples);
- fbo.attach(att, *tex2d_ms);
+ fbo.attach(fa, *tex2d_ms);
textures.push_back(tex2d_ms);
}
else
{
Texture2D *tex2d = new Texture2D;
tex2d->storage(pf, width, height, 1);
- fbo.attach(att, *tex2d);
+ fbo.attach(fa, *tex2d);
textures.push_back(tex2d);
}
}
{
if(i>=textures.size())
throw out_of_range("RenderTarget::get_target_texture");
- if(samples)
+ if(fbo.get_format().get_samples()>1)
throw invalid_operation("RenderTarget::get_target_texture");
return *static_cast<const Texture2D *>(textures[i]);
}
-const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
+const Texture2D &RenderTarget::get_target_texture(FrameAttachment fa) const
{
- int index = format.index(o);
+ int index = fbo.get_format().index(fa);
if(index<0)
- throw key_error(o);
+ throw key_error(fa);
return get_target_texture(index);
}
{
#ifdef DEBUG
fbo.set_debug_name(name+" [FBO]");
+ const FrameFormat &fmt = fbo.get_format();
unsigned i = 0;
- for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
+ for(const UInt16 *j=fmt.begin(); j!=fmt.end(); ++i, ++j)
{
- unsigned type = get_output_type(*j);
+ unsigned attach_pt = get_attach_point(static_cast<FrameAttachment>(*j));
string tex_name;
- if(type>=get_output_type(RENDER_DEPTH))
+ if(attach_pt==get_attach_point(DEPTH_ATTACHMENT))
tex_name = name+"/depth";
+ else if(attach_pt==get_attach_point(STENCIL_ATTACHMENT))
+ tex_name = name+"/stencil";
else
- tex_name = Msp::format("%s/color%d", name, type);
+ tex_name = Msp::format("%s/color%d", name, attach_pt);
textures[i]->set_debug_name(tex_name+".tex2d");
}
class Texture;
class Texture2D;
-enum RenderOutput
-{
- RENDER_COLOR = 0|3,
- RENDER_DEPTH = 192|12
-};
-
-class RenderTargetFormat
-{
-private:
- enum { MAX_OUTPUTS = 7 };
-
- unsigned char count;
- unsigned char outputs[MAX_OUTPUTS];
-
-public:
- RenderTargetFormat();
- RenderTargetFormat(RenderOutput);
-
- RenderTargetFormat operator,(RenderOutput) const;
- RenderTargetFormat operator,(PixelFormat) const;
-
- bool empty() const { return !count; }
- const unsigned char *begin() const { return outputs; }
- const unsigned char *end() const { return outputs+count; }
- int index(RenderOutput) const;
-};
-
-inline RenderTargetFormat operator,(RenderOutput o1, RenderOutput o2)
-{ return (RenderTargetFormat(o1), o2); }
-
-inline RenderTargetFormat operator,(RenderOutput o, PixelFormat f)
-{ return (RenderTargetFormat(o), f); }
-
-inline unsigned get_output_type(unsigned char o)
-{ return o>>4; }
-
-PixelFormat get_output_pixelformat(unsigned char);
-
-
class RenderTarget
{
private:
unsigned width;
unsigned height;
- unsigned samples;
- RenderTargetFormat format;
std::vector<Texture *> textures;
Framebuffer fbo;
public:
- RenderTarget(unsigned, unsigned, RenderOutput);
- RenderTarget(unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
- RenderTarget(unsigned, unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
+ RenderTarget(unsigned, unsigned, const FrameFormat & = (COLOR_ATTACHMENT, DEPTH_ATTACHMENT));
private:
RenderTarget(const RenderTarget &);
RenderTarget &operator=(const RenderTarget &);
- void init(unsigned, unsigned, unsigned, const RenderTargetFormat &);
public:
~RenderTarget();
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
- const RenderTargetFormat &get_format() const { return format; }
+ const FrameFormat &get_format() const { return fbo.get_format(); }
Framebuffer &get_framebuffer() { return fbo; }
const Texture2D &get_target_texture(unsigned) const;
- const Texture2D &get_target_texture(RenderOutput) const;
+ const Texture2D &get_target_texture(FrameAttachment) const;
void set_debug_name(const std::string &);
};
{
unsigned j = i%2;
renderer.set_framebuffer(i+1<postproc.size() ? &target[1-j]->get_framebuffer() : out_fbo);
- const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR);
- const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH);
+ const Texture2D &color = target[j]->get_target_texture(COLOR_ATTACHMENT);
+ const Texture2D &depth = target[j]->get_target_texture(DEPTH_ATTACHMENT);
postproc[i].postproc->render(renderer, color, depth);
}
}
}
PixelFormat color_pf = (hdr ? (alpha ? RGBA16F : RGB16F) : (alpha ? RGBA8 : RGB8));
- RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
+ FrameFormat fmt = (COLOR_ATTACHMENT,color_pf, DEPTH_ATTACHMENT);
if(!postproc.empty() || samples)
{
if(!target[0])
}
if(!target_ms && samples)
- target_ms = new RenderTarget(width, height, samples, fmt);
+ target_ms = new RenderTarget(width, height, fmt.set_samples(samples));
#ifdef DEBUG
if(!debug_name.empty())