Files
simgear/simgear/scene/viewer/CompositorBuffer.cxx
T

232 lines
8.9 KiB
C++

// Copyright (C) 2018 Fernando García Liñán <fernandogarcialinan@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "CompositorBuffer.hxx"
#include <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture2DArray>
#include <osg/Texture2DMultisample>
#include <osg/Texture3D>
#include <osg/TextureRectangle>
#include <osg/TextureCubeMap>
#include <osg/FrameBufferObject>
#include <simgear/props/props.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include "Compositor.hxx"
#include "CompositorUtil.hxx"
namespace simgear {
namespace compositor {
struct BufferFormat {
GLint internal_format;
GLenum source_format;
GLenum source_type;
};
PropStringMap<BufferFormat> buffer_format_map {
{"rgb8", {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE}},
{"rgba8", {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}},
{"rgb16f", {GL_RGB16F_ARB, GL_RGBA, GL_FLOAT}},
{"rgb32f", {GL_RGB32F_ARB, GL_RGBA, GL_FLOAT}},
{"rgba16f", {GL_RGBA16F_ARB, GL_RGBA, GL_FLOAT}},
{"rgba32f", {GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT}},
{"r32f", {GL_R32F, GL_RED, GL_FLOAT}},
{"rg16f", {GL_RG16F, GL_RG, GL_FLOAT}},
{"rg32f", {GL_RG32F, GL_RG, GL_FLOAT}},
{"depth16", {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}},
{"depth24", {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_FLOAT}},
{"depth32", {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT}},
{"depth32f", {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}},
{"depth-stencil", { GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT, GL_FLOAT}}
};
PropStringMap<osg::Texture::WrapMode> wrap_mode_map = {
{"clamp", osg::Texture::CLAMP},
{"clamp-to-edge", osg::Texture::CLAMP_TO_EDGE},
{"clamp-to-border", osg::Texture::CLAMP_TO_BORDER},
{"repeat", osg::Texture::REPEAT},
{"mirror", osg::Texture::MIRROR}
};
PropStringMap<osg::Texture::FilterMode> filter_mode_map = {
{"linear", osg::Texture::LINEAR},
{"linear-mipmap-linear", osg::Texture::LINEAR_MIPMAP_LINEAR},
{"linear-mipmap-nearest", osg::Texture::LINEAR_MIPMAP_NEAREST},
{"nearest", osg::Texture::NEAREST},
{"nearest-mipmap-linear", osg::Texture::NEAREST_MIPMAP_LINEAR},
{"nearest-mipmap-nearest", osg::Texture::NEAREST_MIPMAP_NEAREST}
};
PropStringMap<osg::Texture::ShadowTextureMode> shadow_texture_mode_map = {
{"luminance", osg::Texture::LUMINANCE},
{"intensity", osg::Texture::INTENSITY},
{"alpha", osg::Texture::ALPHA}
};
PropStringMap<osg::Texture::ShadowCompareFunc> shadow_compare_func_map = {
{"never", osg::Texture::NEVER},
{"less", osg::Texture::LESS},
{"equal", osg::Texture::EQUAL},
{"lequal", osg::Texture::LEQUAL},
{"greater", osg::Texture::GREATER},
{"notequal", osg::Texture::NOTEQUAL},
{"gequal", osg::Texture::GEQUAL},
{"always", osg::Texture::ALWAYS}
};
Buffer *
buildBuffer(Compositor *compositor, const SGPropertyNode *node,
const SGReaderWriterOptions *options)
{
std::string type = node->getStringValue("type");
if (type.empty()) {
SG_LOG(SG_INPUT, SG_ALERT, "buildBuffer: No type specified");
return 0;
}
osg::ref_ptr<Buffer> buffer = new Buffer;
osg::Texture *texture;
int width = 0;
const SGPropertyNode *p_width = getPropertyChild(node, "width");
if (p_width) {
if (p_width->getStringValue() == std::string("screen")) {
buffer->width_scale = 1.0f;
const SGPropertyNode *p_w_scale = getPropertyChild(node, "screen-width-scale");
if (p_w_scale)
buffer->width_scale = p_w_scale->getFloatValue();
width = buffer->width_scale * compositor->getViewport()->width();
} else {
width = p_width->getIntValue();
}
}
int height = 0;
const SGPropertyNode *p_height = getPropertyChild(node, "height");
if (p_height) {
if (p_height->getStringValue() == std::string("screen")) {
buffer->height_scale = 1.0f;
const SGPropertyNode *p_h_scale = getPropertyChild(node, "screen-height-scale");
if (p_h_scale)
buffer->height_scale = p_h_scale->getFloatValue();
height = buffer->height_scale * compositor->getViewport()->height();
} else {
height = p_height->getIntValue();
}
}
int depth = 0;
const SGPropertyNode *p_depth = getPropertyChild(node, "depth");
if (p_depth)
depth = p_depth->getIntValue();
if (type == "1d") {
osg::Texture1D *tex1D = new osg::Texture1D;
tex1D->setTextureWidth(width);
texture = tex1D;
} else if (type == "2d") {
osg::Texture2D *tex2D = new osg::Texture2D;
tex2D->setTextureSize(width, height);
texture = tex2D;
} else if (type == "2d-array") {
osg::Texture2DArray *tex2D_array = new osg::Texture2DArray;
tex2D_array->setTextureSize(width, height, depth);
texture = tex2D_array;
} else if (type == "2d-multisample") {
osg::Texture2DMultisample *tex2DMS = new osg::Texture2DMultisample;
tex2DMS->setTextureSize(width, height);
tex2DMS->setNumSamples(node->getIntValue("num-samples", 0));
texture = tex2DMS;
} else if (type == "3d") {
osg::Texture3D *tex3D = new osg::Texture3D;
tex3D->setTextureSize(width, height, depth);
texture = tex3D;
} else if (type == "rect") {
osg::TextureRectangle *tex_rect = new osg::TextureRectangle;
tex_rect->setTextureSize(width, height);
texture = tex_rect;
} else if (type == "cubemap") {
osg::TextureCubeMap *tex_cubemap = new osg::TextureCubeMap;
tex_cubemap->setTextureSize(width, height);
texture = tex_cubemap;
} else {
SG_LOG(SG_INPUT, SG_ALERT, "Unknown texture type '" << type << "'");
return 0;
}
buffer->texture = texture;
bool resize_npot = node->getBoolValue("resize-npot", false);
texture->setResizeNonPowerOfTwoHint(resize_npot);
BufferFormat format;
if (findPropString(node, "format", format, buffer_format_map)) {
texture->setInternalFormat(format.internal_format);
texture->setSourceFormat(format.source_format);
texture->setSourceType(format.source_type);
} else {
texture->setInternalFormat(GL_RGBA);
SG_LOG(SG_INPUT, SG_WARN, "Unknown buffer format specified, using RGBA");
}
osg::Texture::FilterMode filter_mode = osg::Texture::LINEAR;
findPropString(node, "min-filter", filter_mode, filter_mode_map);
texture->setFilter(osg::Texture::MIN_FILTER, filter_mode);
findPropString(node, "mag-filter", filter_mode, filter_mode_map);
texture->setFilter(osg::Texture::MAG_FILTER, filter_mode);
osg::Texture::WrapMode wrap_mode = osg::Texture::CLAMP_TO_BORDER;
findPropString(node, "wrap-s", wrap_mode, wrap_mode_map);
texture->setWrap(osg::Texture::WRAP_S, wrap_mode);
findPropString(node, "wrap-t", wrap_mode, wrap_mode_map);
texture->setWrap(osg::Texture::WRAP_T, wrap_mode);
findPropString(node, "wrap-r", wrap_mode, wrap_mode_map);
texture->setWrap(osg::Texture::WRAP_R, wrap_mode);
float anis = node->getFloatValue("anisotropy", 1.0f);
texture->setMaxAnisotropy(anis);
osg::Vec4f border_color(0.0f, 0.0f, 0.0f, 0.0f);
const SGPropertyNode *p_border_color = node->getChild("border-color");
if (p_border_color)
border_color = toOsg(p_border_color->getValue<SGVec4d>());
texture->setBorderColor(border_color);
bool shadow_comparison = node->getBoolValue("shadow-comparison", false);
texture->setShadowComparison(shadow_comparison);
if (shadow_comparison) {
osg::Texture::ShadowTextureMode shadow_texture_mode =
osg::Texture::LUMINANCE;
findPropString(node, "shadow-texture-mode",
shadow_texture_mode, shadow_texture_mode_map);
texture->setShadowTextureMode(shadow_texture_mode);
osg::Texture::ShadowCompareFunc shadow_compare_func =
osg::Texture::LEQUAL;
findPropString(node, "shadow-compare-func",
shadow_compare_func, shadow_compare_func_map);
texture->setShadowCompareFunc(shadow_compare_func);
}
return buffer.release();
}
} // namespace compositor
} // namespace simgear