Add config option to force alpha-tested materials.
This was SVN commit r11475.
This commit is contained in:
parent
11115770ec
commit
f2260892bd
@ -58,6 +58,9 @@ renderpath = default
|
||||
; Prefer GLSL shaders over ARB shaders (not recommended)
|
||||
preferglsl = false
|
||||
|
||||
; Replace alpha-blending with alpha-testing, for performance experiments
|
||||
forcealphatest = false
|
||||
|
||||
; Opt-in online user reporting system
|
||||
userreport.url = "http://feedback.wildfiregames.com/report/upload/v1/"
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<alpha_blending/>
|
||||
<alternative material="alphatest.xml" if="CFG_FORCE_ALPHATEST"/>
|
||||
|
||||
<shader effect="model_transparent"/>
|
||||
<alpha_blending/>
|
||||
<define name="USE_TRANSPARENT" value="1"/>
|
||||
</material>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<shader effect="model_transparent"/>
|
||||
<alternative material="alphatest_spec.xml" if="CFG_FORCE_ALPHATEST"/>
|
||||
|
||||
<shader effect="model_transparent"/>
|
||||
<alpha_blending/>
|
||||
<define name="USE_TRANSPARENT" value="1"/>
|
||||
|
||||
|
@ -22,7 +22,9 @@
|
||||
#include "lib/ogl.h"
|
||||
#include "maths/Vector4D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/PreprocessorWrapper.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
||||
{
|
||||
@ -40,10 +42,13 @@ CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
||||
#define EL(x) int el_##x = xeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = xeroFile.GetAttributeID(#x)
|
||||
EL(alpha_blending);
|
||||
EL(alternative);
|
||||
EL(define);
|
||||
EL(shader);
|
||||
EL(uniform);
|
||||
AT(effect);
|
||||
AT(if);
|
||||
AT(material);
|
||||
AT(name);
|
||||
AT(value);
|
||||
#undef AT
|
||||
@ -54,11 +59,22 @@ CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
||||
XMBElement root = xeroFile.GetRoot();
|
||||
XMBElementList childNodes = root.GetChildNodes();
|
||||
|
||||
CPreprocessorWrapper preprocessor;
|
||||
preprocessor.AddDefine("CFG_FORCE_ALPHATEST", g_Renderer.m_Options.m_ForceAlphaTest ? "1" : "0");
|
||||
|
||||
XERO_ITER_EL(root, node)
|
||||
{
|
||||
int token = node.GetNodeName();
|
||||
XMBAttributeList attrs = node.GetAttributes();
|
||||
if (token == el_alpha_blending)
|
||||
if (token == el_alternative)
|
||||
{
|
||||
if (preprocessor.TestConditional(attrs.GetNamedItem(at_if)))
|
||||
{
|
||||
material = LoadMaterial(VfsPath("art/materials") / attrs.GetNamedItem(at_material).FromUTF8());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (token == el_alpha_blending)
|
||||
{
|
||||
material.SetUsesAlphaBlending(true);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CStrIntern.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Preprocessor.h"
|
||||
#include "ps/PreprocessorWrapper.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/XML/XMLWriter.h"
|
||||
@ -107,36 +107,6 @@ static GLenum ParseAttribSemantics(const CStr& str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool CheckPreprocessorConditional(CPreprocessor& preprocessor, const CStr& expr)
|
||||
{
|
||||
// Construct a dummy program so we can trigger the preprocessor's expression
|
||||
// code without modifying its public API.
|
||||
// Be careful that the API buggily returns a statically allocated pointer
|
||||
// (which we will try to free()) if the input just causes it to append a single
|
||||
// sequence of newlines to the output; the "\n" after the "#endif" is enough
|
||||
// to avoid this case.
|
||||
CStr input = "#if ";
|
||||
input += expr;
|
||||
input += "\n1\n#endif\n";
|
||||
|
||||
size_t len = 0;
|
||||
char* output = preprocessor.Parse(input.c_str(), input.size(), len);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
LOGERROR(L"Failed to parse conditional expression '%hs'", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = (memchr(output, '1', len) != NULL);
|
||||
|
||||
// Free output if it's not inside the source string
|
||||
if (!(output >= input.c_str() && output < input.c_str() + input.size()))
|
||||
free(output);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program)
|
||||
{
|
||||
PROFILE2("loading shader");
|
||||
@ -191,10 +161,8 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStrIntern, CStrIntern> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
CPreprocessorWrapper preprocessor;
|
||||
preprocessor.AddDefines(baseDefines);
|
||||
|
||||
XMBElement Root = XeroFile.GetRoot();
|
||||
|
||||
@ -222,7 +190,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
||||
XMBAttributeList Attrs = Param.GetAttributes();
|
||||
|
||||
CStr cond = Attrs.GetNamedItem(at_if);
|
||||
if (!cond.empty() && !CheckPreprocessorConditional(preprocessor, cond))
|
||||
if (!cond.empty() && !preprocessor.TestConditional(cond))
|
||||
continue;
|
||||
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
@ -263,7 +231,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
||||
XMBAttributeList Attrs = Param.GetAttributes();
|
||||
|
||||
CStr cond = Attrs.GetNamedItem(at_if);
|
||||
if (!cond.empty() && !CheckPreprocessorConditional(preprocessor, cond))
|
||||
if (!cond.empty() && !preprocessor.TestConditional(cond))
|
||||
continue;
|
||||
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
@ -443,10 +411,8 @@ bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefin
|
||||
bool preferGLSL = (baseDefines.GetInt("SYS_PREFER_GLSL") != 0);
|
||||
|
||||
// Prepare the preprocessor for conditional tests
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStrIntern, CStrIntern> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
CPreprocessorWrapper preprocessor;
|
||||
preprocessor.AddDefines(baseDefines);
|
||||
|
||||
XMBElement Root = XeroFile.GetRoot();
|
||||
|
||||
@ -489,7 +455,7 @@ bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefin
|
||||
else if (!Attrs.GetNamedItem(at_context).empty())
|
||||
{
|
||||
CStr cond = Attrs.GetNamedItem(at_context);
|
||||
if (!CheckPreprocessorConditional(preprocessor, cond))
|
||||
if (!preprocessor.TestConditional(cond))
|
||||
isUsable = false;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Overlay.h"
|
||||
#include "ps/Preprocessor.h"
|
||||
#include "ps/PreprocessorWrapper.h"
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
|
||||
@ -94,13 +94,11 @@ public:
|
||||
if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
|
||||
return;
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStrIntern, CStrIntern> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
CPreprocessorWrapper preprocessor;
|
||||
preprocessor.AddDefines(m_Defines);
|
||||
|
||||
CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
|
||||
CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
|
||||
CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString());
|
||||
CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString());
|
||||
|
||||
// printf(">>>\n%s<<<\n", vertexCode.c_str());
|
||||
// printf(">>>\n%s<<<\n", fragmentCode.c_str());
|
||||
@ -427,10 +425,8 @@ public:
|
||||
if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
|
||||
return;
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStrIntern, CStrIntern> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
CPreprocessorWrapper preprocessor;
|
||||
preprocessor.AddDefines(m_Defines);
|
||||
|
||||
#if CONFIG2_GLES
|
||||
// GLES defines the macro "GL_ES" in its GLSL preprocessor,
|
||||
@ -439,8 +435,8 @@ public:
|
||||
preprocessor.Define("GL_ES", "1");
|
||||
#endif
|
||||
|
||||
CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
|
||||
CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
|
||||
CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString());
|
||||
CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString());
|
||||
|
||||
#if CONFIG2_GLES
|
||||
// Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00,
|
||||
@ -735,26 +731,6 @@ void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v)
|
||||
Uniform(GetUniformBinding(id), v);
|
||||
}
|
||||
|
||||
CStr CShaderProgram::Preprocess(CPreprocessor& preprocessor, const CStr& input)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* output = preprocessor.Parse(input.c_str(), input.size(), len);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
LOGERROR(L"Shader preprocessing failed");
|
||||
return "";
|
||||
}
|
||||
|
||||
CStr ret(output, len);
|
||||
|
||||
// Free output if it's not inside the source string
|
||||
if (!(output >= input.c_str() && output < input.c_str() + input.size()))
|
||||
free(output);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG2_GLES
|
||||
|
||||
// These should all be overridden by CShaderProgramGLSL
|
||||
|
@ -29,7 +29,6 @@
|
||||
struct CColor;
|
||||
class CMatrix3D;
|
||||
class CVector3D;
|
||||
class CPreprocessor;
|
||||
class CShaderDefines;
|
||||
class CStrIntern;
|
||||
|
||||
@ -193,8 +192,6 @@ public:
|
||||
protected:
|
||||
CShaderProgram(int streamflags);
|
||||
|
||||
CStr Preprocess(CPreprocessor& preprocessor, const CStr& input);
|
||||
|
||||
bool m_IsValid;
|
||||
int m_StreamFlags;
|
||||
|
||||
|
86
source/ps/PreprocessorWrapper.cpp
Normal file
86
source/ps/PreprocessorWrapper.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "PreprocessorWrapper.h"
|
||||
|
||||
#include "graphics/ShaderDefines.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
void CPreprocessorWrapper::AddDefine(const char* name, const char* value)
|
||||
{
|
||||
m_Preprocessor.Define(name, value);
|
||||
}
|
||||
|
||||
void CPreprocessorWrapper::AddDefines(const CShaderDefines& defines)
|
||||
{
|
||||
std::map<CStrIntern, CStrIntern> map = defines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = map.begin(); it != map.end(); ++it)
|
||||
m_Preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
}
|
||||
|
||||
bool CPreprocessorWrapper::TestConditional(const CStr& expr)
|
||||
{
|
||||
// Construct a dummy program so we can trigger the preprocessor's expression
|
||||
// code without modifying its public API.
|
||||
// Be careful that the API buggily returns a statically allocated pointer
|
||||
// (which we will try to free()) if the input just causes it to append a single
|
||||
// sequence of newlines to the output; the "\n" after the "#endif" is enough
|
||||
// to avoid this case.
|
||||
CStr input = "#if ";
|
||||
input += expr;
|
||||
input += "\n1\n#endif\n";
|
||||
|
||||
size_t len = 0;
|
||||
char* output = m_Preprocessor.Parse(input.c_str(), input.size(), len);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
LOGERROR(L"Failed to parse conditional expression '%hs'", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = (memchr(output, '1', len) != NULL);
|
||||
|
||||
// Free output if it's not inside the source string
|
||||
if (!(output >= input.c_str() && output < input.c_str() + input.size()))
|
||||
free(output);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
CStr CPreprocessorWrapper::Preprocess(const CStr& input)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* output = m_Preprocessor.Parse(input.c_str(), input.size(), len);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
LOGERROR(L"Shader preprocessing failed");
|
||||
return "";
|
||||
}
|
||||
|
||||
CStr ret(output, len);
|
||||
|
||||
// Free output if it's not inside the source string
|
||||
if (!(output >= input.c_str() && output < input.c_str() + input.size()))
|
||||
free(output);
|
||||
|
||||
return ret;
|
||||
}
|
43
source/ps/PreprocessorWrapper.h
Normal file
43
source/ps/PreprocessorWrapper.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_PREPROCESSORWRAPPER
|
||||
#define INCLUDED_PREPROCESSORWRAPPER
|
||||
|
||||
#include "ps/Preprocessor.h"
|
||||
|
||||
class CShaderDefines;
|
||||
|
||||
/**
|
||||
* Convenience wrapper around CPreprocessor.
|
||||
*/
|
||||
class CPreprocessorWrapper
|
||||
{
|
||||
public:
|
||||
void AddDefine(const char* name, const char* value);
|
||||
|
||||
void AddDefines(const CShaderDefines& defines);
|
||||
|
||||
bool TestConditional(const CStr& expr);
|
||||
|
||||
CStr Preprocess(const CStr& input);
|
||||
|
||||
private:
|
||||
CPreprocessor m_Preprocessor;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_PREPROCESSORWRAPPER
|
@ -409,9 +409,11 @@ CRenderer::CRenderer()
|
||||
m_Options.m_ARBProgramShadow = true;
|
||||
m_Options.m_ShadowPCF = false;
|
||||
m_Options.m_PreferGLSL = false;
|
||||
m_Options.m_ForceAlphaTest = false;
|
||||
|
||||
// TODO: be more consistent in use of the config system
|
||||
CFG_GET_USER_VAL("preferglsl", Bool, m_Options.m_PreferGLSL);
|
||||
CFG_GET_USER_VAL("forcealphatest", Bool, m_Options.m_ForceAlphaTest);
|
||||
|
||||
#if CONFIG2_GLES
|
||||
// Override config option since GLES only supports GLSL
|
||||
|
@ -122,6 +122,7 @@ public:
|
||||
bool m_ARBProgramShadow;
|
||||
bool m_ShadowPCF;
|
||||
bool m_PreferGLSL;
|
||||
bool m_ForceAlphaTest;
|
||||
} m_Options;
|
||||
|
||||
struct Caps {
|
||||
|
Loading…
Reference in New Issue
Block a user