Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Shader with framebuffer #633

Merged
merged 5 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@
- QR Code support, with auto generate it from string [@conde2]
- qr-code-border: 2
- qr-code: Hail OTClient Redemption - Conde2 Dev

##### Sponsored (Features)
- Shader with Framebuffer | ([@SkullzOTS](https://github.com/SkullzOTS), [@Mryukiimaru](https://github.com/Mryukiimaru), [@JeanTheOne](https://github.com/JeanTheOne), [@KizaruHere](https://github.com/KizaruHere))

##### [OTClient V8](https://github.com/OTCv8) (Features)
- Lighting System
Expand Down
19 changes: 11 additions & 8 deletions modules/game_shaders/shaders.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
HOTKEY = 'Ctrl+Y'
MAP_SHADERS = {{
MAP_SHADERS = { {
name = 'Map - Default',
frag = nil
}, {
Expand Down Expand Up @@ -47,9 +47,9 @@ MAP_SHADERS = {{
}, {
name = 'Map - Noise',
frag = 'shaders/fragment/noise.frag'
}}
} }

OUTFIT_SHADERS = {{
OUTFIT_SHADERS = { {
name = 'Outfit - Default',
frag = nil
}, {
Expand All @@ -65,15 +65,19 @@ OUTFIT_SHADERS = {{
}, {
name = 'Outfit - Fragmented',
frag = 'shaders/fragment/noise.frag'
}}
}, {
name = 'Outfit - Outline',
useFramebuffer = true,
frag = 'shaders/fragment/outline.frag'
} }

MOUNT_SHADERS = {{
MOUNT_SHADERS = { {
name = 'Mount - Default',
frag = nil
}, {
name = 'Mount - Rainbow',
frag = 'shaders/fragment/party.frag'
}}
} }

-- Fix for texture offset drawing, adding walking offsets.
local dirs = {
Expand Down Expand Up @@ -172,11 +176,10 @@ function init()

local registerShader = function(opts, method)
local fragmentShaderPath = resolvepath(opts.frag)
local vertexShaderPath = resolvepath(opts.frag ~= nil and opts.vert or 'shaders/core/vertex/default.vert')

if fragmentShaderPath ~= nil then
-- local shader = g_shaders.createShader()
g_shaders.createFragmentShader(opts.name, opts.frag)
g_shaders.createFragmentShader(opts.name, opts.frag, opts.useFramebuffer or false)

if opts.tex1 then
g_shaders.addMultiTexture(opts.name, opts.tex1)
Expand Down
23 changes: 23 additions & 0 deletions modules/game_shaders/shaders/fragment/outline.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const float offset = 1.0 / 64.0;
uniform float u_Time;
uniform sampler2D u_Tex0;
varying vec2 v_TexCoord;

void main()
{
vec4 col = texture2D(u_Tex0, v_TexCoord);
if (col.a > 0.5)
gl_FragColor = col;
else {
float a = texture2D(u_Tex0, vec2(v_TexCoord.x + offset, v_TexCoord.y)).a +
texture2D(u_Tex0, vec2(v_TexCoord.x, v_TexCoord.y - offset)).a +
texture2D(u_Tex0, vec2(v_TexCoord.x - offset, v_TexCoord.y)).a +
texture2D(u_Tex0, vec2(v_TexCoord.x, v_TexCoord.y + offset)).a;
if (col.a < 1.0 && a > 0.0) {
float x = (cos(u_Time * 9.57) + 1.0)/2.0 * 0.2 + 0.8;
gl_FragColor = vec4(x, x, x, x);
} else {
gl_FragColor = col;
}
}
}
15 changes: 9 additions & 6 deletions src/client/shadermanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,22 @@ ShaderManager g_shaders;
void ShaderManager::init() { PainterShaderProgram::release(); }
void ShaderManager::terminate() { m_shaders.clear(); }

void ShaderManager::createShader(const std::string_view name)
void ShaderManager::createShader(const std::string_view name, bool useFramebuffer)
{
g_mainDispatcher.addEvent([&, name = name.data()] {
g_mainDispatcher.addEvent([this, name = name.data(), useFramebuffer] {
const auto& shader = std::make_shared<PainterShaderProgram>();
shader->setUseFramebuffer(useFramebuffer);
m_shaders[name] = shader;
return shader;
});
}

void ShaderManager::createFragmentShader(const std::string_view name, const std::string_view file)
void ShaderManager::createFragmentShader(const std::string_view name, const std::string_view file, bool useFramebuffer)
{
const auto& filePath = g_resources.resolvePath(file.data());
g_mainDispatcher.addEvent([&, name = name.data(), filePath] {
g_mainDispatcher.addEvent([this, name = name.data(), filePath, useFramebuffer] {
const auto& shader = std::make_shared<PainterShaderProgram>();
shader->setUseFramebuffer(useFramebuffer);
if (!shader)
return;

Expand All @@ -66,10 +68,11 @@ void ShaderManager::createFragmentShader(const std::string_view name, const std:
});
}

void ShaderManager::createFragmentShaderFromCode(const std::string_view name, const std::string_view code)
void ShaderManager::createFragmentShaderFromCode(const std::string_view name, const std::string_view code, bool useFramebuffer)
{
g_mainDispatcher.addEvent([&, name = name.data(), code = code.data()] {
g_mainDispatcher.addEvent([this, name = name.data(), code = code.data(), useFramebuffer] {
const auto& shader = std::make_shared<PainterShaderProgram>();
shader->setUseFramebuffer(useFramebuffer);
if (!shader)
return;

Expand Down
6 changes: 3 additions & 3 deletions src/client/shadermanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ class ShaderManager
void setupOutfitShader(const std::string_view name);
void setupMountShader(const std::string_view name);

void createShader(const std::string_view name);
void createFragmentShader(const std::string_view name, const std::string_view file);
void createFragmentShaderFromCode(const std::string_view name, const std::string_view code);
void createShader(const std::string_view name, bool useFramebuffer = false);
void createFragmentShader(const std::string_view name, const std::string_view file, bool useFramebuffer = false);
void createFragmentShaderFromCode(const std::string_view name, const std::string_view code, bool useFramebuffer = false);

void addMultiTexture(const std::string_view name, const std::string_view file);

Expand Down
25 changes: 23 additions & 2 deletions src/client/thingtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,23 @@ void ThingType::unserializeOtml(const OTMLNodePtr& node)
}
}

void ThingType::drawWithFrameBuffer(const Point& dest, const TexturePtr& texture, Rect screenRect, const Rect& textureRect, const Color& color, const DrawConductor& conductor) {
const int size = static_cast<int>(g_gameConfig.getSpriteSize() * m_size.area() * g_drawPool.getScaleFactor());
const auto& p = Point(size / 2);
const auto& destDiff = Rect(dest - p, Size{ size });

g_drawPool.bindFrameBuffer(destDiff.size()); {
g_drawPool.resetShaderProgram();

// Debug
// g_drawPool.addBoundingRect(Rect(Point(0), destDiff.size()), Color::red);

screenRect = Rect(p - (dest - screenRect.topLeft()), screenRect.size());
g_drawPool.addTexturedRect(screenRect, texture, textureRect, color, conductor);
} g_drawPool.releaseFrameBuffer(destDiff);
g_drawPool.resetShaderProgram();
}

void ThingType::draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, const Color& color, bool drawThings, LightView* lightView, const DrawConductor& conductor)
{
if (m_null)
Expand All @@ -628,7 +645,11 @@ void ThingType::draw(const Point& dest, int layer, int xPattern, int yPattern, i

if (drawThings) {
const auto& newColor = m_opacity < 1.0f ? Color(color, m_opacity) : color;
g_drawPool.addTexturedRect(screenRect, texture, textureRect, newColor, conductor);

if (g_drawPool.shaderNeedFramebuffer())
drawWithFrameBuffer(dest, texture, screenRect, textureRect, newColor, conductor);
else
g_drawPool.addTexturedRect(screenRect, texture, textureRect, newColor, conductor);
}

if (lightView && hasLight()) {
Expand Down Expand Up @@ -1048,4 +1069,4 @@ void ThingType::exportImage(const std::string& fileName)

image->savePNG(fileName);
}
#endif
#endif
1 change: 1 addition & 0 deletions src/client/thingtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ class ThingType : public LuaObject
#endif

void draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, const Color& color, bool drawThings = true, LightView* lightView = nullptr, const DrawConductor& conductor = DEFAULT_DRAW_CONDUCTOR);
void drawWithFrameBuffer(const Point& dest, const TexturePtr& texture, Rect screenRect, const Rect& textureRect, const Color& color, const DrawConductor& conductor);

uint16_t getId() { return m_id; }
ThingCategory getCategory() { return m_category; }
Expand Down
33 changes: 33 additions & 0 deletions src/framework/graphics/drawpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,37 @@ void DrawPool::setFramebuffer(const Size& size) {
void DrawPool::removeFramebuffer() {
m_status.first = 0;
m_framebuffer = nullptr;
}

void DrawPool::addAction(const std::function<void()>& action)
{
const uint8_t order = m_type == DrawPoolType::MAP ? DrawOrder::THIRD : DrawOrder::FIRST;
m_objects[m_depthLevel][order].emplace_back(action);
}

void DrawPool::bindFrameBuffer(const Size& size)
{
const uint8_t frameIndex = m_type == DrawPoolType::MAP ? 0 : 1;

m_oldState = std::move(m_state);
m_state = {};
addAction([size, frameIndex, drawState = m_state] {
drawState.execute();
const auto& frame = g_framebuffers.getTemporaryFrameBuffer(frameIndex);
frame->resize(size);
frame->bind();
});
}
void DrawPool::releaseFrameBuffer(const Rect& dest)
{
const uint8_t frameIndex = m_type == DrawPoolType::MAP ? 0 : 1;

m_state = std::move(m_oldState);
addAction([dest, frameIndex, drawState = m_state] {
const auto& frame = g_framebuffers.getTemporaryFrameBuffer(frameIndex);
frame->release();
drawState.execute();
frame->draw(dest);
});
if (hasFrameBuffer() && !dest.isNull()) stdext::hash_union(m_status.second, dest.hash());
}
4 changes: 4 additions & 0 deletions src/framework/graphics/drawpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ class DrawPool
DrawMode drawMode = DrawMode::TRIANGLES, const DrawConductor& conductor = DEFAULT_DRAW_CONDUCTOR,
const CoordsBufferPtr& coordsBuffer = nullptr);

void addAction(const std::function<void()>& action);
void bindFrameBuffer(const Size& size);
void releaseFrameBuffer(const Rect& dest);

inline void setFPS(uint16_t fps) { m_refreshDelay = fps; }

void updateHash(const DrawPool::DrawMethod& method, const TexturePtr& texture, const Color& color);
Expand Down
28 changes: 0 additions & 28 deletions src/framework/graphics/drawpoolmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,34 +207,6 @@ void DrawPoolManager::addBoundingRect(const Rect& dest, const Color& color, uint
getCurrentPool()->add(color, nullptr, method);
}

void DrawPoolManager::addAction(const std::function<void()>& action) const
{
getCurrentPool()->m_objects[0][DrawOrder::FIRST].emplace_back(action);
}

void DrawPoolManager::bindFrameBuffer(const Size& size) const
{
getCurrentPool()->m_oldState = std::move(getCurrentPool()->m_state);
getCurrentPool()->m_state = {};

g_drawPool.addAction([size, drawState = getCurrentPool()->m_state] {
drawState.execute();
const auto& frame = g_framebuffers.getTemporaryFrameBuffer();
frame->resize(size);
frame->bind();
});
}
void DrawPoolManager::releaseFrameBuffer(const Rect& dest) const
{
getCurrentPool()->m_state = std::move(getCurrentPool()->m_oldState);
g_drawPool.addAction([dest, drawState = getCurrentPool()->m_state] {
const auto& frame = g_framebuffers.getTemporaryFrameBuffer();
frame->release();
drawState.execute();
frame->draw(dest);
});
}

void DrawPoolManager::use(const DrawPoolType type, const Rect& dest, const Rect& src, const Color& colorClear)
{
select(type);
Expand Down
7 changes: 4 additions & 3 deletions src/framework/graphics/drawpoolmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,17 @@ class DrawPoolManager
void addFilledRect(const Rect& dest, const Color& color = Color::white, const DrawConductor& condutor = DEFAULT_DRAW_CONDUCTOR) const;
void addFilledTriangle(const Point& a, const Point& b, const Point& c, const Color& color = Color::white) const;
void addBoundingRect(const Rect& dest, const Color& color = Color::white, uint16_t innerLineWidth = 1) const;
void addAction(const std::function<void()>& action) const;
void addAction(const std::function<void()>& action) const { getCurrentPool()->addAction(action); }

void bindFrameBuffer(const Size& size) const;
void releaseFrameBuffer(const Rect& dest) const;
void bindFrameBuffer(const Size& size) const { getCurrentPool()->bindFrameBuffer(size); }
void releaseFrameBuffer(const Rect& dest) const { getCurrentPool()->releaseFrameBuffer(dest); };

void setOpacity(const float opacity, bool onlyOnce = false) const { getCurrentPool()->setOpacity(opacity, onlyOnce); }
void setClipRect(const Rect& clipRect, bool onlyOnce = false) const { getCurrentPool()->setClipRect(clipRect, onlyOnce); }
void setBlendEquation(BlendEquation equation, bool onlyOnce = false) const { getCurrentPool()->setBlendEquation(equation, onlyOnce); }
void setCompositionMode(const CompositionMode mode, bool onlyOnce = false) const { getCurrentPool()->setCompositionMode(mode, onlyOnce); }

bool shaderNeedFramebuffer() const { return getCurrentPool()->m_state.shaderProgram && getCurrentPool()->m_state.shaderProgram->useFramebuffer(); }
void setShaderProgram(const PainterShaderProgramPtr& shaderProgram, const std::function<void()>& action) const { getCurrentPool()->setShaderProgram(shaderProgram, false, action); }
void setShaderProgram(const PainterShaderProgramPtr& shaderProgram, bool onlyOnce = false, const std::function<void()>& action = nullptr) const { getCurrentPool()->setShaderProgram(shaderProgram, onlyOnce, action); }

Expand Down
14 changes: 11 additions & 3 deletions src/framework/graphics/framebuffermanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@
*/

#include "framebuffermanager.h"
#include "drawpoolmanager.h"

FrameBufferManager g_framebuffers;

void FrameBufferManager::init()
{
m_temporaryFramebuffer = std::make_shared<FrameBuffer>();
m_temporaryFramebuffer->setSmooth(true);
m_temporaryFramebuffer.reserve(2);
for (uint_fast8_t i = 0; i < 2; ++i) {
const auto& frame = m_temporaryFramebuffer.emplace_back(std::make_shared<FrameBuffer>());
if (i == 0) {
frame->setSmooth(false);
}
};
}

void FrameBufferManager::terminate() { m_temporaryFramebuffer = nullptr; }
void FrameBufferManager::terminate() {
m_temporaryFramebuffer.clear();
}
6 changes: 4 additions & 2 deletions src/framework/graphics/framebuffermanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ class FrameBufferManager
void init();
void terminate();

const FrameBufferPtr& getTemporaryFrameBuffer() { return m_temporaryFramebuffer; }
const FrameBufferPtr& getTemporaryFrameBuffer(const uint8_t index) const {
return m_temporaryFramebuffer[index];
}

protected:
FrameBufferPtr m_temporaryFramebuffer;
std::vector<FrameBufferPtr> m_temporaryFramebuffer;
};

extern FrameBufferManager g_framebuffers;
10 changes: 10 additions & 0 deletions src/framework/graphics/paintershaderprogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,17 @@ class PainterShaderProgram : public ShaderProgram
void addMultiTexture(const std::string& file);
void bindMultiTextures() const;

void setUseFramebuffer(bool v) {
m_useFramebuffer = v;
}

bool useFramebuffer() const {
return m_useFramebuffer;
}

private:
bool m_useFramebuffer{ false };

float m_startTime{ 0 };
float m_opacity{ 1.f };
float m_time{ 0 };
Expand Down
Loading