diff --git a/modules/game/game.otmod b/modules/game/game.otmod index 7771b880..40577848 100644 --- a/modules/game/game.otmod +++ b/modules/game/game.otmod @@ -8,7 +8,6 @@ Module - client_extended - game_tibiafiles - client_background - //- game_shaders load-later: - game_textmessage @@ -29,6 +28,7 @@ Module - game_questlog - game_ruleviolation - game_bugreport + - game_shaders @onLoad: | importStyle 'styles/items.otui' diff --git a/modules/game_shaders/images/clouds.png b/modules/game_shaders/images/clouds.png new file mode 100644 index 00000000..66f8fb34 Binary files /dev/null and b/modules/game_shaders/images/clouds.png differ diff --git a/modules/game_shaders/map.frag b/modules/game_shaders/map.frag deleted file mode 100644 index b13b0695..00000000 --- a/modules/game_shaders/map.frag +++ /dev/null @@ -1,105 +0,0 @@ -uniform float opacity; // painter opacity -uniform vec4 color; // painter color -uniform float time; // time in seconds since shader linkage -uniform sampler2D tex0; // map texture -varying vec2 texCoord; // map texture coords -//uniform vec4 awareArea; - - -void main() -{ - gl_FragColor = texture2D(tex0, texCoord); -} - -/* -vec4 grayScale(vec4 color, float factor) -{ - float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); - return vec4(gray*factor + (1-factor)*color.r, - gray*factor + (1-factor)*color.g, - gray*factor + (1-factor)*color.b, 1); -} - -// grayscale fog -void main() -{ - vec4 color = texture2D(texture, textureCoords); - float dist = 0; - // left - if(textureCoords.x < awareArea.x && textureCoords.y < awareArea.y) - dist = distance(textureCoords, awareArea.xy); - else if(textureCoords.x < awareArea.x && textureCoords.y < awareArea.w) - dist = distance(textureCoords, vec2(awareArea.x, textureCoords.y)); - else if(textureCoords.x < awareArea.x) - dist = distance(textureCoords, awareArea.xw); - // right - else if(textureCoords.x > awareArea.z && textureCoords.y < awareArea.y) - dist = distance(textureCoords, awareArea.zy); - else if(textureCoords.x > awareArea.z && textureCoords.y < awareArea.w) - dist = distance(textureCoords, vec2(awareArea.z, textureCoords.y)); - else if(textureCoords.x > awareArea.z) - dist = distance(textureCoords, awareArea.zw); - // top - else if(textureCoords.y < awareArea.y) - dist = distance(textureCoords, vec2(textureCoords.x, awareArea.y)); - // bottom - else if(textureCoords.y > awareArea.w) - dist = distance(textureCoords, vec2(textureCoords.x, awareArea.w)); - if(dist > 0) { - float range = 0.01; - float factor = min(dist/range, 1.0); - color = grayScale(color, factor); - //color.rgb *= 1 - (factor * 0.5); - } - gl_FragColor = color; -} -*/ - -/* -sepia -void main() -{ - vec4 color = texture2D(texture, textureCoords); - if(textureCoords.x < awareArea.x || textureCoords.y < awareArea.y || textureCoords.x > awareArea.z || textureCoords.y > awareArea.w) { - gl_FragColor.r = dot(color, vec4(.393, .769, .189, .0)); - gl_FragColor.g = dot(color, vec4(.349, .686, .168, .0)); - gl_FragColor.b = dot(color, vec4(.272, .534, .131, .0)); - gl_FragColor.a = 1; - } else - gl_FragColor = color; -} -*/ - -/* -void main() -{ - vec4 color = texture2D(texture, textureCoords); - vec2 awareRange = (awareArea.zw - awareArea.xy)/2.0; - float dist = distance(textureCoords, awareArea.xy + awareRange); - float start = min(awareRange.x, awareRange.y); - float range = awareRange*0.1; - float endFactor = 0.3; - if(dist >= start) { - color.rgb *= 1 - (min((dist - start)/range, 1.0) * (2.0 - endFactor)); - } - gl_FragColor = color; -} -*/ -/* -void main() -{ - vec4 sum = vec4(0); - vec2 texcoord = texCoord; - int j; - int i; - - for( i= -4 ;i < 4; i++) - { - for (j = -4; j < 4; j++) - { - sum += texture2D(tex0, texcoord + vec2(j, i)*0.0025) * 0.0125; - } - } - gl_FragColor = texture2D(tex0, texCoord) + sum; -} -*/ \ No newline at end of file diff --git a/modules/game_shaders/shaders.lua b/modules/game_shaders/shaders.lua new file mode 100644 index 00000000..99536f12 --- /dev/null +++ b/modules/game_shaders/shaders.lua @@ -0,0 +1,56 @@ +Shaders = {} + +local HOTKEY = 'Ctrl+X' +local SHADERS = { + ['Default'] = 'shaders/default.frag', + ['Bloom'] = 'shaders/bloom.frag', + ['Sepia'] = 'shaders/sepia.frag', + ['Grayscale'] = 'shaders/grayscale.frag', + ['Pulse'] = 'shaders/pulse.frag', + ['Old Tv'] = 'shaders/oldtv.frag', + ['Fog'] = 'shaders/fog.frag', + ['Party'] = 'shaders/party.frag', + ['Radial Blur'] = 'shaders/radialblur.frag', + ['Zomg'] = 'shaders/zomg.frag', +} + +local shadersPanel + +function Shaders.init() + importStyle 'shaders.otui' + + + Keyboard.bindKeyDown(HOTKEY, Shaders.toggle) + + shadersPanel = createWidget('ShadersPanel', GameInterface.getMapPanel()) + shadersPanel:hide() + + local mapComboBox = shadersPanel:getChildById('mapComboBox') + mapComboBox.onOptionChange = function(combobox, option) + local map = GameInterface.getMapPanel() + map:setMapShader(g_shaders.getShader(option)) + print(option) + end + + for name,file in pairs(SHADERS) do + local shader = g_shaders.createFragmentShader(name, file) + mapComboBox:addOption(name) + + if name == 'Fog' then + shader:addMultiTexture('images/clouds.png') + end + end + + local map = GameInterface.getMapPanel() + map:setMapShader(g_shaders.getShader('Default')) +end + +function Shaders.terminate() + Keyboard.unbindKeyDown(HOTKEY) + shadersPanel:destroy() + shadersPanel = nil +end + +function Shaders.toggle() + shadersPanel:setVisible(not shadersPanel:isVisible()) +end diff --git a/modules/game_shaders/shaders.otmod b/modules/game_shaders/shaders.otmod new file mode 100644 index 00000000..f63e3ba6 --- /dev/null +++ b/modules/game_shaders/shaders.otmod @@ -0,0 +1,15 @@ +Module + name: game_shaders + description: Manage game shaders + author: edubart + website: www.otclient.info + + dependencies: + - game + + @onLoad: | + dofile 'shaders' + Shaders.init() + + @onUnload: | + Shaders.terminate() diff --git a/modules/game_shaders/shaders.otui b/modules/game_shaders/shaders.otui new file mode 100644 index 00000000..27cecdb5 --- /dev/null +++ b/modules/game_shaders/shaders.otui @@ -0,0 +1,15 @@ +ShadersPanel < UIWidget + focusable: false + + anchors.top: parent.top + anchors.left: parent.left + border-color: red + border-width: 1 + + width: 100 + layout: + type: verticalBox + fit-children: true + + ComboBox + id: mapComboBox \ No newline at end of file diff --git a/modules/game_shaders/shaders/bloom.frag b/modules/game_shaders/shaders/bloom.frag new file mode 100644 index 00000000..55abbc00 --- /dev/null +++ b/modules/game_shaders/shaders/bloom.frag @@ -0,0 +1,16 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +void main() +{ + vec4 color = texture2D(u_Tex0, v_TexCoord); + int j; + int i; + + for(i = -2 ;i <= 2; i++) + for(j = -2; j <= 2; j++) + color += texture2D(u_Tex0, v_TexCoord + vec2(i, j)*0.0025) * 0.025; + + gl_FragColor = color; +} diff --git a/modules/game_shaders/shaders/default.frag b/modules/game_shaders/shaders/default.frag new file mode 100644 index 00000000..b54ca882 --- /dev/null +++ b/modules/game_shaders/shaders/default.frag @@ -0,0 +1,8 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +void main() +{ + gl_FragColor = texture2D(u_Tex0, v_TexCoord); +} diff --git a/modules/game_shaders/shaders/fog.frag b/modules/game_shaders/shaders/fog.frag new file mode 100644 index 00000000..da1fe4ca --- /dev/null +++ b/modules/game_shaders/shaders/fog.frag @@ -0,0 +1,18 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +uniform sampler2D u_Tex1; +varying vec2 v_TexCoord; + +vec2 direction = vec2(1.0,0.3); +float speed = 0.05; +float pressure = 0.6; +float zoom = 0.5; + +void main(void) +{ + vec2 offset = (v_TexCoord + (direction * u_Time * speed)) / zoom; + vec3 bgcol = texture2D(u_Tex0, v_TexCoord).xyz; + vec3 fogcol = texture2D(u_Tex1, offset).xyz; + vec3 col = bgcol + fogcol*pressure; + gl_FragColor = vec4(col,1.0); +} diff --git a/modules/game_shaders/shaders/grayscale.frag b/modules/game_shaders/shaders/grayscale.frag new file mode 100644 index 00000000..00ad1e75 --- /dev/null +++ b/modules/game_shaders/shaders/grayscale.frag @@ -0,0 +1,14 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +vec4 grayscale(vec4 color) +{ + float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); + return vec4(gray, gray, gray, 1); +} + +void main() +{ + gl_FragColor = grayscale(texture2D(u_Tex0, v_TexCoord)); +} diff --git a/modules/game_shaders/shaders/oldtv.frag b/modules/game_shaders/shaders/oldtv.frag new file mode 100644 index 00000000..ea470c0f --- /dev/null +++ b/modules/game_shaders/shaders/oldtv.frag @@ -0,0 +1,24 @@ +uniform float u_Time; +varying vec2 v_TexCoord; +uniform sampler2D u_Tex0; + +void main(void) +{ + vec2 q = v_TexCoord; + vec2 uv = 0.5 + (q-0.5)*(0.9 + 0.1*sin(0.2*u_Time)); + + vec3 oricol = texture2D(u_Tex0,vec2(q.x,q.y)).xyz; + vec3 col = oricol; + + col = clamp(col*0.5+0.5*col*col*1.2,0.0,1.0); + + col *= 0.5 + 0.5*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y); + + col *= vec3(0.8,1.0,0.7); + + col *= 0.9+0.1*sin(10.0*u_Time+uv.y*1000.0); + + col *= 0.97+0.03*sin(110.0*u_Time); + + gl_FragColor = vec4(col,1.0); +} diff --git a/modules/game_shaders/shaders/party.frag b/modules/game_shaders/shaders/party.frag new file mode 100644 index 00000000..a3e801a3 --- /dev/null +++ b/modules/game_shaders/shaders/party.frag @@ -0,0 +1,13 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +void main() +{ + vec4 col = texture2D(u_Tex0, v_TexCoord); + float d = u_Time * 2; + col.x += (1.0 + sin(d))*0.25; + col.y += (1.0 + sin(d*2))*0.25; + col.z += (1.0 + sin(d*4))*0.25; + gl_FragColor = col; +} diff --git a/modules/game_shaders/shaders/pulse.frag b/modules/game_shaders/shaders/pulse.frag new file mode 100644 index 00000000..bb4dc60d --- /dev/null +++ b/modules/game_shaders/shaders/pulse.frag @@ -0,0 +1,19 @@ +uniform float u_Time; +uniform vec2 u_Resolution; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +void main(void) +{ + vec2 halfres = u_Resolution.xy/2.0; + vec2 cPos = v_TexCoord.xy * u_Resolution; + + cPos.x -= 0.5*halfres.x*sin(u_Time/2.0)+0.3*halfres.x*cos(u_Time)+halfres.x; + cPos.y -= 0.4*halfres.y*sin(u_Time/5.0)+0.3*halfres.y*cos(u_Time)+halfres.y; + float cLength = length(cPos); + + vec2 uv = v_TexCoord.xy+ ((cPos/cLength)*sin(cLength/30.0-u_Time*10.0)/25.0)*0.15; + vec3 col = texture2D(u_Tex0,uv).xyz * 250.0/cLength; + + gl_FragColor = vec4(col,1.0); +} \ No newline at end of file diff --git a/modules/game_shaders/shaders/radialblur.frag b/modules/game_shaders/shaders/radialblur.frag new file mode 100644 index 00000000..b07301bc --- /dev/null +++ b/modules/game_shaders/shaders/radialblur.frag @@ -0,0 +1,46 @@ +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +// some const, tweak for best look +const float sampleDist = 1.0; +const float sampleStrength = 2.2; + +void main(void) +{ + // some sample positions + float samples[10] = + float[](-0.08,-0.05,-0.03,-0.02,-0.01,0.01,0.02,0.03,0.05,0.08); + + // 0.5,0.5 is the center of the screen + // so substracting v_TexCoord from it will result in + // a vector pointing to the middle of the screen + vec2 dir = 0.5 - v_TexCoord; + + // calculate the distance to the center of the screen + float dist = sqrt(dir.x*dir.x + dir.y*dir.y); + + // normalize the direction (reuse the distance) + dir = dir/dist; + + // this is the original colour of this fragment + // using only this would result in a nonblurred version + vec4 color = texture2D(u_Tex0,v_TexCoord); + + vec4 sum = color; + + // take 10 additional blur samples in the direction towards + // the center of the screen + for(int i = 0; i < 10; i++) + sum += texture2D(u_Tex0, v_TexCoord + dir * samples[i] * sampleDist); + + // we have taken eleven samples + sum *= 1.0/11.0; + + // weighten the blur effect with the distance to the + // center of the screen ( further out is blurred more) + float t = dist * sampleStrength; + t = clamp(t ,0.0,1.0); //0 <= t <= 1 + + //Blend the original color with the averaged pixels + gl_FragColor = mix(color, sum, t); +} \ No newline at end of file diff --git a/modules/game_shaders/shaders/sepia.frag b/modules/game_shaders/shaders/sepia.frag new file mode 100644 index 00000000..a20dd6d8 --- /dev/null +++ b/modules/game_shaders/shaders/sepia.frag @@ -0,0 +1,16 @@ +uniform float u_Time; +uniform sampler2D u_Tex0; +varying vec2 v_TexCoord; + +vec4 sepia(vec4 color) +{ + return vec4(dot(color, vec4(.393, .769, .189, .0)), + dot(color, vec4(.349, .686, .168, .0)), + dot(color, vec4(.272, .534, .131, .0)), + 1); +} + +void main() +{ + gl_FragColor = sepia(texture2D(u_Tex0, v_TexCoord)); +} \ No newline at end of file diff --git a/modules/game_shaders/shaders/zomg.frag b/modules/game_shaders/shaders/zomg.frag new file mode 100644 index 00000000..8285021b --- /dev/null +++ b/modules/game_shaders/shaders/zomg.frag @@ -0,0 +1,13 @@ +uniform sampler2D u_Tex0; +uniform float u_Time; +varying vec2 v_TexCoord; + +vec2 tibiaDir = vec2(1.0, 1.0); +void main(void) +{ + vec2 dir = 0.5 - v_TexCoord; + float dist = sqrt(dir.x*dir.x + dir.y*dir.y); + float scale = 0.8 + dist*0.5; + vec4 color = texture2D(u_Tex0, -(dir*scale - 0.5)); + gl_FragColor = color; +} diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index d6579ddb..fa25364a 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -16,12 +16,17 @@ IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo) ENDIF() -# setup compiler options -SET(CXX_WARNS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable") -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARNS} -std=gnu++0x -pipe") +IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(ARCH_FLAGS "-m64 -march=x86-64 -mtune=generic") +ELSE() + SET(ARCH_FLAGS "-m32 -march=i686 -mtune=generic") +ENDIF() +SET(WARNS_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable") +SET(SECURE_FLAGS "-fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARNS} ${SECURE_FLAGS} ${ARCH_FLAGS} -std=gnu++0x -pipe") SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -ggdb -fno-omit-frame-pointer") -SET(CMAKE_CXX_FLAGS_RELEASE "-O3") +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -static-libgcc -static-libstdc++ -Wl,--as-needed") @@ -222,8 +227,6 @@ SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/graphics/painterogl2.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/painterogl2.h ${CMAKE_CURRENT_LIST_DIR}/graphics/painterogl2_shadersources.h - ${CMAKE_CURRENT_LIST_DIR}/graphics/paintershadermanager.cpp - ${CMAKE_CURRENT_LIST_DIR}/graphics/paintershadermanager.h ${CMAKE_CURRENT_LIST_DIR}/graphics/paintershaderprogram.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/paintershaderprogram.h ${CMAKE_CURRENT_LIST_DIR}/graphics/particleaffector.cpp diff --git a/src/framework/application.cpp b/src/framework/application.cpp index b748197f..07c16bcf 100644 --- a/src/framework/application.cpp +++ b/src/framework/application.cpp @@ -201,10 +201,8 @@ void Application::run() } if(redraw) { - g_graphics.beginRender(); - if(cacheForeground) { - Rect viewportRect(0, 0, g_graphics.getViewportSize()); + Rect viewportRect(0, 0, g_painter->getResolution()); // draw the foreground into a texture if(updateForeground) { @@ -236,8 +234,6 @@ void Application::run() g_ui.render(Fw::BothPanes); } - g_graphics.endRender(); - // update screen pixels g_window.swapBuffers(); } diff --git a/src/framework/graphics/font.cpp b/src/framework/graphics/font.cpp index 27f46763..92f41613 100644 --- a/src/framework/graphics/font.cpp +++ b/src/framework/graphics/font.cpp @@ -68,7 +68,7 @@ void Font::load(const OTMLNodePtr& fontNode) void Font::drawText(const std::string& text, const Point& startPos) { - Size boxSize = g_graphics.getViewportSize() - startPos.toSize(); + Size boxSize = g_painter->getResolution() - startPos.toSize(); Rect screenCoords(startPos, boxSize); drawText(text, screenCoords, Fw::AlignTopLeft); } diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index 6efd0dea..88517f87 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -86,22 +86,13 @@ void FrameBuffer::resize(const Size& size) void FrameBuffer::bind() { g_painter->saveAndResetState(); - internalBind(); - - Matrix3 projectionMatrix = { 2.0f/m_texture->getWidth(), 0.0f, 0.0f, - 0.0f, -2.0f/m_texture->getHeight(), 0.0f, - -1.0f, 1.0f, 1.0f }; - g_painter->setProjectionMatrix(projectionMatrix); - - m_oldViewportSize = g_graphics.getViewportSize(); - g_graphics.setViewportSize(m_texture->getSize()); + g_painter->setResolution(m_texture->getSize()); } void FrameBuffer::release() { internalRelease(); - g_graphics.setViewportSize(m_oldViewportSize); g_painter->restoreSavedState(); } diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index faa9a1b8..eb3ce17c 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -195,51 +195,18 @@ bool Graphics::selectPainterEngine(PainterEngine painterEngine) void Graphics::resize(const Size& size) { - setViewportSize(size); - - // The projection matrix converts from Painter's coordinate system to GL's coordinate system - // * GL's viewport is 2x2, Painter's is width x height - // * GL has +y -> -y going from bottom -> top, Painter is the other way round - // * GL has [0,0] in the center, Painter has it in the top-left - // - // This results in the Projection matrix below. - // - // Projection Matrix - // Painter Coord ------------------------------------------------ GL Coord - // ------------- | 2.0 / width | 0.0 | 0.0 | --------------- - // | x y 1 | * | 0.0 | -2.0 / height | 0.0 | = | x' y' 1 | - // ------------- | -1.0 | 1.0 | 1.0 | --------------- - // ------------------------------------------------ - Matrix3 projectionMatrix = { 2.0f/size.width(), 0.0f, 0.0f, - 0.0f, -2.0f/size.height(), 0.0f, - -1.0f, 1.0f, 1.0f }; - + m_viewportSize = size; #ifdef PAINTER_OGL1 if(g_painterOGL1) - g_painterOGL1->setProjectionMatrix(projectionMatrix); + g_painterOGL1->setResolution(size); #endif #ifdef PAINTER_OGL2 if(g_painterOGL2) - g_painterOGL2->setProjectionMatrix(projectionMatrix); + g_painterOGL2->setResolution(size); #endif } -void Graphics::beginRender() -{ - //g_painter->clear(Color::black); -} - -void Graphics::endRender() -{ -} - -void Graphics::setViewportSize(const Size& size) -{ - glViewport(0, 0, size.width(), size.height()); - m_viewportSize = size; -} - bool Graphics::canUseDrawArrays() { #ifdef OPENGL_ES diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index ad728577..25a1ea76 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -46,8 +46,6 @@ public: PainterEngine getPainterEngine() { return m_selectedPainterEngine; } void resize(const Size& size); - void beginRender(); - void endRender(); void setViewportSize(const Size& size); diff --git a/src/framework/graphics/painter.cpp b/src/framework/graphics/painter.cpp index 2c3ddda9..d92fad10 100644 --- a/src/framework/graphics/painter.cpp +++ b/src/framework/graphics/painter.cpp @@ -54,6 +54,7 @@ void Painter::refreshState() updateGlClipRect(); updateGlTexture(); updateGlAlphaWriting(); + updateGlViewport(); } void Painter::saveState() @@ -68,6 +69,7 @@ void Painter::saveState() m_olderStates[m_oldStateIndex].shaderProgram = m_shaderProgram; m_olderStates[m_oldStateIndex].texture = m_texture; m_olderStates[m_oldStateIndex].alphaWriting = m_alphaWriting; + m_olderStates[m_oldStateIndex].resolution = m_resolution; m_oldStateIndex++; } @@ -88,6 +90,7 @@ void Painter::restoreSavedState() setClipRect(m_olderStates[m_oldStateIndex].clipRect); setShaderProgram(m_olderStates[m_oldStateIndex].shaderProgram); setTexture(m_olderStates[m_oldStateIndex].texture); + setResolution(m_olderStates[m_oldStateIndex].resolution); } void Painter::clear(const Color& color) @@ -150,6 +153,36 @@ void Painter::setAlphaWriting(bool enable) updateGlAlphaWriting(); } +void Painter::setResolution(const Size& resolution) +{ + if(m_resolution == resolution) + return; + + + // The projection matrix converts from Painter's coordinate system to GL's coordinate system + // * GL's viewport is 2x2, Painter's is width x height + // * GL has +y -> -y going from bottom -> top, Painter is the other way round + // * GL has [0,0] in the center, Painter has it in the top-left + // + // This results in the Projection matrix below. + // + // Projection Matrix + // Painter Coord ------------------------------------------------ GL Coord + // ------------- | 2.0 / width | 0.0 | 0.0 | --------------- + // | x y 1 | * | 0.0 | -2.0 / height | 0.0 | = | x' y' 1 | + // ------------- | -1.0 | 1.0 | 1.0 | --------------- + + Matrix3 projectionMatrix = { 2.0f/resolution.width(), 0.0f, 0.0f, + 0.0f, -2.0f/resolution.height(), 0.0f, + -1.0f, 1.0f, 1.0f }; + + m_resolution = resolution; + + setProjectionMatrix(projectionMatrix); + if(g_painter == this) + updateGlViewport(); +} + void Painter::updateGlTexture() { if(m_glTextureId != 0) @@ -184,7 +217,7 @@ void Painter::updateGlClipRect() { if(m_clipRect.isValid()) { glEnable(GL_SCISSOR_TEST); - glScissor(m_clipRect.left(), g_graphics.getViewportSize().height() - m_clipRect.bottom() - 1, m_clipRect.width(), m_clipRect.height()); + glScissor(m_clipRect.left(), m_resolution.height() - m_clipRect.bottom() - 1, m_clipRect.width(), m_clipRect.height()); } else { glDisable(GL_SCISSOR_TEST); } @@ -197,3 +230,8 @@ void Painter::updateGlAlphaWriting() else glColorMask(1,1,1,0); } + +void Painter::updateGlViewport() +{ + glViewport(0, 0, m_resolution.width(), m_resolution.height()); +} diff --git a/src/framework/graphics/painter.h b/src/framework/graphics/painter.h index 01eeecee..9ba17f90 100644 --- a/src/framework/graphics/painter.h +++ b/src/framework/graphics/painter.h @@ -53,6 +53,7 @@ public: Texture *texture; PainterShaderProgram *shaderProgram; bool alphaWriting; + Size resolution; }; Painter(); @@ -91,6 +92,7 @@ public: void setShaderProgram(const PainterShaderProgramPtr& shaderProgram) { setShaderProgram(shaderProgram.get()); } void setTexture(const TexturePtr& texture) { setTexture(texture.get()); } + void setResolution(const Size& resolution); Matrix3 getProjectionMatrix() { return m_projectionMatrix; } Matrix3 getTextureMatrix() { return m_textureMatrix; } @@ -100,6 +102,7 @@ public: Rect getClipRect() { return m_clipRect; } PainterShaderProgram *getShaderProgram() { return m_shaderProgram; } bool getAlphaWriting() { return m_alphaWriting; } + Size getResolution() { return m_resolution; }; void resetColor() { setColor(Color::white); } void resetOpacity() { setOpacity(1.0f); } @@ -109,11 +112,14 @@ public: void resetTexture() { setTexture(nullptr); } void resetAlphaWriting() { setAlphaWriting(false); } + virtual bool hasShaders() = 0; + protected: void updateGlTexture(); void updateGlCompositionMode(); void updateGlClipRect(); void updateGlAlphaWriting(); + void updateGlViewport(); CoordsBuffer m_coordsBuffer; @@ -126,6 +132,7 @@ protected: Texture *m_texture; PainterShaderProgram *m_shaderProgram; bool m_alphaWriting; + Size m_resolution; PainterState m_olderStates[10]; int m_oldStateIndex; diff --git a/src/framework/graphics/painterogl1.h b/src/framework/graphics/painterogl1.h index 1db679dc..cda15233 100644 --- a/src/framework/graphics/painterogl1.h +++ b/src/framework/graphics/painterogl1.h @@ -62,6 +62,8 @@ public: void setColor(const Color& color); void setOpacity(float opacity); + bool hasShaders() { return false; } + private: void updateGlColor(); void updateGlMatrixMode(); diff --git a/src/framework/graphics/painterogl2.cpp b/src/framework/graphics/painterogl2.cpp index bee48f95..48ab55ed 100644 --- a/src/framework/graphics/painterogl2.cpp +++ b/src/framework/graphics/painterogl2.cpp @@ -22,7 +22,9 @@ #include "painterogl2.h" #include "texture.h" -#include "paintershadermanager.h" +#include "graphics.h" +#include "painterogl2_shadersources.h" +#include PainterOGL2 *g_painterOGL2 = nullptr; @@ -31,12 +33,25 @@ PainterOGL2::PainterOGL2() m_drawProgram = nullptr; resetState(); - g_shaders.init(); + m_drawTexturedProgram = PainterShaderProgramPtr(new PainterShaderProgram); + assert(m_drawTexturedProgram); + m_drawTexturedProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + m_drawTexturedProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslTextureSrcFragmentShader); + m_drawTexturedProgram->link(); + + m_drawSolidColorProgram = PainterShaderProgramPtr(new PainterShaderProgram); + assert(m_drawSolidColorProgram); + m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Vertex, glslMainVertexShader + glslPositionOnlyVertexShader); + m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslSolidColorFragmentShader); + m_drawSolidColorProgram->link(); + + PainterShaderProgram::release(); } PainterOGL2::~PainterOGL2() { - g_shaders.terminate(); + m_drawTexturedProgram = nullptr; + m_drawSolidColorProgram = nullptr; } void PainterOGL2::bind() @@ -71,10 +86,13 @@ void PainterOGL2::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode) // update shader with the current painter state m_drawProgram->bind(); m_drawProgram->setProjectionMatrix(m_projectionMatrix); - if(textured) + if(textured) { m_drawProgram->setTextureMatrix(m_textureMatrix); + m_drawProgram->bindMultiTextures(); + } m_drawProgram->setOpacity(m_opacity); m_drawProgram->setColor(m_color); + m_drawProgram->setResolution(m_resolution); m_drawProgram->updateTime(); // update coords buffer hardware caches if enabled @@ -107,7 +125,7 @@ void PainterOGL2::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr if(texture->isEmpty()) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get()); setTexture(texture); drawCoords(coordsBuffer); } @@ -117,7 +135,7 @@ void PainterOGL2::drawTexturedRect(const Rect& dest, const TexturePtr& texture, if(dest.isEmpty() || src.isEmpty() || texture->isEmpty()) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get()); setTexture(texture); m_coordsBuffer.clear(); @@ -130,7 +148,7 @@ void PainterOGL2::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& t if(dest.isEmpty() || src.isEmpty() || texture->isEmpty()) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get()); setTexture(texture); m_coordsBuffer.clear(); @@ -143,7 +161,7 @@ void PainterOGL2::drawFilledRect(const Rect& dest) if(dest.isEmpty()) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawSolidColorProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get()); m_coordsBuffer.clear(); m_coordsBuffer.addRect(dest); @@ -155,7 +173,7 @@ void PainterOGL2::drawFilledTriangle(const Point& a, const Point& b, const Point if(a == b || a == c || b == c) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawSolidColorProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get()); m_coordsBuffer.clear(); m_coordsBuffer.addTriangle(a, b, c); @@ -167,7 +185,7 @@ void PainterOGL2::drawBoundingRect(const Rect& dest, int innerLineWidth) if(dest.isEmpty() || innerLineWidth == 0) return; - setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawSolidColorProgram().get()); + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get()); m_coordsBuffer.clear(); m_coordsBuffer.addBoudingRect(dest, innerLineWidth); diff --git a/src/framework/graphics/painterogl2.h b/src/framework/graphics/painterogl2.h index 3e3bfd68..8358d2bd 100644 --- a/src/framework/graphics/painterogl2.h +++ b/src/framework/graphics/painterogl2.h @@ -51,8 +51,12 @@ public: void setDrawProgram(PainterShaderProgram *drawProgram) { m_drawProgram = drawProgram; } + bool hasShaders() { return true; } + private: PainterShaderProgram *m_drawProgram; + PainterShaderProgramPtr m_drawTexturedProgram; + PainterShaderProgramPtr m_drawSolidColorProgram; }; extern PainterOGL2 *g_painterOGL2; diff --git a/src/framework/graphics/painterogl2_shadersources.h b/src/framework/graphics/painterogl2_shadersources.h index a4fd3fce..1607beca 100644 --- a/src/framework/graphics/painterogl2_shadersources.h +++ b/src/framework/graphics/painterogl2_shadersources.h @@ -27,42 +27,42 @@ static const std::string glslMainVertexShader = "\n\ }\n"; static const std::string glslMainWithTexCoordsVertexShader = "\n\ - attribute highp vec2 a_texCoord;\n\ - uniform highp mat3 textureMatrix;\n\ - varying highp vec2 texCoord;\n\ + attribute highp vec2 a_TexCoord;\n\ + uniform highp mat3 u_TextureMatrix;\n\ + varying highp vec2 v_TexCoord;\n\ highp vec4 calculatePosition();\n\ void main()\n\ {\n\ gl_Position = calculatePosition();\n\ - texCoord = (textureMatrix * vec3(a_texCoord,1)).xy;\n\ + v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1)).xy;\n\ }\n"; static std::string glslPositionOnlyVertexShader = "\n\ - attribute highp vec2 a_vertex;\n\ - uniform highp mat3 projectionMatrix;\n\ + attribute highp vec2 a_Vertex;\n\ + uniform highp mat3 u_ProjectionMatrix;\n\ highp vec4 calculatePosition() {\n\ - return vec4(projectionMatrix * vec3(a_vertex.xy, 1), 1);\n\ + return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1), 1);\n\ }\n"; static const std::string glslMainFragmentShader = "\n\ - uniform lowp float opacity;\n\ + uniform lowp float u_Opacity;\n\ lowp vec4 calculatePixel();\n\ void main()\n\ {\n\ gl_FragColor = calculatePixel();\n\ - gl_FragColor.a *= opacity;\n\ + gl_FragColor.a *= u_Opacity;\n\ }\n"; static const std::string glslTextureSrcFragmentShader = "\n\ - varying mediump vec2 texCoord;\n\ - uniform lowp vec4 color;\n\ - uniform sampler2D tex0;\n\ + varying mediump vec2 v_TexCoord;\n\ + uniform lowp vec4 u_Color;\n\ + uniform sampler2D u_Tex0;\n\ lowp vec4 calculatePixel() {\n\ - return texture2D(tex0, texCoord) * color;\n\ + return texture2D(u_Tex0, v_TexCoord) * u_Color;\n\ }\n"; static const std::string glslSolidColorFragmentShader = "\n\ - uniform lowp vec4 color;\n\ + uniform lowp vec4 u_Color;\n\ lowp vec4 calculatePixel() {\n\ - return color;\n\ + return u_Color;\n\ }\n"; diff --git a/src/framework/graphics/paintershadermanager.cpp b/src/framework/graphics/paintershadermanager.cpp deleted file mode 100644 index 2dd7bf6d..00000000 --- a/src/framework/graphics/paintershadermanager.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "paintershadermanager.h" -#include "painterogl2.h" -#include "texture.h" -#include "painterogl2_shadersources.h" -#include "paintershaderprogram.h" -#include "shaderprogram.h" -#include "graphics.h" - -PainterShaderManager g_shaders; - -void PainterShaderManager::init() -{ - m_drawTexturedProgram = createShader(); - assert(m_drawTexturedProgram); - m_drawTexturedProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); - m_drawTexturedProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslTextureSrcFragmentShader); - m_drawTexturedProgram->link(); - - m_drawSolidColorProgram = createShader(); - assert(m_drawSolidColorProgram); - m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Vertex, glslMainVertexShader + glslPositionOnlyVertexShader); - m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslSolidColorFragmentShader); - m_drawSolidColorProgram->link(); - - PainterShaderProgram::release(); -} - -void PainterShaderManager::terminate() -{ - m_drawTexturedProgram = nullptr; - m_drawSolidColorProgram = nullptr; -} - -PainterShaderProgramPtr PainterShaderManager::createShader() -{ - if(!g_graphics.canUseShaders()) - return nullptr; - return PainterShaderProgramPtr(new PainterShaderProgram); -} - -PainterShaderProgramPtr PainterShaderManager::createTexturedFragmentShader(const std::string& shaderFile) -{ - PainterShaderProgramPtr shader = createShader(); - if(!shader) - return nullptr; - - shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); - shader->addShaderFromSourceFile(Shader::Fragment, shaderFile); - - if(!shader->link()) - return nullptr; - - return shader; -} diff --git a/src/framework/graphics/paintershaderprogram.cpp b/src/framework/graphics/paintershaderprogram.cpp index 7d18dc03..faac9a66 100644 --- a/src/framework/graphics/paintershaderprogram.cpp +++ b/src/framework/graphics/paintershaderprogram.cpp @@ -24,7 +24,9 @@ #include "painter.h" #include "texture.h" #include "texturemanager.h" +#include "graphics.h" #include +#include PainterShaderProgram::PainterShaderProgram() { @@ -34,28 +36,35 @@ PainterShaderProgram::PainterShaderProgram() m_time = 0; } +void PainterShaderProgram::setupUniforms() +{ + bindUniformLocation(PROJECTION_MATRIX_UNIFORM, "u_ProjectionMatrix"); + bindUniformLocation(TEXTURE_MATRIX_UNIFORM, "u_TextureMatrix"); + bindUniformLocation(COLOR_UNIFORM, "u_Color"); + bindUniformLocation(OPACITY_UNIFORM, "u_Opacity"); + bindUniformLocation(TIME_UNIFORM, "u_Time"); + bindUniformLocation(TEX0_UNIFORM, "u_Tex0"); + bindUniformLocation(TEX1_UNIFORM, "u_Tex1"); + bindUniformLocation(RESOLUTION_UNIFORM, "u_Resolution"); + + setUniformValue(PROJECTION_MATRIX_UNIFORM, m_projectionMatrix); + setUniformValue(TEXTURE_MATRIX_UNIFORM, m_textureMatrix); + setUniformValue(COLOR_UNIFORM, m_color); + setUniformValue(OPACITY_UNIFORM, m_opacity); + setUniformValue(TIME_UNIFORM, m_time); + setUniformValue(TEX0_UNIFORM, 0); + setUniformValue(TEX1_UNIFORM, 1); + setUniformValue(RESOLUTION_UNIFORM, (float)m_resolution.width(), (float)m_resolution.height()); +} + bool PainterShaderProgram::link() { m_startTime = g_clock.seconds(); - bindAttributeLocation(VERTEX_ATTR, "a_vertex"); - bindAttributeLocation(TEXCOORD_ATTR, "a_texCoord"); + bindAttributeLocation(VERTEX_ATTR, "a_Vertex"); + bindAttributeLocation(TEXCOORD_ATTR, "a_TexCoord"); if(ShaderProgram::link()) { - bindUniformLocation(PROJECTION_MATRIX_UNIFORM, "projectionMatrix"); - bindUniformLocation(TEXTURE_MATRIX_UNIFORM, "textureMatrix"); - bindUniformLocation(COLOR_UNIFORM, "color"); - bindUniformLocation(OPACITY_UNIFORM, "opacity"); - bindUniformLocation(TIME_UNIFORM, "time"); - bindUniformLocation(TEX0_UNIFORM, "tex0"); - bindUniformLocation(TEX1_UNIFORM, "tex1"); - bind(); - setUniformValue(PROJECTION_MATRIX_UNIFORM, m_projectionMatrix); - setUniformValue(TEXTURE_MATRIX_UNIFORM, m_textureMatrix); - setUniformValue(COLOR_UNIFORM, m_color); - setUniformValue(OPACITY_UNIFORM, m_opacity); - setUniformValue(TIME_UNIFORM, m_time); - setUniformValue(TEX0_UNIFORM, 0); - setUniformValue(TEX1_UNIFORM, 1); + setupUniforms(); release(); return true; } @@ -102,6 +111,16 @@ void PainterShaderProgram::setOpacity(float opacity) m_opacity = opacity; } +void PainterShaderProgram::setResolution(const Size& resolution) +{ + if(m_resolution == resolution) + return; + + bind(); + setUniformValue(RESOLUTION_UNIFORM, (float)resolution.width(), (float)resolution.height()); + m_resolution = resolution; +} + void PainterShaderProgram::updateTime() { float time = g_clock.seconds() - m_startTime; @@ -112,3 +131,32 @@ void PainterShaderProgram::updateTime() setUniformValue(TIME_UNIFORM, time); m_time = time; } + +void PainterShaderProgram::addMultiTexture(const std::string& file) +{ + if(m_multiTextures.size() > 3) + g_logger.error("cannot add more multi textures to shader, the max is 3"); + + TexturePtr texture = g_textures.getTexture(file); + if(!texture) + return; + + texture->setSmooth(true); + texture->setRepeat(true); + + m_multiTextures.push_back(texture); +} + +void PainterShaderProgram::bindMultiTextures() +{ + if(m_multiTextures.size() == 0) + return; + + int i=1; + for(const TexturePtr& tex : m_multiTextures) { + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, tex->getId()); + } + + glActiveTexture(GL_TEXTURE0); +} diff --git a/src/framework/graphics/paintershaderprogram.h b/src/framework/graphics/paintershaderprogram.h index 547753c7..49809a63 100644 --- a/src/framework/graphics/paintershaderprogram.h +++ b/src/framework/graphics/paintershaderprogram.h @@ -40,12 +40,13 @@ protected: TIME_UNIFORM = 4, TEX0_UNIFORM = 5, TEX1_UNIFORM = 6, - //TEX2_UNIFORM = 7, - //TEX3_UNIFORM = 8, + RESOLUTION_UNIFORM = 7, }; friend class PainterOGL2; + virtual void setupUniforms(); + public: PainterShaderProgram(); @@ -55,8 +56,12 @@ public: void setTextureMatrix(const Matrix3& textureMatrix); void setColor(const Color& color); void setOpacity(float opacity); + void setResolution(const Size& resolution); void updateTime(); + void addMultiTexture(const std::string& file); + void bindMultiTextures(); + private: float m_startTime; @@ -64,7 +69,9 @@ private: float m_opacity; Matrix3 m_projectionMatrix; Matrix3 m_textureMatrix; + Size m_resolution; float m_time; + std::vector m_multiTextures; }; #endif diff --git a/src/framework/graphics/shader.cpp b/src/framework/graphics/shader.cpp index ba6670e6..699f6547 100644 --- a/src/framework/graphics/shader.cpp +++ b/src/framework/graphics/shader.cpp @@ -72,8 +72,12 @@ bool Shader::compileSourceCode(const std::string& sourceCode) bool Shader::compileSourceFile(const std::string& sourceFile) { - std::string sourceCode = g_resources.loadFile(sourceFile); - return compileSourceCode(sourceCode); + try { + std::string sourceCode = g_resources.loadFile(sourceFile); + return compileSourceCode(sourceCode); + } catch(stdext::exception& e) { + g_logger.error(stdext::format("unable to load shader source form file: %s", sourceFile)); + } } std::string Shader::log() diff --git a/src/framework/graphics/shaderprogram.h b/src/framework/graphics/shaderprogram.h index 31976820..e029c3d9 100644 --- a/src/framework/graphics/shaderprogram.h +++ b/src/framework/graphics/shaderprogram.h @@ -24,12 +24,14 @@ #define SHADERPROGRAM_H #include "shader.h" +#include -class ShaderProgram +class ShaderProgram : public LuaObject { enum { MAX_UNIFORM_LOCATIONS = 30 }; + public: ShaderProgram(); ~ShaderProgram(); diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index 1bc43945..9e8a460b 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -124,6 +124,16 @@ void Texture::setSmooth(bool smooth) setupFilters(); } +void Texture::setRepeat(bool repeat) +{ + if(m_repeat == repeat) + return; + + m_repeat = repeat; + bind(); + setupWrap(); +} + void Texture::setUpsideDown(bool upsideDown) { if(m_upsideDown == upsideDown) @@ -163,9 +173,11 @@ bool Texture::setupSize(const Size& size, bool forcePowerOfTwo) void Texture::setupWrap() { - GLint texParam = GL_REPEAT; - if(g_graphics.canUseClampToEdge()) - texParam = GL_CLAMP_TO_EDGE; // disable texture borders by default + GLint texParam; + if(!m_repeat && g_graphics.canUseClampToEdge()) + texParam = GL_CLAMP_TO_EDGE; + else + texParam = GL_REPEAT; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParam); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParam); diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index bc5bcc90..7939539e 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -38,6 +38,7 @@ public: bool buildHardwareMipmaps(); void setSmooth(bool smooth); + void setRepeat(bool repeat); void setUpsideDown(bool upsideDown); GLuint getId() { return m_id; } @@ -47,6 +48,7 @@ public: const Size& getGlSize() { return m_glSize; } const Matrix3& getTransformMatrix() { return m_transformMatrix; } bool isEmpty() { return m_id == 0; } + bool hasRepeat() { return m_repeat; } bool hasMipmaps() { return m_hasMipmaps; } protected: @@ -64,6 +66,7 @@ protected: Boolean m_hasMipmaps; Boolean m_smooth; Boolean m_upsideDown; + Boolean m_repeat; }; #endif diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 4e723c73..f3bf3fb8 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -473,6 +473,10 @@ void Application::registerLuaFunctions() g_lua.bindClassMemberFunction("encryptRSA", &OutputMessage::encryptRSA); g_lua.bindClassMemberFunction("getMessageSize", &OutputMessage::getMessageSize); + g_lua.registerClass(); + g_lua.registerClass(); + g_lua.bindClassMemberFunction("addMultiTexture", &PainterShaderProgram::addMultiTexture); + // Application g_lua.registerStaticClass("g_app"); g_lua.bindClassStaticFunction("g_app", "exit", std::bind(&Application::exit, g_app)); diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index 8f128bbb..482571dc 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -44,8 +44,8 @@ SET(otclient_SOURCES ${otclient_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/core/effect.h ${CMAKE_CURRENT_LIST_DIR}/core/game.cpp ${CMAKE_CURRENT_LIST_DIR}/core/game.h - ${CMAKE_CURRENT_LIST_DIR}/core/gameshadermanager.cpp - ${CMAKE_CURRENT_LIST_DIR}/core/gameshadermanager.h + ${CMAKE_CURRENT_LIST_DIR}/core/shadermanager.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/shadermanager.h ${CMAKE_CURRENT_LIST_DIR}/core/item.cpp ${CMAKE_CURRENT_LIST_DIR}/core/item.h ${CMAKE_CURRENT_LIST_DIR}/core/localplayer.cpp diff --git a/src/otclient/core/declarations.h b/src/otclient/core/declarations.h index 80a5bcbe..db5482da 100644 --- a/src/otclient/core/declarations.h +++ b/src/otclient/core/declarations.h @@ -43,6 +43,7 @@ class AnimatedText; class StaticText; class ThingType; class ThingsType; +class ItemShader; typedef std::shared_ptr MapViewPtr; typedef std::shared_ptr TilePtr; @@ -58,6 +59,7 @@ typedef std::shared_ptr EffectPtr; typedef std::shared_ptr MissilePtr; typedef std::shared_ptr AnimatedTextPtr; typedef std::shared_ptr StaticTextPtr; +typedef std::shared_ptr ItemShaderPtr; typedef std::vector ThingList; diff --git a/src/otclient/core/gameshadermanager.cpp b/src/otclient/core/gameshadermanager.cpp deleted file mode 100644 index f5ff369b..00000000 --- a/src/otclient/core/gameshadermanager.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "gameshadermanager.h" - diff --git a/src/otclient/core/gameshadermanager.h b/src/otclient/core/gameshadermanager.h deleted file mode 100644 index d1e4acdb..00000000 --- a/src/otclient/core/gameshadermanager.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef GAMESHADERMANAGER_H -#define GAMESHADERMANAGER_H - -class GameShaderManager -{ -}; - -#endif diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index 49e7fdf4..419c07fc 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -25,16 +25,16 @@ #include "spritemanager.h" #include "thing.h" #include "tile.h" +#include "shadermanager.h" #include #include #include -#include -#include Item::Item() : Thing() { m_id = 0; m_countOrSubType = 1; + m_shaderProgram = g_shaders.getDefaultItemShader(); } ItemPtr Item::create(int id) @@ -48,10 +48,6 @@ ItemPtr Item::create(int id) return item; } -/* -PainterShaderProgramPtr itemProgram; -int ITEM_ID_UNIFORM = 10; -*/ void Item::draw(const Point& dest, float scaleFactor, bool animate) { if(m_id == 0) @@ -166,25 +162,18 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate) zPattern = m_position.z % getNumPatternsZ(); } - // setup item drawing shader - /* - if(!itemProgram) { - itemProgram = PainterShaderProgramPtr(new PainterShaderProgram); - itemProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); - itemProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/item.frag"); - itemProgram->link(); - itemProgram->bindUniformLocation(ITEM_ID_UNIFORM, "itemId"); + bool useShader = g_painter->hasShaders() && m_shaderProgram; + if(useShader) { + m_shaderProgram->bind(); + m_shaderProgram->setUniformValue(ShaderManager::ITEM_ID_UNIFORM, (int)m_id); + + g_painter->setShaderProgram(m_shaderProgram); } - g_painter->setShaderProgram(itemProgram); - //itemProgram->bind(); - //itemProgram->setUniformValue(ITEM_ID_UNIFORM, (int)m_id); - */ - // now we can draw the item m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase); - // release draw shader - //g_painter->resetShaderProgram(); + if(useShader) + g_painter->resetShaderProgram(); } void Item::setId(uint32 id) diff --git a/src/otclient/core/item.h b/src/otclient/core/item.h index be2998c5..62054a2d 100644 --- a/src/otclient/core/item.h +++ b/src/otclient/core/item.h @@ -51,6 +51,7 @@ public: private: uint16 m_id; uint8 m_countOrSubType; + PainterShaderProgramPtr m_shaderProgram; }; #endif diff --git a/src/otclient/core/mapview.cpp b/src/otclient/core/mapview.cpp index a7795b87..ec8088b7 100644 --- a/src/otclient/core/mapview.cpp +++ b/src/otclient/core/mapview.cpp @@ -24,13 +24,13 @@ #include #include -#include #include "creature.h" #include "map.h" #include "tile.h" #include "statictext.h" #include "animatedtext.h" #include "missile.h" +#include "shadermanager.h" #include MapView::MapView() @@ -44,7 +44,7 @@ MapView::MapView() m_framebuffer = FrameBufferPtr(new FrameBuffer()); setVisibleDimension(Size(15, 11)); - m_shaderProgram = g_shaders.createTexturedFragmentShader("/game_shaders/map.frag"); + m_shader = g_shaders.getDefaultMapShader(); } void MapView::draw(const Rect& rect) @@ -109,12 +109,11 @@ void MapView::draw(const Rect& rect) m_framebuffer->release(); // generating mipmaps each frame can be slow in older cards - //m_framebuffer->getTexture()->generateHardwareMipmaps(); + //m_framebuffer->getTexture()->buildHardwareMipmaps(); m_mustDrawVisibleTilesCache = false; } - //g_painter->setShaderProgram(m_shaderProgram); Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize; if(m_followingCreature) @@ -129,6 +128,7 @@ void MapView::draw(const Rect& rect) g_painter->setColor(Color::white); glDisable(GL_BLEND); + g_painter->setShaderProgram(m_shader); #if 0 // debug source area g_painter->saveAndResetState(); @@ -141,9 +141,9 @@ void MapView::draw(const Rect& rect) #else m_framebuffer->draw(rect, srcRect); #endif + g_painter->resetShaderProgram(); glEnable(GL_BLEND); - //g_painter->resetShaderProgram(); // this could happen if the player position is not known yet if(!cameraPosition.isValid()) diff --git a/src/otclient/core/mapview.h b/src/otclient/core/mapview.h index 0c9d7153..a6e9be1a 100644 --- a/src/otclient/core/mapview.h +++ b/src/otclient/core/mapview.h @@ -103,6 +103,9 @@ public: void setAnimated(bool animated) { m_animated = animated; requestVisibleTilesCacheUpdate(); } bool isAnimating() { return m_animated; } + void setShader(const PainterShaderProgramPtr& shader) { m_shader = shader; } + PainterShaderProgramPtr getShader() { return m_shader; } + // get tile TilePtr getTile(const Point& mousePos, const Rect& mapRect); @@ -139,7 +142,7 @@ private: EventPtr m_updateTilesCacheEvent; CreaturePtr m_followingCreature; FrameBufferPtr m_framebuffer; - PainterShaderProgramPtr m_shaderProgram; + PainterShaderProgramPtr m_shader; ViewMode m_viewMode; Otc::DrawFlags m_drawFlags; }; diff --git a/src/otclient/core/shadermanager.cpp b/src/otclient/core/shadermanager.cpp new file mode 100644 index 00000000..88892a45 --- /dev/null +++ b/src/otclient/core/shadermanager.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shadermanager.h" +#include +#include +#include + +ShaderManager g_shaders; + +void ShaderManager::init() +{ + if(!g_graphics.canUseShaders()) + return; + + m_defaultItemShader = createFragmentShaderFromCode("Item", glslMainFragmentShader + glslTextureSrcFragmentShader); + setupItemShader(m_defaultItemShader); + + m_defaultMapShader = createFragmentShaderFromCode("Map", glslMainFragmentShader + glslTextureSrcFragmentShader); + + PainterShaderProgram::release(); +} + +void ShaderManager::terminate() +{ + m_defaultItemShader = nullptr; + m_defaultMapShader = nullptr; +} + +PainterShaderProgramPtr ShaderManager::createShader(const std::string& name) +{ + if(!g_graphics.canUseShaders()) { + g_logger.error(stdext::format("unable to create shader, shaders are not supported")); + return nullptr; + } + + PainterShaderProgramPtr shader(new PainterShaderProgram); + m_shaders[name] = shader; + return shader; +} + +PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, const std::string& file) +{ + PainterShaderProgramPtr shader = createShader(name); + if(!shader) + return nullptr; + + shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + if(!shader->addShaderFromSourceFile(Shader::Fragment, file)) { + g_logger.error(stdext::format("unable to load fragment shader '%s' from source file '%s'", name, file)); + return nullptr; + } + + if(!shader->link()) { + g_logger.error(stdext::format("unable to link shader '%s' from file '%s'", name, file)); + return nullptr; + } + + m_shaders[name] = shader; + return shader; +} + +PainterShaderProgramPtr ShaderManager::createFragmentShaderFromCode(const std::string& name, const std::string& code) +{ + PainterShaderProgramPtr shader = createShader(name); + if(!shader) + return nullptr; + + shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + if(!shader->addShaderFromSourceCode(Shader::Fragment, code)) { + g_logger.error(stdext::format("unable to load fragment shader '%s'", name)); + return nullptr; + } + + if(!shader->link()) { + g_logger.error(stdext::format("unable to link shader '%s'", name)); + return nullptr; + } + + m_shaders[name] = shader; + return shader; +} + +PainterShaderProgramPtr ShaderManager::createItemShader(const std::string& name, const std::string& file) +{ + PainterShaderProgramPtr shader = createFragmentShader(name, file); + if(shader) + setupItemShader(shader); + return shader; +} + +void ShaderManager::setupItemShader(const PainterShaderProgramPtr& shader) +{ + if(!shader) + return; + shader->bindUniformLocation(ITEM_ID_UNIFORM, "u_ItemId"); +} + +PainterShaderProgramPtr ShaderManager::getShader(const std::string& name) +{ + auto it = m_shaders.find(name); + if(it != m_shaders.end()) + return it->second; + return nullptr; +} diff --git a/src/otclient/core/shadermanager.h b/src/otclient/core/shadermanager.h new file mode 100644 index 00000000..f2a9e908 --- /dev/null +++ b/src/otclient/core/shadermanager.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GAMESHADERS_H +#define GAMESHADERS_H + +#include "declarations.h" +#include + +class ShaderManager +{ +public: + enum { + ITEM_ID_UNIFORM = 10 + }; + + void init(); + void terminate(); + + PainterShaderProgramPtr createShader(const std::string& name); + PainterShaderProgramPtr createFragmentShader(const std::string& name, const std::string& file); + PainterShaderProgramPtr createFragmentShaderFromCode(const std::string& name, const std::string& code); + + PainterShaderProgramPtr createItemShader(const std::string& name, const std::string& file); + PainterShaderProgramPtr createMapShader(const std::string& name, const std::string& file) { return createFragmentShader(name, file); } + + PainterShaderProgramPtr getDefaultItemShader() { return m_defaultItemShader; } + PainterShaderProgramPtr getDefaultMapShader() { return m_defaultMapShader; } + + PainterShaderProgramPtr getShader(const std::string& name); + +private: + void setupItemShader(const PainterShaderProgramPtr& shader); + + PainterShaderProgramPtr m_defaultItemShader; + PainterShaderProgramPtr m_defaultMapShader; + std::unordered_map m_shaders; +}; + + +extern ShaderManager g_shaders; + +#endif diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 94bf3188..7a37ef2b 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -171,6 +172,16 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("g_game", "getClientVersion", std::bind(&Game::getClientVersion, &g_game)); g_lua.bindClassStaticFunction("g_game", "getFeature", std::bind(&Game::getFeature, &g_game, std::placeholders::_1)); + g_lua.registerStaticClass("g_shaders"); + g_lua.bindClassStaticFunction("g_shaders", "createShader", std::bind(&ShaderManager::createShader, &g_shaders, std::placeholders::_1)); + g_lua.bindClassStaticFunction("g_shaders", "createFragmentShader", std::bind(&ShaderManager::createFragmentShader, &g_shaders, std::placeholders::_1, std::placeholders::_2)); + g_lua.bindClassStaticFunction("g_shaders", "createFragmentShaderFromCode", std::bind(&ShaderManager::createFragmentShaderFromCode, &g_shaders, std::placeholders::_1, std::placeholders::_2)); + g_lua.bindClassStaticFunction("g_shaders", "createItemShader", std::bind(&ShaderManager::createItemShader, &g_shaders, std::placeholders::_1, std::placeholders::_2)); + g_lua.bindClassStaticFunction("g_shaders", "createMapShader", std::bind(&ShaderManager::createMapShader, &g_shaders, std::placeholders::_1, std::placeholders::_2)); + g_lua.bindClassStaticFunction("g_shaders", "getDefaultItemShader", std::bind(&ShaderManager::getDefaultItemShader, &g_shaders)); + g_lua.bindClassStaticFunction("g_shaders", "getDefaultMapShader", std::bind(&ShaderManager::getDefaultMapShader, &g_shaders)); + g_lua.bindClassStaticFunction("g_shaders", "getShader", std::bind(&ShaderManager::getShader, &g_shaders, std::placeholders::_1)); + g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor); g_lua.registerClass(); @@ -375,6 +386,7 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("setDrawMinimapColors", &UIMap::setDrawMinimapColors); g_lua.bindClassMemberFunction("setAnimated", &UIMap::setAnimated); g_lua.bindClassMemberFunction("setKeepAspectRatio", &UIMap::setKeepAspectRatio); + g_lua.bindClassMemberFunction("setMapShader", &UIMap::setMapShader); g_lua.bindClassMemberFunction("isMultifloor", &UIMap::isMultifloor); g_lua.bindClassMemberFunction("isAutoViewModeEnabled", &UIMap::isAutoViewModeEnabled); g_lua.bindClassMemberFunction("isDrawingTexts", &UIMap::isDrawingTexts); @@ -390,6 +402,7 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("getMaxZoomIn", &UIMap::getMaxZoomIn); g_lua.bindClassMemberFunction("getMaxZoomOut", &UIMap::getMaxZoomOut); g_lua.bindClassMemberFunction("getZoom", &UIMap::getZoom); + g_lua.bindClassMemberFunction("getMapShader", &UIMap::getMapShader); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return UIProgressRectPtr(new UIProgressRect); } ); diff --git a/src/otclient/otclient.cpp b/src/otclient/otclient.cpp index 4c73d8a3..f2153c0f 100644 --- a/src/otclient/otclient.cpp +++ b/src/otclient/otclient.cpp @@ -26,6 +26,7 @@ #include #include "core/game.h" #include "core/map.h" +#include "core/shadermanager.h" OTClient::OTClient() : Application(Otc::AppCompactName) { @@ -87,6 +88,8 @@ void OTClient::init(const std::vector& args) g_logger.setLogFile(stdext::format("%s.txt", Otc::AppCompactName)); Application::init(args); + g_shaders.init(); + g_modules.discoverModules(); // core modules 0-99 @@ -110,3 +113,9 @@ void OTClient::init(const std::vector& args) } } } + +void OTClient::terminate() +{ + g_shaders.terminate(); + Application::terminate(); +} diff --git a/src/otclient/otclient.h b/src/otclient/otclient.h index 1401ee17..2e6ed4e1 100644 --- a/src/otclient/otclient.h +++ b/src/otclient/otclient.h @@ -31,6 +31,7 @@ class OTClient : public Application public: OTClient(); void init(const std::vector& args); + void terminate(); void registerLuaFunctions(); }; diff --git a/src/otclient/ui/uimap.h b/src/otclient/ui/uimap.h index 3c021b17..1dcb263e 100644 --- a/src/otclient/ui/uimap.h +++ b/src/otclient/ui/uimap.h @@ -54,6 +54,7 @@ public: void setDrawMinimapColors(bool enable) { m_mapView->setDrawMinimapColors(enable); } void setAnimated(bool enable) { m_mapView->setAnimated(enable); } void setKeepAspectRatio(bool enable); + void setMapShader(const PainterShaderProgramPtr& shader) { m_mapView->setShader(shader); } bool isMultifloor() { return m_mapView->isMultifloor(); } bool isAutoViewModeEnabled() { return m_mapView->isAutoViewModeEnabled(); } @@ -71,6 +72,7 @@ public: int getMaxZoomIn() { return m_maxZoomIn; } int getMaxZoomOut() { return m_maxZoomOut; } int getZoom() { return m_zoom; } + PainterShaderProgramPtr getMapShader() { return m_mapView->getShader(); } protected: virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);