mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-05-01 14:27:59 +03:00
Merge branch 'post_malone' into 'master'
Post Processing See merge request OpenMW/openmw!1124
This commit is contained in:
commit
f092d8da9a
136 changed files with 8966 additions and 618 deletions
|
@ -82,6 +82,10 @@ add_component_dir (to_utf8
|
|||
|
||||
add_component_dir(esm attr common defs esmcommon reader records util luascripts format)
|
||||
|
||||
add_component_dir(fx pass technique lexer widgets stateupdater)
|
||||
|
||||
add_component_dir(std140 ubo)
|
||||
|
||||
add_component_dir (esm3
|
||||
esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell
|
||||
loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||
|
|
301
components/fx/lexer.cpp
Normal file
301
components/fx/lexer.cpp
Normal file
|
@ -0,0 +1,301 @@
|
|||
#include "lexer.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <exception>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Lexer
|
||||
{
|
||||
Lexer::Lexer(std::string_view buffer)
|
||||
: mHead(buffer.data())
|
||||
, mTail(mHead + buffer.length())
|
||||
, mAbsolutePos(0)
|
||||
, mColumn(0)
|
||||
, mLine(0)
|
||||
, mBuffer(buffer)
|
||||
, mLastToken(Eof{})
|
||||
{ }
|
||||
|
||||
Token Lexer::next()
|
||||
{
|
||||
if (mLookahead)
|
||||
{
|
||||
auto token = *mLookahead;
|
||||
drop();
|
||||
return token;
|
||||
}
|
||||
|
||||
mLastToken = scanToken();
|
||||
|
||||
return mLastToken;
|
||||
}
|
||||
|
||||
Token Lexer::peek()
|
||||
{
|
||||
if (!mLookahead)
|
||||
mLookahead = scanToken();
|
||||
|
||||
return *mLookahead;
|
||||
}
|
||||
|
||||
void Lexer::drop()
|
||||
{
|
||||
mLookahead = std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string_view> Lexer::jump()
|
||||
{
|
||||
bool multi = false;
|
||||
bool single = false;
|
||||
auto start = mHead;
|
||||
std::size_t level = 1;
|
||||
|
||||
mLastJumpBlock.line = mLine;
|
||||
|
||||
if (head() == '}')
|
||||
{
|
||||
mLastJumpBlock.content = {};
|
||||
return mLastJumpBlock.content;
|
||||
}
|
||||
|
||||
for (; mHead != mTail; advance())
|
||||
{
|
||||
if (head() == '\n')
|
||||
{
|
||||
mLine++;
|
||||
mColumn = 0;
|
||||
if (single)
|
||||
{
|
||||
single = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (multi && head() == '*' && peekChar('/'))
|
||||
{
|
||||
multi = false;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
else if (multi || single)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (head() == '/' && peekChar('/'))
|
||||
{
|
||||
single = true;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
else if (head() == '/' && peekChar('*'))
|
||||
{
|
||||
multi = true;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (head() == '{')
|
||||
level++;
|
||||
else if (head() == '}')
|
||||
level--;
|
||||
|
||||
if (level == 0)
|
||||
{
|
||||
mHead--;
|
||||
auto sv = std::string_view{start, static_cast<std::string_view::size_type>(mHead + 1 - start)};
|
||||
mLastJumpBlock.content = sv;
|
||||
return sv;
|
||||
}
|
||||
}
|
||||
|
||||
mLastJumpBlock = {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Lexer::Block Lexer::getLastJumpBlock() const
|
||||
{
|
||||
return mLastJumpBlock;
|
||||
}
|
||||
|
||||
[[noreturn]] void Lexer::error(const std::string& msg)
|
||||
{
|
||||
throw LexerException(Misc::StringUtils::format("Line %zu Col %zu. %s", mLine + 1, mColumn, msg));
|
||||
}
|
||||
|
||||
void Lexer::advance()
|
||||
{
|
||||
mAbsolutePos++;
|
||||
mHead++;
|
||||
mColumn++;
|
||||
}
|
||||
|
||||
char Lexer::head()
|
||||
{
|
||||
return *mHead;
|
||||
}
|
||||
|
||||
bool Lexer::peekChar(char c)
|
||||
{
|
||||
if (mHead == mTail)
|
||||
return false;
|
||||
return *(mHead + 1) == c;
|
||||
}
|
||||
|
||||
Token Lexer::scanToken()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (mHead == mTail)
|
||||
return {Eof{}};
|
||||
|
||||
if (head() == '\n')
|
||||
{
|
||||
mLine++;
|
||||
mColumn = 0;
|
||||
}
|
||||
|
||||
if (!std::isspace(head()))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (head() == '\"')
|
||||
return scanStringLiteral();
|
||||
|
||||
if (std::isalpha(head()))
|
||||
return scanLiteral();
|
||||
|
||||
if (std::isdigit(head()) || head() == '.' || head() == '-')
|
||||
return scanNumber();
|
||||
|
||||
switch(head())
|
||||
{
|
||||
case '=':
|
||||
advance();
|
||||
return {Equal{}};
|
||||
case '{':
|
||||
advance();
|
||||
return {Open_bracket{}};
|
||||
case '}':
|
||||
advance();
|
||||
return {Close_bracket{}};
|
||||
case '(':
|
||||
advance();
|
||||
return {Open_Parenthesis{}};
|
||||
case ')':
|
||||
advance();
|
||||
return {Close_Parenthesis{}};
|
||||
case '\"':
|
||||
advance();
|
||||
return {Quote{}};
|
||||
case ':':
|
||||
advance();
|
||||
return {Colon{}};
|
||||
case ';':
|
||||
advance();
|
||||
return {SemiColon{}};
|
||||
case '|':
|
||||
advance();
|
||||
return {VBar{}};
|
||||
case ',':
|
||||
advance();
|
||||
return {Comma{}};
|
||||
default:
|
||||
error(Misc::StringUtils::format("unexpected token <%c>", head()));
|
||||
}
|
||||
}
|
||||
|
||||
Token Lexer::scanLiteral()
|
||||
{
|
||||
auto start = mHead;
|
||||
advance();
|
||||
|
||||
while (mHead != mTail && (std::isalnum(head()) || head() == '_'))
|
||||
advance();
|
||||
|
||||
std::string_view value{start, static_cast<std::string_view::size_type>(mHead - start)};
|
||||
|
||||
if (value == "shared") return Shared{};
|
||||
if (value == "technique") return Technique{};
|
||||
if (value == "main_pass") return Main_Pass{};
|
||||
if (value == "render_target") return Render_Target{};
|
||||
if (value == "vertex") return Vertex{};
|
||||
if (value == "fragment") return Fragment{};
|
||||
if (value == "compute") return Compute{};
|
||||
if (value == "sampler_1d") return Sampler_1D{};
|
||||
if (value == "sampler_2d") return Sampler_2D{};
|
||||
if (value == "sampler_3d") return Sampler_3D{};
|
||||
if (value == "uniform_bool") return Uniform_Bool{};
|
||||
if (value == "uniform_float") return Uniform_Float{};
|
||||
if (value == "uniform_int") return Uniform_Int{};
|
||||
if (value == "uniform_vec2") return Uniform_Vec2{};
|
||||
if (value == "uniform_vec3") return Uniform_Vec3{};
|
||||
if (value == "uniform_vec4") return Uniform_Vec4{};
|
||||
if (value == "true") return True{};
|
||||
if (value == "false") return False{};
|
||||
if (value == "vec2") return Vec2{};
|
||||
if (value == "vec3") return Vec3{};
|
||||
if (value == "vec4") return Vec4{};
|
||||
|
||||
return Literal{value};
|
||||
}
|
||||
|
||||
Token Lexer::scanStringLiteral()
|
||||
{
|
||||
advance(); // consume quote
|
||||
auto start = mHead;
|
||||
|
||||
bool terminated = false;
|
||||
|
||||
for (; mHead != mTail; advance())
|
||||
{
|
||||
if (head() == '\"')
|
||||
{
|
||||
terminated = true;
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!terminated)
|
||||
error("unterminated string");
|
||||
|
||||
return String{{start, static_cast<std::string_view::size_type>(mHead - start - 1)}};
|
||||
}
|
||||
|
||||
Token Lexer::scanNumber()
|
||||
{
|
||||
double buffer;
|
||||
|
||||
char* endPtr;
|
||||
buffer = std::strtod(mHead, &endPtr);
|
||||
|
||||
if (endPtr == nullptr)
|
||||
error("critical error while parsing number");
|
||||
|
||||
const char* tmp = mHead;
|
||||
mHead = endPtr;
|
||||
|
||||
for (; tmp != endPtr; ++tmp)
|
||||
{
|
||||
if ((*tmp == '.'))
|
||||
return Float{static_cast<float>(buffer)};
|
||||
}
|
||||
|
||||
return Integer{static_cast<int>(buffer)};
|
||||
}
|
||||
}
|
||||
}
|
75
components/fx/lexer.hpp
Normal file
75
components/fx/lexer.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_LEXER_H
|
||||
#define OPENMW_COMPONENTS_FX_LEXER_H
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
#include "lexer_types.hpp"
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Lexer
|
||||
{
|
||||
struct LexerException : std::runtime_error
|
||||
{
|
||||
LexerException(const std::string& message) : std::runtime_error(message) {}
|
||||
LexerException(const char* message) : std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
class Lexer
|
||||
{
|
||||
public:
|
||||
struct Block
|
||||
{
|
||||
int line;
|
||||
std::string_view content;
|
||||
};
|
||||
|
||||
Lexer(std::string_view buffer);
|
||||
Lexer() = delete;
|
||||
|
||||
Token next();
|
||||
Token peek();
|
||||
|
||||
// Jump ahead to next uncommented closing bracket at level zero. Assumes the head is at an opening bracket.
|
||||
// Returns the contents of the block excluding the brackets and places cursor at closing bracket.
|
||||
std::optional<std::string_view> jump();
|
||||
|
||||
Block getLastJumpBlock() const;
|
||||
|
||||
[[noreturn]] void error(const std::string& msg);
|
||||
|
||||
private:
|
||||
void drop();
|
||||
void advance();
|
||||
char head();
|
||||
bool peekChar(char c);
|
||||
|
||||
Token scanToken();
|
||||
Token scanLiteral();
|
||||
Token scanStringLiteral();
|
||||
Token scanNumber();
|
||||
|
||||
const char* mHead;
|
||||
const char* mTail;
|
||||
std::size_t mAbsolutePos;
|
||||
std::size_t mColumn;
|
||||
std::size_t mLine;
|
||||
std::string_view mBuffer;
|
||||
Token mLastToken;
|
||||
std::optional<Token> mLookahead;
|
||||
|
||||
Block mLastJumpBlock;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
56
components/fx/lexer_types.hpp
Normal file
56
components/fx/lexer_types.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_LEXER_TYPES_H
|
||||
#define OPENMW_COMPONENTS_FX_LEXER_TYPES_H
|
||||
|
||||
#include <variant>
|
||||
#include <string_view>
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Lexer
|
||||
{
|
||||
struct Float { inline static constexpr std::string_view repr = "float"; float value = 0.0;};
|
||||
struct Integer { inline static constexpr std::string_view repr = "integer"; int value = 0;};
|
||||
struct Boolean { inline static constexpr std::string_view repr = "boolean"; bool value = false;};
|
||||
struct Literal { inline static constexpr std::string_view repr = "literal"; std::string_view value;};
|
||||
struct String { inline static constexpr std::string_view repr = "string"; std::string_view value;};
|
||||
struct Shared { inline static constexpr std::string_view repr = "shared"; };
|
||||
struct Vertex { inline static constexpr std::string_view repr = "vertex"; };
|
||||
struct Fragment { inline static constexpr std::string_view repr = "fragment"; };
|
||||
struct Compute { inline static constexpr std::string_view repr = "compute"; };
|
||||
struct Technique { inline static constexpr std::string_view repr = "technique"; };
|
||||
struct Main_Pass { inline static constexpr std::string_view repr = "main_pass"; };
|
||||
struct Render_Target { inline static constexpr std::string_view repr = "render_target"; };
|
||||
struct Sampler_1D { inline static constexpr std::string_view repr = "sampler_1d"; };
|
||||
struct Sampler_2D { inline static constexpr std::string_view repr = "sampler_2d"; };
|
||||
struct Sampler_3D { inline static constexpr std::string_view repr = "sampler_3d"; };
|
||||
struct Uniform_Bool { inline static constexpr std::string_view repr = "uniform_bool"; };
|
||||
struct Uniform_Float { inline static constexpr std::string_view repr = "uniform_float"; };
|
||||
struct Uniform_Int { inline static constexpr std::string_view repr = "uniform_int"; };
|
||||
struct Uniform_Vec2 { inline static constexpr std::string_view repr = "uniform_vec2"; };
|
||||
struct Uniform_Vec3 { inline static constexpr std::string_view repr = "uniform_vec3"; };
|
||||
struct Uniform_Vec4 { inline static constexpr std::string_view repr = "uniform_vec4"; };
|
||||
struct Eof { inline static constexpr std::string_view repr = "eof"; };
|
||||
struct Equal { inline static constexpr std::string_view repr = "equal"; };
|
||||
struct Open_bracket { inline static constexpr std::string_view repr = "open_bracket"; };
|
||||
struct Close_bracket { inline static constexpr std::string_view repr = "close_bracket"; };
|
||||
struct Open_Parenthesis { inline static constexpr std::string_view repr = "open_parenthesis"; };
|
||||
struct Close_Parenthesis{ inline static constexpr std::string_view repr = "close_parenthesis"; };
|
||||
struct Quote { inline static constexpr std::string_view repr = "quote"; };
|
||||
struct SemiColon { inline static constexpr std::string_view repr = "semicolon"; };
|
||||
struct Comma { inline static constexpr std::string_view repr = "comma"; };
|
||||
struct VBar { inline static constexpr std::string_view repr = "vbar"; };
|
||||
struct Colon { inline static constexpr std::string_view repr = "colon"; };
|
||||
struct True { inline static constexpr std::string_view repr = "true"; };
|
||||
struct False { inline static constexpr std::string_view repr = "false"; };
|
||||
struct Vec2 { inline static constexpr std::string_view repr = "vec2"; };
|
||||
struct Vec3 { inline static constexpr std::string_view repr = "vec3"; };
|
||||
struct Vec4 { inline static constexpr std::string_view repr = "vec4"; };
|
||||
|
||||
using Token = std::variant<Float, Integer, Boolean, String, Literal, Equal, Open_bracket, Close_bracket, Open_Parenthesis,
|
||||
Close_Parenthesis, Quote, SemiColon, Comma, VBar, Colon, Shared, Technique, Render_Target, Vertex, Fragment,
|
||||
Compute, Sampler_1D, Sampler_2D, Sampler_3D, Uniform_Bool, Uniform_Float, Uniform_Int, Uniform_Vec2, Uniform_Vec3, Uniform_Vec4,
|
||||
True, False, Vec2, Vec3, Vec4, Main_Pass, Eof>;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
133
components/fx/parse_constants.hpp
Normal file
133
components/fx/parse_constants.hpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_PARSE_CONSTANTS_H
|
||||
#define OPENMW_COMPONENTS_FX_PARSE_CONSTANTS_H
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
|
||||
#include <osg/Texture>
|
||||
#include <osg/Image>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/BlendEquation>
|
||||
|
||||
#include <components/sceneutil/color.hpp>
|
||||
|
||||
#include "technique.hpp"
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace constants
|
||||
{
|
||||
constexpr std::array<std::pair<std::string_view, fx::FlagsType>, 6> TechniqueFlag = {{
|
||||
{"disable_interiors" , Technique::Flag_Disable_Interiors},
|
||||
{"disable_exteriors" , Technique::Flag_Disable_Exteriors},
|
||||
{"disable_underwater" , Technique::Flag_Disable_Underwater},
|
||||
{"disable_abovewater" , Technique::Flag_Disable_Abovewater},
|
||||
{"disable_sunglare" , Technique::Flag_Disable_SunGlare},
|
||||
{"hidden" , Technique::Flag_Hidden}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, int>, 6> SourceFormat = {{
|
||||
{"red" , GL_RED},
|
||||
{"rg" , GL_RG},
|
||||
{"rgb" , GL_RGB},
|
||||
{"bgr" , GL_BGR},
|
||||
{"rgba", GL_RGBA},
|
||||
{"bgra", GL_BGRA},
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, int>, 9> SourceType = {{
|
||||
{"byte" , GL_BYTE},
|
||||
{"unsigned_byte" , GL_UNSIGNED_BYTE},
|
||||
{"short" , GL_SHORT},
|
||||
{"unsigned_short" , GL_UNSIGNED_SHORT},
|
||||
{"int" , GL_INT},
|
||||
{"unsigned_int" , GL_UNSIGNED_INT},
|
||||
{"unsigned_int_24_8", GL_UNSIGNED_INT_24_8},
|
||||
{"float" , GL_FLOAT},
|
||||
{"double" , GL_DOUBLE},
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, int>, 16> InternalFormat = {{
|
||||
{"red" , GL_RED},
|
||||
{"r16f" , GL_R16F},
|
||||
{"r32f" , GL_R32F},
|
||||
{"rg" , GL_RG},
|
||||
{"rg16f" , GL_RG16F},
|
||||
{"rg32f" , GL_RG32F},
|
||||
{"rgb" , GL_RGB},
|
||||
{"rgb16f" , GL_RGB16F},
|
||||
{"rgb32f" , GL_RGB32F},
|
||||
{"rgba" , GL_RGBA},
|
||||
{"rgba16f" , GL_RGBA16F},
|
||||
{"rgba32f" , GL_RGBA32F},
|
||||
{"depth_component16" , GL_DEPTH_COMPONENT16},
|
||||
{"depth_component24" , GL_DEPTH_COMPONENT24},
|
||||
{"depth_component32" , GL_DEPTH_COMPONENT32},
|
||||
{"depth_component32f", GL_DEPTH_COMPONENT32F}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, osg::Texture::InternalFormatMode>, 13> Compression = {{
|
||||
{"auto" , osg::Texture::USE_USER_DEFINED_FORMAT},
|
||||
{"arb" , osg::Texture::USE_ARB_COMPRESSION},
|
||||
{"s3tc_dxt1" , osg::Texture::USE_S3TC_DXT1_COMPRESSION},
|
||||
{"s3tc_dxt3" , osg::Texture::USE_S3TC_DXT3_COMPRESSION},
|
||||
{"s3tc_dxt5" , osg::Texture::USE_S3TC_DXT5_COMPRESSION},
|
||||
{"pvrtc_2bpp" , osg::Texture::USE_PVRTC_2BPP_COMPRESSION},
|
||||
{"pvrtc_4bpp" , osg::Texture::USE_PVRTC_4BPP_COMPRESSION},
|
||||
{"etc" , osg::Texture::USE_ETC_COMPRESSION},
|
||||
{"etc2" , osg::Texture::USE_ETC2_COMPRESSION},
|
||||
{"rgtc1" , osg::Texture::USE_RGTC1_COMPRESSION},
|
||||
{"rgtc2" , osg::Texture::USE_RGTC2_COMPRESSION},
|
||||
{"s3tc_dxt1c" , osg::Texture::USE_S3TC_DXT1c_COMPRESSION},
|
||||
{"s3tc_dxt1a" , osg::Texture::USE_S3TC_DXT1a_COMPRESSION}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, osg::Texture::WrapMode>, 6> WrapMode = {{
|
||||
{"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}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, osg::Texture::FilterMode>, 6> FilterMode = {{
|
||||
{"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}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, osg::BlendFunc::BlendFuncMode>, 15> BlendFunc = {{
|
||||
{"dst_alpha" , osg::BlendFunc::DST_ALPHA},
|
||||
{"dst_color" , osg::BlendFunc::DST_COLOR},
|
||||
{"one" , osg::BlendFunc::ONE},
|
||||
{"one_minus_dst_alpha" , osg::BlendFunc::ONE_MINUS_DST_ALPHA},
|
||||
{"one_minus_dst_color" , osg::BlendFunc::ONE_MINUS_DST_COLOR},
|
||||
{"one_minus_src_alpha" , osg::BlendFunc::ONE_MINUS_SRC_ALPHA},
|
||||
{"one_minus_src_color" , osg::BlendFunc::ONE_MINUS_SRC_COLOR},
|
||||
{"src_alpha" , osg::BlendFunc::SRC_ALPHA},
|
||||
{"src_alpha_saturate" , osg::BlendFunc::SRC_ALPHA_SATURATE},
|
||||
{"src_color" , osg::BlendFunc::SRC_COLOR},
|
||||
{"constant_color" , osg::BlendFunc::CONSTANT_COLOR},
|
||||
{"one_minus_constant_color" , osg::BlendFunc::ONE_MINUS_CONSTANT_COLOR},
|
||||
{"constant_alpha" , osg::BlendFunc::CONSTANT_ALPHA},
|
||||
{"one_minus_constant_alpha" , osg::BlendFunc::ONE_MINUS_CONSTANT_ALPHA},
|
||||
{"zero" , osg::BlendFunc::ZERO}
|
||||
}};
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, osg::BlendEquation::Equation>, 8> BlendEquation = {{
|
||||
{"rgba_min" , osg::BlendEquation::RGBA_MIN},
|
||||
{"rgba_max" , osg::BlendEquation::RGBA_MAX},
|
||||
{"alpha_min" , osg::BlendEquation::ALPHA_MIN},
|
||||
{"alpha_max" , osg::BlendEquation::ALPHA_MAX},
|
||||
{"logic_op" , osg::BlendEquation::LOGIC_OP},
|
||||
{"add" , osg::BlendEquation::FUNC_ADD},
|
||||
{"subtract" , osg::BlendEquation::FUNC_SUBTRACT},
|
||||
{"reverse_subtract" , osg::BlendEquation::FUNC_REVERSE_SUBTRACT}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
283
components/fx/pass.cpp
Normal file
283
components/fx/pass.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
#include "pass.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <osg/Program>
|
||||
#include <osg/Shader>
|
||||
#include <osg/State>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/BindImageTexture>
|
||||
#include <osg/FrameBufferObject>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
#include <components/sceneutil/clearcolor.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/stereo/multiview.hpp>
|
||||
|
||||
#include "technique.hpp"
|
||||
#include "stateupdater.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr char s_DefaultVertex[] = R"GLSL(
|
||||
#if OMW_USE_BINDINGS
|
||||
omw_In vec2 omw_Vertex;
|
||||
#endif
|
||||
omw_Out vec2 omw_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
omw_Position = vec4(omw_Vertex.xy, 0.0, 1.0);
|
||||
omw_TexCoord = omw_Position.xy * 0.5 + 0.5;
|
||||
})GLSL";
|
||||
|
||||
}
|
||||
|
||||
namespace fx
|
||||
{
|
||||
Pass::Pass(Pass::Type type, Pass::Order order, bool ubo)
|
||||
: mCompiled(false)
|
||||
, mType(type)
|
||||
, mOrder(order)
|
||||
, mLegacyGLSL(true)
|
||||
, mUBO(ubo)
|
||||
{
|
||||
}
|
||||
|
||||
std::string Pass::getPassHeader(Technique& technique, std::string_view preamble, bool fragOut)
|
||||
{
|
||||
std::string header = R"GLSL(
|
||||
#version @version @profile
|
||||
@extensions
|
||||
|
||||
@uboStruct
|
||||
|
||||
#define OMW_REVERSE_Z @reverseZ
|
||||
#define OMW_RADIAL_FOG @radialFog
|
||||
#define OMW_HDR @hdr
|
||||
#define OMW_NORMALS @normals
|
||||
#define OMW_USE_BINDINGS @useBindings
|
||||
#define OMW_MULTIVIEW @multiview
|
||||
#define omw_In @in
|
||||
#define omw_Out @out
|
||||
#define omw_Position @position
|
||||
#define omw_Texture1D @texture1D
|
||||
#define omw_Texture2D @texture2D
|
||||
#define omw_Texture3D @texture3D
|
||||
#define omw_Vertex @vertex
|
||||
#define omw_FragColor @fragColor
|
||||
|
||||
@fragBinding
|
||||
|
||||
uniform @builtinSampler omw_SamplerLastShader;
|
||||
uniform @builtinSampler omw_SamplerLastPass;
|
||||
uniform highp @builtinSampler omw_SamplerDepth;
|
||||
uniform @builtinSampler omw_SamplerNormals;
|
||||
|
||||
uniform vec4 omw_PointLights[@pointLightCount];
|
||||
uniform int omw_PointLightsCount;
|
||||
|
||||
int omw_GetPointLightCount()
|
||||
{
|
||||
return omw_PointLightsCount;
|
||||
}
|
||||
|
||||
vec3 omw_GetPointLightViewPos(int index)
|
||||
{
|
||||
return omw_PointLights[(index * 3)].xyz;
|
||||
}
|
||||
|
||||
vec3 omw_GetPointLightDiffuse(int index)
|
||||
{
|
||||
return omw_PointLights[(index * 3) + 1].xyz;
|
||||
}
|
||||
|
||||
vec3 omw_GetPointLightAttenuation(int index)
|
||||
{
|
||||
return omw_PointLights[(index * 3) + 2].xyz;
|
||||
}
|
||||
|
||||
float omw_GetPointLightRadius(int index)
|
||||
{
|
||||
return omw_PointLights[(index * 3) + 2].w;
|
||||
}
|
||||
|
||||
#if @ubo
|
||||
layout(std140) uniform _data { _omw_data omw; };
|
||||
#else
|
||||
uniform _omw_data omw;
|
||||
#endif
|
||||
|
||||
float omw_GetDepth(vec2 uv)
|
||||
{
|
||||
#if OMW_MULTIVIEW
|
||||
float depth = omw_Texture2D(omw_SamplerDepth, vec3(uv, gl_ViewID_OVR)).r;
|
||||
#else
|
||||
float depth = omw_Texture2D(omw_SamplerDepth, uv).r;
|
||||
#endif
|
||||
#if OMW_REVERSE_Z
|
||||
return 1.0 - depth;
|
||||
#else
|
||||
return depth;
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 omw_GetLastShader(vec2 uv)
|
||||
{
|
||||
#if OMW_MULTIVIEW
|
||||
return omw_Texture2D(omw_SamplerLastShader, vec3(uv, gl_ViewID_OVR));
|
||||
#else
|
||||
return omw_Texture2D(omw_SamplerLastShader, uv);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 omw_GetLastPass(vec2 uv)
|
||||
{
|
||||
#if OMW_MULTIVIEW
|
||||
return omw_Texture2D(omw_SamplerLastPass, vec3(uv, gl_ViewID_OVR));
|
||||
#else
|
||||
return omw_Texture2D(omw_SamplerLastPass, uv);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 omw_GetNormals(vec2 uv)
|
||||
{
|
||||
#if OMW_MULTIVIEW
|
||||
return omw_Texture2D(omw_SamplerNormals, vec3(uv, gl_ViewID_OVR)).rgb * 2.0 - 1.0;
|
||||
#else
|
||||
return omw_Texture2D(omw_SamplerNormals, uv).rgb * 2.0 - 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OMW_HDR
|
||||
uniform sampler2D omw_EyeAdaptation;
|
||||
#endif
|
||||
|
||||
float omw_GetEyeAdaptation()
|
||||
{
|
||||
#if OMW_HDR
|
||||
return omw_Texture2D(omw_EyeAdaptation, vec2(0.5, 0.5)).r;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
)GLSL";
|
||||
|
||||
std::stringstream extBlock;
|
||||
for (const auto& extension : technique.getGLSLExtensions())
|
||||
extBlock << "#ifdef " << extension << '\n' << "\t#extension " << extension << ": enable" << '\n' << "#endif" << '\n';
|
||||
|
||||
const std::vector<std::pair<std::string,std::string>> defines = {
|
||||
{"@pointLightCount", std::to_string(SceneUtil::PPLightBuffer::sMaxPPLightsArraySize)},
|
||||
{"@version", std::to_string(technique.getGLSLVersion())},
|
||||
{"@multiview", Stereo::getMultiview() ? "1" : "0"},
|
||||
{"@builtinSampler", Stereo::getMultiview() ? "sampler2DArray" : "sampler2D"},
|
||||
{"@profile", technique.getGLSLProfile()},
|
||||
{"@extensions", extBlock.str()},
|
||||
{"@uboStruct", StateUpdater::getStructDefinition()},
|
||||
{"@ubo", mUBO ? "1" : "0"},
|
||||
{"@normals", technique.getNormals() ? "1" : "0"},
|
||||
{"@reverseZ", SceneUtil::AutoDepth::isReversed() ? "1" : "0"},
|
||||
{"@radialFog", Settings::Manager::getBool("radial fog", "Shaders") ? "1" : "0"},
|
||||
{"@hdr", technique.getHDR() ? "1" : "0"},
|
||||
{"@in", mLegacyGLSL ? "varying" : "in"},
|
||||
{"@out", mLegacyGLSL ? "varying" : "out"},
|
||||
{"@position", "gl_Position"},
|
||||
{"@texture1D", mLegacyGLSL ? "texture1D" : "texture"},
|
||||
{"@texture2D", mLegacyGLSL ? "texture2D" : "texture"},
|
||||
{"@texture3D", mLegacyGLSL ? "texture3D" : "texture"},
|
||||
{"@vertex", mLegacyGLSL ? "gl_Vertex" : "_omw_Vertex"},
|
||||
{"@fragColor", mLegacyGLSL ? "gl_FragColor" : "_omw_FragColor"},
|
||||
{"@useBindings", mLegacyGLSL ? "0" : "1"},
|
||||
{"@fragBinding", mLegacyGLSL ? "" : "out vec4 omw_FragColor;"}
|
||||
};
|
||||
|
||||
for (const auto& [define, value]: defines)
|
||||
for (size_t pos = header.find(define); pos != std::string::npos; pos = header.find(define))
|
||||
header.replace(pos, define.size(), value);
|
||||
|
||||
for (auto& uniform : technique.getUniformMap())
|
||||
if (auto glsl = uniform->getGLSL())
|
||||
header.append(glsl.value());
|
||||
|
||||
header.append(preamble);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
void Pass::prepareStateSet(osg::StateSet* stateSet, const std::string& name) const
|
||||
{
|
||||
osg::ref_ptr<osg::Program> program = new osg::Program;
|
||||
if (mType == Type::Pixel)
|
||||
{
|
||||
program->addShader(new osg::Shader(*mVertex));
|
||||
program->addShader(new osg::Shader(*mFragment));
|
||||
}
|
||||
else if (mType == Type::Compute)
|
||||
{
|
||||
program->addShader(new osg::Shader(*mCompute));
|
||||
}
|
||||
|
||||
if (mUBO)
|
||||
program->addBindUniformBlock("_data", static_cast<int>(Resource::SceneManager::UBOBinding::PostProcessor));
|
||||
|
||||
program->setName(name);
|
||||
|
||||
if (!mLegacyGLSL)
|
||||
{
|
||||
program->addBindFragDataLocation("_omw_FragColor", 0);
|
||||
program->addBindAttribLocation("_omw_Vertex", 0);
|
||||
}
|
||||
|
||||
stateSet->setAttribute(program);
|
||||
|
||||
if (mBlendSource && mBlendDest)
|
||||
stateSet->setAttribute(new osg::BlendFunc(mBlendSource.value(), mBlendDest.value()));
|
||||
|
||||
if (mBlendEq)
|
||||
stateSet->setAttribute(new osg::BlendEquation(mBlendEq.value()));
|
||||
|
||||
if (mClearColor)
|
||||
stateSet->setAttribute(new SceneUtil::ClearColor(mClearColor.value(), GL_COLOR_BUFFER_BIT));
|
||||
}
|
||||
|
||||
void Pass::dirty()
|
||||
{
|
||||
mVertex = nullptr;
|
||||
mFragment = nullptr;
|
||||
mCompute = nullptr;
|
||||
mCompiled = false;
|
||||
}
|
||||
|
||||
void Pass::compile(Technique& technique, std::string_view preamble)
|
||||
{
|
||||
if (mCompiled)
|
||||
return;
|
||||
|
||||
mLegacyGLSL = technique.getGLSLVersion() != 330;
|
||||
|
||||
if (mType == Type::Pixel)
|
||||
{
|
||||
if (!mVertex)
|
||||
mVertex = new osg::Shader(osg::Shader::VERTEX, s_DefaultVertex);
|
||||
|
||||
mVertex->setShaderSource(getPassHeader(technique, preamble).append(mVertex->getShaderSource()));
|
||||
mFragment->setShaderSource(getPassHeader(technique, preamble, true).append(mFragment->getShaderSource()));
|
||||
|
||||
mVertex->setName(mName);
|
||||
mFragment->setName(mName);
|
||||
}
|
||||
else if (mType == Type::Compute)
|
||||
{
|
||||
mCompute->setShaderSource(getPassHeader(technique, preamble).append(mCompute->getShaderSource()));
|
||||
mCompute->setName(mName);
|
||||
}
|
||||
|
||||
mCompiled = true;
|
||||
}
|
||||
|
||||
}
|
79
components/fx/pass.hpp
Normal file
79
components/fx/pass.hpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_PASS_H
|
||||
#define OPENMW_COMPONENTS_FX_PASS_H
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
|
||||
#include <osg/Timer>
|
||||
#include <osg/Program>
|
||||
#include <osg/Shader>
|
||||
#include <osg/State>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/BlendEquation>
|
||||
#include <osg/BlendFunc>
|
||||
|
||||
namespace fx
|
||||
{
|
||||
class Technique;
|
||||
|
||||
class Pass
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Order
|
||||
{
|
||||
Forward,
|
||||
Post
|
||||
};
|
||||
|
||||
enum class Type
|
||||
{
|
||||
None,
|
||||
Pixel,
|
||||
Compute
|
||||
};
|
||||
|
||||
friend class Technique;
|
||||
|
||||
Pass(Type type=Type::Pixel, Order order=Order::Post, bool ubo = false);
|
||||
|
||||
void compile(Technique& technique, std::string_view preamble);
|
||||
|
||||
std::string_view getTarget() const { return mTarget; }
|
||||
|
||||
void prepareStateSet(osg::StateSet* stateSet, const std::string& name) const;
|
||||
|
||||
std::string getName() const { return mName; }
|
||||
|
||||
void dirty();
|
||||
|
||||
private:
|
||||
std::string getPassHeader(Technique& technique, std::string_view preamble, bool fragOut = false);
|
||||
|
||||
bool mCompiled;
|
||||
|
||||
osg::ref_ptr<osg::Shader> mVertex;
|
||||
osg::ref_ptr<osg::Shader> mFragment;
|
||||
osg::ref_ptr<osg::Shader> mCompute;
|
||||
|
||||
Type mType;
|
||||
Order mOrder;
|
||||
std::string mName;
|
||||
bool mLegacyGLSL;
|
||||
bool mUBO;
|
||||
bool mSupportsNormals;
|
||||
|
||||
std::string_view mTarget;
|
||||
std::optional<osg::Vec4f> mClearColor;
|
||||
|
||||
std::optional<osg::BlendFunc::BlendFuncMode> mBlendSource;
|
||||
std::optional<osg::BlendFunc::BlendFuncMode> mBlendDest;
|
||||
std::optional<osg::BlendEquation::Equation> mBlendEq;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
63
components/fx/stateupdater.cpp
Normal file
63
components/fx/stateupdater.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "stateupdater.hpp"
|
||||
|
||||
#include <osg/BufferObject>
|
||||
#include <osg/BufferIndexBinding>
|
||||
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
namespace fx
|
||||
{
|
||||
StateUpdater::StateUpdater(bool useUBO) : mUseUBO(useUBO) {}
|
||||
|
||||
void StateUpdater::setDefaults(osg::StateSet* stateset)
|
||||
{
|
||||
if (mUseUBO)
|
||||
{
|
||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||
|
||||
osg::ref_ptr<osg::BufferTemplate<UniformData::BufferType>> data = new osg::BufferTemplate<UniformData::BufferType>();
|
||||
data->setBufferObject(ubo);
|
||||
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Resource::SceneManager::UBOBinding::PostProcessor), data, 0, mData.getGPUSize());
|
||||
|
||||
stateset->setAttributeAndModes(ubb, osg::StateAttribute::ON);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto createUniform = [&] (const auto& v) {
|
||||
using T = std::decay_t<decltype(v)>;
|
||||
std::string name = "omw." + std::string(T::sName);
|
||||
stateset->addUniform(new osg::Uniform(name.c_str(), mData.get<T>()));
|
||||
};
|
||||
|
||||
std::apply([&] (const auto& ... v) { (createUniform(v) , ...); }, mData.getData());
|
||||
}
|
||||
}
|
||||
|
||||
void StateUpdater::apply(osg::StateSet* stateset, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (mUseUBO)
|
||||
{
|
||||
osg::UniformBufferBinding* ubb = dynamic_cast<osg::UniformBufferBinding*>(stateset->getAttribute(osg::StateAttribute::UNIFORMBUFFERBINDING, static_cast<int>(Resource::SceneManager::UBOBinding::PostProcessor)));
|
||||
|
||||
auto& dest = static_cast<osg::BufferTemplate<UniformData::BufferType>*>(ubb->getBufferData())->getData();
|
||||
mData.copyTo(dest);
|
||||
|
||||
ubb->getBufferData()->dirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto setUniform = [&] (const auto& v) {
|
||||
using T = std::decay_t<decltype(v)>;
|
||||
std::string name = "omw." + std::string(T::sName);
|
||||
stateset->getUniform(name)->set(mData.get<T>());
|
||||
};
|
||||
|
||||
std::apply([&] (const auto& ... v) { (setUniform(v) , ...); }, mData.getData());
|
||||
}
|
||||
|
||||
if (mPointLightBuffer)
|
||||
mPointLightBuffer->applyUniforms(nv->getTraversalNumber(), stateset);
|
||||
}
|
||||
}
|
200
components/fx/stateupdater.hpp
Normal file
200
components/fx/stateupdater.hpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_STATEUPDATER_H
|
||||
#define OPENMW_COMPONENTS_FX_STATEUPDATER_H
|
||||
|
||||
#include <osg/BufferTemplate>
|
||||
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
#include <components/sceneutil/statesetupdater.hpp>
|
||||
#include <components/std140/ubo.hpp>
|
||||
|
||||
namespace fx
|
||||
{
|
||||
class StateUpdater : public SceneUtil::StateSetUpdater
|
||||
{
|
||||
public:
|
||||
StateUpdater(bool useUBO);
|
||||
|
||||
void setProjectionMatrix(const osg::Matrixf& matrix)
|
||||
{
|
||||
mData.get<ProjectionMatrix>() = matrix;
|
||||
mData.get<InvProjectionMatrix>() = osg::Matrixf::inverse(matrix);
|
||||
}
|
||||
|
||||
void setViewMatrix(const osg::Matrixf& matrix) { mData.get<ViewMatrix>() = matrix; }
|
||||
|
||||
void setInvViewMatrix(const osg::Matrixf& matrix) { mData.get<InvViewMatrix>() = matrix; }
|
||||
|
||||
void setPrevViewMatrix(const osg::Matrixf& matrix) { mData.get<PrevViewMatrix>() = matrix;}
|
||||
|
||||
void setEyePos(const osg::Vec3f& pos) { mData.get<EyePos>() = osg::Vec4f(pos, 0.f); }
|
||||
|
||||
void setEyeVec(const osg::Vec3f& vec) { mData.get<EyeVec>() = osg::Vec4f(vec, 0.f); }
|
||||
|
||||
void setFogColor(const osg::Vec4f& color) { mData.get<FogColor>() = color; }
|
||||
|
||||
void setSunColor(const osg::Vec4f& color) { mData.get<SunColor>() = color; }
|
||||
|
||||
void setSunPos(const osg::Vec4f& pos, bool night)
|
||||
{
|
||||
mData.get<SunPos>() = pos;
|
||||
|
||||
if (night)
|
||||
mData.get<SunPos>().z() *= -1.f;
|
||||
}
|
||||
|
||||
void setResolution(const osg::Vec2f& size)
|
||||
{
|
||||
mData.get<Resolution>() = size;
|
||||
mData.get<RcpResolution>() = {1.f / size.x(), 1.f / size.y()};
|
||||
}
|
||||
|
||||
void setSunVis(float vis)
|
||||
{
|
||||
mData.get<SunVis>() = vis;
|
||||
}
|
||||
|
||||
void setFogRange(float near, float far)
|
||||
{
|
||||
mData.get<FogNear>() = near;
|
||||
mData.get<FogFar>() = far;
|
||||
}
|
||||
|
||||
void setNearFar(float near, float far)
|
||||
{
|
||||
mData.get<Near>() = near;
|
||||
mData.get<Far>() = far;
|
||||
}
|
||||
|
||||
void setIsUnderwater(bool underwater) { mData.get<IsUnderwater>() = underwater; }
|
||||
|
||||
void setIsInterior(bool interior) { mData.get<IsInterior>() = interior; }
|
||||
|
||||
void setFov(float fov) { mData.get<Fov>() = fov; }
|
||||
|
||||
void setGameHour(float hour) { mData.get<GameHour>() = hour; }
|
||||
|
||||
void setWeatherId(int id) { mData.get<WeatherID>() = id; }
|
||||
|
||||
void setNextWeatherId(int id) { mData.get<NextWeatherID>() = id; }
|
||||
|
||||
void setWaterHeight(float height) { mData.get<WaterHeight>() = height; }
|
||||
|
||||
void setSimulationTime(float time) { mData.get<SimulationTime>() = time; }
|
||||
|
||||
void setDeltaSimulationTime(float time) { mData.get<DeltaSimulationTime>() = time; }
|
||||
|
||||
void setWindSpeed(float speed) { mData.get<WindSpeed>() = speed; }
|
||||
|
||||
void setWeatherTransition(float transition) { mData.get<WeatherTransition>() = transition; }
|
||||
|
||||
void bindPointLights(std::shared_ptr<SceneUtil::PPLightBuffer> buffer)
|
||||
{
|
||||
mPointLightBuffer = buffer;
|
||||
}
|
||||
|
||||
static std::string getStructDefinition()
|
||||
{
|
||||
static std::string definition = UniformData::getDefinition("_omw_data");
|
||||
return definition;
|
||||
}
|
||||
|
||||
void setDefaults(osg::StateSet* stateset) override;
|
||||
|
||||
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override;
|
||||
|
||||
private:
|
||||
struct ProjectionMatrix : std140::Mat4 { static constexpr std::string_view sName = "projectionMatrix"; };
|
||||
|
||||
struct InvProjectionMatrix : std140::Mat4 { static constexpr std::string_view sName = "invProjectionMatrix"; };
|
||||
|
||||
struct ViewMatrix : std140::Mat4 { static constexpr std::string_view sName = "viewMatrix"; };
|
||||
|
||||
struct PrevViewMatrix : std140::Mat4 { static constexpr std::string_view sName = "prevViewMatrix"; };
|
||||
|
||||
struct InvViewMatrix : std140::Mat4 { static constexpr std::string_view sName = "invViewMatrix"; };
|
||||
|
||||
struct EyePos : std140::Vec4 { static constexpr std::string_view sName = "eyePos"; };
|
||||
|
||||
struct EyeVec : std140::Vec4 { static constexpr std::string_view sName = "eyeVec"; };
|
||||
|
||||
struct FogColor : std140::Vec4 { static constexpr std::string_view sName = "fogColor"; };
|
||||
|
||||
struct SunColor : std140::Vec4 { static constexpr std::string_view sName = "sunColor"; };
|
||||
|
||||
struct SunPos : std140::Vec4 { static constexpr std::string_view sName = "sunPos"; };
|
||||
|
||||
struct Resolution : std140::Vec2 { static constexpr std::string_view sName = "resolution"; };
|
||||
|
||||
struct RcpResolution : std140::Vec2 { static constexpr std::string_view sName = "rcpResolution"; };
|
||||
|
||||
struct FogNear : std140::Float { static constexpr std::string_view sName = "fogNear"; };
|
||||
|
||||
struct FogFar : std140::Float { static constexpr std::string_view sName = "fogFar"; };
|
||||
|
||||
struct Near : std140::Float { static constexpr std::string_view sName = "near"; };
|
||||
|
||||
struct Far : std140::Float { static constexpr std::string_view sName = "far"; };
|
||||
|
||||
struct Fov : std140::Float { static constexpr std::string_view sName = "fov"; };
|
||||
|
||||
struct GameHour : std140::Float { static constexpr std::string_view sName = "gameHour"; };
|
||||
|
||||
struct SunVis : std140::Float { static constexpr std::string_view sName = "sunVis"; };
|
||||
|
||||
struct WaterHeight : std140::Float { static constexpr std::string_view sName = "waterHeight"; };
|
||||
|
||||
struct SimulationTime : std140::Float { static constexpr std::string_view sName = "simulationTime"; };
|
||||
|
||||
struct DeltaSimulationTime : std140::Float { static constexpr std::string_view sName = "deltaSimulationTime"; };
|
||||
|
||||
struct WindSpeed : std140::Float { static constexpr std::string_view sName = "windSpeed"; };
|
||||
|
||||
struct WeatherTransition : std140::Float { static constexpr std::string_view sName = "weatherTransition"; };
|
||||
|
||||
struct WeatherID : std140::Int { static constexpr std::string_view sName = "weatherID"; };
|
||||
|
||||
struct NextWeatherID : std140::Int { static constexpr std::string_view sName = "nextWeatherID"; };
|
||||
|
||||
struct IsUnderwater : std140::Bool { static constexpr std::string_view sName = "isUnderwater"; };
|
||||
|
||||
struct IsInterior : std140::Bool { static constexpr std::string_view sName = "isInterior"; };
|
||||
|
||||
using UniformData = std140::UBO<
|
||||
ProjectionMatrix,
|
||||
InvProjectionMatrix,
|
||||
ViewMatrix,
|
||||
PrevViewMatrix,
|
||||
InvViewMatrix,
|
||||
EyePos,
|
||||
EyeVec,
|
||||
FogColor,
|
||||
SunColor,
|
||||
SunPos,
|
||||
Resolution,
|
||||
RcpResolution,
|
||||
FogNear,
|
||||
FogFar,
|
||||
Near,
|
||||
Far,
|
||||
Fov,
|
||||
GameHour,
|
||||
SunVis,
|
||||
WaterHeight,
|
||||
SimulationTime,
|
||||
DeltaSimulationTime,
|
||||
WindSpeed,
|
||||
WeatherTransition,
|
||||
WeatherID,
|
||||
NextWeatherID,
|
||||
IsUnderwater,
|
||||
IsInterior
|
||||
>;
|
||||
|
||||
UniformData mData;
|
||||
bool mUseUBO;
|
||||
|
||||
std::shared_ptr<SceneUtil::PPLightBuffer> mPointLightBuffer;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
1052
components/fx/technique.cpp
Normal file
1052
components/fx/technique.cpp
Normal file
File diff suppressed because it is too large
Load diff
303
components/fx/technique.hpp
Normal file
303
components/fx/technique.hpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_TECHNIQUE_H
|
||||
#define OPENMW_COMPONENTS_FX_TECHNIQUE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Program>
|
||||
#include <osg/Shader>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/BlendEquation>
|
||||
|
||||
#include "pass.hpp"
|
||||
#include "lexer.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
class ImageManager;
|
||||
}
|
||||
|
||||
namespace VFS
|
||||
{
|
||||
class Manager;
|
||||
}
|
||||
|
||||
namespace fx
|
||||
{
|
||||
using FlagsType = size_t;
|
||||
|
||||
struct DispatchNode
|
||||
{
|
||||
DispatchNode() = default;
|
||||
|
||||
DispatchNode(const DispatchNode& other, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY)
|
||||
: mHandle(other.mHandle)
|
||||
, mFlags(other.mFlags)
|
||||
, mRootStateSet(other.mRootStateSet)
|
||||
{
|
||||
mPasses.reserve(other.mPasses.size());
|
||||
|
||||
for (const auto& subpass : other.mPasses)
|
||||
mPasses.emplace_back(subpass, copyOp);
|
||||
}
|
||||
|
||||
struct SubPass {
|
||||
SubPass() = default;
|
||||
|
||||
osg::ref_ptr<osg::StateSet> mStateSet = new osg::StateSet;
|
||||
osg::ref_ptr<osg::FrameBufferObject> mRenderTarget;
|
||||
osg::ref_ptr<osg::Texture2D> mRenderTexture;
|
||||
|
||||
SubPass(const SubPass& other, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY)
|
||||
: mStateSet(new osg::StateSet(*other.mStateSet, copyOp))
|
||||
{
|
||||
if (other.mRenderTarget)
|
||||
mRenderTarget = new osg::FrameBufferObject(*other.mRenderTarget, copyOp);
|
||||
if (other.mRenderTexture)
|
||||
mRenderTexture = new osg::Texture2D(*other.mRenderTexture, copyOp);
|
||||
}
|
||||
};
|
||||
|
||||
// not safe to read/write in draw thread
|
||||
std::shared_ptr<fx::Technique> mHandle = nullptr;
|
||||
|
||||
FlagsType mFlags = 0;
|
||||
|
||||
std::vector<SubPass> mPasses;
|
||||
|
||||
osg::ref_ptr<osg::StateSet> mRootStateSet = new osg::StateSet;
|
||||
};
|
||||
|
||||
using DispatchArray = std::vector<DispatchNode>;
|
||||
|
||||
class Technique
|
||||
{
|
||||
public:
|
||||
using PassList = std::vector<std::shared_ptr<Pass>>;
|
||||
using TexList = std::vector<osg::ref_ptr<osg::Texture>>;
|
||||
|
||||
using UniformMap = std::vector<std::shared_ptr<Types::UniformBase>>;
|
||||
using RenderTargetMap = std::unordered_map<std::string_view, Types::RenderTarget>;
|
||||
|
||||
inline static std::string sExt = ".omwfx";
|
||||
inline static std::string sSubdir = "shaders";
|
||||
|
||||
enum class Status
|
||||
{
|
||||
Success,
|
||||
Uncompiled,
|
||||
File_Not_exists,
|
||||
Parse_Error
|
||||
};
|
||||
|
||||
static constexpr FlagsType Flag_Disable_Interiors = (1 << 0);
|
||||
static constexpr FlagsType Flag_Disable_Exteriors = (1 << 1);
|
||||
static constexpr FlagsType Flag_Disable_Underwater = (1 << 2);
|
||||
static constexpr FlagsType Flag_Disable_Abovewater = (1 << 3);
|
||||
static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4);
|
||||
static constexpr FlagsType Flag_Hidden = (1 << 5);
|
||||
|
||||
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals);
|
||||
|
||||
bool compile();
|
||||
|
||||
std::string getName() const;
|
||||
|
||||
std::string getFileName() const;
|
||||
|
||||
void setLastModificationTime(std::filesystem::file_time_type timeStamp, bool dirty = true);
|
||||
|
||||
bool isDirty() const { return mDirty; }
|
||||
|
||||
void setDirty(bool dirty) { mDirty = dirty; }
|
||||
|
||||
bool isValid() const { return mValid; }
|
||||
|
||||
bool getHDR() const { return mHDR; }
|
||||
|
||||
bool getNormals() const { return mNormals && mSupportsNormals; }
|
||||
|
||||
bool getLights() const { return mLights; }
|
||||
|
||||
const PassList& getPasses() { return mPasses; }
|
||||
|
||||
const TexList& getTextures() const { return mTextures; }
|
||||
|
||||
Status getStatus() const { return mStatus; }
|
||||
|
||||
std::string_view getAuthor() const { return mAuthor; }
|
||||
|
||||
std::string_view getDescription() const { return mDescription; }
|
||||
|
||||
std::string_view getVersion() const { return mVersion; }
|
||||
|
||||
int getGLSLVersion() const { return mGLSLVersion; }
|
||||
|
||||
std::string getGLSLProfile() const { return mGLSLProfile; }
|
||||
|
||||
const std::unordered_set<std::string>& getGLSLExtensions() const { return mGLSLExtensions; }
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> getMainTemplate() const { return mMainTemplate; }
|
||||
|
||||
FlagsType getFlags() const { return mFlags; }
|
||||
|
||||
bool getHidden() const { return mFlags & Flag_Hidden; }
|
||||
|
||||
UniformMap& getUniformMap() { return mDefinedUniforms; }
|
||||
|
||||
RenderTargetMap& getRenderTargetsMap() { return mRenderTargets; }
|
||||
|
||||
std::string getLastError() const { return mLastError; }
|
||||
|
||||
UniformMap::iterator findUniform(const std::string& name);
|
||||
|
||||
private:
|
||||
[[noreturn]] void error(const std::string& msg);
|
||||
|
||||
void clear();
|
||||
|
||||
std::string_view asLiteral() const;
|
||||
|
||||
template<class T>
|
||||
void expect(const std::string& err="");
|
||||
|
||||
template<class T, class T2>
|
||||
void expect(const std::string& err="");
|
||||
|
||||
template <class T>
|
||||
bool isNext();
|
||||
|
||||
void parse(std::string&& buffer);
|
||||
|
||||
template <class SrcT, class T>
|
||||
void parseUniform();
|
||||
|
||||
template <class T>
|
||||
void parseSampler();
|
||||
|
||||
template <class T>
|
||||
void parseBlock(bool named=true);
|
||||
|
||||
template <class T>
|
||||
void parseBlockImp() {}
|
||||
|
||||
void parseBlockHeader();
|
||||
|
||||
bool parseBool();
|
||||
|
||||
std::string_view parseString();
|
||||
|
||||
float parseFloat();
|
||||
|
||||
int parseInteger();
|
||||
|
||||
int parseInternalFormat();
|
||||
|
||||
int parseSourceType();
|
||||
|
||||
int parseSourceFormat();
|
||||
|
||||
osg::BlendEquation::Equation parseBlendEquation();
|
||||
|
||||
osg::BlendFunc::BlendFuncMode parseBlendFuncMode();
|
||||
|
||||
osg::Texture::WrapMode parseWrapMode();
|
||||
|
||||
osg::Texture::InternalFormatMode parseCompression();
|
||||
|
||||
FlagsType parseFlags();
|
||||
|
||||
osg::Texture::FilterMode parseFilterMode();
|
||||
|
||||
template <class TDelimeter>
|
||||
std::vector<std::string_view> parseLiteralList();
|
||||
|
||||
template <class OSGVec, class T>
|
||||
OSGVec parseVec();
|
||||
|
||||
std::string getBlockWithLineDirective();
|
||||
|
||||
std::unique_ptr<Lexer::Lexer> mLexer;
|
||||
Lexer::Token mToken;
|
||||
|
||||
std::string mShared;
|
||||
std::string mName;
|
||||
std::string mFileName;
|
||||
std::string_view mBlockName;
|
||||
std::string_view mAuthor;
|
||||
std::string_view mDescription;
|
||||
std::string_view mVersion;
|
||||
|
||||
std::unordered_set<std::string> mGLSLExtensions;
|
||||
int mGLSLVersion;
|
||||
std::string mGLSLProfile;
|
||||
|
||||
FlagsType mFlags;
|
||||
|
||||
Status mStatus;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
std::filesystem::file_time_type mLastModificationTime;
|
||||
bool mDirty;
|
||||
bool mValid;
|
||||
bool mHDR;
|
||||
bool mNormals;
|
||||
bool mLights;
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> mMainTemplate;
|
||||
RenderTargetMap mRenderTargets;
|
||||
|
||||
TexList mTextures;
|
||||
PassList mPasses;
|
||||
|
||||
std::unordered_map<std::string_view, std::shared_ptr<Pass>> mPassMap;
|
||||
std::vector<std::string_view> mPassKeys;
|
||||
|
||||
Pass::Type mLastAppliedType;
|
||||
|
||||
UniformMap mDefinedUniforms;
|
||||
|
||||
const VFS::Manager& mVFS;
|
||||
Resource::ImageManager& mImageManager;
|
||||
bool mUBO;
|
||||
bool mSupportsNormals;
|
||||
|
||||
std::string mBuffer;
|
||||
|
||||
std::string mLastError;
|
||||
};
|
||||
|
||||
template<> void Technique::parseBlockImp<Lexer::Shared>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Technique>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Main_Pass>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Render_Target>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Vertex>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Fragment>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Compute>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Sampler_1D>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Sampler_2D>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Sampler_3D>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Bool>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Float>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Int>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Vec2>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Vec3>();
|
||||
template<> void Technique::parseBlockImp<Lexer::Uniform_Vec4>();
|
||||
}
|
||||
|
||||
#endif
|
259
components/fx/types.hpp
Normal file
259
components/fx/types.hpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_TYPES_H
|
||||
#define OPENMW_COMPONENTS_FX_TYPES_H
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Uniform>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/BlendEquation>
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
#include <components/settings/shadermanager.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "pass.hpp"
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Types
|
||||
{
|
||||
struct SizeProxy
|
||||
{
|
||||
std::optional<float> mWidthRatio;
|
||||
std::optional<float> mHeightRatio;
|
||||
std::optional<int> mWidth;
|
||||
std::optional<int> mHeight;
|
||||
|
||||
std::tuple<int,int> get(int width, int height) const
|
||||
{
|
||||
int scaledWidth = width;
|
||||
int scaledHeight = height;
|
||||
|
||||
if (mWidthRatio)
|
||||
scaledWidth = width * mWidthRatio.value();
|
||||
else if (mWidth)
|
||||
scaledWidth = mWidth.value();
|
||||
|
||||
if (mHeightRatio > 0.f)
|
||||
scaledHeight = height * mHeightRatio.value();
|
||||
else if (mHeight)
|
||||
scaledHeight = mHeight.value();
|
||||
|
||||
return std::make_tuple(scaledWidth, scaledHeight);
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderTarget
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> mTarget = new osg::Texture2D;
|
||||
SizeProxy mSize;
|
||||
bool mMipMap = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Uniform
|
||||
{
|
||||
std::optional<T> mValue;
|
||||
T mDefault;
|
||||
T mMin = std::numeric_limits<T>::lowest();
|
||||
T mMax = std::numeric_limits<T>::max();
|
||||
|
||||
using value_type = T;
|
||||
|
||||
T getValue() const
|
||||
{
|
||||
return mValue.value_or(mDefault);
|
||||
}
|
||||
};
|
||||
|
||||
using Uniform_t = std::variant<
|
||||
Uniform<osg::Vec2f>,
|
||||
Uniform<osg::Vec3f>,
|
||||
Uniform<osg::Vec4f>,
|
||||
Uniform<bool>,
|
||||
Uniform<float>,
|
||||
Uniform<int>
|
||||
>;
|
||||
|
||||
enum SamplerType
|
||||
{
|
||||
Texture_1D,
|
||||
Texture_2D,
|
||||
Texture_3D
|
||||
};
|
||||
|
||||
struct UniformBase
|
||||
{
|
||||
std::string mName;
|
||||
std::string mHeader;
|
||||
std::string mTechniqueName;
|
||||
std::string mDescription;
|
||||
|
||||
bool mStatic = true;
|
||||
std::optional<SamplerType> mSamplerType = std::nullopt;
|
||||
double mStep;
|
||||
|
||||
Uniform_t mData;
|
||||
|
||||
template <class T>
|
||||
T getValue() const
|
||||
{
|
||||
auto value = Settings::ShaderManager::get().getValue<T>(mTechniqueName, mName);
|
||||
|
||||
return value.value_or(std::get<Uniform<T>>(mData).getValue());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T getMin() const
|
||||
{
|
||||
return std::get<Uniform<T>>(mData).mMin;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T getMax() const
|
||||
{
|
||||
return std::get<Uniform<T>>(mData).mMax;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T getDefault() const
|
||||
{
|
||||
return std::get<Uniform<T>>(mData).mDefault;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void setValue(const T& value)
|
||||
{
|
||||
std::visit([&, value](auto&& arg){
|
||||
using U = typename std::decay_t<decltype(arg)>::value_type;
|
||||
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
{
|
||||
arg.mValue = value;
|
||||
|
||||
if (mStatic)
|
||||
Settings::ShaderManager::get().setValue<T>(mTechniqueName, mName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Debug::Warning) << "Attempting to set uniform '" << mName << "' with wrong type";
|
||||
}
|
||||
}, mData);
|
||||
}
|
||||
|
||||
void setUniform(osg::Uniform* uniform)
|
||||
{
|
||||
auto type = getType();
|
||||
if (!type || type.value() != uniform->getType())
|
||||
return;
|
||||
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
const auto value = arg.getValue();
|
||||
uniform->set(value);
|
||||
}, mData);
|
||||
}
|
||||
|
||||
std::optional<osg::Uniform::Type> getType() const
|
||||
{
|
||||
return std::visit([](auto&& arg) -> std::optional<osg::Uniform::Type> {
|
||||
using T = typename std::decay_t<decltype(arg)>::value_type;
|
||||
|
||||
if constexpr (std::is_same_v<T, osg::Vec2f>)
|
||||
return osg::Uniform::FLOAT_VEC2;
|
||||
else if constexpr (std::is_same_v<T, osg::Vec3f>)
|
||||
return osg::Uniform::FLOAT_VEC3;
|
||||
else if constexpr (std::is_same_v<T, osg::Vec4f>)
|
||||
return osg::Uniform::FLOAT_VEC4;
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
return osg::Uniform::FLOAT;
|
||||
else if constexpr (std::is_same_v<T, int>)
|
||||
return osg::Uniform::INT;
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
return osg::Uniform::BOOL;
|
||||
|
||||
return std::nullopt;
|
||||
}, mData);
|
||||
}
|
||||
|
||||
std::optional<std::string> getGLSL()
|
||||
{
|
||||
if (mSamplerType)
|
||||
{
|
||||
switch (mSamplerType.value())
|
||||
{
|
||||
case Texture_1D:
|
||||
return Misc::StringUtils::format("uniform sampler1D %s;", mName);
|
||||
case Texture_2D:
|
||||
return Misc::StringUtils::format("uniform sampler2D %s;", mName);
|
||||
case Texture_3D:
|
||||
return Misc::StringUtils::format("uniform sampler3D %s;", mName);
|
||||
}
|
||||
}
|
||||
|
||||
bool useUniform = (Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug || mStatic == false);
|
||||
|
||||
return std::visit([&](auto&& arg) -> std::optional<std::string> {
|
||||
using T = typename std::decay_t<decltype(arg)>::value_type;
|
||||
|
||||
auto value = arg.getValue();
|
||||
|
||||
if constexpr (std::is_same_v<T, osg::Vec2f>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform vec2 %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const vec2 %s=vec2(%f,%f);", mName, value[0], value[1]);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, osg::Vec3f>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform vec3 %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const vec3 %s=vec3(%f,%f,%f);", mName, value[0], value[1], value[2]);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, osg::Vec4f>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform vec4 %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const vec4 %s=vec4(%f,%f,%f,%f);", mName, value[0], value[1], value[2], value[3]);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform float %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const float %s=%f;", mName, value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform int %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const int %s=%i;", mName, value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
if (useUniform)
|
||||
return Misc::StringUtils::format("uniform bool %s;", mName);
|
||||
|
||||
return Misc::StringUtils::format("const bool %s=%s;", mName, value ? "true" : "false");
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
||||
}, mData);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
164
components/fx/widgets.cpp
Normal file
164
components/fx/widgets.cpp
Normal file
|
@ -0,0 +1,164 @@
|
|||
#include "widgets.hpp"
|
||||
|
||||
#include <components/widgets/box.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class T, class WidgetT>
|
||||
void createVectorWidget(const std::shared_ptr<fx::Types::UniformBase>& uniform, MyGUI::Widget* client, fx::Widgets::UniformBase* base)
|
||||
{
|
||||
int height = client->getHeight();
|
||||
base->setSize(base->getSize().width, (base->getSize().height - height) + (height * T::num_components));
|
||||
client->setSize(client->getSize().width, height * T::num_components);
|
||||
|
||||
for (int i = 0; i < T::num_components; ++i)
|
||||
{
|
||||
auto* widget = client->createWidget<WidgetT>("MW_ValueEditNumber", {0, height * i, client->getWidth(), height}, MyGUI::Align::Default);
|
||||
widget->setData(uniform, static_cast<fx::Widgets::Index>(i));
|
||||
base->addItem(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Widgets
|
||||
{
|
||||
void EditBool::setValue(bool value)
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
mCheckbutton->setCaptionWithReplacing(value ? "#{sOn}" : "#{sOff}");
|
||||
|
||||
uniform->setValue<bool>(value);
|
||||
}
|
||||
|
||||
void EditBool::setValueFromUniform()
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
setValue(uniform->template getValue<bool>());
|
||||
}
|
||||
|
||||
void EditBool::toDefault()
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
setValue(uniform->getDefault<bool>());
|
||||
}
|
||||
|
||||
void EditBool::initialiseOverride()
|
||||
{
|
||||
Base::initialiseOverride();
|
||||
|
||||
assignWidget(mCheckbutton, "Checkbutton");
|
||||
|
||||
mCheckbutton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditBool::notifyMouseButtonClick);
|
||||
}
|
||||
|
||||
|
||||
void EditBool::notifyMouseButtonClick(MyGUI::Widget* sender)
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
setValue(!uniform->getValue<bool>());
|
||||
}
|
||||
|
||||
void UniformBase::init(const std::shared_ptr<fx::Types::UniformBase>& uniform)
|
||||
{
|
||||
mLabel->setCaption(uniform->mName);
|
||||
|
||||
if (uniform->mDescription.empty())
|
||||
{
|
||||
mLabel->setUserString("ToolTipType", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
mLabel->setUserString("ToolTipType", "Layout");
|
||||
mLabel->setUserString("ToolTipLayout", "TextToolTip");
|
||||
mLabel->setUserString("Caption_Text", uniform->mDescription);
|
||||
}
|
||||
|
||||
std::visit([this, &uniform](auto&& arg) {
|
||||
using T = typename std::decay_t<decltype(arg)>::value_type;
|
||||
|
||||
if constexpr (std::is_same_v<osg::Vec4f, T>)
|
||||
{
|
||||
createVectorWidget<T, EditNumberFloat4>(uniform, mClient, this);
|
||||
}
|
||||
else if constexpr (std::is_same_v<osg::Vec3f, T>)
|
||||
{
|
||||
createVectorWidget<T, EditNumberFloat3>(uniform, mClient, this);
|
||||
}
|
||||
else if constexpr (std::is_same_v<osg::Vec2f, T>)
|
||||
{
|
||||
createVectorWidget<T, EditNumberFloat2>(uniform, mClient, this);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
{
|
||||
auto* widget = mClient->createWidget<EditNumberFloat>("MW_ValueEditNumber", {0, 0, mClient->getWidth(), mClient->getHeight()}, MyGUI::Align::Stretch);
|
||||
widget->setData(uniform);
|
||||
mBases.emplace_back(widget);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, int>)
|
||||
{
|
||||
auto* widget = mClient->createWidget<EditNumberInt>("MW_ValueEditNumber", {0, 0, mClient->getWidth(), mClient->getHeight()}, MyGUI::Align::Stretch);
|
||||
widget->setData(uniform);
|
||||
mBases.emplace_back(widget);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
auto* widget = mClient->createWidget<EditBool>("MW_ValueEditBool", {0, 0, mClient->getWidth(), mClient->getHeight()}, MyGUI::Align::Stretch);
|
||||
widget->setData(uniform);
|
||||
mBases.emplace_back(widget);
|
||||
}
|
||||
|
||||
mReset->eventMouseButtonClick += MyGUI::newDelegate(this, &UniformBase::notifyResetClicked);
|
||||
|
||||
for (EditBase* base : mBases)
|
||||
base->setValueFromUniform();
|
||||
|
||||
}, uniform->mData);
|
||||
}
|
||||
|
||||
void UniformBase::addItem(EditBase* item)
|
||||
{
|
||||
mBases.emplace_back(item);
|
||||
}
|
||||
|
||||
void UniformBase::toDefault()
|
||||
{
|
||||
for (EditBase* base : mBases)
|
||||
{
|
||||
if (base)
|
||||
base->toDefault();
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBase::notifyResetClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
toDefault();
|
||||
}
|
||||
|
||||
void UniformBase::initialiseOverride()
|
||||
{
|
||||
Base::initialiseOverride();
|
||||
|
||||
assignWidget(mReset, "Reset");
|
||||
assignWidget(mLabel, "Label");
|
||||
assignWidget(mClient, "Client");
|
||||
}
|
||||
}
|
||||
}
|
266
components/fx/widgets.hpp
Normal file
266
components/fx/widgets.hpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
#ifndef OPENMW_COMPONENTS_FX_WIDGETS_H
|
||||
#define OPENMW_COMPONENTS_FX_WIDGETS_H
|
||||
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_Button.h>
|
||||
#include <MyGUI_ScrollView.h>
|
||||
#include <MyGUI_InputManager.h>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "technique.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class AutoSizedTextBox;
|
||||
class AutoSizedButton;
|
||||
}
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Widgets
|
||||
{
|
||||
enum Index
|
||||
{
|
||||
None = -1,
|
||||
Zero = 0,
|
||||
One = 1,
|
||||
Two = 2,
|
||||
Three = 3
|
||||
};
|
||||
|
||||
class EditBase
|
||||
{
|
||||
public:
|
||||
virtual ~EditBase() = default;
|
||||
|
||||
void setData(const std::shared_ptr<fx::Types::UniformBase>& uniform, Index index = None)
|
||||
{
|
||||
mUniform = uniform;
|
||||
mIndex = index;
|
||||
}
|
||||
|
||||
virtual void setValueFromUniform() = 0;
|
||||
|
||||
virtual void toDefault() = 0;
|
||||
|
||||
protected:
|
||||
std::weak_ptr<fx::Types::UniformBase> mUniform;
|
||||
Index mIndex;
|
||||
};
|
||||
|
||||
class EditBool : public EditBase, public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(EditBool)
|
||||
|
||||
public:
|
||||
void setValue(bool value);
|
||||
void setValueFromUniform() override;
|
||||
void toDefault() override;
|
||||
|
||||
private:
|
||||
void initialiseOverride() override;
|
||||
void notifyMouseButtonClick(MyGUI::Widget* sender);
|
||||
|
||||
MyGUI::Button* mCheckbutton;
|
||||
};
|
||||
|
||||
template <class T, class UType>
|
||||
class EditNumber : public EditBase, public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(EditNumber)
|
||||
|
||||
public:
|
||||
EditNumber() : mLastPointerX(0) {}
|
||||
|
||||
void setValue(T value)
|
||||
{
|
||||
mValue = value;
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
mValueLabel->setCaption(Misc::StringUtils::format("%.3f", mValue));
|
||||
else
|
||||
mValueLabel->setCaption(std::to_string(mValue));
|
||||
|
||||
if (auto uniform = mUniform.lock())
|
||||
{
|
||||
if constexpr (std::is_fundamental_v<UType>)
|
||||
uniform->template setValue<UType>(mValue);
|
||||
else
|
||||
{
|
||||
UType uvalue = uniform->template getValue<UType>();
|
||||
uvalue[mIndex] = mValue;
|
||||
uniform->template setValue<UType>(uvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setValueFromUniform() override
|
||||
{
|
||||
if (auto uniform = mUniform.lock())
|
||||
{
|
||||
T value;
|
||||
|
||||
if constexpr (std::is_fundamental_v<UType>)
|
||||
value = uniform->template getValue<UType>();
|
||||
else
|
||||
value = uniform->template getValue<UType>()[mIndex];
|
||||
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void toDefault() override
|
||||
{
|
||||
if (auto uniform = mUniform.lock())
|
||||
{
|
||||
if constexpr (std::is_fundamental_v<UType>)
|
||||
setValue(uniform->template getDefault<UType>());
|
||||
else
|
||||
setValue(uniform->template getDefault<UType>()[mIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void initialiseOverride() override
|
||||
{
|
||||
Base::initialiseOverride();
|
||||
|
||||
assignWidget(mDragger, "Dragger");
|
||||
assignWidget(mValueLabel, "Value");
|
||||
assignWidget(mButtonIncrease, "ButtonIncrease");
|
||||
assignWidget(mButtonDecrease, "ButtonDecrease");
|
||||
|
||||
mButtonIncrease->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNumber::notifyButtonClicked);
|
||||
mButtonDecrease->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNumber::notifyButtonClicked);
|
||||
|
||||
mDragger->eventMouseButtonPressed += MyGUI::newDelegate(this, &EditNumber::notifyMouseButtonPressed);
|
||||
mDragger->eventMouseDrag += MyGUI::newDelegate(this, &EditNumber::notifyMouseButtonDragged);
|
||||
mDragger->eventMouseWheel += MyGUI::newDelegate(this, &EditNumber::notifyMouseWheel);
|
||||
}
|
||||
|
||||
void notifyMouseWheel(MyGUI::Widget* sender, int rel)
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
if (rel > 0)
|
||||
increment(uniform->mStep);
|
||||
else
|
||||
increment(-uniform->mStep);
|
||||
}
|
||||
|
||||
void notifyMouseButtonDragged(MyGUI::Widget* sender, int left, int top, MyGUI::MouseButton id)
|
||||
{
|
||||
if (id != MyGUI::MouseButton::Left)
|
||||
return;
|
||||
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
int delta = left - mLastPointerX;
|
||||
|
||||
// allow finer tuning when shift is pressed
|
||||
constexpr double scaling = 20.0;
|
||||
T step = MyGUI::InputManager::getInstance().isShiftPressed() ? uniform->mStep / scaling : uniform->mStep;
|
||||
|
||||
if (step == 0)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
step = 1;
|
||||
else
|
||||
step = uniform->mStep;
|
||||
}
|
||||
|
||||
if (delta > 0)
|
||||
increment(step);
|
||||
else if (delta < 0)
|
||||
increment(-step);
|
||||
|
||||
mLastPointerX = left;
|
||||
}
|
||||
|
||||
void notifyMouseButtonPressed(MyGUI::Widget* sender, int left, int top, MyGUI::MouseButton id)
|
||||
{
|
||||
if (id != MyGUI::MouseButton::Left)
|
||||
return;
|
||||
|
||||
mLastPointerX = left;
|
||||
}
|
||||
|
||||
void increment(T step)
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
if constexpr (std::is_fundamental_v<UType>)
|
||||
setValue(std::clamp<T>(uniform->template getValue<UType>() + step, uniform->template getMin<UType>(), uniform->template getMax<T>()));
|
||||
else
|
||||
setValue(std::clamp<T>(uniform->template getValue<UType>()[mIndex] + step, uniform->template getMin<UType>()[mIndex], uniform->template getMax<UType>()[mIndex]));
|
||||
}
|
||||
|
||||
void notifyButtonClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
auto uniform = mUniform.lock();
|
||||
|
||||
if (!uniform)
|
||||
return;
|
||||
|
||||
if (sender == mButtonDecrease)
|
||||
increment(-uniform->mStep);
|
||||
else if (sender == mButtonIncrease)
|
||||
increment(uniform->mStep);
|
||||
}
|
||||
|
||||
MyGUI::Button* mButtonDecrease;
|
||||
MyGUI::Button* mButtonIncrease;
|
||||
MyGUI::Widget* mDragger;
|
||||
MyGUI::TextBox* mValueLabel;
|
||||
T mValue;
|
||||
|
||||
int mLastPointerX;
|
||||
};
|
||||
|
||||
class EditNumberFloat4 : public EditNumber<float, osg::Vec4f> { MYGUI_RTTI_DERIVED(EditNumberFloat4) };
|
||||
class EditNumberFloat3 : public EditNumber<float, osg::Vec3f> { MYGUI_RTTI_DERIVED(EditNumberFloat3) };
|
||||
class EditNumberFloat2 : public EditNumber<float, osg::Vec2f> { MYGUI_RTTI_DERIVED(EditNumberFloat2) };
|
||||
class EditNumberFloat : public EditNumber<float, float> { MYGUI_RTTI_DERIVED(EditNumberFloat) };
|
||||
class EditNumberInt : public EditNumber<int, int> { MYGUI_RTTI_DERIVED(EditNumberInt) };
|
||||
|
||||
class UniformBase final : public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(UniformBase)
|
||||
|
||||
public:
|
||||
void init(const std::shared_ptr<fx::Types::UniformBase>& uniform);
|
||||
|
||||
void toDefault();
|
||||
|
||||
void addItem(EditBase* item);
|
||||
|
||||
private:
|
||||
|
||||
void notifyResetClicked(MyGUI::Widget* sender);
|
||||
|
||||
void initialiseOverride() override;
|
||||
|
||||
Gui::AutoSizedButton* mReset;
|
||||
Gui::AutoSizedTextBox* mLabel;
|
||||
MyGUI::Widget* mClient;
|
||||
std::vector<EditBase*> mBases;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -39,6 +39,9 @@ const float TorsoHeight = 0.75f;
|
|||
static constexpr float sStepSizeUp = 34.0f;
|
||||
static constexpr float sMaxSlope = 46.0f;
|
||||
|
||||
// Identifier for main scene camera
|
||||
const std::string SceneCamera = "SceneCam";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace Resource
|
|||
: ResourceManager(vfs)
|
||||
, mWarningImage(createWarningImage())
|
||||
, mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba ignoreTga2Fields"))
|
||||
, mOptionsNoFlip(new osgDB::Options("dds_dxt1_detect_rgba ignoreTga2Fields"))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ namespace Resource
|
|||
return true;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Image> ImageManager::getImage(const std::string &filename)
|
||||
osg::ref_ptr<osg::Image> ImageManager::getImage(const std::string &filename, bool disableFlip)
|
||||
{
|
||||
const std::string normalized = mVFS->normalizeFilename(filename);
|
||||
|
||||
|
@ -135,7 +136,7 @@ namespace Resource
|
|||
stream->seekg(0);
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, mOptions);
|
||||
osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, disableFlip ? mOptionsNoFlip : mOptions);
|
||||
if (!result.success())
|
||||
{
|
||||
Log(Debug::Error) << "Error loading " << filename << ": " << result.message() << " code " << result.status();
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace Resource
|
|||
|
||||
/// Create or retrieve an Image
|
||||
/// Returns the dummy image if the given image is not found.
|
||||
osg::ref_ptr<osg::Image> getImage(const std::string& filename);
|
||||
osg::ref_ptr<osg::Image> getImage(const std::string& filename, bool disableFlip = false);
|
||||
|
||||
osg::Image* getWarningImage();
|
||||
|
||||
|
@ -37,6 +37,7 @@ namespace Resource
|
|||
private:
|
||||
osg::ref_ptr<osg::Image> mWarningImage;
|
||||
osg::ref_ptr<osgDB::Options> mOptions;
|
||||
osg::ref_ptr<osgDB::Options> mOptionsNoFlip;
|
||||
|
||||
ImageManager(const ImageManager&);
|
||||
void operator = (const ImageManager&);
|
||||
|
|
|
@ -318,7 +318,7 @@ namespace Resource
|
|||
, mApplyLightingToEnvMaps(false)
|
||||
, mLightingMethod(SceneUtil::LightingMethod::FFP)
|
||||
, mConvertAlphaTestToAlphaToCoverage(false)
|
||||
, mDepthFormat(0)
|
||||
, mSupportsNormalsRT(false)
|
||||
, mSharedStateManager(new SharedStateManager)
|
||||
, mImageManager(imageManager)
|
||||
, mNifFileManager(nifFileManager)
|
||||
|
@ -348,7 +348,7 @@ namespace Resource
|
|||
if (forceShadersForNode)
|
||||
shaderVisitor->setForceShaders(true);
|
||||
if (disableSoftParticles)
|
||||
shaderVisitor->setOpaqueDepthTex(nullptr);
|
||||
shaderVisitor->setOpaqueDepthTex(nullptr, nullptr);
|
||||
node->accept(*shaderVisitor);
|
||||
}
|
||||
|
||||
|
@ -368,16 +368,6 @@ namespace Resource
|
|||
return mClampLighting;
|
||||
}
|
||||
|
||||
void SceneManager::setDepthFormat(GLenum format)
|
||||
{
|
||||
mDepthFormat = format;
|
||||
}
|
||||
|
||||
GLenum SceneManager::getDepthFormat() const
|
||||
{
|
||||
return mDepthFormat;
|
||||
}
|
||||
|
||||
void SceneManager::setAutoUseNormalMaps(bool use)
|
||||
{
|
||||
mAutoUseNormalMaps = use;
|
||||
|
@ -440,9 +430,9 @@ namespace Resource
|
|||
mConvertAlphaTestToAlphaToCoverage = convert;
|
||||
}
|
||||
|
||||
void SceneManager::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texture)
|
||||
void SceneManager::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong)
|
||||
{
|
||||
mOpaqueDepthTex = texture;
|
||||
mOpaqueDepthTex = { texturePing, texturePong };
|
||||
}
|
||||
|
||||
SceneManager::~SceneManager()
|
||||
|
@ -930,7 +920,8 @@ namespace Resource
|
|||
shaderVisitor->setSpecularMapPattern(mSpecularMapPattern);
|
||||
shaderVisitor->setApplyLightingToEnvMaps(mApplyLightingToEnvMaps);
|
||||
shaderVisitor->setConvertAlphaTestToAlphaToCoverage(mConvertAlphaTestToAlphaToCoverage);
|
||||
shaderVisitor->setOpaqueDepthTex(mOpaqueDepthTex);
|
||||
shaderVisitor->setOpaqueDepthTex(mOpaqueDepthTex[0], mOpaqueDepthTex[1]);
|
||||
shaderVisitor->setSupportsNormalsRT(mSupportsNormalsRT);
|
||||
return shaderVisitor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,9 +91,6 @@ namespace Resource
|
|||
void setClampLighting(bool clamp);
|
||||
bool getClampLighting() const;
|
||||
|
||||
void setDepthFormat(GLenum format);
|
||||
GLenum getDepthFormat() const;
|
||||
|
||||
/// @see ShaderVisitor::setAutoUseNormalMaps
|
||||
void setAutoUseNormalMaps(bool use);
|
||||
|
||||
|
@ -112,12 +109,13 @@ namespace Resource
|
|||
void setSupportedLightingMethods(const SceneUtil::LightManager::SupportedMethods& supported);
|
||||
bool isSupportedLightingMethod(SceneUtil::LightingMethod method) const;
|
||||
|
||||
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texture);
|
||||
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong);
|
||||
|
||||
enum class UBOBinding
|
||||
{
|
||||
// If we add more UBO's, we should probably assign their bindings dynamically according to the current count of UBO's in the programTemplate
|
||||
LightBuffer
|
||||
LightBuffer,
|
||||
PostProcessor
|
||||
};
|
||||
void setLightingMethod(SceneUtil::LightingMethod method);
|
||||
SceneUtil::LightingMethod getLightingMethod() const;
|
||||
|
@ -195,6 +193,9 @@ namespace Resource
|
|||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
||||
|
||||
void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; }
|
||||
bool getSupportsNormalsRT() const { return mSupportsNormalsRT; }
|
||||
|
||||
private:
|
||||
|
||||
Shader::ShaderVisitor* createShaderVisitor(const std::string& shaderPrefix = "objects");
|
||||
|
@ -211,8 +212,8 @@ namespace Resource
|
|||
SceneUtil::LightingMethod mLightingMethod;
|
||||
SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods;
|
||||
bool mConvertAlphaTestToAlphaToCoverage;
|
||||
GLenum mDepthFormat;
|
||||
osg::ref_ptr<osg::Texture2D> mOpaqueDepthTex;
|
||||
bool mSupportsNormalsRT;
|
||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mOpaqueDepthTex;
|
||||
|
||||
osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager;
|
||||
mutable std::mutex mSharedStateMutex;
|
||||
|
|
42
components/sceneutil/clearcolor.hpp
Executable file
42
components/sceneutil/clearcolor.hpp
Executable file
|
@ -0,0 +1,42 @@
|
|||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_CLEARCOLOR_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_CLEARCOLOR_H
|
||||
|
||||
#include <osg/StateAttribute>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class ClearColor : public osg::StateAttribute
|
||||
{
|
||||
public:
|
||||
ClearColor() : mMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) {}
|
||||
ClearColor(const osg::Vec4f& color, GLbitfield mask) : mColor(color), mMask(mask) {}
|
||||
|
||||
ClearColor(const ClearColor& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::StateAttribute(copy,copyop), mColor(copy.mColor), mMask(copy.mMask) {}
|
||||
|
||||
META_StateAttribute(fx, ClearColor, static_cast<osg::StateAttribute::Type>(100))
|
||||
|
||||
int compare(const StateAttribute& sa) const override
|
||||
{
|
||||
COMPARE_StateAttribute_Types(ClearColor, sa);
|
||||
|
||||
COMPARE_StateAttribute_Parameter(mColor);
|
||||
COMPARE_StateAttribute_Parameter(mMask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply(osg::State& state) const override
|
||||
{
|
||||
glClearColor(mColor[0], mColor[1], mColor[2], mColor[3]);
|
||||
glClear(mMask);
|
||||
}
|
||||
|
||||
private:
|
||||
osg::Vec4f mColor;
|
||||
GLbitfield mMask;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -44,18 +44,6 @@ namespace SceneUtil
|
|||
);
|
||||
}
|
||||
|
||||
bool isFloatingPointDepthFormat(GLenum format)
|
||||
{
|
||||
constexpr std::array<GLenum, 4> formats = {
|
||||
GL_DEPTH_COMPONENT32F,
|
||||
GL_DEPTH_COMPONENT32F_NV,
|
||||
GL_DEPTH32F_STENCIL8,
|
||||
GL_DEPTH32F_STENCIL8_NV,
|
||||
};
|
||||
|
||||
return std::find(formats.cbegin(), formats.cend(), format) != formats.cend();
|
||||
}
|
||||
|
||||
bool isDepthFormat(GLenum format)
|
||||
{
|
||||
constexpr std::array<GLenum, 8> formats = {
|
||||
|
|
|
@ -45,9 +45,6 @@ namespace SceneUtil
|
|||
// Returns an orthographic projection matrix for use with a reversed z-buffer.
|
||||
osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far);
|
||||
|
||||
// Returns true if the GL format is a floating point depth format.
|
||||
bool isFloatingPointDepthFormat(GLenum format);
|
||||
|
||||
// Returns true if the GL format is a depth format
|
||||
bool isDepthFormat(GLenum format);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <components/misc/hash.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
|
@ -839,6 +840,7 @@ namespace SceneUtil
|
|||
, mPointLightFadeEnd(copy.mPointLightFadeEnd)
|
||||
, mPointLightFadeStart(copy.mPointLightFadeStart)
|
||||
, mMaxLights(copy.mMaxLights)
|
||||
, mPPLightBuffer(copy.mPPLightBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1001,6 +1003,9 @@ namespace SceneUtil
|
|||
|
||||
void LightManager::update(size_t frameNum)
|
||||
{
|
||||
if (mPPLightBuffer)
|
||||
mPPLightBuffer->clear(frameNum);
|
||||
|
||||
getLightIndexMap(frameNum).clear();
|
||||
mLights.clear();
|
||||
mLightsInViewSpace.clear();
|
||||
|
@ -1132,6 +1137,17 @@ namespace SceneUtil
|
|||
l.mLightSource = transform.mLightSource;
|
||||
l.mViewBound = viewBound;
|
||||
it->second.push_back(l);
|
||||
|
||||
if (mPPLightBuffer && it->first->getName() == Constants::SceneCamera)
|
||||
{
|
||||
const auto* light = l.mLightSource->getLight(frameNum);
|
||||
mPPLightBuffer->setLight(frameNum, light->getPosition() * (*viewMatrix),
|
||||
light->getDiffuse(),
|
||||
light->getConstantAttenuation(),
|
||||
light->getLinearAttenuation(),
|
||||
light->getQuadraticAttenuation(),
|
||||
l.mLightSource->getRadius());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1168,6 +1184,14 @@ namespace SceneUtil
|
|||
return uniform;
|
||||
}
|
||||
|
||||
void LightManager::setCollectPPLights(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
mPPLightBuffer = std::make_shared<PPLightBuffer>();
|
||||
else
|
||||
mPPLightBuffer = nullptr;
|
||||
}
|
||||
|
||||
LightSource::LightSource()
|
||||
: mRadius(0.f)
|
||||
, mActorFade(1.f)
|
||||
|
|
|
@ -26,6 +26,64 @@ namespace SceneUtil
|
|||
class LightBuffer;
|
||||
struct StateSetGenerator;
|
||||
|
||||
class PPLightBuffer
|
||||
{
|
||||
public:
|
||||
inline static constexpr auto sMaxPPLights = 30;
|
||||
inline static constexpr auto sMaxPPLightsArraySize = sMaxPPLights * 3;
|
||||
|
||||
PPLightBuffer()
|
||||
{
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
mIndex[i] = 0;
|
||||
mUniformBuffers[i] = new osg::Uniform(osg::Uniform::FLOAT_VEC4, "omw_PointLights", sMaxPPLightsArraySize);
|
||||
mUniformCount[i] = new osg::Uniform("omw_PointLightsCount", static_cast<int>(0));
|
||||
}
|
||||
}
|
||||
|
||||
void applyUniforms(size_t frame, osg::StateSet* stateset)
|
||||
{
|
||||
size_t frameId = frame % 2;
|
||||
|
||||
if (!stateset->getUniform("omw_PointLights"))
|
||||
stateset->addUniform(mUniformBuffers[frameId]);
|
||||
if (!stateset->getUniform("omw_PointLightsCount"))
|
||||
stateset->addUniform(mUniformCount[frameId]);
|
||||
|
||||
mUniformBuffers[frameId]->dirty();
|
||||
mUniformCount[frameId]->dirty();
|
||||
}
|
||||
|
||||
void clear(size_t frame)
|
||||
{
|
||||
mIndex[frame % 2] = 0;
|
||||
}
|
||||
|
||||
void setLight(size_t frame, const osg::Vec4f& position, osg::Vec4f diffuse, float ac, float al, float aq, float radius)
|
||||
{
|
||||
size_t frameId = frame % 2;
|
||||
size_t i = mIndex[frameId];
|
||||
|
||||
if (i >= (sMaxPPLights - 1))
|
||||
return;
|
||||
|
||||
i *= 3;
|
||||
|
||||
mUniformBuffers[frameId]->setElement(i + 0, position);
|
||||
mUniformBuffers[frameId]->setElement(i + 1, diffuse);
|
||||
mUniformBuffers[frameId]->setElement(i + 2, osg::Vec4f(ac, al, aq, radius));
|
||||
|
||||
mIndex[frameId]++;
|
||||
mUniformCount[frameId]->set(static_cast<int>(mIndex[frameId]));
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<size_t, 2> mIndex;
|
||||
std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformBuffers;
|
||||
std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformCount;
|
||||
};
|
||||
|
||||
enum class LightingMethod
|
||||
{
|
||||
FFP,
|
||||
|
@ -227,6 +285,11 @@ namespace SceneUtil
|
|||
|
||||
osg::ref_ptr<osg::Uniform> generateLightBufferUniform(const osg::Matrixf& sun);
|
||||
|
||||
// Whether to collect main scene camera points lights into a buffer to be later sent to postprocessing shaders
|
||||
void setCollectPPLights(bool enabled);
|
||||
|
||||
std::shared_ptr<PPLightBuffer> getPPLightsBuffer() { return mPPLightBuffer; }
|
||||
|
||||
private:
|
||||
void initFFP(int targetLights);
|
||||
void initPerObjectUniform(int targetLights);
|
||||
|
@ -285,6 +348,8 @@ namespace SceneUtil
|
|||
static constexpr auto mFFPMaxLights = 8;
|
||||
|
||||
static const std::unordered_map<std::string, LightingMethod> mLightingMethodSettingMap;
|
||||
|
||||
std::shared_ptr<PPLightBuffer> mPPLightBuffer;
|
||||
};
|
||||
|
||||
/// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace SceneUtil
|
|||
, mSamples(samples)
|
||||
, mGenerateMipmaps(generateMipmaps)
|
||||
, mColorBufferInternalFormat(Color::colorInternalFormat())
|
||||
, mDepthBufferInternalFormat(AutoDepth::depthInternalFormat())
|
||||
, mDepthBufferInternalFormat(SceneUtil::AutoDepth::depthInternalFormat())
|
||||
, mRenderOrderNum(renderOrderNum)
|
||||
, mStereoAwareness(stereoAwareness)
|
||||
{
|
||||
|
|
|
@ -152,42 +152,6 @@ void GlowUpdater::setDuration(float duration)
|
|||
mDuration = duration;
|
||||
}
|
||||
|
||||
// Allows camera to render to a color and floating point depth texture with a multisampled framebuffer.
|
||||
class AttachMultisampledDepthColorCallback : public SceneUtil::NodeCallback<AttachMultisampledDepthColorCallback, osg::Node*, osgUtil::CullVisitor*>
|
||||
{
|
||||
public:
|
||||
AttachMultisampledDepthColorCallback(osg::Texture2D* colorTex, osg::Texture2D* depthTex, int samples, int colorSamples)
|
||||
{
|
||||
int width = colorTex->getTextureWidth();
|
||||
int height = colorTex->getTextureHeight();
|
||||
|
||||
osg::ref_ptr<osg::RenderBuffer> rbColor = new osg::RenderBuffer(width, height, colorTex->getInternalFormat(), samples, colorSamples);
|
||||
osg::ref_ptr<osg::RenderBuffer> rbDepth = new osg::RenderBuffer(width, height, depthTex->getInternalFormat(), samples, colorSamples);
|
||||
|
||||
mMsaaFbo = new osg::FrameBufferObject;
|
||||
mMsaaFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(rbColor));
|
||||
mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(rbDepth));
|
||||
|
||||
mFbo = new osg::FrameBufferObject;
|
||||
mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(colorTex));
|
||||
mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthTex));
|
||||
}
|
||||
|
||||
void operator()(osg::Node* node, osgUtil::CullVisitor* cv)
|
||||
{
|
||||
osgUtil::RenderStage* renderStage = cv->getCurrentRenderStage();
|
||||
|
||||
renderStage->setMultisampleResolveFramebufferObject(mFbo);
|
||||
renderStage->setFrameBufferObject(mMsaaFbo);
|
||||
|
||||
traverse(node, cv);
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::FrameBufferObject> mFbo;
|
||||
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
|
||||
};
|
||||
|
||||
osg::Vec4f colourFromRGB(unsigned int clr)
|
||||
{
|
||||
osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f,
|
||||
|
|
64
components/serialization/osgyaml.hpp
Normal file
64
components/serialization/osgyaml.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef OPENMW_COMPONENTS_SERIALIZATION_OSGYAML_H
|
||||
#define OPENMW_COMPONENTS_SERIALIZATION_OSGYAML_H
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
namespace Serialization
|
||||
{
|
||||
template <class OSGVec>
|
||||
YAML::Node encodeOSGVec(const OSGVec& rhs)
|
||||
{
|
||||
YAML::Node node;
|
||||
for (int i = 0; i < OSGVec::num_components; ++i)
|
||||
node.push_back(rhs[i]);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
template <class OSGVec>
|
||||
bool decodeOSGVec(const YAML::Node& node, OSGVec& rhs)
|
||||
{
|
||||
if (!node.IsSequence() || node.size() != OSGVec::num_components)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < OSGVec::num_components; ++i)
|
||||
rhs[i] = node[i].as<typename OSGVec::value_type>();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
|
||||
template<>
|
||||
struct convert<osg::Vec2f>
|
||||
{
|
||||
static Node encode(const osg::Vec2f& rhs) { return Serialization::encodeOSGVec(rhs); }
|
||||
|
||||
static bool decode(const Node& node, osg::Vec2f& rhs) { return Serialization::decodeOSGVec(node, rhs); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<osg::Vec3f>
|
||||
{
|
||||
static Node encode(const osg::Vec3f& rhs) { return Serialization::encodeOSGVec(rhs); }
|
||||
|
||||
static bool decode(const Node& node, osg::Vec3f& rhs) { return Serialization::decodeOSGVec(node, rhs); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<osg::Vec4f>
|
||||
{
|
||||
static Node encode(const osg::Vec4f& rhs) { return Serialization::encodeOSGVec(rhs); }
|
||||
|
||||
static bool decode(const Node& node, osg::Vec4f& rhs) { return Serialization::decodeOSGVec(node, rhs); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
174
components/settings/shadermanager.hpp
Normal file
174
components/settings/shadermanager.hpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
#ifndef OPENMW_COMPONENTS_SETTINGS_SHADERMANAGER_H
|
||||
#define OPENMW_COMPONENTS_SETTINGS_SHADERMANAGER_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <fstream>
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
#include <components/serialization/osgyaml.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
/*
|
||||
* Manages the shader.yaml file which is auto-generated and lives next to settings.cfg.
|
||||
* This YAML file is simply a mapping of technique name to a list of uniforms and their values.
|
||||
* Currently only vec2f, vec3f, vec4f, int, and float uniforms are supported.
|
||||
*
|
||||
* config:
|
||||
* TECHNIQUE:
|
||||
* MY_FLOAT: 10.34
|
||||
* MY_VEC2: [0.23, 0.34]
|
||||
* TECHNIQUE2:
|
||||
* MY_VEC3: [0.22, 0.33, 0.20]
|
||||
*/
|
||||
class ShaderManager
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Mode
|
||||
{
|
||||
Normal,
|
||||
Debug
|
||||
};
|
||||
|
||||
ShaderManager() = default;
|
||||
ShaderManager(ShaderManager const&) = delete;
|
||||
void operator=(ShaderManager const&) = delete;
|
||||
|
||||
static ShaderManager& get()
|
||||
{
|
||||
static ShaderManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Mode getMode()
|
||||
{
|
||||
return mMode;
|
||||
}
|
||||
|
||||
void setMode(Mode mode)
|
||||
{
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
const YAML::Node& getRoot()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool setValue(const std::string& tname, const std::string& uname, const T& value)
|
||||
{
|
||||
if (mData.IsNull())
|
||||
{
|
||||
Log(Debug::Warning) << "Failed setting " << tname << ", " << uname << " : shader settings failed to load";
|
||||
return false;
|
||||
}
|
||||
|
||||
mData["config"][tname][uname] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::optional<T> getValue(const std::string& tname, const std::string& uname)
|
||||
{
|
||||
if (mData.IsNull())
|
||||
{
|
||||
Log(Debug::Warning) << "Failed getting " << tname << ", " << uname << " : shader settings failed to load";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto value = mData["config"][tname][uname];
|
||||
|
||||
if (!value)
|
||||
return std::nullopt;
|
||||
|
||||
return value.as<T>();
|
||||
}
|
||||
catch(const YAML::BadConversion& e)
|
||||
{
|
||||
Log(Debug::Warning) << "Failed retrieving " << tname << ", " << uname << " : mismatched types in config file.";
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool load(const std::string& path)
|
||||
{
|
||||
mData = YAML::Null;
|
||||
mPath = std::filesystem::path(path);
|
||||
|
||||
Log(Debug::Info) << "Loading shader settings file: " << mPath;
|
||||
|
||||
if (!std::filesystem::exists(mPath))
|
||||
{
|
||||
std::ofstream fout(mPath);
|
||||
if (!fout)
|
||||
{
|
||||
Log(Debug::Error) << "Failed creating shader settings file: " << mPath;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mData = YAML::LoadFile(mPath.string());
|
||||
mData.SetStyle(YAML::EmitterStyle::Block);
|
||||
|
||||
if (!mData["config"])
|
||||
mData["config"] = YAML::Node();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(const YAML::Exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Shader settings failed to load, " << e.msg;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool save()
|
||||
{
|
||||
if (mData.IsNull())
|
||||
{
|
||||
Log(Debug::Error) << "Shader settings failed to load, settings will not be saved: " << mPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(Debug::Info) << "Saving shader settings file: " << mPath;
|
||||
|
||||
YAML::Emitter out;
|
||||
out.SetMapFormat(YAML::Block);
|
||||
out << mData;
|
||||
|
||||
std::ofstream fout(mPath.string());
|
||||
fout << out.c_str();
|
||||
|
||||
if (!fout)
|
||||
{
|
||||
Log(Debug::Error) << "Failed saving shader settings file: " << mPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::filesystem::path mPath;
|
||||
YAML::Node mData;
|
||||
Mode mMode = Mode::Normal;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
#include <osg/Multisample>
|
||||
#include <osg/Texture>
|
||||
#include <osg/ValueObject>
|
||||
#include <osg/Capability>
|
||||
|
||||
#include <osgParticle/ParticleSystem>
|
||||
|
||||
|
@ -28,6 +29,50 @@
|
|||
#include "removedalphafunc.hpp"
|
||||
#include "shadermanager.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class OpaqueDepthAttribute : public osg::StateAttribute
|
||||
{
|
||||
public:
|
||||
OpaqueDepthAttribute() = default;
|
||||
|
||||
OpaqueDepthAttribute(const OpaqueDepthAttribute& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::StateAttribute(copy, copyop), mTextures(copy.mTextures), mUnit(copy.mUnit) {}
|
||||
|
||||
void setTexturesAndUnit(const std::array<osg::ref_ptr<osg::Texture2D>, 2>& textures, int unit)
|
||||
{
|
||||
mTextures = textures;
|
||||
mUnit = unit;
|
||||
}
|
||||
|
||||
META_StateAttribute(Shader, OpaqueDepthAttribute, osg::StateAttribute::TEXTURE)
|
||||
|
||||
int compare(const StateAttribute& sa) const override
|
||||
{
|
||||
COMPARE_StateAttribute_Types(OpaqueDepthAttribute, sa);
|
||||
|
||||
COMPARE_StateAttribute_Parameter(mTextures);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply(osg::State& state) const override
|
||||
{
|
||||
auto index = state.getFrameStamp()->getFrameNumber() % 2;
|
||||
|
||||
if (!mTextures[index])
|
||||
return;
|
||||
|
||||
state.setActiveTextureUnit(mUnit);
|
||||
state.applyTextureAttribute(mUnit, mTextures[index]);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::array<osg::ref_ptr<osg::Texture2D>, 2> mTextures;
|
||||
int mUnit;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Shader
|
||||
{
|
||||
/**
|
||||
|
@ -165,6 +210,7 @@ namespace Shader
|
|||
, mAutoUseSpecularMaps(false)
|
||||
, mApplyLightingToEnvMaps(false)
|
||||
, mConvertAlphaTestToAlphaToCoverage(false)
|
||||
, mSupportsNormalsRT(false)
|
||||
, mShaderManager(shaderManager)
|
||||
, mImageManager(imageManager)
|
||||
, mDefaultShaderPrefix(defaultShaderPrefix)
|
||||
|
@ -611,6 +657,14 @@ namespace Shader
|
|||
defineMap["endLight"] = "0";
|
||||
}
|
||||
|
||||
if (reqs.mAlphaBlend && mSupportsNormalsRT)
|
||||
{
|
||||
if (reqs.mSoftParticles)
|
||||
defineMap["disableNormals"] = "1";
|
||||
else
|
||||
writableStateSet->setAttribute(new osg::Disablei(GL_BLEND, 1));
|
||||
}
|
||||
|
||||
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST))
|
||||
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
||||
// This disables the deprecated fixed-function alpha test
|
||||
|
@ -629,7 +683,7 @@ namespace Shader
|
|||
updateRemovedState(*writableUserData, removedState);
|
||||
}
|
||||
|
||||
if (reqs.mSoftParticles)
|
||||
if (reqs.mSoftParticles && mOpaqueDepthTex.front())
|
||||
{
|
||||
osg::ref_ptr<osg::Depth> depth = new SceneUtil::AutoDepth;
|
||||
depth->setWriteMask(false);
|
||||
|
@ -639,14 +693,18 @@ namespace Shader
|
|||
writableStateSet->addUniform(new osg::Uniform("particleSize", reqs.mSoftParticleSize));
|
||||
addedState->addUniform("particleSize");
|
||||
|
||||
writableStateSet->addUniform(new osg::Uniform("opaqueDepthTex", 2));
|
||||
constexpr int unit = 2;
|
||||
|
||||
writableStateSet->addUniform(new osg::Uniform("opaqueDepthTex", unit));
|
||||
addedState->addUniform("opaqueDepthTex");
|
||||
|
||||
writableStateSet->setTextureAttributeAndModes(2, mOpaqueDepthTex, osg::StateAttribute::ON);
|
||||
addedState->setTextureAttributeAndModes(2, mOpaqueDepthTex);
|
||||
osg::ref_ptr<OpaqueDepthAttribute> opaqueDepthAttr = new OpaqueDepthAttribute;
|
||||
opaqueDepthAttr->setTexturesAndUnit(mOpaqueDepthTex, unit);
|
||||
writableStateSet->setAttributeAndModes(opaqueDepthAttr, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
addedState->setAttributeAndModes(opaqueDepthAttr);
|
||||
}
|
||||
|
||||
defineMap["softParticles"] = reqs.mSoftParticles ? "1" : "0";
|
||||
defineMap["softParticles"] = reqs.mSoftParticles && mOpaqueDepthTex.front() ? "1" : "0";
|
||||
|
||||
Stereo::Manager::instance().shaderStereoDefines(defineMap);
|
||||
|
||||
|
@ -840,7 +898,7 @@ namespace Shader
|
|||
{
|
||||
pushRequirements(drawable);
|
||||
|
||||
if (partsys && mOpaqueDepthTex)
|
||||
if (partsys)
|
||||
{
|
||||
mRequirements.back().mSoftParticles = true;
|
||||
mRequirements.back().mSoftParticleSize = partsys->getDefaultParticleTemplate().getSizeRange().maximum;
|
||||
|
@ -915,9 +973,9 @@ namespace Shader
|
|||
mConvertAlphaTestToAlphaToCoverage = convert;
|
||||
}
|
||||
|
||||
void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texture)
|
||||
void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong)
|
||||
{
|
||||
mOpaqueDepthTex = texture;
|
||||
mOpaqueDepthTex = { texturePing, texturePong };
|
||||
}
|
||||
|
||||
ReinstateRemovedStateVisitor::ReinstateRemovedStateVisitor(bool allowedToModifyStateSets)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef OPENMW_COMPONENTS_SHADERVISITOR_H
|
||||
#define OPENMW_COMPONENTS_SHADERVISITOR_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/Program>
|
||||
#include <osg/Texture2D>
|
||||
|
@ -46,7 +48,9 @@ namespace Shader
|
|||
|
||||
void setConvertAlphaTestToAlphaToCoverage(bool convert);
|
||||
|
||||
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texture);
|
||||
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong);
|
||||
|
||||
void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; }
|
||||
|
||||
void apply(osg::Node& node) override;
|
||||
|
||||
|
@ -73,6 +77,8 @@ namespace Shader
|
|||
|
||||
bool mConvertAlphaTestToAlphaToCoverage;
|
||||
|
||||
bool mSupportsNormalsRT;
|
||||
|
||||
ShaderManager& mShaderManager;
|
||||
Resource::ImageManager& mImageManager;
|
||||
|
||||
|
@ -87,7 +93,7 @@ namespace Shader
|
|||
bool mShaderRequired;
|
||||
|
||||
int mColorMode;
|
||||
|
||||
|
||||
bool mMaterialOverridden;
|
||||
bool mAlphaTestOverridden;
|
||||
bool mAlphaBlendOverridden;
|
||||
|
@ -116,7 +122,7 @@ namespace Shader
|
|||
bool adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs);
|
||||
|
||||
osg::ref_ptr<const osg::Program> mProgramTemplate;
|
||||
osg::ref_ptr<osg::Texture2D> mOpaqueDepthTex;
|
||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mOpaqueDepthTex;
|
||||
};
|
||||
|
||||
class ReinstateRemovedStateVisitor : public osg::NodeVisitor
|
||||
|
|
162
components/std140/ubo.hpp
Normal file
162
components/std140/ubo.hpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
#ifndef COMPONENTS_STD140_UBO_H
|
||||
#define COMPONENTS_STD140_UBO_H
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/Matrixf>
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace std140
|
||||
{
|
||||
struct Mat4
|
||||
{
|
||||
using Value = osg::Matrixf;
|
||||
Value mValue;
|
||||
static constexpr size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "mat4";
|
||||
};
|
||||
|
||||
struct Vec4
|
||||
{
|
||||
using Value = osg::Vec4f;
|
||||
Value mValue;
|
||||
static constexpr size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "vec4";
|
||||
};
|
||||
|
||||
struct Vec3
|
||||
{
|
||||
using Value = osg::Vec3f;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = 4 * sizeof(osg::Vec3f::value_type);
|
||||
static constexpr std::string_view sTypeName = "vec3";
|
||||
};
|
||||
|
||||
struct Vec2
|
||||
{
|
||||
using Value = osg::Vec2f;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "vec2";
|
||||
};
|
||||
|
||||
struct Float
|
||||
{
|
||||
using Value = float;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "float";
|
||||
};
|
||||
|
||||
struct Int
|
||||
{
|
||||
using Value = std::int32_t;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "int";
|
||||
};
|
||||
|
||||
struct UInt
|
||||
{
|
||||
using Value = std::uint32_t;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "uint";
|
||||
};
|
||||
|
||||
struct Bool
|
||||
{
|
||||
using Value = std::int32_t;
|
||||
Value mValue;
|
||||
static constexpr std::size_t sAlign = sizeof(Value);
|
||||
static constexpr std::string_view sTypeName = "bool";
|
||||
};
|
||||
|
||||
template <class... CArgs>
|
||||
class UBO
|
||||
{
|
||||
private:
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct contains : std::bool_constant<(std::is_base_of_v<Args, T> || ...)> { };
|
||||
|
||||
static_assert((contains<CArgs, Mat4, Vec4, Vec3, Vec2, Float, Int, UInt, Bool>() && ...));
|
||||
|
||||
static constexpr size_t roundUpRemainder(size_t x, size_t multiple)
|
||||
{
|
||||
size_t remainder = x % multiple;
|
||||
if (remainder == 0)
|
||||
return 0;
|
||||
return multiple - remainder;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static constexpr std::size_t getOffset()
|
||||
{
|
||||
bool found = false;
|
||||
std::size_t size = 0;
|
||||
((
|
||||
found = found || std::is_same_v<T, CArgs>,
|
||||
size += (found ? 0 : sizeof(typename CArgs::Value) + roundUpRemainder(size, CArgs::sAlign))
|
||||
) , ...);
|
||||
return size + roundUpRemainder(size, T::sAlign);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t getGPUSize()
|
||||
{
|
||||
std::size_t size = 0;
|
||||
((size += (sizeof(typename CArgs::Value) + roundUpRemainder(size, CArgs::sAlign))), ...);
|
||||
return size;
|
||||
}
|
||||
|
||||
static std::string getDefinition(const std::string& name)
|
||||
{
|
||||
std::string structDefinition = "struct " + name + " {\n";
|
||||
((structDefinition += (" " + std::string(CArgs::sTypeName) + " " + std::string(CArgs::sName) + ";\n")), ...);
|
||||
return structDefinition + "};";
|
||||
}
|
||||
|
||||
using BufferType = std::array<char, getGPUSize()>;
|
||||
using TupleType = std::tuple<CArgs...>;
|
||||
|
||||
template <class T>
|
||||
typename T::Value& get()
|
||||
{
|
||||
return std::get<T>(mData).mValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const typename T::Value& get() const
|
||||
{
|
||||
return std::get<T>(mData).mValue;
|
||||
}
|
||||
|
||||
void copyTo(BufferType& buffer) const
|
||||
{
|
||||
const auto copy = [&] (const auto& v) {
|
||||
static_assert(std::is_standard_layout_v<std::decay_t<decltype(v.mValue)>>);
|
||||
constexpr std::size_t offset = getOffset<std::decay_t<decltype(v)>>();
|
||||
std::memcpy(buffer.data() + offset, &v.mValue, sizeof(v.mValue));
|
||||
};
|
||||
|
||||
std::apply([&] (const auto& ... v) { (copy(v) , ...); }, mData);
|
||||
}
|
||||
|
||||
const auto& getData() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<CArgs...> mData;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -3,7 +3,6 @@
|
|||
#include <osg/FrameBufferObject>
|
||||
#include <osg/GLExtensions>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Texture2DMultisample>
|
||||
#include <osg/Texture2DArray>
|
||||
#include <osgUtil/RenderStage>
|
||||
#include <osgUtil/CullVisitor>
|
||||
|
@ -322,10 +321,7 @@ namespace Stereo
|
|||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
if (mSamples > 1)
|
||||
{
|
||||
mMsaaColorTexture[i] = createTextureMsaa(sourceFormat, sourceType, internalFormat);
|
||||
mLayerMsaaFbo[i]->setAttachment(osg::Camera::COLOR_BUFFER, osg::FrameBufferAttachment(mMsaaColorTexture[i]));
|
||||
}
|
||||
mLayerMsaaFbo[i]->setAttachment(osg::Camera::COLOR_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(mWidth, mHeight, internalFormat, mSamples)));
|
||||
mColorTexture[i] = createTexture(sourceFormat, sourceType, internalFormat);
|
||||
mLayerFbo[i]->setAttachment(osg::Camera::COLOR_BUFFER, osg::FrameBufferAttachment(mColorTexture[i]));
|
||||
}
|
||||
|
@ -351,10 +347,7 @@ namespace Stereo
|
|||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
if (mSamples > 1)
|
||||
{
|
||||
mMsaaDepthTexture[i] = createTextureMsaa(sourceFormat, sourceType, internalFormat);
|
||||
mLayerMsaaFbo[i]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(mMsaaDepthTexture[i]));
|
||||
}
|
||||
mLayerMsaaFbo[i]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(mWidth, mHeight, internalFormat, mSamples)));
|
||||
mDepthTexture[i] = createTexture(sourceFormat, sourceType, internalFormat);
|
||||
mLayerFbo[i]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(mDepthTexture[i]));
|
||||
}
|
||||
|
@ -381,6 +374,11 @@ namespace Stereo
|
|||
return mMultiviewColorTexture;
|
||||
}
|
||||
|
||||
osg::Texture2DArray* MultiviewFramebuffer::multiviewDepthBuffer()
|
||||
{
|
||||
return mMultiviewDepthTexture;
|
||||
}
|
||||
|
||||
osg::Texture2D* MultiviewFramebuffer::layerColorBuffer(int i)
|
||||
{
|
||||
return mColorTexture[i];
|
||||
|
@ -451,22 +449,6 @@ namespace Stereo
|
|||
return texture;
|
||||
}
|
||||
|
||||
osg::Texture2DMultisample* MultiviewFramebuffer::createTextureMsaa(GLint sourceFormat, GLint sourceType, GLint internalFormat)
|
||||
{
|
||||
osg::Texture2DMultisample* texture = new osg::Texture2DMultisample;
|
||||
texture->setTextureSize(mWidth, mHeight);
|
||||
texture->setNumSamples(mSamples);
|
||||
texture->setSourceFormat(sourceFormat);
|
||||
texture->setSourceType(sourceType);
|
||||
texture->setInternalFormat(internalFormat);
|
||||
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
||||
return texture;
|
||||
}
|
||||
|
||||
osg::Texture2DArray* MultiviewFramebuffer::createTextureArray(GLint sourceFormat, GLint sourceType, GLint internalFormat)
|
||||
{
|
||||
osg::Texture2DArray* textureArray = new osg::Texture2DArray;
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace osg
|
|||
class FrameBufferObject;
|
||||
class Texture;
|
||||
class Texture2D;
|
||||
class Texture2DMultisample;
|
||||
class Texture2DArray;
|
||||
}
|
||||
|
||||
|
@ -50,6 +49,7 @@ namespace Stereo
|
|||
osg::FrameBufferObject* layerFbo(int i);
|
||||
osg::FrameBufferObject* layerMsaaFbo(int i);
|
||||
osg::Texture2DArray* multiviewColorBuffer();
|
||||
osg::Texture2DArray* multiviewDepthBuffer();
|
||||
osg::Texture2D* layerColorBuffer(int i);
|
||||
osg::Texture2D* layerDepthBuffer(int i);
|
||||
|
||||
|
@ -62,7 +62,6 @@ namespace Stereo
|
|||
|
||||
private:
|
||||
osg::Texture2D* createTexture(GLint sourceFormat, GLint sourceType, GLint internalFormat);
|
||||
osg::Texture2DMultisample* createTextureMsaa(GLint sourceFormat, GLint sourceType, GLint internalFormat);
|
||||
osg::Texture2DArray* createTextureArray(GLint sourceFormat, GLint sourceType, GLint internalFormat);
|
||||
|
||||
int mWidth;
|
||||
|
@ -76,9 +75,7 @@ namespace Stereo
|
|||
osg::ref_ptr<osg::Texture2DArray> mMultiviewColorTexture;
|
||||
osg::ref_ptr<osg::Texture2DArray> mMultiviewDepthTexture;
|
||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mColorTexture;
|
||||
std::array<osg::ref_ptr<osg::Texture2DMultisample>, 2> mMsaaColorTexture;
|
||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
|
||||
std::array<osg::ref_ptr<osg::Texture2DMultisample>, 2> mMsaaDepthTexture;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace osg
|
|||
{
|
||||
class FrameBufferObject;
|
||||
class Texture2D;
|
||||
class Texture2DMultisample;
|
||||
class Texture2DArray;
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ std::vector<osg::ref_ptr<osg::StateSet> > ChunkManager::createPasses(float chunk
|
|||
|
||||
float blendmapScale = mStorage->getBlendmapScale(chunkSize);
|
||||
|
||||
return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale);
|
||||
return ::Terrain::createPasses(useShaders, mSceneManager, layers, blendmapTextures, blendmapScale, blendmapScale);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry)
|
||||
|
@ -268,7 +268,7 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
|||
layer.mDiffuseMap = compositeMap->mTexture;
|
||||
layer.mParallax = false;
|
||||
layer.mSpecular = false;
|
||||
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
|
||||
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager, std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
#include <osg/Texture2D>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Capability>
|
||||
|
||||
#include <components/stereo/stereomanager.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/shader/shadermanager.hpp>
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
|
||||
|
@ -194,9 +196,10 @@ namespace
|
|||
|
||||
namespace Terrain
|
||||
{
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector<TextureLayer> &layers,
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager, const std::vector<TextureLayer> &layers,
|
||||
const std::vector<osg::ref_ptr<osg::Texture2D> > &blendmaps, int blendmapScale, float layerTileSize)
|
||||
{
|
||||
auto& shaderManager = sceneManager->getShaderManager();
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > passes;
|
||||
|
||||
unsigned int blendmapIndex = 0;
|
||||
|
@ -209,6 +212,8 @@ namespace Terrain
|
|||
if (!blendmaps.empty())
|
||||
{
|
||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
if (sceneManager->getSupportsNormalsRT())
|
||||
stateset->setAttribute(new osg::Disablei(GL_BLEND, 1));
|
||||
stateset->setRenderBinDetails(firstLayer ? 0 : 1, "RenderBin");
|
||||
if (!firstLayer)
|
||||
{
|
||||
|
@ -251,18 +256,18 @@ namespace Terrain
|
|||
defineMap["blendMap"] = (!blendmaps.empty()) ? "1" : "0";
|
||||
defineMap["specularMap"] = it->mSpecular ? "1" : "0";
|
||||
defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0";
|
||||
|
||||
defineMap["writeNormals"] = (it == layers.end() - 1) ? "1" : "0";
|
||||
Stereo::Manager::instance().shaderStereoDefines(defineMap);
|
||||
|
||||
osg::ref_ptr<osg::Shader> vertexShader = shaderManager->getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX);
|
||||
osg::ref_ptr<osg::Shader> fragmentShader = shaderManager->getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT);
|
||||
osg::ref_ptr<osg::Shader> vertexShader = shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX);
|
||||
osg::ref_ptr<osg::Shader> fragmentShader = shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT);
|
||||
if (!vertexShader || !fragmentShader)
|
||||
{
|
||||
// Try again without shader. Error already logged by above
|
||||
return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize);
|
||||
return createPasses(false, sceneManager, layers, blendmaps, blendmapScale, layerTileSize);
|
||||
}
|
||||
|
||||
stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader));
|
||||
stateset->setAttributeAndModes(shaderManager.getProgram(vertexShader, fragmentShader));
|
||||
stateset->addUniform(UniformCollection::value().mColorMode);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace osg
|
|||
class Texture2D;
|
||||
}
|
||||
|
||||
namespace Shader
|
||||
namespace Resource
|
||||
{
|
||||
class ShaderManager;
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace Terrain
|
||||
|
@ -26,7 +26,7 @@ namespace Terrain
|
|||
bool mSpecular;
|
||||
};
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Shader::ShaderManager* shaderManager,
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager,
|
||||
const std::vector<TextureLayer>& layers,
|
||||
const std::vector<osg::ref_ptr<osg::Texture2D> >& blendmaps, int blendmapScale, float layerTileSize);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace VFS
|
|||
virtual ~File() {}
|
||||
|
||||
virtual Files::IStreamPtr open() = 0;
|
||||
|
||||
virtual std::string getPath() = 0;
|
||||
};
|
||||
|
||||
class Archive
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace VFS
|
|||
|
||||
Files::IStreamPtr open() override;
|
||||
|
||||
std::string getPath() override { return mInfo->name(); }
|
||||
|
||||
const Bsa::BSAFile::FileStruct* mInfo;
|
||||
Bsa::BSAFile* mFile;
|
||||
};
|
||||
|
@ -26,6 +28,8 @@ namespace VFS
|
|||
|
||||
Files::IStreamPtr open() override;
|
||||
|
||||
std::string getPath() override { return mInfo->name(); }
|
||||
|
||||
const Bsa::BSAFile::FileStruct* mInfo;
|
||||
Bsa::CompressedBSAFile* mCompressedFile;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace VFS
|
|||
|
||||
Files::IStreamPtr open() override;
|
||||
|
||||
std::string getPath() override { return mPath; }
|
||||
|
||||
private:
|
||||
std::string mPath;
|
||||
|
||||
|
|
|
@ -105,6 +105,17 @@ namespace VFS
|
|||
return {};
|
||||
}
|
||||
|
||||
std::string Manager::getAbsoluteFileName(const std::string& name) const
|
||||
{
|
||||
std::string normalized = name;
|
||||
normalize_path(normalized, mStrict);
|
||||
|
||||
std::map<std::string, File*>::const_iterator found = mIndex.find(normalized);
|
||||
if (found == mIndex.end())
|
||||
throw std::runtime_error("Resource '" + normalized + "' not found");
|
||||
return found->second->getPath();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool startsWith(std::string_view text, std::string_view start)
|
||||
|
|
|
@ -90,6 +90,11 @@ namespace VFS
|
|||
/// @note May be called from any thread once the index has been built.
|
||||
RecursiveDirectoryRange getRecursiveDirectoryIterator(const std::string& path) const;
|
||||
|
||||
/// Retrieve the absolute path to the file
|
||||
/// @note Throws an exception if the file can not be found.
|
||||
/// @note May be called from any thread once the index has been built.
|
||||
std::string getAbsoluteFileName(const std::string& name) const;
|
||||
|
||||
private:
|
||||
bool mStrict;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue