Split shaders into their own files
some unrelated directives thing too
This commit is contained in:
parent
4328119e1c
commit
6832c10ed5
38
assets/opensb/rendering/opengl20.config
Normal file
38
assets/opensb/rendering/opengl20.config
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"effectParameters" : {
|
||||
"lightMapEnabled" : {
|
||||
"type" : "bool",
|
||||
"default" : false,
|
||||
"uniform" : "lightMapEnabled"
|
||||
},
|
||||
"lightMapScale" : {
|
||||
"type" : "vec2",
|
||||
"default" : [1, 1],
|
||||
"uniform" : "lightMapScale"
|
||||
},
|
||||
"lightMapOffset" : {
|
||||
"type" : "vec2",
|
||||
"default" : [0, 0],
|
||||
"uniform" : "lightMapOffset"
|
||||
},
|
||||
"lightMapMultiplier" : {
|
||||
"type" : "float",
|
||||
"default" : 1.0,
|
||||
"uniform" : "lightMapMultiplier"
|
||||
}
|
||||
},
|
||||
|
||||
"effectTextures" : {
|
||||
"lightMap" : {
|
||||
"textureUniform" : "lightMap",
|
||||
"textureSizeUniform" : "lightMapSize",
|
||||
"textureAddressing" : "clamp",
|
||||
"textureFiltering" : "linear"
|
||||
}
|
||||
},
|
||||
|
||||
"effectShaders" : {
|
||||
"vertex" : "opengl20.vert",
|
||||
"fragment" : "opengl20.frag"
|
||||
}
|
||||
}
|
75
assets/opensb/rendering/opengl20.frag
Normal file
75
assets/opensb/rendering/opengl20.frag
Normal file
@ -0,0 +1,75 @@
|
||||
#version 110
|
||||
|
||||
uniform sampler2D texture0;
|
||||
uniform sampler2D texture1;
|
||||
uniform sampler2D texture2;
|
||||
uniform sampler2D texture3;
|
||||
uniform bool lightMapEnabled;
|
||||
uniform vec2 lightMapSize;
|
||||
uniform sampler2D lightMap;
|
||||
uniform float lightMapMultiplier;
|
||||
|
||||
varying vec2 fragmentTextureCoordinate;
|
||||
varying float fragmentTextureIndex;
|
||||
varying vec4 fragmentColor;
|
||||
varying float fragmentLightMapMultiplier;
|
||||
varying vec2 fragmentLightMapCoordinate;
|
||||
|
||||
vec4 cubic(float v) {
|
||||
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
|
||||
vec4 s = n * n * n;
|
||||
float x = s.x;
|
||||
float y = s.y - 4.0 * s.x;
|
||||
float z = s.z - 4.0 * s.y + 6.0 * s.x;
|
||||
float w = 6.0 - x - y - z;
|
||||
return vec4(x, y, z, w);
|
||||
}
|
||||
|
||||
vec4 bicubicSample(sampler2D texture, vec2 texcoord, vec2 texscale) {
|
||||
texcoord = texcoord - vec2(0.5, 0.5);
|
||||
|
||||
float fx = fract(texcoord.x);
|
||||
float fy = fract(texcoord.y);
|
||||
texcoord.x -= fx;
|
||||
texcoord.y -= fy;
|
||||
|
||||
vec4 xcubic = cubic(fx);
|
||||
vec4 ycubic = cubic(fy);
|
||||
|
||||
vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y - 0.5, texcoord.y + 1.5);
|
||||
vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x + ycubic.y, ycubic.z + ycubic.w);
|
||||
vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) / s;
|
||||
|
||||
vec4 sample0 = texture2D(texture, vec2(offset.x, offset.z) * texscale);
|
||||
vec4 sample1 = texture2D(texture, vec2(offset.y, offset.z) * texscale);
|
||||
vec4 sample2 = texture2D(texture, vec2(offset.x, offset.w) * texscale);
|
||||
vec4 sample3 = texture2D(texture, vec2(offset.y, offset.w) * texscale);
|
||||
|
||||
float sx = s.x / (s.x + s.y);
|
||||
float sy = s.z / (s.z + s.w);
|
||||
|
||||
return mix(
|
||||
mix(sample3, sample2, sx),
|
||||
mix(sample1, sample0, sx), sy);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 texColor;
|
||||
if (fragmentTextureIndex > 2.9) {
|
||||
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
||||
} else if (fragmentTextureIndex > 1.9) {
|
||||
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
||||
} else if (fragmentTextureIndex > 0.9) {
|
||||
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
||||
} else {
|
||||
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
||||
}
|
||||
if (texColor.a <= 0.0)
|
||||
discard;
|
||||
|
||||
vec4 finalColor = texColor * fragmentColor;
|
||||
float finalLightMapMultiplier = fragmentLightMapMultiplier * lightMapMultiplier;
|
||||
if (lightMapEnabled && finalLightMapMultiplier > 0.0)
|
||||
finalColor.rgb *= bicubicSample(lightMap, fragmentLightMapCoordinate, 1.0 / lightMapSize).rgb * finalLightMapMultiplier;
|
||||
gl_FragColor = finalColor;
|
||||
}
|
41
assets/opensb/rendering/opengl20.vert
Normal file
41
assets/opensb/rendering/opengl20.vert
Normal file
@ -0,0 +1,41 @@
|
||||
#version 110
|
||||
|
||||
uniform vec2 textureSize0;
|
||||
uniform vec2 textureSize1;
|
||||
uniform vec2 textureSize2;
|
||||
uniform vec2 textureSize3;
|
||||
uniform vec2 screenSize;
|
||||
uniform mat3 vertexTransform;
|
||||
uniform vec2 lightMapSize;
|
||||
uniform vec2 lightMapScale;
|
||||
uniform vec2 lightMapOffset;
|
||||
|
||||
attribute vec2 vertexPosition;
|
||||
attribute vec2 vertexTextureCoordinate;
|
||||
attribute float vertexTextureIndex;
|
||||
attribute vec4 vertexColor;
|
||||
attribute float vertexParam1;
|
||||
|
||||
varying vec2 fragmentTextureCoordinate;
|
||||
varying float fragmentTextureIndex;
|
||||
varying vec4 fragmentColor;
|
||||
varying float fragmentLightMapMultiplier;
|
||||
varying vec2 fragmentLightMapCoordinate;
|
||||
|
||||
void main() {
|
||||
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
||||
fragmentLightMapMultiplier = vertexParam1;
|
||||
fragmentLightMapCoordinate = (screenPosition / lightMapScale) - lightMapOffset * lightMapSize / screenSize;
|
||||
if (vertexTextureIndex > 2.9) {
|
||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
||||
} else if (vertexTextureIndex > 1.9) {
|
||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
||||
} else if (vertexTextureIndex > 0.9) {
|
||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
||||
} else {
|
||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
||||
}
|
||||
fragmentTextureIndex = vertexTextureIndex;
|
||||
fragmentColor = vertexColor;
|
||||
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
@ -117,7 +117,7 @@ public:
|
||||
// specific to each type of renderer, so it will be necessary to key the
|
||||
// configuration off of the renderId string. This should not be called every
|
||||
// frame, because it will result in a recompile of the underlying shader set.
|
||||
virtual void setEffectConfig(Json const& effectConfig) = 0;
|
||||
virtual void setEffectConfig(Json const& effectConfig, StringMap<String> const& shaders) = 0;
|
||||
|
||||
// The effect config will specify named parameters and textures which can be
|
||||
// set here.
|
||||
|
@ -7,9 +7,7 @@ namespace Star {
|
||||
|
||||
size_t const MultiTextureCount = 4;
|
||||
|
||||
char const* DefaultEffectConfig = R"JSON(
|
||||
{
|
||||
"vertexShader" : "
|
||||
char const* DefaultVertexShader = R"SHADER(
|
||||
#version 110
|
||||
|
||||
uniform vec2 textureSize0;
|
||||
@ -44,9 +42,9 @@ char const* DefaultEffectConfig = R"JSON(
|
||||
fragmentTextureIndex = vertexTextureIndex;
|
||||
fragmentColor = vertexColor;
|
||||
}
|
||||
",
|
||||
)SHADER";
|
||||
|
||||
"fragmentShader" : "
|
||||
char const* DefaultFragmentShader = R"SHADER(
|
||||
#version 110
|
||||
|
||||
uniform sampler2D texture0;
|
||||
@ -69,9 +67,7 @@ char const* DefaultEffectConfig = R"JSON(
|
||||
gl_FragColor = texture2D(texture0, fragmentTextureCoordinate) * fragmentColor;
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
)JSON";
|
||||
)SHADER";
|
||||
|
||||
OpenGl20Renderer::OpenGl20Renderer() {
|
||||
if (glewInit() != GLEW_OK)
|
||||
@ -97,7 +93,7 @@ OpenGl20Renderer::OpenGl20Renderer() {
|
||||
TextureFiltering::Nearest);
|
||||
m_immediateRenderBuffer = createGlRenderBuffer();
|
||||
|
||||
setEffectConfig(Json::parse(DefaultEffectConfig));
|
||||
setEffectConfig(JsonObject(), {{"vertex", DefaultVertexShader}, {"fragment", DefaultFragmentShader}});
|
||||
|
||||
m_limitTextureGroupSize = false;
|
||||
m_useMultiTexturing = true;
|
||||
@ -119,43 +115,43 @@ Vec2U OpenGl20Renderer::screenSize() const {
|
||||
return m_screenSize;
|
||||
}
|
||||
|
||||
void OpenGl20Renderer::setEffectConfig(Json const& effectConfig) {
|
||||
void OpenGl20Renderer::setEffectConfig(Json const& effectConfig, StringMap<String> const& shaders) {
|
||||
flushImmediatePrimitives();
|
||||
|
||||
GLint status = 0;
|
||||
char logBuffer[1024];
|
||||
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
String vertexSource = effectConfig.getString("vertexShader");
|
||||
char const* vertexSourcePtr = vertexSource.utf8Ptr();
|
||||
glShaderSource(vertexShader, 1, &vertexSourcePtr, NULL);
|
||||
glCompileShader(vertexShader);
|
||||
auto compileShader = [&](GLenum type, String const& name) -> GLuint {
|
||||
GLuint shader = glCreateShader(type);
|
||||
auto* source = shaders.ptr(name);
|
||||
if (!source)
|
||||
return 0;
|
||||
char const* sourcePtr = source->utf8Ptr();
|
||||
glShaderSource(shader, 1, &sourcePtr, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (!status) {
|
||||
glGetShaderInfoLog(vertexShader, sizeof(logBuffer), NULL, logBuffer);
|
||||
throw RendererException(strf("Failed to compile vertex shader: %s\n", logBuffer));
|
||||
glGetShaderInfoLog(shader, sizeof(logBuffer), NULL, logBuffer);
|
||||
throw RendererException(strf("Failed to compile %s shader: %s\n", name, logBuffer));
|
||||
}
|
||||
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
String fragmentSource = effectConfig.getString("fragmentShader");
|
||||
char const* fragmentSourcePtr = fragmentSource.utf8Ptr();
|
||||
glShaderSource(fragmentShader, 1, &fragmentSourcePtr, NULL);
|
||||
glCompileShader(fragmentShader);
|
||||
return shader;
|
||||
};
|
||||
|
||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
|
||||
if (!status) {
|
||||
glGetShaderInfoLog(fragmentShader, sizeof(logBuffer), NULL, logBuffer);
|
||||
throw RendererException(strf("Failed to compile fragment shader: %s\n", logBuffer));
|
||||
}
|
||||
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, "vertex");
|
||||
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, "fragment");
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
if (vertexShader)
|
||||
glAttachShader(program, vertexShader);
|
||||
if (fragmentShader)
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
|
||||
if (vertexShader)
|
||||
glDeleteShader(vertexShader);
|
||||
if (fragmentShader)
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
String rendererId() const override;
|
||||
Vec2U screenSize() const override;
|
||||
|
||||
void setEffectConfig(Json const& effectConfig) override;
|
||||
void setEffectConfig(Json const& effectConfig, StringMap<String> const& shaders) override;
|
||||
void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
|
||||
void setEffectTexture(String const& textureName, Image const& image) override;
|
||||
|
||||
|
@ -196,10 +196,25 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
|
||||
|
||||
void ClientApplication::renderInit(RendererPtr renderer) {
|
||||
Application::renderInit(renderer);
|
||||
auto assets = m_root->assets();
|
||||
|
||||
String rendererConfig = strf("/rendering/%s.config", renderer->rendererId());
|
||||
if (m_root->assets()->assetExists(rendererConfig))
|
||||
renderer->setEffectConfig(m_root->assets()->json(rendererConfig));
|
||||
if (assets->assetExists(rendererConfig)) {
|
||||
StringMap<String> shaders;
|
||||
auto config = assets->json(rendererConfig);
|
||||
auto shaderConfig = config.getObject("effectShaders");
|
||||
for (auto& entry : shaderConfig) {
|
||||
if (entry.second.isType(Json::Type::String)) {
|
||||
String shader = entry.second.toString();
|
||||
if (!shader.hasChar('\n')) {
|
||||
auto shaderBytes = assets->bytes(AssetPath::relativeTo(rendererConfig, shader));
|
||||
shader = std::string(shaderBytes->ptr(), shaderBytes->size());
|
||||
}
|
||||
shaders[entry.first] = shader;
|
||||
}
|
||||
}
|
||||
renderer->setEffectConfig(config, shaders);
|
||||
}
|
||||
else
|
||||
Logger::warn("No rendering config found for renderer with id '%s'", renderer->rendererId());
|
||||
|
||||
|
@ -38,6 +38,7 @@ SET (star_game_HEADERS
|
||||
StarDamageManager.hpp
|
||||
StarDamageTypes.hpp
|
||||
StarDanceDatabase.hpp
|
||||
StarDirectives.hpp
|
||||
StarDrawable.hpp
|
||||
StarDungeonGenerator.hpp
|
||||
StarDungeonImagePart.hpp
|
||||
@ -296,6 +297,7 @@ SET (star_game_SOURCES
|
||||
StarDamageManager.cpp
|
||||
StarDamageTypes.cpp
|
||||
StarDanceDatabase.cpp
|
||||
StarDirectives.cpp
|
||||
StarDrawable.cpp
|
||||
StarDungeonGenerator.cpp
|
||||
StarDungeonImagePart.cpp
|
||||
|
51
source/game/StarDirectives.cpp
Normal file
51
source/game/StarDirectives.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "StarImage.hpp"
|
||||
#include "StarImageProcessing.hpp"
|
||||
#include "StarDirectives.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
NestedDirectives::NestedDirectives() {}
|
||||
NestedDirectives::NestedDirectives(String const& string) : m_root{ Leaf{ parseImageOperations(string), string} } {}
|
||||
|
||||
void NestedDirectives::addBranch(const Branch& newBranch) {
|
||||
convertToBranches();
|
||||
|
||||
m_root.value.get<Branches>().emplace_back(newBranch);
|
||||
}
|
||||
|
||||
String NestedDirectives::toString() const {
|
||||
String string;
|
||||
buildString(string, m_root);
|
||||
return string;
|
||||
}
|
||||
|
||||
void NestedDirectives::forEach() const {
|
||||
|
||||
}
|
||||
|
||||
Image NestedDirectives::apply(Image& image) const {
|
||||
Image current = image;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
void NestedDirectives::buildString(String& string, const Cell& cell) const {
|
||||
if (auto leaf = cell.value.ptr<Leaf>())
|
||||
string += leaf->string;
|
||||
else {
|
||||
for (auto& branch : cell.value.get<Branches>())
|
||||
buildString(string, *branch);
|
||||
}
|
||||
}
|
||||
|
||||
void NestedDirectives::convertToBranches() {
|
||||
if (m_root.value.is<Branches>())
|
||||
return;
|
||||
|
||||
Leaf& leaf = m_root.value.get<Leaf>();
|
||||
Branches newBranches;
|
||||
newBranches.emplace_back(std::make_shared<Cell const>(move(leaf)));
|
||||
m_root.value = move(newBranches);
|
||||
}
|
||||
|
||||
}
|
50
source/game/StarDirectives.hpp
Normal file
50
source/game/StarDirectives.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef STAR_DIRECTIVES_HPP
|
||||
#define STAR_DIRECTIVES_HPP
|
||||
|
||||
#include "StarImageProcessing.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(NestedDirectives);
|
||||
|
||||
// Attempt at reducing memory allocation and per-frame string parsing for extremely long directives
|
||||
class NestedDirectives {
|
||||
public:
|
||||
struct Leaf {
|
||||
List<ImageOperation> operations;
|
||||
String string;
|
||||
};
|
||||
|
||||
struct Cell;
|
||||
typedef std::shared_ptr<Cell const> Branch;
|
||||
typedef List<Branch> Branches;
|
||||
|
||||
struct Cell {
|
||||
Variant<Leaf, Branches> value;
|
||||
|
||||
Cell() : value(Leaf()) {};
|
||||
Cell(Leaf&& leaf) : value(move(leaf)) {};
|
||||
Cell(Branches&& branches) : value(move(branches)) {};
|
||||
Cell(const Leaf& leaf) : value(leaf) {};
|
||||
Cell(const Branches& branches) : value(branches) {};
|
||||
};
|
||||
|
||||
|
||||
NestedDirectives();
|
||||
NestedDirectives(String const& string);
|
||||
|
||||
void addBranch(const Branch& newBranch);
|
||||
const Branch& branch() const;
|
||||
String toString() const;
|
||||
void forEach() const;
|
||||
Image apply(Image& image) const;
|
||||
private:
|
||||
void buildString(String& string, const Cell& cell) const;
|
||||
void convertToBranches();
|
||||
|
||||
Cell m_root;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -787,6 +787,10 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
||||
m_outgoingPackets.append(make_shared<EntityMessageResponsePacket>(makeLeft("Entity delivery error"), entityMessagePacket->uuid));
|
||||
|
||||
} else {
|
||||
ConnectionId fromConnection = entityMessagePacket->fromConnection;
|
||||
if (fromConnection == *m_clientId) // Kae: The server should not be able to forge entity messages that appear as if they're from us
|
||||
fromConnection = ServerConnectionId;
|
||||
|
||||
auto response = entity->receiveMessage(entityMessagePacket->fromConnection, entityMessagePacket->message, entityMessagePacket->args);
|
||||
if (response)
|
||||
m_outgoingPackets.append(make_shared<EntityMessageResponsePacket>(makeRight(response.take()), entityMessagePacket->uuid));
|
||||
@ -805,7 +809,13 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
||||
response.fail(entityMessageResponsePacket->response.left());
|
||||
|
||||
} else if (auto updateWorldProperties = as<UpdateWorldPropertiesPacket>(packet)) {
|
||||
m_worldProperties.merge(updateWorldProperties->updatedProperties, true);
|
||||
// Kae: Properties set to null (nil from Lua) should be erased instead of lingering around
|
||||
for (auto& pair : updateWorldProperties->updatedProperties) {
|
||||
if (pair.second.isNull())
|
||||
m_worldProperties.erase(pair.first);
|
||||
else
|
||||
m_worldProperties[pair.first] = pair.second;
|
||||
}
|
||||
|
||||
} else if (auto updateTileProtection = as<UpdateTileProtectionPacket>(packet)) {
|
||||
setTileProtection(updateTileProtection->dungeonId, updateTileProtection->isProtected);
|
||||
|
Loading…
Reference in New Issue
Block a user