diff --git a/TODO b/TODO index e78600a8..1f448fd0 100644 --- a/TODO +++ b/TODO @@ -14,11 +14,10 @@ fix moving windows and tooltips conflicts todo display otclient icon in window bar remake otui styles states system padding - +break UILabel lines rename Game to g_game, etc implement Console key binding -fatal error if sprite load fails impl vertical sync, clipboard crash handler modify COnnection::poll() @@ -29,4 +28,7 @@ bind every global lua function in a static class use metatable for Point,Rect,Color,Size lua classes lua binder generator restore win32 platform -set special types for g_configs like lists/point/size \ No newline at end of file +set special types for g_configs like lists/point/size +restore ctrl+g and keybindings +create a class for reading binary files +handle corrupt errors in dat/spr \ No newline at end of file diff --git a/modules/addon_console/commands.lua b/modules/addon_console/commands.lua new file mode 100644 index 00000000..03ddf63d --- /dev/null +++ b/modules/addon_console/commands.lua @@ -0,0 +1,5 @@ +function dumpWidgets() + for i=1,UI.root:getChildCount() do + print(UI.root:getChildByIndex(i):getId()) + end +end \ No newline at end of file diff --git a/modules/addon_console/console.lua b/modules/addon_console/console.lua index 57dd9802..41a8e222 100644 --- a/modules/addon_console/console.lua +++ b/modules/addon_console/console.lua @@ -34,7 +34,7 @@ local function completeCommand() local cursorPos = commandLineEdit:getCursorPos() if cursorPos == 0 then return end - local commandBegin = string.sub(commandLineEdit:getText(), 1, cursorPos) + local commandBegin = commandLineEdit:getText():sub(1, cursorPos) local possibleCommands = {} -- create a list containing all globals @@ -43,7 +43,7 @@ local function completeCommand() -- match commands for k,v in pairs(allVars) do - if string.sub(k, 1, cursorPos) == commandBegin then + if k:sub(1, cursorPos) == commandBegin then table.insert(possibleCommands, k) end end @@ -63,9 +63,9 @@ local function completeCommand() if #possibleCommands[1] < cursorPos then break end - expandedComplete = commandBegin .. string.sub(possibleCommands[1], cursorPos, cursorPos) + expandedComplete = commandBegin .. possibleCommands[1]:sub(cursorPos, cursorPos) for i,v in ipairs(possibleCommands) do - if string.sub(v, 1, #expandedComplete) ~= expandedComplete then + if v:sub(1, #expandedComplete) ~= expandedComplete then done = true end end diff --git a/modules/addon_console/console.otmod b/modules/addon_console/console.otmod index bc6972b1..2a1634be 100644 --- a/modules/addon_console/console.otmod +++ b/modules/addon_console/console.otmod @@ -8,11 +8,9 @@ Module autoLoad: true autoLoadPriority: 20 - dependencies: - - core - onLoad: | require 'console' + require 'commands' Console.init() return true diff --git a/modules/client/client.lua b/modules/client/client.lua index 99ae68a5..8d074c04 100644 --- a/modules/client/client.lua +++ b/modules/client/client.lua @@ -3,7 +3,7 @@ Client = { } -- TODO: load and save configurations function Client.init() g_window.move({ x=220, y=220 }) - g_window.resize({ width=800, height=600 }) + g_window.resize({ width=800, height=480 }) g_window.setTitle('OTClient') g_window.setIcon('clienticon.png') return true diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 93caf339..ba38bb3c 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -23,8 +23,8 @@ local function onError(protocol, error) end local function onMotd(protocol, motd) - motdNumber = tonumber(string.sub(motd, 0, string.find(motd, "\n"))) - motdMessage = string.sub(motd, string.find(motd, "\n") + 1, string.len(motd)) + motdNumber = tonumber(motd:sub(0, motd:find("\n"))) + motdMessage = motd:sub(motd:find("\n") + 1, #motd) TopMenu.getButton('motdButton'):show() end diff --git a/modules/client_options/options.lua b/modules/client_options/options.lua index 30fa3b79..68f6060a 100644 --- a/modules/client_options/options.lua +++ b/modules/client_options/options.lua @@ -7,7 +7,7 @@ local vsyncEnabled = false function getConfig(name, default) if g_configs.exists(name) then - local val = string.trim(g_configs.get(name)) + local val = g_configs.get(name):trim() if val == 'true' or val == 'false' then return toboolean(val) else diff --git a/modules/core_scripts/constants.lua b/modules/core_scripts/const.lua similarity index 96% rename from modules/core_scripts/constants.lua rename to modules/core_scripts/const.lua index b40cbb10..2783a32d 100644 --- a/modules/core_scripts/constants.lua +++ b/modules/core_scripts/const.lua @@ -1,4 +1,3 @@ --- AnchorEdge AnchorNone = 0 AnchorTop = 1 AnchorBottom = 2 @@ -15,9 +14,6 @@ LogFatal = 4 ActiveFocusReason = 2 -EmptyFunction = function() end - --- KeyCodes KeyUnknown = 0 KeyEscape = 1 KeyTab = 2 @@ -57,7 +53,7 @@ KeyLeftParen = 40 -- ( KeyRightParen = 41 -- ) KeyAsterisk = 42 -- * KeyPlus = 43 -- + -KeyComma = 44 -- +KeyComma = 44 -- , KeyMinus = 45 -- - KeyPeriod = 46 -- . KeySlash = 47 -- / diff --git a/modules/core_scripts/core_scripts.otmod b/modules/core_scripts/core_scripts.otmod index 8c52ba30..a4478608 100644 --- a/modules/core_scripts/core_scripts.otmod +++ b/modules/core_scripts/core_scripts.otmod @@ -7,10 +7,14 @@ Module onLoad: | require 'ext/table' require 'ext/string' - require 'constants' + require 'util/point' + require 'util/size' + require 'util/color' + require 'util/rect' + require 'const' require 'util' require 'dispatcher' require 'widget' require 'ui' - require 'gfx' + require 'effects' return true diff --git a/modules/core_scripts/dispatcher.lua b/modules/core_scripts/dispatcher.lua index bea374b8..ee13f5a0 100644 --- a/modules/core_scripts/dispatcher.lua +++ b/modules/core_scripts/dispatcher.lua @@ -1,43 +1,33 @@ local eventId = 0 -local eventsTable = { } -local orig = { scheduleEvent = scheduleEvent, - addEvent = addEvent } +local eventList = {} --- fix original scheduleEvent function scheduleEvent(func, delay) eventId = eventId + 1 local id = eventId local function proxyFunc() - if eventsTable[id] then - func() - eventsTable[id] = nil + if eventList[id] then + if eventList[id].active then + func() + end + eventList[id] = nil end end - eventsTable[id] = proxyFunc - orig.scheduleEvent(proxyFunc, delay) + eventList[id] = { func = proxyFunc, active = true } + if delay and delay > 0 then + g_dispatcher.scheduleEvent(proxyFunc, delay) + else + g_dispatcher.addEvent(proxyFunc, false) + end return id end --- FIXME: the event function can be collected --- and the dispatcher would call an invalid function, generating an warning +function addEvent(func) + return scheduleEvent(func, 0) +end + function removeEvent(id) - if id and eventsTable[id] then - eventsTable[id] = nil + if id and eventList[id] then + eventList[id].active = false return true end end - --- fix original addEvent -function addEvent(func) - eventId = eventId + 1 - local id = eventId - local function proxyFunc() - if eventsTable[id] then - func() - eventsTable[id] = nil - end - end - eventsTable[id] = proxyFunc - orig.addEvent(proxyFunc) - return id -end \ No newline at end of file diff --git a/modules/core_scripts/gfx.lua b/modules/core_scripts/effects.lua similarity index 85% rename from modules/core_scripts/gfx.lua rename to modules/core_scripts/effects.lua index af0aa0db..b92307a8 100644 --- a/modules/core_scripts/gfx.lua +++ b/modules/core_scripts/effects.lua @@ -1,6 +1,6 @@ -GFX = { } +Effects = {} -function GFX.fadeIn(widget, time, elapsed) +function Effects.fadeIn(widget, time, elapsed) if not elapsed then elapsed = 0 end if not time then time = 250 end widget:setOpacity(math.min((255*elapsed)/time, 255)) @@ -11,7 +11,7 @@ function GFX.fadeIn(widget, time, elapsed) end end -function GFX.fadeOut(widget, time, elapsed) +function Effects.fadeOut(widget, time, elapsed) if not elapsed then elapsed = 0 end if not time then time = 250 end widget:setOpacity((255*(time - elapsed))/time) diff --git a/modules/core_scripts/ext/string.lua b/modules/core_scripts/ext/string.lua index a619a7a9..b3bb10b6 100644 --- a/modules/core_scripts/ext/string.lua +++ b/modules/core_scripts/ext/string.lua @@ -13,12 +13,12 @@ function string:starts(start) return self:sub(1, #start) == start end -function string.trim(str) - return str:match'^%s*(.*%S)' or '' +function string:trim() + return self:match('^%s*(.*%S)') or '' end function toboolean(str) - str = string.trim(str) + str = str:trim() if str == '1' or str == 'true' then return true end diff --git a/modules/core_scripts/ext/table.lua b/modules/core_scripts/ext/table.lua index 8627cc5f..5a8e8e68 100644 --- a/modules/core_scripts/ext/table.lua +++ b/modules/core_scripts/ext/table.lua @@ -1,7 +1,7 @@ function table.dump(t, depth) if not depth then depth = 0 end for k,v in pairs(t) do - str = string.rep(' ', depth * 2) .. k .. ': ' + str = (' '):rep(depth * 2) .. k .. ': ' if type(v) ~= "table" then print(str .. tostring(v)) else diff --git a/modules/core_scripts/util.lua b/modules/core_scripts/util.lua index 9bf33688..cd65806e 100644 --- a/modules/core_scripts/util.lua +++ b/modules/core_scripts/util.lua @@ -6,10 +6,8 @@ function print(...) Logger.log(LogInfo, msg) end -function createEnvironment() - local env = { } - setmetatable(env, { __index = _G} ) - return env +function fatal(msg) + Logger.log(LogFatal, msg) end function connect(object, signalsAndSlots, pushFront) @@ -28,10 +26,10 @@ function connect(object, signalsAndSlots, pushFront) end end -function dumpWidgets() - for i=1,UI.root:getChildCount() do - print(UI.root:getChildByIndex(i):getId()) - end +function createEnvironment() + local env = { } + setmetatable(env, { __index = _G} ) + return env end function getCallingScriptSourcePath(depth) diff --git a/modules/core_scripts/ext/color.lua b/modules/core_scripts/util/color.lua similarity index 100% rename from modules/core_scripts/ext/color.lua rename to modules/core_scripts/util/color.lua diff --git a/modules/core_scripts/ext/point.lua b/modules/core_scripts/util/point.lua similarity index 100% rename from modules/core_scripts/ext/point.lua rename to modules/core_scripts/util/point.lua diff --git a/modules/core_scripts/ext/rect.lua b/modules/core_scripts/util/rect.lua similarity index 100% rename from modules/core_scripts/ext/rect.lua rename to modules/core_scripts/util/rect.lua diff --git a/modules/core_scripts/ext/size.lua b/modules/core_scripts/util/size.lua similarity index 100% rename from modules/core_scripts/ext/size.lua rename to modules/core_scripts/util/size.lua diff --git a/modules/core_scripts/widget.lua b/modules/core_scripts/widget.lua index edcc0b09..88e82ca0 100644 --- a/modules/core_scripts/widget.lua +++ b/modules/core_scripts/widget.lua @@ -16,4 +16,4 @@ function UIWidget:setMargin(...) self:setMarginBottom(params[3]) self:setMarginLeft(params[4]) end -end \ No newline at end of file +end diff --git a/modules/core_widgets/messagebox/messagebox.lua b/modules/core_widgets/messagebox/messagebox.lua index 6486371a..cd4704ba 100644 --- a/modules/core_widgets/messagebox/messagebox.lua +++ b/modules/core_widgets/messagebox/messagebox.lua @@ -28,7 +28,7 @@ function MessageBox.create(title, text, flags) if flags == MessageBoxOk then buttonRight:setText("Ok") - box.onOk = EmptyFunction + box.onOk = function() end buttonRight.onClick = function() box.onOk() box:destroy() @@ -37,7 +37,7 @@ function MessageBox.create(title, text, flags) window.onEscape = buttonRight.onClick elseif flags == MessageBoxCancel then buttonRight:setText("Cancel") - box.onCancel = EmptyFunction + box.onCancel = function() end buttonRight.onClick = function() box.onCancel() box:destroy() diff --git a/modules/core_widgets/tooltip/tooltip.lua b/modules/core_widgets/tooltip/tooltip.lua index 0dcc88ba..20630da0 100644 --- a/modules/core_widgets/tooltip/tooltip.lua +++ b/modules/core_widgets/tooltip/tooltip.lua @@ -28,7 +28,7 @@ function ToolTip.display(text) local size = label:getSize() size.width = size.width + 4 size.height = size.height + 4 - currentToolTip:setSize(size) + currentToolTip:resize(size) moveToolTip(currentToolTip) end end diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 659fc10a..a2497ef8 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -135,6 +135,7 @@ SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/graphics/font.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp + ${CMAKE_CURRENT_LIST_DIR}/graphics/painter.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/texture.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffer.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.cpp @@ -142,6 +143,9 @@ SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/graphics/texturemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/borderimage.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/image.cpp + ${CMAKE_CURRENT_LIST_DIR}/graphics/shader.cpp + ${CMAKE_CURRENT_LIST_DIR}/graphics/shaderprogram.cpp + ${CMAKE_CURRENT_LIST_DIR}/graphics/paintershaderprogram.cpp # framework otml ${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp diff --git a/src/framework/application.cpp b/src/framework/application.cpp index 25542cc3..5adeecb4 100644 --- a/src/framework/application.cpp +++ b/src/framework/application.cpp @@ -31,7 +31,9 @@ #include #include #include +#include #include +#include <../../oglrenderer/graphics/painter.h> Application *g_app = nullptr; @@ -134,7 +136,6 @@ void Application::terminate() // terminate graphics if(m_appFlags & Fw::AppEnableGraphics) { g_ui.terminate(); - g_graphics.terminate(); g_window.terminate(); } @@ -217,8 +218,8 @@ void Application::render() void Application::resize(const Size& size) { - g_graphics.resize(size); g_ui.resize(size); + g_graphics.resize(size); } void Application::inputEvent(const InputEvent& event) diff --git a/src/framework/core/module.cpp b/src/framework/core/module.cpp index a6bb2377..ea2361ae 100644 --- a/src/framework/core/module.cpp +++ b/src/framework/core/module.cpp @@ -79,15 +79,13 @@ bool Module::load() } } - if(m_loadCallback) { - m_loaded = m_loadCallback(); - if(!m_loaded) { - logError("Unable to load module '", m_name, "' because its onLoad event returned false"); - return false; - } + if(m_loadCallback && !m_loadCallback()) { + logError("Unable to load module '", m_name, "' because its onLoad event returned false"); + return false; } logInfo("Loaded module '", m_name, "'"); + m_loaded = true; return true; } diff --git a/src/framework/graphics/animatedtexture.cpp b/src/framework/graphics/animatedtexture.cpp index d84077b6..7d200e51 100644 --- a/src/framework/graphics/animatedtexture.cpp +++ b/src/framework/graphics/animatedtexture.cpp @@ -29,7 +29,7 @@ AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFra Texture(), m_numFrames(numFrames) { - m_size.setSize(width, height); + m_size.resize(width, height); m_framesTextureId.resize(numFrames); m_framesDelay.resize(numFrames); diff --git a/src/framework/graphics/borderimage.cpp b/src/framework/graphics/borderimage.cpp index 2fa82dca..9e5dd228 100644 --- a/src/framework/graphics/borderimage.cpp +++ b/src/framework/graphics/borderimage.cpp @@ -137,68 +137,63 @@ void BorderImage::draw(const Rect& screenCoords) Rect rectCoords; Size centerSize = screenCoords.size() - m_bordersSize; - g_graphics.bindTexture(m_texture); - g_graphics.startDrawing(); - // first the center if(centerSize.area() > 0) { rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(), screenCoords.top() + m_topBorderTexCoords.height(), centerSize); - g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_centerTexCoords); + g_painter.drawRepeatedTexturedRect(rectCoords, m_texture, m_centerTexCoords); } // top left corner rectCoords = Rect(screenCoords.topLeft(), m_topLeftCornerTexCoords.size()); - g_graphics.drawTexturedRect(rectCoords, m_texture, m_topLeftCornerTexCoords); + g_painter.drawTexturedRect(rectCoords, m_texture, m_topLeftCornerTexCoords); // top rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width(), screenCoords.topLeft().y, centerSize.width(), m_topBorderTexCoords.height()); - g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_topBorderTexCoords); + g_painter.drawRepeatedTexturedRect(rectCoords, m_texture, m_topBorderTexCoords); // top right corner rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(), screenCoords.top(), m_topRightCornerTexCoords.size()); - g_graphics.drawTexturedRect(rectCoords, m_texture, m_topRightCornerTexCoords); + g_painter.drawTexturedRect(rectCoords, m_texture, m_topRightCornerTexCoords); // left rectCoords = Rect(screenCoords.left(), screenCoords.top() + m_topLeftCornerTexCoords.height(), m_leftBorderTexCoords.width(), centerSize.height()); - g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_leftBorderTexCoords); + g_painter.drawRepeatedTexturedRect(rectCoords, m_texture, m_leftBorderTexCoords); // right rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(), screenCoords.top() + m_topRightCornerTexCoords.height(), m_rightBorderTexCoords.width(), centerSize.height()); - g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_rightBorderTexCoords); + g_painter.drawRepeatedTexturedRect(rectCoords, m_texture, m_rightBorderTexCoords); // bottom left corner rectCoords = Rect(screenCoords.left(), screenCoords.top() + m_topLeftCornerTexCoords.height() + centerSize.height(), m_bottomLeftCornerTexCoords.size()); - g_graphics.drawTexturedRect(rectCoords, m_texture, m_bottomLeftCornerTexCoords); + g_painter.drawTexturedRect(rectCoords, m_texture, m_bottomLeftCornerTexCoords); // bottom rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width(), screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(), centerSize.width(), m_bottomBorderTexCoords.height()); - g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_bottomBorderTexCoords); + g_painter.drawRepeatedTexturedRect(rectCoords, m_texture, m_bottomBorderTexCoords); // bottom right corner rectCoords = Rect(screenCoords.left() + m_bottomLeftCornerTexCoords.width() + centerSize.width(), screenCoords.top() + m_topRightCornerTexCoords.height() + centerSize.height(), m_bottomRightCornerTexCoords.size()); - g_graphics.drawTexturedRect(rectCoords, m_texture, m_bottomRightCornerTexCoords); - - g_graphics.stopDrawing(); + g_painter.drawTexturedRect(rectCoords, m_texture, m_bottomRightCornerTexCoords); } \ No newline at end of file diff --git a/src/framework/graphics/declarations.h b/src/framework/graphics/declarations.h index 54a14cac..132d6343 100644 --- a/src/framework/graphics/declarations.h +++ b/src/framework/graphics/declarations.h @@ -32,6 +32,9 @@ class Font; class Image; class BorderImage; class FrameBuffer; +class Shader; +class ShaderProgram; +class PainterShaderProgram; typedef std::weak_ptr TextureWeakPtr; @@ -41,5 +44,9 @@ typedef std::shared_ptr FontPtr; typedef std::shared_ptr ImagePtr; typedef std::shared_ptr BorderImagePtr; typedef std::shared_ptr FrameBufferPtr; +typedef std::shared_ptr ShaderPtr; +typedef std::shared_ptr ShaderProgramPtr; +typedef std::shared_ptr PainterShaderProgramPtr; +typedef std::vector ShaderList; #endif diff --git a/src/framework/graphics/font.cpp b/src/framework/graphics/font.cpp index 29a4246c..ac7c0cef 100644 --- a/src/framework/graphics/font.cpp +++ b/src/framework/graphics/font.cpp @@ -64,7 +64,7 @@ void Font::renderText(const std::string& text, const Point& startPos, const Color& color) { - Size boxSize = g_graphics.getScreenSize() - startPos.toSize(); + Size boxSize = g_graphics.getViewportSize() - startPos.toSize(); Rect screenCoords(startPos, boxSize); renderText(text, screenCoords, Fw::AlignTopLeft, color); } @@ -85,9 +85,7 @@ void Font::renderText(const std::string& text, Size textBoxSize; const std::vector& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize); - g_graphics.bindColor(color); - g_graphics.bindTexture(m_texture); - g_graphics.startDrawing(); + g_painter.setColor(color); for(int i = 0; i < textLenght; ++i) { int glyph = (uchar)text[i]; @@ -149,10 +147,8 @@ void Font::renderText(const std::string& text, } // render glyph - g_graphics.drawTexturedRect(glyphScreenCoords, m_texture, glyphTextureCoords); + g_painter.drawTexturedRect(glyphScreenCoords, m_texture, glyphTextureCoords); } - - g_graphics.stopDrawing(); } const std::vector& Font::calculateGlyphsPositions(const std::string& text, @@ -172,7 +168,7 @@ const std::vector& Font::calculateGlyphsPositions(const std::string& text // return if there is no text if(textLength == 0) { if(textBoxSize) - textBoxSize->setSize(0,m_glyphHeight); + textBoxSize->resize(0,m_glyphHeight); return glyphsPositions; } @@ -280,6 +276,6 @@ void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) lastColumnFilledPixels = columnFilledPixels; } // store glyph size - m_glyphsSize[glyph].setSize(width, m_glyphHeight); + m_glyphsSize[glyph].resize(width, m_glyphHeight); } } diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index 3cd16bdb..8d7ba498 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -26,110 +26,52 @@ FrameBuffer::FrameBuffer(int width, int height) { - m_fbo = 0; - // create FBO texture m_texture = TexturePtr(new Texture(width, height, 4)); m_texture->enableBilinearFilter(); - // use FBO ext only if supported - if(g_graphics.isExtensionSupported("GL_ARB_framebuffer_object")) { - m_fallbackOldImp = false; - - // generate FBO - glGenFramebuffers(1, &m_fbo); - glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); + // generate FBO + glGenFramebuffers(1, &m_fbo); + if(!m_fbo) + logFatal("Unable to create framebuffer object"); - // attach 2D texture to this FBO - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture->getId(), 0); + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); - switch(status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - //ok - break; - default: // fallback to old implementation - m_fallbackOldImp = true; - break; - } + // attach 2D texture to this FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->getId(), 0); - // restore back buffer - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - glDrawBuffer(GL_BACK); - glReadBuffer(GL_BACK); - } else { - // otherwise fallback to copy texture from screen implementation - m_fallbackOldImp = true; - } + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if(status != GL_FRAMEBUFFER_COMPLETE) + logFatal("Unable to create framebuffer object"); - if(m_fallbackOldImp) - logInfo("Framebuffers not supported, falling back to old implementation."); + // restore back buffer + glBindFramebuffer(GL_FRAMEBUFFER, 0); } FrameBuffer::~FrameBuffer() { - if(m_fbo) - glDeleteFramebuffers(1, &m_fbo); + glDeleteFramebuffers(1, &m_fbo); } void FrameBuffer::bind() { - if(!m_fallbackOldImp) { - // bind framebuffer - glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); - } else { - int screenWidth = g_graphics.getScreenSize().width(); - int screenHeight = g_graphics.getScreenSize().height(); - - if(!m_screenBackup || m_screenBackup->getSize() != g_graphics.getScreenSize()) - m_screenBackup = TexturePtr(new Texture(screenWidth, screenHeight, 4)); - - // save screen state - glBindTexture(GL_TEXTURE_2D, m_screenBackup->getId()); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight); - } - - // setup framebuffer viewport - glViewport(0, 0, m_texture->getWidth(), m_texture->getHeight()); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0f, m_texture->getWidth(), m_texture->getHeight(), 0, -1, 1); - - // back to model view - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // clear framebuffer - glClearColor(0.0, 0.0, 0.0, 1.0); + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, m_texture->getWidth(), m_texture->getHeight()); + g_painter.updateProjectionMatrix(m_texture->getSize(), true); } -void FrameBuffer::unbind() +void FrameBuffer::release() { - if(!m_fallbackOldImp) { - // bind back buffer again - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - glDrawBuffer(GL_BACK); - glReadBuffer(GL_BACK); - - // restore graphics viewport - g_graphics.restoreViewport(); - } else { - // copy screen to texture - glBindTexture(GL_TEXTURE_2D, m_texture->getId()); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_texture->getWidth(), m_texture->getHeight()); - - // restore graphics viewport - g_graphics.restoreViewport(); + // bind back buffer again + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // restore screen - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - g_graphics.drawTexturedRect(Rect(Point(0,0), g_graphics.getScreenSize()), m_screenBackup, Rect(), true); - } + // restore graphics viewport + glViewport(0, 0, g_graphics.getViewportSize().width(), g_graphics.getViewportSize().height()); + g_painter.updateProjectionMatrix(g_graphics.getViewportSize()); } -void FrameBuffer::draw(const Rect& screenCoords, const Rect& framebufferCoords) +void FrameBuffer::draw(const Rect& dest) { - g_graphics.drawTexturedRect(screenCoords, m_texture, framebufferCoords, true); + g_painter.drawTexturedRect(dest, m_texture); } diff --git a/src/framework/graphics/framebuffer.h b/src/framework/graphics/framebuffer.h index 182ef1a9..16ce6cdc 100644 --- a/src/framework/graphics/framebuffer.h +++ b/src/framework/graphics/framebuffer.h @@ -32,8 +32,8 @@ public: virtual ~FrameBuffer(); void bind(); - void unbind(); - void draw(const Rect& screenCoords, const Rect& framebufferCoords = Rect()); + void release(); + void draw(const Rect& dest); TexturePtr getTexture() { return m_texture; } diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index d768b568..b8ca60b3 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -30,307 +30,48 @@ Graphics g_graphics; void Graphics::init() { // setup opengl - glEnable(GL_ALPHA_TEST); // enable alpha by default - glAlphaFunc(GL_GREATER, 0.0f); // default alpha func - glDisable(GL_DEPTH_TEST); // we are rendering 2D only, we don't need depth buffer - glEnable(GL_TEXTURE_2D); // enable textures by default - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - glShadeModel(GL_SMOOTH); glEnable(GL_BLEND); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); logInfo("GPU ", glGetString(GL_RENDERER)); logInfo("OpenGL ", glGetString(GL_VERSION)); - m_drawing = false; - m_opacity = 255; + //if(!isExtensionSupported("GL_ARB_framebuffer_object")) + // logFatal("Your graphics card is not supported."); + m_emptyTexture = TexturePtr(new Texture); - bindColor(Fw::white); - bindBlendFunc(Fw::BlendDefault); + g_painter.init(); } void Graphics::terminate() { g_fonts.releaseFonts(); + g_painter.terminate(); m_emptyTexture.reset(); } bool Graphics::isExtensionSupported(const char *extension) { - const GLubyte *extensions = NULL; - const GLubyte *start; - GLubyte *where, *terminator; - where = (GLubyte *)strchr(extension, ' '); - - if(where || *extension == '\0') - return 0; - - extensions = glGetString(GL_EXTENSIONS); - - start = extensions; - while(true) { - where = (GLubyte *) strstr((const char *)start, extension); - if(!where) - break; - - terminator = where + strlen(extension); - - if(where == start || *(where - 1) == ' ') - if(*terminator == ' ' || *terminator == '\0') - return 1; - - start = terminator; - } - return 0; + std::string extensionsString = (const char*)glGetString(GL_EXTENSIONS); + auto extensions = Fw::split(extensionsString); + return std::find(extensions.begin(), extensions.end(), extension) != extensions.end(); } void Graphics::resize(const Size& size) { - m_screenSize = size; - restoreViewport(); -} - -void Graphics::restoreViewport() -{ - const int& width = m_screenSize.width(); - const int& height = m_screenSize.height(); - - // resize gl viewport - glViewport(0, 0, width, height); - - /* - 0,0---------0,w - | | - | | - | | - h,0---------h,w - */ - // setup view region like above - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0f, width, height, 0.0f, -1, 1); - - // back to model view - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glViewport(0, 0, size.width(), size.height()); + g_painter.updateProjectionMatrix(size); + m_viewportSize = size; } void Graphics::beginRender() { glClear(GL_COLOR_BUFFER_BIT); - glLoadIdentity(); } void Graphics::endRender() { - assert(!m_drawing); -} - -void Graphics::drawTexturedRect(const Rect& screenCoords, - const TexturePtr& texture, - const Rect& textureCoords, - bool upsideDown) -{ - if(screenCoords.isEmpty() || texture->getId() == 0) - return; - - // rect correction for opengl - int right = screenCoords.right() + 1; - int bottom = screenCoords.bottom() + 1; - int top = screenCoords.top(); - int left = screenCoords.left(); - - float textureRight; - float textureBottom; - float textureTop; - float textureLeft; - const Size& textureSize = texture->getGlSize(); - - if(textureCoords.isEmpty()) { - textureRight = texture->getWidth() / (float)textureSize.width(); - if(upsideDown) { - textureBottom = 0.0f; - textureTop = texture->getHeight() / (float)textureSize.height(); - } else { - textureBottom = texture->getHeight() / (float)textureSize.height(); - textureTop = 0.0f; - } - textureLeft = 0.0f; - } else { - textureRight = (textureCoords.right() + 1) / (float)textureSize.width(); - if(upsideDown) { - textureTop = (textureCoords.bottom() + 1) / (float)textureSize.height(); - textureBottom = textureCoords.top() / (float)textureSize.height(); - } else { - textureBottom = (textureCoords.bottom() + 1) / (float)textureSize.height(); - textureTop = textureCoords.top() / (float)textureSize.height(); - } - textureLeft = textureCoords.left() / (float)textureSize.width(); - } - - if(!m_drawing) { - bindTexture(texture); - glBegin(GL_QUADS); - } - - glTexCoord2f(textureLeft, textureTop); glVertex2i(left, top); - glTexCoord2f(textureLeft, textureBottom); glVertex2i(left, bottom); - glTexCoord2f(textureRight, textureBottom); glVertex2i(right, bottom); - glTexCoord2f(textureRight, textureTop); glVertex2i(right, top); - - if(!m_drawing) - glEnd(); -} - -void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, - const TexturePtr& texture, - const Rect& textureCoords) -{ - if(screenCoords.isEmpty() || texture->getId() == 0 || textureCoords.isEmpty()) - return; - - bool mustStopDrawing = false; - if(!m_drawing) { - bindTexture(texture); - startDrawing(); - mustStopDrawing = true; - } - - // render many repeated texture rects - Rect virtualScreenCoords(0,0,screenCoords.size()); - for(int y = 0; y <= virtualScreenCoords.height(); y += textureCoords.height()) { - for(int x = 0; x <= virtualScreenCoords.width(); x += textureCoords.width()) { - Rect partialCoords(x, y, textureCoords.size()); - Rect partialTextureCoords = textureCoords; - - // partialCoords to screenCoords bottomRight - if(partialCoords.bottom() > virtualScreenCoords.bottom()) { - partialTextureCoords.setBottom(partialTextureCoords.bottom() + - (virtualScreenCoords.bottom() - partialCoords.bottom())); - partialCoords.setBottom(virtualScreenCoords.bottom()); - } - if(partialCoords.right() > virtualScreenCoords.right()) { - partialTextureCoords.setRight(partialTextureCoords.right() + - (virtualScreenCoords.right() - partialCoords.right())); - partialCoords.setRight(virtualScreenCoords.right()); - } - - partialCoords.translate(screenCoords.topLeft()); - drawTexturedRect(partialCoords, texture, partialTextureCoords); - } - } - - if(mustStopDrawing) - stopDrawing(); -} - -void Graphics::drawFilledRect(const Rect& screenCoords) -{ - assert(!m_drawing); - - if(screenCoords.isEmpty()) - return; - - // rect correction for opengl - int right = screenCoords.right() + 1; - int bottom = screenCoords.bottom() + 1; - int top = screenCoords.top(); - int left = screenCoords.left(); - - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - - glVertex2i(left, top); - glVertex2i(left, bottom); - glVertex2i(right, bottom); - glVertex2i(right, top); - - glEnd(); - glEnable(GL_TEXTURE_2D); -} - - -void Graphics::drawBoundingRect(const Rect& screenCoords, - int innerLineWidth) -{ - assert(!m_drawing); - - if(screenCoords.isEmpty() || 2 * innerLineWidth > screenCoords.height()) - return; - - // rect correction for opengl - int right = screenCoords.right()+1; - int bottom = screenCoords.bottom()+1; - int top = screenCoords.top(); - int left = screenCoords.left(); - - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - - // top line - glVertex2i(left, top); - glVertex2i(left, top + innerLineWidth); - glVertex2i(right, top + innerLineWidth); - glVertex2i(right, top); - - // left - glVertex2i(left, screenCoords.top() + innerLineWidth); - glVertex2i(left, bottom - innerLineWidth); - glVertex2i(left + innerLineWidth, bottom - innerLineWidth); - glVertex2i(left + innerLineWidth, screenCoords.top() + innerLineWidth); - - // bottom line - glVertex2i(left, bottom); - glVertex2i(left, bottom - innerLineWidth); - glVertex2i(right, bottom - innerLineWidth); - glVertex2i(right, bottom); - - // right line - glVertex2i(right , top + innerLineWidth); - glVertex2i(right , bottom - innerLineWidth); - glVertex2i(right - innerLineWidth, bottom - innerLineWidth); - glVertex2i(right - innerLineWidth, top + innerLineWidth); - - glEnd(); - glEnable(GL_TEXTURE_2D); -} - -void Graphics::bindColor(const Color& color) -{ - Color tmp = color; - tmp.setAlpha(std::min((uint8)m_opacity, color.a())); - glColor4ubv(tmp.rgbaPtr()); -} - -void Graphics::bindTexture(const TexturePtr& texture) -{ - glBindTexture(GL_TEXTURE_2D, texture->getId()); -} - -void Graphics::bindBlendFunc(Fw::BlendFunc blendType) -{ - switch(blendType) { - case Fw::BlendDefault: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case Fw::BlendColorzing: - glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); - break; - } -} - -void Graphics::startDrawing() -{ - assert(!m_drawing); - glBegin(GL_QUADS); - m_drawing = true; -} - -void Graphics::stopDrawing() -{ - assert(m_drawing); - glEnd(); - m_drawing = false; + glFlush(); } diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index fcc26feb..4096666b 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -24,64 +24,25 @@ #define GRAPHICS_H #include "declarations.h" +#include "painter.h" class Graphics { public: - /// Initialize default OpenGL states void init(); - - /// Termiante graphics void terminate(); - /// Check if a GL extension is supported bool isExtensionSupported(const char *extension); - /// Resizes OpenGL viewport void resize(const Size& size); - - /// Restore original viewport - void restoreViewport(); - - /// Called before every render void beginRender(); - - /// Called after every render void endRender(); - void bindColor(const Color& color); - void bindTexture(const TexturePtr& texture); - void bindBlendFunc(Fw::BlendFunc blendType); - - // drawing API - void drawTexturedRect(const Rect& screenCoords, - const TexturePtr& texture, - const Rect& textureCoords = Rect(), - bool upsideDown = false); - - void drawRepeatedTexturedRect(const Rect& screenCoords, - const TexturePtr& texture, - const Rect& textureCoords); - - void drawFilledRect(const Rect& screenCoords); - - void drawBoundingRect(const Rect& screenCoords, - int innerLineWidth = 1); - - const Size& getScreenSize() const { return m_screenSize; } - - void startDrawing(); - void stopDrawing(); - bool isDrawing() const { return m_drawing; } - - int getOpacity() const { return m_opacity; } - void setOpacity(int opacity) { m_opacity = opacity; } + const Size& getViewportSize() const { return m_viewportSize; } TexturePtr getEmptyTexture() { return m_emptyTexture; } private: - bool m_drawing; - int m_opacity; - Size m_screenSize; + Size m_viewportSize; TexturePtr m_emptyTexture; }; diff --git a/src/framework/graphics/image.cpp b/src/framework/graphics/image.cpp index 146f0016..e3e04fd0 100644 --- a/src/framework/graphics/image.cpp +++ b/src/framework/graphics/image.cpp @@ -63,12 +63,12 @@ void Image::draw(const Rect& screenCoords) else if(texSize.width() > texCoordsSize.width()) texCoordsOffset.x = (texSize.width() - texCoordsSize.width())/2; - g_graphics.drawTexturedRect(screenCoords, m_texture, Rect(texCoordsOffset, texCoordsSize)); + g_painter.drawTexturedRect(screenCoords, m_texture, Rect(texCoordsOffset, texCoordsSize)); } else { if(m_repeated) - g_graphics.drawRepeatedTexturedRect(screenCoords, m_texture, m_textureCoords); + g_painter.drawRepeatedTexturedRect(screenCoords, m_texture, m_textureCoords); else - g_graphics.drawTexturedRect(screenCoords, m_texture, m_textureCoords); + g_painter.drawTexturedRect(screenCoords, m_texture, m_textureCoords); } } } diff --git a/src/framework/graphics/painter.cpp b/src/framework/graphics/painter.cpp new file mode 100644 index 00000000..3a439513 --- /dev/null +++ b/src/framework/graphics/painter.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2010-2011 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 "painter.h" +#include "texture.h" +#include "paintershadersources.h" +#include "paintershaderprogram.h" +#include "shaderprogram.h" +#include "graphics.h" + +Painter g_painter; + +void Painter::init() +{ + setColor(Fw::white); + setOpacity(255); + setCompositionMode(CompositionMode_SourceOver); + + PainterShaderProgramPtr program = PainterShaderProgramPtr(new PainterShaderProgram); + program->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader); + program->addShaderFromSourceCode(Shader::Vertex, glslPositionOnlyVertexShader); + program->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader); + program->addShaderFromSourceCode(Shader::Fragment, glslTextureSrcFragmentShader); + program->bindAttributeLocation(VERTEX_COORDS_ATTR, "vertexCoord"); + program->bindAttributeLocation(TEXTURE_COORDS_ATTR, "textureCoord"); + assert(program->link()); + program->bindUniformLocation(PainterShaderProgram::PROJECTION_MATRIX_UNIFORM, "projectionMatrix"); + program->bindUniformLocation(PainterShaderProgram::TEXTURE_TRANSFORM_MATRIX_UNIFORM, "textureTransformMatrix"); + program->bindUniformLocation(PainterShaderProgram::COLOR_UNIFORM, "color"); + program->bindUniformLocation(PainterShaderProgram::OPACITY_UNIFORM, "opacity"); + program->bindUniformLocation(PainterShaderProgram::TEXTURE_UNIFORM, "texture"); + m_drawTexturedProgram = program; + + program = PainterShaderProgramPtr(new PainterShaderProgram); + program->addShaderFromSourceCode(Shader::Vertex, glslMainVertexShader); + program->addShaderFromSourceCode(Shader::Vertex, glslPositionOnlyVertexShader); + program->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader); + program->addShaderFromSourceCode(Shader::Fragment, glslSolidColorFragmentShader); + program->bindAttributeLocation(VERTEX_COORDS_ATTR, "vertexCoord"); + assert(program->link()); + program->bindUniformLocation(PainterShaderProgram::PROJECTION_MATRIX_UNIFORM, "projectionMatrix"); + program->bindUniformLocation(PainterShaderProgram::COLOR_UNIFORM, "color"); + program->bindUniformLocation(PainterShaderProgram::OPACITY_UNIFORM, "opacity"); + m_drawSolidColorProgram = program; +} + +void Painter::terminate() +{ + m_drawTexturedProgram.reset(); + m_drawSolidColorProgram.reset(); +} + +void Painter::updateProjectionMatrix(const Size& viewportSize, bool inverseYAxis) +{ + // 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, which is multiplied by the painter's + // transformation matrix, as shown below: + // + // Projection Matrix Painter Coord GL Coord + // ------------------------------------------------ --------- --------- + // | 2.0 / width | 0.0 | -1.0 | | x | | y' | + // | 0.0 | -2.0 / height | 1.0 | * | y | = | x' | + // | 0.0 | 0.0 | 0.0 | | 1 | | 0 | + // ------------------------------------------------ --------- --------- + float w = viewportSize.width(); + float h = viewportSize.height(); + if(inverseYAxis) { + m_projectionMatrix[0][0] = 2.0f/w; m_projectionMatrix[0][1] = 0.0f; m_projectionMatrix[0][2] =-1.0f; + m_projectionMatrix[1][0] = 0.0f; m_projectionMatrix[1][1] = 2.0f/h; m_projectionMatrix[1][2] =-1.0f; + m_projectionMatrix[2][0] = 0.0f; m_projectionMatrix[2][1] = 0.0f; m_projectionMatrix[2][2] = 0.0f; + } else { + m_projectionMatrix[0][0] = 2.0f/w; m_projectionMatrix[0][1] = 0.0f; m_projectionMatrix[0][2] =-1.0f; + m_projectionMatrix[1][0] = 0.0f; m_projectionMatrix[1][1] =-2.0f/h; m_projectionMatrix[1][2] = 1.0f; + m_projectionMatrix[2][0] = 0.0f; m_projectionMatrix[2][1] = 0.0f; m_projectionMatrix[2][2] = 0.0f; + } +} + +void Painter::drawTexturedRect(const Rect& dest, const TexturePtr& texture) +{ + drawTexturedRect(dest, texture, Rect(Point(0,0), texture->getSize())); +} + +void Painter::drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src) +{ + if(dest.isEmpty() || src.isEmpty() || !texture->getId()) + return; + + GLfloat vertexCoords[] = { (float)dest.left(), (float)dest.top(), + (float)dest.right()+1, (float)dest.top(), + (float)dest.left(), (float)dest.bottom()+1, + (float)dest.right()+1, (float)dest.bottom()+1 }; + + GLfloat textureCoords[] = { (float)src.left(), (float)src.top(), + (float)src.right()+1, (float)src.top(), + (float)src.left(), (float)src.bottom()+1, + (float)src.right()+1, (float)src.bottom()+1 }; + + m_drawTexturedProgram->prepareForDraw(); + m_drawTexturedProgram->setProjectionMatrix(m_projectionMatrix); + m_drawTexturedProgram->setOpacity(m_currentOpacity); + m_drawTexturedProgram->setColor(m_currentColor); + m_drawTexturedProgram->setTexture(texture); + m_drawTexturedProgram->setVertexCoords(vertexCoords); + m_drawTexturedProgram->setTextureCoords(textureCoords); + m_drawTexturedProgram->drawTriangleStrip(4); + m_drawTexturedProgram->releaseFromDraw(); +} + +void Painter::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src) +{ + if(dest.isEmpty() || src.isEmpty() || !texture->getId()) + return; + + //TODO: use vertex arrays.. + Rect virtualDest(0, 0, dest.size()); + for(int y = 0; y <= virtualDest.height(); y += src.height()) { + for(int x = 0; x <= virtualDest.width(); x += src.width()) { + Rect partialDest(x, y, src.size()); + Rect partialSrc = src; + + // partialCoords to screenCoords bottomRight + if(partialDest.bottom() > virtualDest.bottom()) { + partialSrc.setBottom(partialSrc.bottom() + (virtualDest.bottom() - partialDest.bottom())); + partialDest.setBottom(virtualDest.bottom()); + } + if(partialDest.right() > virtualDest.right()) { + partialSrc.setRight(partialSrc.right() + (virtualDest.right() - partialDest.right())); + partialDest.setRight(virtualDest.right()); + } + + partialDest.translate(dest.topLeft()); + drawTexturedRect(partialDest, texture, partialSrc); + } + } +} + +void Painter::drawFilledRect(const Rect& dest) +{ + if(dest.isEmpty()) + return; + + GLfloat right = dest.right()+1; + GLfloat bottom = dest.bottom()+1; + GLfloat top = dest.top(); + GLfloat left = dest.left(); + + GLfloat vertexCoords[] = { left, top, + right, top, + left, bottom, + right, bottom }; + + m_drawSolidColorProgram->prepareForDraw(); + m_drawSolidColorProgram->setProjectionMatrix(m_projectionMatrix); + m_drawSolidColorProgram->setOpacity(m_currentOpacity); + m_drawSolidColorProgram->setColor(m_currentColor); + m_drawSolidColorProgram->setVertexCoords(vertexCoords); + m_drawSolidColorProgram->drawTriangleStrip(4); + m_drawSolidColorProgram->releaseFromDraw(); +} + +void Painter::drawBoundingRect(const Rect& dest, int innerLineWidth) +{ + if(dest.isEmpty() || innerLineWidth == 0) + return; + + GLfloat right = dest.right()+1; + GLfloat bottom = dest.bottom()+1; + GLfloat top = dest.top(); + GLfloat left = dest.left(); + GLfloat w = innerLineWidth; + + GLfloat vertexCoords[] = { left, top, + right, top, + left, top+w, + right, top+w, + right-w, top+w, + right, bottom, + right-w, bottom, + right-w, bottom-w, + left, bottom, + left, bottom-w, + left+w, bottom-w, + left, top+w, + left+w, top+w }; + + m_drawSolidColorProgram->prepareForDraw(); + m_drawSolidColorProgram->setProjectionMatrix(m_projectionMatrix); + m_drawSolidColorProgram->setOpacity(m_currentOpacity); + m_drawSolidColorProgram->setColor(m_currentColor); + m_drawSolidColorProgram->setVertexCoords(vertexCoords); + m_drawSolidColorProgram->drawTriangleStrip(13); + m_drawSolidColorProgram->releaseFromDraw(); +} + +void Painter::setCompositionMode(Painter::CompositionMode compositionMode) +{ + switch(compositionMode) { + case CompositionMode_SourceOver: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case CompositionMode_ColorizeDest: + glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + break; + } +} diff --git a/src/framework/graphics/painter.h b/src/framework/graphics/painter.h new file mode 100644 index 00000000..b336d90c --- /dev/null +++ b/src/framework/graphics/painter.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2011 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 PAINTER_H +#define PAINTER_H + +#include "declarations.h" + +class Painter +{ +public: + enum CompositionMode { + CompositionMode_SourceOver, + CompositionMode_ColorizeDest + }; + + void init(); + void terminate(); + + void updateProjectionMatrix(const Size& viewportSize, bool inverseYAxis = false); + void drawTexturedRect(const Rect& dest, const TexturePtr& texture); + void drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); + void drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); + void drawFilledRect(const Rect& dest); + void drawBoundingRect(const Rect& dest, int innerLineWidth = 1); + + void setColor(const Color& color) { m_currentColor = color; } + Color getColor() { return m_currentColor; } + + void setOpacity(int opacity) { m_currentOpacity = opacity / 255.0f; } + int getOpacity() { return m_currentOpacity * 255.0f; } + + void setCompositionMode(CompositionMode compositionMode); + +private: + PainterShaderProgramPtr m_drawTexturedProgram; + PainterShaderProgramPtr m_drawSolidColorProgram; + GLfloat m_projectionMatrix[3][3]; + Color m_currentColor; + GLfloat m_currentOpacity; +}; + +extern Painter g_painter; + +#endif diff --git a/src/framework/graphics/paintershaderprogram.cpp b/src/framework/graphics/paintershaderprogram.cpp new file mode 100644 index 00000000..645078e2 --- /dev/null +++ b/src/framework/graphics/paintershaderprogram.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010-2011 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 "paintershaderprogram.h" +#include "painter.h" +#include "texture.h" +#include "texturemanager.h" + +void PainterShaderProgram::setProjectionMatrix(float projectionMatrix[3][3]) +{ + setUniformValue(PROJECTION_MATRIX_UNIFORM, projectionMatrix, true); +} + +void PainterShaderProgram::setColor(const Color& color) +{ + setUniformValue(COLOR_UNIFORM, + color.r() / 255.0f, + color.g() / 255.0f, + color.b() / 255.0f, + color.a() / 255.0f); +} + +void PainterShaderProgram::setOpacity(GLfloat opacity) +{ + setUniformValue(OPACITY_UNIFORM, opacity); +} + +void PainterShaderProgram::setTexture(const TexturePtr& texture) +{ + float w = texture->getGlSize().width(); + float h = texture->getGlSize().height(); + + GLfloat textureTransformMatrix[2][2] = { + { 1.0f/w, 0.0f }, + { 0.0f, 1.0f/h } + }; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->getId()); + setUniformValue(TEXTURE_UNIFORM, 0); + setUniformValue(TEXTURE_TRANSFORM_MATRIX_UNIFORM, textureTransformMatrix, true); +} + +void PainterShaderProgram::setVertexCoords(const GLfloat *vertices) +{ + enableAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR); + setAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR, vertices, 2); +} + +void PainterShaderProgram::setTextureCoords(const GLfloat *textureCoords) +{ + enableAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR); + setAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR, textureCoords, 2); + m_mustDisableTexCoordsArray = true; +} + +void PainterShaderProgram::prepareForDraw() +{ + assert(bind()); +} + +void PainterShaderProgram::drawTriangleStrip(int numVertices) +{ + glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices); +} + +void PainterShaderProgram::releaseFromDraw() +{ + if(m_mustDisableTexCoordsArray) { + disableAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR); + m_mustDisableTexCoordsArray = false; + } + + if(m_mustDisableVertexArray) { + disableAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR); + m_mustDisableVertexArray = false; + } + + //release(); +} diff --git a/src/framework/graphics/paintershaderprogram.h b/src/framework/graphics/paintershaderprogram.h new file mode 100644 index 00000000..74bb728e --- /dev/null +++ b/src/framework/graphics/paintershaderprogram.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010-2011 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 PAINTERSHADER_H +#define PAINTERSHADER_H + +#include "shaderprogram.h" + +class PainterShaderProgram : public ShaderProgram +{ +public: + enum { + VERTEX_COORDS_ATTR = 0, + TEXTURE_COORDS_ATTR = 1, + PROJECTION_MATRIX_UNIFORM = 0, + TEXTURE_TRANSFORM_MATRIX_UNIFORM = 1, + COLOR_UNIFORM = 2, + OPACITY_UNIFORM = 3, + TEXTURE_UNIFORM = 4 + }; + + void setProjectionMatrix(GLfloat projectionMatrix[3][3]); + void setColor(const Color& color); + void setOpacity(GLfloat opacity); + void setTexture(const TexturePtr& texture); + void setVertexCoords(const GLfloat *vertices); + void setTextureCoords(const GLfloat *textureCoords); + + void prepareForDraw(); + void drawTriangleStrip(int numVertices); + void releaseFromDraw(); + +private: + Boolean m_mustDisableVertexArray; + Boolean m_mustDisableTexCoordsArray; +}; + +#endif diff --git a/src/framework/graphics/paintershadersources.h b/src/framework/graphics/paintershadersources.h new file mode 100644 index 00000000..a020be4b --- /dev/null +++ b/src/framework/graphics/paintershadersources.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010-2011 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. + */ + +static int VERTEX_COORDS_ATTR = 0; +static int TEXTURE_COORDS_ATTR = 1; + +static int PROJECTION_MATRIX_UNIFORM = 0; +static int TEXTURE_TRANSFORM_MATRIX_UNIFORM = 1; +static int COLOR_UNIFORM = 2; +static int OPACITY_UNIFORM = 3; +static int TEXTURE_UNIFORM = 4; + +static const char *glslMainVertexShader = "\n\ + vec4 calculatePosition();\n\ + void main() {\n\ + gl_Position = calculatePosition();\n\ + }\n"; + +static const char *glslMainWithTexCoordsVertexShader = "\n\ + attribute vec2 textureCoord;\n\ + uniform mat2 textureTransformMatrix;\n\ + varying vec2 textureCoords;\n\ + vec4 calculatePosition();\n\ + void main()\n\ + {\n\ + gl_Position = calculatePosition();\n\ + textureCoords = textureTransformMatrix * textureCoord;\n\ + }\n"; + +static const char *glslPositionOnlyVertexShader = "\n\ + attribute vec2 vertexCoord;\n\ + uniform mat3 projectionMatrix;\n\ + vec4 calculatePosition() {\n\ + return vec4(projectionMatrix * vec3(vertexCoord.xy, 1), 1);\n\ + }\n"; + +static const char *glslMainFragmentShader = "\n\ + uniform float opacity;\n\ + vec4 calculatePixel();\n\ + void main()\n\ + {\n\ + gl_FragColor = calculatePixel() * opacity;\n\ + }\n"; + +static const char *glslTextureSrcFragmentShader = "\n\ + varying vec2 textureCoords;\n\ + uniform vec4 color;\n\ + uniform sampler2D texture;\n\ + vec4 calculatePixel() {\n\ + return texture2D(texture, textureCoords) * color;\n\ + }\n"; + +static const char *glslSolidColorFragmentShader = "\n\ + uniform vec4 color;\n\ + vec4 calculatePixel() {\n\ + return color;\n\ + }\n"; diff --git a/src/framework/graphics/shader.cpp b/src/framework/graphics/shader.cpp new file mode 100644 index 00000000..328ae81c --- /dev/null +++ b/src/framework/graphics/shader.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010-2011 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 "shader.h" + +Shader::Shader(Shader::ShaderType shaderType) +{ + m_shaderType = shaderType; + switch(shaderType) { + case Vertex: + m_shaderId = glCreateShader(GL_VERTEX_SHADER); + break; + case Fragment: + m_shaderId = glCreateShader(GL_FRAGMENT_SHADER); + break; + } + + if(!m_shaderId) + logFatal("Unable to create GL shader"); +} + +Shader::~Shader() +{ + glDeleteShader(m_shaderId); +} + +bool Shader::compileSourceCode(const std::string& sourceCode) +{ + const char *c_source = sourceCode.c_str(); + glShaderSource(m_shaderId, 1, &c_source, NULL); + glCompileShader(m_shaderId); + + int res; + glGetShaderiv(m_shaderId, GL_COMPILE_STATUS, &res); + return (res == GL_TRUE); +} + +bool Shader::compileSourceFile(const std::string& sourceFile) +{ + std::ifstream fin(sourceFile); + std::string sourceCode((std::istreambuf_iterator(fin)), std::istreambuf_iterator()); + return compileSourceCode(sourceCode); +} + +std::string Shader::log() +{ + std::string infoLog; + GLint infoLogLength; + glGetShaderiv(m_shaderId, GL_INFO_LOG_LENGTH, &infoLogLength); + if(infoLogLength > 1) { + std::vector buf(infoLogLength); + glGetShaderInfoLog(m_shaderId, infoLogLength-1, NULL, &buf[0]); + infoLog = &buf[0]; + } + return infoLog; +} diff --git a/src/framework/graphics/shader.h b/src/framework/graphics/shader.h new file mode 100644 index 00000000..226fe20e --- /dev/null +++ b/src/framework/graphics/shader.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2011 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 SHADER_H +#define SHADER_H + +#include "declarations.h" + +class Shader +{ +public: + enum ShaderType { + Vertex, + Fragment + }; + + Shader(ShaderType shaderType); + ~Shader(); + + bool compileSourceCode(const std::string& sourceCode); + bool compileSourceFile(const std::string& sourceFile); + std::string log(); + + GLuint getShaderId() { return m_shaderId; } + ShaderType getShaderType() { return m_shaderType; } + +private: + GLuint m_shaderId; + ShaderType m_shaderType; +}; + +#endif diff --git a/src/framework/graphics/shaderprogram.cpp b/src/framework/graphics/shaderprogram.cpp new file mode 100644 index 00000000..8899f07a --- /dev/null +++ b/src/framework/graphics/shaderprogram.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010-2011 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 "shaderprogram.h" + +GLuint ShaderProgram::m_currentProgram = 0; + +ShaderProgram::ShaderProgram() +{ + m_linked = false; + m_programId = glCreateProgram(); + m_uniformLocations.fill(-1); + if(!m_programId) + logFatal("Unable to create GL shader program"); +} + +ShaderProgram::~ShaderProgram() +{ + glDeleteProgram(m_programId); +} + +bool ShaderProgram::addShader(const ShaderPtr& shader) { + glAttachShader(m_programId, shader->getShaderId()); + m_linked = false; + m_shaders.push_back(shader); + return true; +} + +bool ShaderProgram::addShaderFromSourceCode(Shader::ShaderType shaderType, const std::string& sourceCode) { + ShaderPtr shader(new Shader(shaderType)); + if(!shader->compileSourceCode(sourceCode)) { + logError("failed to compile shader: ", shader->log()); + return false; + } + return addShader(shader); +} + +bool ShaderProgram::addShaderFromSourceFile(Shader::ShaderType shaderType, const std::string& sourceFile) { + ShaderPtr shader(new Shader(shaderType)); + if(!shader->compileSourceFile(sourceFile)) { + logError("failed to compile shader: ", shader->log()); + return false; + } + return addShader(shader); +} + +void ShaderProgram::removeShader(const ShaderPtr& shader) +{ + auto it = std::find(m_shaders.begin(), m_shaders.end(), shader); + if(it == m_shaders.end()) + return; + + glDetachShader(m_programId, shader->getShaderId()); + m_shaders.erase(it); + m_linked = false; +} + +void ShaderProgram::removeAllShaders() +{ + while(!m_shaders.empty()) + removeShader(m_shaders.front()); +} + +bool ShaderProgram::link() +{ + if(m_linked) + return true; + + glLinkProgram(m_programId); + + GLint value; + glGetProgramiv(m_programId, GL_LINK_STATUS, &value); + m_linked = (value != GL_FALSE); + + if(!m_linked) + logTraceWarning(log()); + return m_linked; +} + +bool ShaderProgram::bind() +{ + if(m_currentProgram != m_programId) { + if(!m_linked && !link()) + return false; + glUseProgram(m_programId); + m_currentProgram = m_programId; + } + return true; +} + +void ShaderProgram::release() +{ + m_currentProgram = 0; + glUseProgram(0); +} + +std::string ShaderProgram::log() +{ + std::string infoLog; + GLint infoLogLength; + glGetProgramiv(m_programId, GL_INFO_LOG_LENGTH, &infoLogLength); + if(infoLogLength > 1) { + std::vector buf(infoLogLength); + glGetShaderInfoLog(m_programId, infoLogLength-1, NULL, &buf[0]); + infoLog = &buf[0]; + } + return infoLog; +} + +int ShaderProgram::getAttributeLocation(const char* name) +{ + return glGetAttribLocation(m_programId, name); +} + +void ShaderProgram::bindAttributeLocation(int location, const char* name) +{ + return glBindAttribLocation(m_programId, location, name); +} + +void ShaderProgram::bindUniformLocation(int location, const char* name) +{ + assert(m_linked); + assert(location >= 0 && location < 10); + m_uniformLocations[location] = glGetUniformLocation(m_programId, name); +} diff --git a/src/framework/graphics/shaderprogram.h b/src/framework/graphics/shaderprogram.h new file mode 100644 index 00000000..b1096415 --- /dev/null +++ b/src/framework/graphics/shaderprogram.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010-2011 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 SHADERPROGRAM_H +#define SHADERPROGRAM_H + +#include "shader.h" + +class ShaderProgram +{ + enum { + MAX_UNIFORM_LOCATIONS = 10 + }; +public: + ShaderProgram(); + ~ShaderProgram(); + + bool addShader(const ShaderPtr& shader); + bool addShaderFromSourceCode(Shader::ShaderType shaderType, const std::string& sourceCode); + bool addShaderFromSourceFile(Shader::ShaderType shaderType, const std::string& sourceFile); + void removeShader(const ShaderPtr& shader); + void removeAllShaders(); + bool link(); + bool bind(); + void release(); + std::string log(); + + void disableAttributeArray(int location) { glDisableVertexAttribArray(location); } + void enableAttributeArray(int location) { glEnableVertexAttribArray(location); } + void disableAttributeArray(const char *name) { glDisableVertexAttribArray(getAttributeLocation(name)); } + void enableAttributeArray(const char *name) { glEnableVertexAttribArray(getAttributeLocation(name)); } + + int getAttributeLocation(const char *name); + void bindAttributeLocation(int location, const char *name); + void bindUniformLocation(int location, const char *name); + + void setAttributeArray(int location, const GLfloat *values, int size, int stride = 0) { glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, stride, values); } + void setAttributeValue(int location, GLfloat value) { glVertexAttrib1f(location, value); } + void setAttributeValue(int location, GLfloat x, GLfloat y) { glVertexAttrib2f(location, x, y); } + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z) { glVertexAttrib3f(location, x, y, z); } + void setAttributeArray(const char *name, const GLfloat *values, int size, int stride = 0) { glVertexAttribPointer(getAttributeLocation(name), size, GL_FLOAT, GL_FALSE, stride, values); } + void setAttributeValue(const char *name, GLfloat value) { glVertexAttrib1f(getAttributeLocation(name), value); } + void setAttributeValue(const char *name, GLfloat x, GLfloat y) { glVertexAttrib2f(getAttributeLocation(name), x, y); } + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z) { glVertexAttrib3f(getAttributeLocation(name), x, y, z); } + + void setUniformValue(int location, GLint value) { glUniform1i(m_uniformLocations[location], value); } + void setUniformValue(int location, GLfloat value) { glUniform1f(m_uniformLocations[location], value); } + void setUniformValue(int location, GLfloat x, GLfloat y) { glUniform2f(m_uniformLocations[location], x, y); } + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z) { glUniform3f(m_uniformLocations[location], x, y, z); } + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { glUniform4f(m_uniformLocations[location], x, y, z, w); } + void setUniformValue(int location, GLfloat mat2[2][2], bool transpose) { glUniformMatrix2fv(m_uniformLocations[location], 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat2); } + void setUniformValue(int location, GLfloat mat3[3][3], bool transpose) { glUniformMatrix3fv(m_uniformLocations[location], 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat3); } + void setUniformValue(const char *name, GLint value) { glUniform1i(glGetUniformLocation(m_programId, name), value); } + void setUniformValue(const char *name, GLfloat value) { glUniform1f(glGetUniformLocation(m_programId, name), value); } + void setUniformValue(const char *name, GLfloat x, GLfloat y) { glUniform2f(glGetUniformLocation(m_programId, name), x, y); } + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z) { glUniform3f(glGetUniformLocation(m_programId, name), x, y, z); } + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { glUniform4f(glGetUniformLocation(m_programId, name), x, y, z, w); } + void setUniformValue(const char *name, GLfloat mat2[2][2], bool transpose = false) { glUniformMatrix2fv(glGetUniformLocation(m_programId, name), 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat2); } + void setUniformValue(const char *name, GLfloat mat3[3][3], bool transpose = false) { glUniformMatrix3fv(glGetUniformLocation(m_programId, name), 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat3); } + + // Point, PointF, Color, Size, SizeF, + bool isLinked() { return m_linked; } + GLuint getProgramId() { return m_programId; } + ShaderList getShaders() { return m_shaders; } + +private: + bool m_linked; + GLuint m_programId; + static GLuint m_currentProgram; + ShaderList m_shaders; + std::array m_uniformLocations; +}; + +#endif diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index ef3a8de2..2ce5dc7c 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -36,7 +36,6 @@ Texture::Texture(int width, int height, int channels, uchar *pixels) Texture::~Texture() { - assert(!g_graphics.isDrawing()); // free texture from gl memory if(m_textureId > 0) glDeleteTextures(1, &m_textureId); @@ -44,9 +43,7 @@ Texture::~Texture() uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int height) { - assert(!g_graphics.isDrawing()); - - m_size.setSize(width, height); + m_size.resize(width, height); // gets max texture size supported by the driver static GLint maxTexSize = -1; @@ -70,7 +67,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int std::vector tmp; // old opengl drivers only accept power of two dimensions - //if(!g_graphics.isExtensionSupported("GL_ARB_texture_non_power_of_two")) { + //if(!g_painter.isExtensionSupported("GL_ARB_texture_non_power_of_two")) { int glWidth = 1; while(glWidth < width) glWidth = glWidth << 1; @@ -88,7 +85,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int pixels = &tmp[0]; } - m_glSize.setSize(glWidth, glHeight); + m_glSize.resize(glWidth, glHeight); //} else // m_glSize = m_size; @@ -110,7 +107,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int } // load pixels into gl memory - glTexImage2D(GL_TEXTURE_2D, 0, channels, m_glSize.width(), m_glSize.height(), 0, format, GL_UNSIGNED_BYTE, pixels); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_glSize.width(), m_glSize.height(), 0, format, GL_UNSIGNED_BYTE, pixels); // disable texture border glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -119,7 +116,6 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int // nearest filtering (non smooth) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - return id; } diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index e0e88795..0fe4cd73 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -37,22 +37,22 @@ public: virtual void enableBilinearFilter(); /// Get OpenGL texture id - uint getId() const { return m_textureId; } + GLuint getId() { return m_textureId; } /// Copy pixels from OpenGL texture std::vector getPixels(); - int getWidth() const { return m_size.width(); } - int getHeight() const { return m_size.height(); } - const Size& getSize() const { return m_size; } - const Size& getGlSize() const { return m_glSize; } + int getWidth() { return m_size.width(); } + int getHeight() { return m_size.height(); } + const Size& getSize() { return m_size; } + const Size& getGlSize() { return m_glSize; } bool isEmpty() const { return m_textureId == 0; } protected: - uint internalLoadGLTexture(uchar* pixels, int channels, int w, int h); + GLuint internalLoadGLTexture(uchar* pixels, int channels, int w, int h); - uint m_textureId; + GLuint m_textureId; Size m_size; Size m_glSize; }; diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 8c57cf3b..c9aad99b 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -36,73 +36,110 @@ void Application::registerLuaFunctions() // UIWidget g_lua.registerClass(); g_lua.bindClassStaticFunction("create", &UIWidget::create); - g_lua.bindClassMemberFunction("getId", &UIWidget::getId); - g_lua.bindClassMemberFunction("setId", &UIWidget::setId); - g_lua.bindClassMemberFunction("isEnabled", &UIWidget::isEnabled); - g_lua.bindClassMemberFunction("setEnabled", &UIWidget::setEnabled); - g_lua.bindClassMemberFunction("isExplicitlyVisible", &UIWidget::isExplicitlyVisible); + g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy); g_lua.bindClassMemberFunction("setVisible", &UIWidget::setVisible); - g_lua.bindClassMemberFunction("getWidth", &UIWidget::getWidth); + g_lua.bindClassMemberFunction("setEnabled", &UIWidget::setEnabled); + g_lua.bindClassMemberFunction("setPressed", &UIWidget::setPressed); + g_lua.bindClassMemberFunction("setId", &UIWidget::setId); + g_lua.bindClassMemberFunction("setFocusable", &UIWidget::setFocusable); + g_lua.bindClassMemberFunction("setPhantom", &UIWidget::setPhantom); + g_lua.bindClassMemberFunction("setStyle", &UIWidget::setStyle); + g_lua.bindClassMemberFunction("setStyleFromNode", &UIWidget::setStyleFromNode); + //g_lua.bindClassMemberFunction("setLayout", &UIWidget::setLayout); + g_lua.bindClassMemberFunction("setParent", &UIWidget::setParent); + g_lua.bindClassMemberFunction("setRect", &UIWidget::setRect); + g_lua.bindClassMemberFunction("setX", &UIWidget::setX); + g_lua.bindClassMemberFunction("setY", &UIWidget::setY); g_lua.bindClassMemberFunction("setWidth", &UIWidget::setWidth); - g_lua.bindClassMemberFunction("getHeight", &UIWidget::getHeight); g_lua.bindClassMemberFunction("setHeight", &UIWidget::setHeight); - g_lua.bindClassMemberFunction("getSize", &UIWidget::getSize); - g_lua.bindClassMemberFunction("setSize", &UIWidget::resize); - g_lua.bindClassMemberFunction("getPosition", &UIWidget::getPosition); - g_lua.bindClassMemberFunction("getX", &UIWidget::getX); - g_lua.bindClassMemberFunction("getY", &UIWidget::getY); - g_lua.bindClassMemberFunction("moveTo", &UIWidget::moveTo); - g_lua.bindClassMemberFunction("moveChildToIndex", &UIWidget::moveChildToIndex); - g_lua.bindClassMemberFunction("getParent", &UIWidget::getParent); - g_lua.bindClassMemberFunction("setParent", &UIWidget::setParent); - g_lua.bindClassMemberFunction("getBackgroundColor", &UIWidget::getBackgroundColor); + //g_lua.bindClassMemberFunction("setImage", &UIWidget::setImage); + //g_lua.bindClassMemberFunction("setFont", &UIWidget::setFont); + g_lua.bindClassMemberFunction("setOpacity", &UIWidget::setOpacity); g_lua.bindClassMemberFunction("setBackgroundColor", &UIWidget::setBackgroundColor); - g_lua.bindClassMemberFunction("getForegroundColor", &UIWidget::getForegroundColor); g_lua.bindClassMemberFunction("setForegroundColor", &UIWidget::setForegroundColor); - g_lua.bindClassMemberFunction("getOpacity", &UIWidget::getOpacity); - g_lua.bindClassMemberFunction("setOpacity", &UIWidget::setOpacity); - g_lua.bindClassMemberFunction("setStyle", &UIWidget::setStyle); - g_lua.bindClassMemberFunction("applyStyle", &UIWidget::applyStyle); - g_lua.bindClassMemberFunction("getStyle", &UIWidget::getStyle); - g_lua.bindClassMemberFunction("getMarginTop", &UIWidget::getMarginTop); g_lua.bindClassMemberFunction("setMarginTop", &UIWidget::setMarginTop); - g_lua.bindClassMemberFunction("getMarginBottom", &UIWidget::getMarginBottom); + g_lua.bindClassMemberFunction("setMarginRight", &UIWidget::setMarginRight); g_lua.bindClassMemberFunction("setMarginBottom", &UIWidget::setMarginBottom); - g_lua.bindClassMemberFunction("getMarginLeft", &UIWidget::getMarginLeft); g_lua.bindClassMemberFunction("setMarginLeft", &UIWidget::setMarginLeft); - g_lua.bindClassMemberFunction("getMarginRight", &UIWidget::getMarginRight); - g_lua.bindClassMemberFunction("setMarginRight", &UIWidget::setMarginRight); - g_lua.bindClassMemberFunction("isVisible", &UIWidget::isVisible); - g_lua.bindClassMemberFunction("isHidden", &UIWidget::isHidden); - g_lua.bindClassMemberFunction("isHovered", &UIWidget::isHovered); - g_lua.bindClassMemberFunction("isFocused", &UIWidget::isFocused); - g_lua.bindClassMemberFunction("isPressed", &UIWidget::isPressed); - g_lua.bindClassMemberFunction("isEnabled", &UIWidget::isEnabled); - g_lua.bindClassMemberFunction("isDisabled", &UIWidget::isDisabled); - g_lua.bindClassMemberFunction("isActive", &UIWidget::isActive); + g_lua.bindClassMemberFunction("setSizeFixed", &UIWidget::setSizeFixed); + g_lua.bindClassMemberFunction("setLastFocusReason", &UIWidget::setLastFocusReason); + g_lua.bindClassMemberFunction("resize", &UIWidget::resize); + g_lua.bindClassMemberFunction("moveTo", &UIWidget::moveTo); g_lua.bindClassMemberFunction("hide", &UIWidget::hide); g_lua.bindClassMemberFunction("show", &UIWidget::show); + g_lua.bindClassMemberFunction("disable", &UIWidget::disable); + g_lua.bindClassMemberFunction("enable", &UIWidget::enable); g_lua.bindClassMemberFunction("lock", &UIWidget::lock); g_lua.bindClassMemberFunction("unlock", &UIWidget::unlock); g_lua.bindClassMemberFunction("focus", &UIWidget::focus); + g_lua.bindClassMemberFunction("isActive", &UIWidget::isActive); + g_lua.bindClassMemberFunction("isEnabled", &UIWidget::isEnabled); + g_lua.bindClassMemberFunction("isDisabled", &UIWidget::isDisabled); + g_lua.bindClassMemberFunction("isFocused", &UIWidget::isFocused); + g_lua.bindClassMemberFunction("isHovered", &UIWidget::isHovered); + g_lua.bindClassMemberFunction("isPressed", &UIWidget::isPressed); + g_lua.bindClassMemberFunction("isVisible", &UIWidget::isVisible); + g_lua.bindClassMemberFunction("isHidden", &UIWidget::isHidden); + g_lua.bindClassMemberFunction("isExplicitlyEnabled", &UIWidget::isExplicitlyEnabled); + g_lua.bindClassMemberFunction("isExplicitlyVisible", &UIWidget::isExplicitlyVisible); + g_lua.bindClassMemberFunction("isFocusable", &UIWidget::isFocusable); + g_lua.bindClassMemberFunction("isPhantom", &UIWidget::isPhantom); + g_lua.bindClassMemberFunction("isSizeFixed", &UIWidget::isSizeFixed); + g_lua.bindClassMemberFunction("hasChildren", &UIWidget::hasChildren); + g_lua.bindClassMemberFunction("hasChild", &UIWidget::hasChild); + g_lua.bindClassMemberFunction("getId", &UIWidget::getId); + g_lua.bindClassMemberFunction("getChildCount", &UIWidget::getChildCount); + //g_lua.bindClassMemberFunction("getLayout", &UIWidget::getLayout); + g_lua.bindClassMemberFunction("getParent", &UIWidget::getParent); + g_lua.bindClassMemberFunction("getRootParent", &UIWidget::getRootParent); + g_lua.bindClassMemberFunction("getPosition", &UIWidget::getPosition); + g_lua.bindClassMemberFunction("getSize", &UIWidget::getSize); + g_lua.bindClassMemberFunction("getRect", &UIWidget::getRect); + g_lua.bindClassMemberFunction("getX", &UIWidget::getX); + g_lua.bindClassMemberFunction("getY", &UIWidget::getY); + g_lua.bindClassMemberFunction("getWidth", &UIWidget::getWidth); + g_lua.bindClassMemberFunction("getHeight", &UIWidget::getHeight); + //g_lua.bindClassMemberFunction("getImage", &UIWidget::getImage); + //g_lua.bindClassMemberFunction("getFont", &UIWidget::getFont); + g_lua.bindClassMemberFunction("getForegroundColor", &UIWidget::getForegroundColor); + g_lua.bindClassMemberFunction("getBackgroundColor", &UIWidget::getBackgroundColor); + g_lua.bindClassMemberFunction("getOpacity", &UIWidget::getOpacity); + g_lua.bindClassMemberFunction("getMarginTop", &UIWidget::getMarginTop); + g_lua.bindClassMemberFunction("getMarginRight", &UIWidget::getMarginRight); + g_lua.bindClassMemberFunction("getMarginBottom", &UIWidget::getMarginBottom); + g_lua.bindClassMemberFunction("getMarginLeft", &UIWidget::getMarginLeft); + g_lua.bindClassMemberFunction("getLastFocusReason", &UIWidget::getLastFocusReason); + g_lua.bindClassMemberFunction("getStyle", &UIWidget::getStyle); g_lua.bindClassMemberFunction("getChildren", &UIWidget::getChildren); - g_lua.bindClassMemberFunction("recursiveGetChildById", &UIWidget::recursiveGetChildById); + g_lua.bindClassMemberFunction("getFocusedChild", &UIWidget::getFocusedChild); + g_lua.bindClassMemberFunction("getChildAfter", &UIWidget::getChildAfter); + g_lua.bindClassMemberFunction("getChildBefore", &UIWidget::getChildBefore); g_lua.bindClassMemberFunction("getChildById", &UIWidget::getChildById); + g_lua.bindClassMemberFunction("getChildByPos", &UIWidget::getChildByPos); g_lua.bindClassMemberFunction("getChildByIndex", &UIWidget::getChildByIndex); - g_lua.bindClassMemberFunction("getChildCount", &UIWidget::getChildCount); - g_lua.bindClassMemberFunction("getFocusedChild", &UIWidget::getFocusedChild); + g_lua.bindClassMemberFunction("recursiveGetChildById", &UIWidget::recursiveGetChildById); + g_lua.bindClassMemberFunction("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos); + g_lua.bindClassMemberFunction("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById); + g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild); g_lua.bindClassMemberFunction("insertChild", &UIWidget::insertChild); g_lua.bindClassMemberFunction("removeChild", &UIWidget::removeChild); - g_lua.bindClassMemberFunction("hasChild", &UIWidget::hasChild); - g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild); g_lua.bindClassMemberFunction("focusChild", &UIWidget::focusChild); g_lua.bindClassMemberFunction("focusNextChild", &UIWidget::focusNextChild); g_lua.bindClassMemberFunction("focusPreviousChild", &UIWidget::focusPreviousChild); + g_lua.bindClassMemberFunction("moveChildToTop", &UIWidget::moveChildToTop); + g_lua.bindClassMemberFunction("moveChildToIndex", &UIWidget::moveChildToIndex); g_lua.bindClassMemberFunction("lockChild", &UIWidget::lockChild); g_lua.bindClassMemberFunction("unlockChild", &UIWidget::unlockChild); - g_lua.bindClassMemberFunction("updateLayout", &UIWidget::updateLayout); + g_lua.bindClassMemberFunction("isChildLocked", &UIWidget::isChildLocked); + g_lua.bindClassMemberFunction("getChildIndex", &UIWidget::getChildIndex); g_lua.bindClassMemberFunction("updateParentLayout", &UIWidget::updateParentLayout); - g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy); + g_lua.bindClassMemberFunction("updateLayout", &UIWidget::updateLayout); + g_lua.bindClassMemberFunction("updateStates", &UIWidget::updateStates); + g_lua.bindClassMemberFunction("updateState", &UIWidget::updateState); + g_lua.bindClassMemberFunction("setState", &UIWidget::setState); + g_lua.bindClassMemberFunction("hasState", &UIWidget::hasState); + g_lua.bindClassMemberFunction("updateStyle", &UIWidget::updateStyle); + g_lua.bindClassMemberFunction("applyStyle", &UIWidget::applyStyle); // UILabel g_lua.registerClass(); @@ -175,12 +212,27 @@ void Application::registerLuaFunctions() g_lua.bindClassStaticFunction("fireOldMessages", std::bind(&Logger::fireOldMessages, &g_logger)); g_lua.bindClassStaticFunction("setOnLog", std::bind(&Logger::setOnLog, &g_logger, _1)); + // Font + + /* + // FontManager + g_lua.registerStaticClass("g_fonts"); + g_lua.bindClassStaticFunction("g_fonts", "releaseFonts", std::bind(&FontManager::releaseFonts, &g_fonts)); + g_lua.bindClassStaticFunction("g_fonts", "importFont", std::bind(&FontManager::importFont, &g_fonts, _1)); + g_lua.bindClassStaticFunction("g_fonts", "fontExists", std::bind(&FontManager::fontExists, &g_fonts, _1)); + g_lua.bindClassStaticFunction("g_fonts", "getFont", std::bind(&FontManager::getFont, &g_fonts, _1)); + g_lua.bindClassStaticFunction("g_fonts", "getDefaultFont", std::bind(&FontManager::getDefaultFont, &g_fonts)); + g_lua.bindClassStaticFunction("g_fonts", "setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1)); + */ + + g_lua.registerStaticClass("g_dispatcher"); + g_lua.bindClassStaticFunction("g_dispatcher", "addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, _2)); + g_lua.bindClassStaticFunction("g_dispatcher", "scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2)); + // global functions g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1)); g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1)); g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1)); g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1, _2)); g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui)); - g_lua.bindGlobalFunction("addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, false)); - g_lua.bindGlobalFunction("scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2)); } diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index eeab1bf4..09f6ed12 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -340,7 +340,7 @@ void X11Window::internalChooseGLVisual() m_rootWindow = RootWindow(m_display, m_visual->screen); #else static int attrList[] = { - EGL_BUFFER_SIZE, 16, + EGL_BUFFER_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index a8650f8b..da42d0cb 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -40,9 +40,9 @@ void UIButton::render() if(m_icon) { Rect iconRect; - iconRect.setSize(m_icon->getSize()); + iconRect.resize(m_icon->getSize()); iconRect.moveCenter(m_rect.center()); - g_graphics.drawTexturedRect(iconRect, m_icon); + g_painter.drawTexturedRect(iconRect, m_icon); } Rect textRect = m_rect; diff --git a/src/framework/ui/uicheckbox.cpp b/src/framework/ui/uicheckbox.cpp index 5dc7962c..444414c2 100644 --- a/src/framework/ui/uicheckbox.cpp +++ b/src/framework/ui/uicheckbox.cpp @@ -38,10 +38,10 @@ void UICheckBox::render() { if(m_image) { Rect boxRect; - boxRect.setSize(m_boxSize); + boxRect.resize(m_boxSize); boxRect.moveLeft(m_rect.left()); boxRect.moveVerticalCenter(m_rect.verticalCenter()); - g_graphics.bindColor(m_backgroundColor); + g_painter.setColor(m_backgroundColor); m_image->draw(boxRect); } diff --git a/src/framework/ui/uilineedit.cpp b/src/framework/ui/uilineedit.cpp index 91df18e9..31ea118d 100644 --- a/src/framework/ui/uilineedit.cpp +++ b/src/framework/ui/uilineedit.cpp @@ -47,9 +47,9 @@ void UILineEdit::render() int textLength = m_text.length(); const TexturePtr& texture = m_font->getTexture(); - g_graphics.bindColor(m_foregroundColor); + g_painter.setColor(m_foregroundColor); for(int i=0;i= 0) { @@ -63,7 +63,7 @@ void UILineEdit::render() cursorRect = Rect(m_drawArea.left()-1, m_drawArea.top(), 1, m_font->getGlyphHeight()); else cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight()); - g_graphics.drawFilledRect(cursorRect); + g_painter.drawFilledRect(cursorRect); } else if(g_clock.ticksElapsed(m_cursorTicks) >= 2*delay) { m_cursorTicks = g_clock.ticks(); } diff --git a/src/framework/ui/uimanager.cpp b/src/framework/ui/uimanager.cpp index 6a8b3ada..344302c8 100644 --- a/src/framework/ui/uimanager.cpp +++ b/src/framework/ui/uimanager.cpp @@ -25,6 +25,7 @@ #include #include +#include UIManager g_ui; @@ -33,7 +34,7 @@ void UIManager::init() // creates root widget m_rootWidget = UIWidget::create(); m_rootWidget->setId("root"); - m_rootWidget->resize(g_graphics.getScreenSize()); + m_rootWidget->resize(g_window.getSize()); } void UIManager::terminate() @@ -50,7 +51,7 @@ void UIManager::render() void UIManager::resize(const Size& size) { - m_rootWidget->resize(g_graphics.getScreenSize()); + m_rootWidget->resize(g_window.getSize()); } void UIManager::inputEvent(const InputEvent& event) @@ -174,12 +175,15 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const U if(parent) parent->addChild(widget); - widget->setStyleFromNode(styleNode); + if(widget) { + widget->setStyleFromNode(styleNode); - for(const OTMLNodePtr& childNode : widgetNode->children()) { - if(!childNode->isUnique()) - loadWidgetFromOTML(childNode, widget); - } + for(const OTMLNodePtr& childNode : widgetNode->children()) { + if(!childNode->isUnique()) + loadWidgetFromOTML(childNode, widget); + } + } else + logError("Unable to create widget of type '", widgetType, "'"); return widget; } diff --git a/src/framework/ui/uiprogressbar.cpp b/src/framework/ui/uiprogressbar.cpp index 12013a1c..27ba173a 100644 --- a/src/framework/ui/uiprogressbar.cpp +++ b/src/framework/ui/uiprogressbar.cpp @@ -35,14 +35,14 @@ void UIProgressBar::render() { UIWidget::render(); - g_graphics.bindColor(m_foregroundColor); - g_graphics.drawBoundingRect(m_rect, 1); + g_painter.setColor(m_foregroundColor); + g_painter.drawBoundingRect(m_rect, 1); Rect fillRect = m_rect.expanded(-1); fillRect.setWidth(fillRect.width() * m_percent / 100.0); - g_graphics.bindColor(m_backgroundColor); - g_graphics.drawFilledRect(fillRect); + g_painter.setColor(m_backgroundColor); + g_painter.drawFilledRect(fillRect); } void UIProgressBar::setPercent(double percent) diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 53dfe14d..96d13480 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -69,7 +69,7 @@ void UIWidget::renderSelf() { // draw background if(m_image) { - g_graphics.bindColor(m_backgroundColor); + g_painter.setColor(m_backgroundColor); m_image->draw(m_rect); } } @@ -81,20 +81,20 @@ void UIWidget::renderChildren() // render only visible children with a valid rect inside our rect if(child->isExplicitlyVisible() && child->getRect().isValid() && child->getRect().intersects(m_rect)) { // store current graphics opacity - int oldOpacity = g_graphics.getOpacity(); + int oldOpacity = g_painter.getOpacity(); // decrease to self opacity if(child->getOpacity() < oldOpacity) - g_graphics.setOpacity(child->getOpacity()); + g_painter.setOpacity(child->getOpacity()); child->render(); // debug draw box - //g_graphics.bindColor(Fw::green); - //g_graphics.drawBoundingRect(child->getRect()); + //g_painter.setColor(Fw::green); + //g_painter.drawBoundingRect(child->getRect()); //g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Fw::red); - g_graphics.setOpacity(oldOpacity); + g_painter.setOpacity(oldOpacity); } } } diff --git a/src/framework/util/rect.h b/src/framework/util/rect.h index f5e699b8..68d68387 100644 --- a/src/framework/util/rect.h +++ b/src/framework/util/rect.h @@ -78,8 +78,8 @@ public: void setBottomLeft(const TPoint &p) { x1 = p.x; y2 = p.y; } void setWidth(T width) { x2 = x1 + width - 1; } void setHeight(T height) { y2 = y1 + height- 1; } - void setSize(T width, T height) { x2 = x1 + width - 1; y2 = y1 + height - 1; } - void setSize(const TSize& size) { x2 = x1 + size.width() - 1; y2 = y1 + size.height() - 1; } + void resize(T width, T height) { x2 = x1 + width - 1; y2 = y1 + height - 1; } + void resize(const TSize& size) { x2 = x1 + size.width() - 1; y2 = y1 + size.height() - 1; } void setRect(T x, T y, T width, T height) { x1 = x; y1 = y; x2 = (x + width - 1); y2 = (y + height - 1); } void setCoords(int left, int top, int right, int bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; } diff --git a/src/framework/util/size.h b/src/framework/util/size.h index f76204f5..9b373eee 100644 --- a/src/framework/util/size.h +++ b/src/framework/util/size.h @@ -43,7 +43,7 @@ public: int width() const { return wd; } int height() const { return ht; } - void setSize(T w, T h) { wd = w; ht = h; } + void resize(T w, T h) { wd = w; ht = h; } void setWidth(T w) { wd = w; } void setHeight(T h) { ht = h; } @@ -115,7 +115,7 @@ std::istream& operator>>(std::istream& in, TSize& size) { T w, h; in >> w >> h; - size.setSize(w, h); + size.resize(w, h); return in; } diff --git a/src/framework/util/tools.h b/src/framework/util/tools.h index 03ff0ed4..73dd18a7 100644 --- a/src/framework/util/tools.h +++ b/src/framework/util/tools.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "types.h" #include "exception.h" @@ -258,6 +260,16 @@ inline std::string ip2str(uint32 ip) { return std::string(host); } +template +std::vector split(const std::string& str, const std::string& separators = " ") { + std::vector splitted; + boost::split(splitted, str, boost::is_any_of(std::string(separators))); + std::vector results(splitted.size()); + for(uint i=0;i(splitted[i]); + return results; +} + template void throwException(const T&... args) { throw Exception(Fw::mkstr(args...)); diff --git a/src/main.cpp b/src/main.cpp index 982cf3a2..53a1a48c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,9 +25,9 @@ int main(int argc, const char* argv[]) { std::vector args(argv, argv + argc); - OTClient otclient; - otclient.init(args); - otclient.run(); - otclient.terminate(); + OTClient app; + app.init(args); + app.run(); + app.terminate(); return 0; } diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index 35f11bd2..b8ece933 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -47,8 +47,8 @@ void Creature::draw(const Point& p) { // TODO: activate on attack, follow, discover how 'attacked' works if(m_showSquareColor) { - g_graphics.bindColor(Outfit::getColor(m_squareColor)); - g_graphics.drawBoundingRect(Rect(p + m_walkOffset - 8, Size(32, 32)), 2); + g_painter.setColor(Outfit::getColor(m_squareColor)); + g_painter.drawBoundingRect(Rect(p + m_walkOffset - 8, Size(32, 32)), 2); } // Render creature @@ -59,33 +59,33 @@ void Creature::draw(const Point& p) continue; // draw white item - g_graphics.bindColor(Fw::white); + g_painter.setColor(Fw::white); internalDraw(p + m_walkOffset, 0); // draw mask if exists if(m_type->dimensions[ThingType::Layers] > 1) { // switch to blend color mode - g_graphics.bindBlendFunc(Fw::BlendColorzing); + g_painter.setCompositionMode(Painter::CompositionMode_ColorizeDest); // head - g_graphics.bindColor(m_outfit.getHeadColor()); + g_painter.setColor(m_outfit.getHeadColor()); internalDraw(p + m_walkOffset, 1, Otc::SpriteYellowMask); // body - g_graphics.bindColor(m_outfit.getBodyColor()); + g_painter.setColor(m_outfit.getBodyColor()); internalDraw(p + m_walkOffset, 1, Otc::SpriteRedMask); // legs - g_graphics.bindColor(m_outfit.getLegsColor()); + g_painter.setColor(m_outfit.getLegsColor()); internalDraw(p + m_walkOffset, 1, Otc::SpriteGreenMask); // feet - g_graphics.bindColor(m_outfit.getFeetColor()); + g_painter.setColor(m_outfit.getFeetColor()); internalDraw(p + m_walkOffset, 1, Otc::SpriteBlueMask); // restore default blend func - g_graphics.bindBlendFunc(Fw::BlendDefault); - g_graphics.bindColor(Fw::white); + g_painter.setCompositionMode(Painter::CompositionMode_SourceOver); + g_painter.setColor(Fw::white); } } } @@ -115,11 +115,11 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& rect) healthRect.setWidth((m_healthPercent / 100.0) * 25); // draw - g_graphics.bindColor(Fw::black); - g_graphics.drawFilledRect(backgroundRect); + g_painter.setColor(Fw::black); + g_painter.drawFilledRect(backgroundRect); - g_graphics.bindColor(fillColor); - g_graphics.drawFilledRect(healthRect); + g_painter.setColor(fillColor); + g_painter.drawFilledRect(healthRect); m_informationFont->renderText(m_name, textRect, Fw::AlignTopCenter, fillColor); } diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index 54a7e8e1..72173ef3 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -41,7 +41,7 @@ void Map::draw(const Rect& rect) if(!m_framebuffer) m_framebuffer = FrameBufferPtr(new FrameBuffer(m_visibleSize.width() * NUM_TILE_PIXELS, m_visibleSize.height() * NUM_TILE_PIXELS)); - g_graphics.bindColor(Fw::white); + g_painter.setColor(Fw::white); m_framebuffer->bind(); // draw offsets @@ -80,9 +80,9 @@ void Map::draw(const Rect& rect) } } - m_framebuffer->unbind(); + m_framebuffer->release(); - g_graphics.bindColor(Fw::white); + g_painter.setColor(Fw::white); m_framebuffer->draw(rect); // calculate stretch factor diff --git a/src/otclient/core/thing.cpp b/src/otclient/core/thing.cpp index 6066047a..972d4ee1 100644 --- a/src/otclient/core/thing.cpp +++ b/src/otclient/core/thing.cpp @@ -55,7 +55,7 @@ void Thing::internalDraw(const Point& p, int layers, Otc::SpriteMask mask) Rect drawRect((p.x - xi*32) - m_type->parameters[ThingType::DisplacementX], (p.y - yi*32) - m_type->parameters[ThingType::DisplacementY], 32, 32); - g_graphics.drawTexturedRect(drawRect, spriteTex); + g_painter.drawTexturedRect(drawRect, spriteTex); } } } diff --git a/src/otclient/otclient.cpp b/src/otclient/otclient.cpp index ef2c282a..6d5e4f47 100644 --- a/src/otclient/otclient.cpp +++ b/src/otclient/otclient.cpp @@ -36,6 +36,5 @@ void OTClient::init(const std::vector& args) g_modules.discoverModules(); g_modules.autoLoadModules(100); g_modules.ensureModuleLoaded("client"); - g_modules.ensureModuleLoaded("game"); g_modules.autoLoadModules(1000); } diff --git a/src/otclient/ui/uicreature.cpp b/src/otclient/ui/uicreature.cpp index f78751e2..76973b84 100644 --- a/src/otclient/ui/uicreature.cpp +++ b/src/otclient/ui/uicreature.cpp @@ -34,7 +34,7 @@ void UICreature::render() renderSelf(); if(m_creature) { - g_graphics.bindColor(Fw::white); + g_painter.setColor(Fw::white); m_creature->draw(m_rect.bottomRight() - Point(32, 32) + m_creatureMargin); } diff --git a/src/otclient/ui/uiitem.cpp b/src/otclient/ui/uiitem.cpp index da19fb0c..7a98c979 100644 --- a/src/otclient/ui/uiitem.cpp +++ b/src/otclient/ui/uiitem.cpp @@ -34,7 +34,7 @@ void UIItem::render() renderSelf(); if(m_item) { - g_graphics.bindColor(Fw::white); + g_painter.setColor(Fw::white); m_item->draw(m_rect.bottomRight() - Point(32, 32) + m_itemMargin); } diff --git a/src/otclient/ui/uimap.cpp b/src/otclient/ui/uimap.cpp index 3523562a..2359b539 100644 --- a/src/otclient/ui/uimap.cpp +++ b/src/otclient/ui/uimap.cpp @@ -35,8 +35,8 @@ void UIMap::render() { renderSelf(); - g_graphics.bindColor(Fw::black); - g_graphics.drawBoundingRect(m_mapRect.expanded(1)); + g_painter.setColor(Fw::black); + g_painter.drawBoundingRect(m_mapRect.expanded(1)); g_map.draw(m_mapRect); renderChildren(); @@ -78,6 +78,6 @@ void UIMap::onGeometryUpdate(const Rect& oldRect, const Rect& newRect) Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS); mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); - m_mapRect.setSize(mapSize); + m_mapRect.resize(mapSize); m_mapRect.moveCenter(newRect.center()); } diff --git a/tools/lua-binding-generator/generate_lua_bindings.lua b/tools/lua-binding-generator/generate_lua_bindings.lua index b77022d2..a887bd2f 100755 --- a/tools/lua-binding-generator/generate_lua_bindings.lua +++ b/tools/lua-binding-generator/generate_lua_bindings.lua @@ -15,16 +15,16 @@ if not io.open(cppclassheader, 'r') then return false end -function string.matchcount(str, pattern) +function string:matchcount(pattern) local count = 0 - for w in str:gmatch(pattern) do count = count + 1 end + for w in self:gmatch(pattern) do count = count + 1 end return count end -function string.splitlines(str) +function string:splitlines() local t = {} local function helper(line) table.insert(t, line) return "" end - helper((str:gsub("(.-)\r?\n", helper))) + helper((self:gsub("(.-)\r?\n", helper))) return t end @@ -34,7 +34,7 @@ for line in io.lines(cppclassheader) do foundclassname = line:match('^class ([%w_]+)') if foundclassname then if not cppclassname then - guessedclassname = cppclassheader:match('([%w_]+).h'):lower() + guessedclassname = cppclassheader:match('([%w_]+)\.h$'):lower() if foundclassname:lower() == guessedclassname then cppclassname = foundclassname end @@ -69,8 +69,9 @@ for line in io.lines(cppclassheader) do elseif line:match('private:') or line:match('protected:') then publicmethods = false elseif publicmethods then - for funcname,args in line:gmatch(' *[%w :_]* ([%w_]+)%(([^%(]*%)) *[;{].*$') do - if funcname ~= cppclassname then + funcname, args = line:match('^ *[%w <>&\*:_]* ([%w_]+)%(([^%)]*%))[%w ]*[;{].*$') + if funcname then + if funcname ~= cppclassname and funcname ~= 'create' then numargs = args:matchcount('[^,)]+[,)]') if cppclassinstance then