Merge branch 'revgraphics'

Conflicts:
	src/framework/CMakeLists.txt
	src/framework/application.cpp
	src/framework/graphics/graphics.cpp
This commit is contained in:
Eduardo Bart 2011-12-09 12:23:32 -02:00
commit 2030a4da29
81 changed files with 1988 additions and 767 deletions

12
TODO
View File

@ -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()
@ -30,3 +29,12 @@ 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
restore ctrl+g and keybindings
create a class for reading binary files
handle corrupt errors in dat/spr
create image class
use CoordsBuffer in font
cache into framebuffers
implement glbuffer for CoordsBuffer
use indices in CoordsBuffer

View File

@ -0,0 +1,5 @@
function dumpWidgets()
for i=1,UI.root:getChildCount() do
print(UI.root:getChildByIndex(i):getId())
end
end

View File

@ -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

View File

@ -8,11 +8,9 @@ Module
autoLoad: true
autoLoadPriority: 20
dependencies:
- core
onLoad: |
require 'console'
require 'commands'
Console.init()
return true

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 -- /

View File

@ -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

View File

@ -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
if eventList[id] then
if eventList[id].active then
func()
eventsTable[id] = nil
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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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

49
modules/outfit.frag Normal file
View File

@ -0,0 +1,49 @@
uniform float opacity;
uniform vec4 color;
uniform float ticks;
uniform sampler2D texture; // outfit texture
varying vec2 textureCoords; // outfit texture coords
uniform sampler2D maskTexture; // outfit color mask
uniform vec4 headColor;
uniform vec4 bodyColor;
uniform vec4 legsColor;
uniform vec4 feetColor;
vec4 calcPixel(vec2 texCoord)
{
vec4 pixel = texture2D(texture, texCoord);
vec4 maskColor = texture2D(maskTexture, texCoord);
vec4 outColor = vec4(0);
if(maskColor.r == 1.0 && maskColor.g == 1.0) {
outColor = headColor;
} else if(maskColor.r == 1.0) {
outColor = bodyColor;
} else if(maskColor.g == 1.0) {
outColor = legsColor;
} else if(maskColor.b == 1.0) {
outColor = feetColor;
}
if(outColor.a != 0.0)
pixel = pixel * outColor;
return pixel;
}
void main()
{
vec4 pixel = calcPixel(textureCoords);
int num = 16;
vec4 sum = vec4(0);
int i, j;
for(i=-num/2;i<num/2;++i) {
for(j=-num/2;j<num/2;++j) {
sum += calcPixel(textureCoords + vec2(i+1, j+1)*0.005) * 1.0/(num*num);
}
}
sum = sin(ticks/500.0)*sum;
gl_FragColor = pixel * color * opacity + sum;
}

123
modules/shadertest.frag Normal file
View File

@ -0,0 +1,123 @@
varying vec2 textureCoords;
uniform float opacity;
uniform vec4 color;
uniform float ticks;
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture, textureCoords) * color * opacity;
}
/*
varying vec2 textureCoords;
uniform vec4 color;
uniform float ticks;
uniform sampler2D texture;
void main()
{
int num = 4;
vec4 sum = vec4(0);
int i, j;
for(i=-num/2;i<num/2;++i) {
for(j=-num/2;j<num/2;++j) {
sum += texture2D(texture, textureCoords + vec2(i+1, j+1)*0.001) * 1.0/(num*num);
}
}
float period = ticks/1000.0;
float a = (sin(period)+1.0)/2.0;
sum.a = 0;
gl_FragColor = vec4(1,1,1,2) - texture2D(texture, textureCoords);
}
*/
/*
uniform sampler2D texture;
varying vec2 textureCoords;
void main()
{
vec4 sum = vec4(0);
vec2 texcoord = textureCoords;
int j;
int i;
for( i= -4 ;i < 4; i++)
{
for (j = -3; j < 3; j++)
{
sum += texture2D(texture, texcoord + vec2(j, i)*0.004) * 0.25;
}
}
if (texture2D(texture, texcoord).r < 0.3)
{
gl_FragColor = sum*sum*0.012 + texture2D(texture, texcoord);
}
else
{
if (texture2D(texture, texcoord).r < 0.5)
{
gl_FragColor = sum*sum*0.009 + texture2D(texture, texcoord);
}
else
{
gl_FragColor = sum*sum*0.0075 + texture2D(texture, texcoord);
}
}
}
*/
/*
uniform sampler2D texture;
varying vec2 textureCoords;
uniform vec4 color;
uniform float opacity;
uniform float ticks;
uniform float rt_w = 18*32;
uniform float rt_h = 14*32;
uniform float radius = 300.0;
uniform float angle = 0.2;
uniform vec2 center = vec2(8*32, 5*32);
vec4 PostFX(sampler2D tex, vec2 uv, float time)
{
vec2 texSize = vec2(rt_w, rt_h);
vec2 tc = uv * texSize;
tc -= center;
float dist = length(tc);
if (dist < radius)
{
float percent = (radius - dist) / radius;
float theta = percent * percent * ((int)ticks % 1000)/1000.0 * 8.0;
float s = sin(theta);
float c = cos(theta);
tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
}
tc += center;
vec3 color = texture2D(texture, tc / texSize).rgb;
return vec4(color, 1.0);
}
void main (void)
{
vec2 uv = textureCoords.st;
gl_FragColor = PostFX(texture, uv, ticks) * opacity;
}
*/
/*
uniform float opacity;
vec4 calculatePixel();
void main()
{
gl_FragColor = calculatePixel() * opacity;
}
varying vec2 textureCoords;
uniform vec4 color;
uniform sampler2D texture;
vec4 calculatePixel() {
return texture2D(texture, textureCoords) * color;
}
*/

View File

@ -79,7 +79,7 @@ IF(WIN32)
ENDIF(NO_CONSOLE)
ELSE(WIN32)
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic")
SET(ADDITIONAL_LIBRARIES pthread)
SET(ADDITIONAL_LIBRARIES pthread X11)
SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp)
ENDIF(WIN32)
@ -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
@ -144,6 +145,10 @@ SET(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/image.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/particlesmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/particlessystem.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/shader.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/shaderprogram.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/paintershaderprogram.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/coordsbuffer.cpp
# framework otml
${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp

View File

@ -32,6 +32,7 @@
#include <framework/ui/uiwidget.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/particlesmanager.h>
#include <framework/graphics/painter.h>
#include <framework/luascript/luainterface.h>
Application *g_app = nullptr;
@ -135,7 +136,6 @@ void Application::terminate()
// terminate graphics
if(m_appFlags & Fw::AppEnableGraphics) {
g_ui.terminate();
g_graphics.terminate();
g_window.terminate();
}
@ -222,8 +222,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)

View File

@ -178,12 +178,6 @@ namespace Fw
LogFatal
};
enum BlendFunc {
BlendDefault,
BlendColorzing,
BlendParticles
};
enum AspectRatioMode {
IgnoreAspectRatio,
KeepAspectRatio,

View File

@ -79,15 +79,13 @@ bool Module::load()
}
}
if(m_loadCallback) {
m_loaded = m_loadCallback();
if(!m_loaded) {
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;
}

View File

@ -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);

View File

@ -133,72 +133,72 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
void BorderImage::draw(const Rect& screenCoords)
{
//TODO: borderimage drawing could be optimized by caching the render into a texture
if(screenCoords != m_cachedScreenCoords) {
m_cachedScreenCoords = screenCoords;
m_coordsBuffer.clear();
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);
m_coordsBuffer.addRepeatedRects(rectCoords, m_centerTexCoords);
}
// top left corner
rectCoords = Rect(screenCoords.topLeft(),
m_topLeftCornerTexCoords.size());
g_graphics.drawTexturedRect(rectCoords, m_texture, m_topLeftCornerTexCoords);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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);
m_coordsBuffer.addRepeatedRects(rectCoords, 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();
m_coordsBuffer.addRepeatedRects(rectCoords, m_bottomRightCornerTexCoords);
}
g_painter.drawTextureCoords(m_coordsBuffer, m_texture);
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 "coordsbuffer.h"
void CoordsBuffer::clear()
{
m_destRects.reset();
m_srcRects.reset();
m_textureCoords.clear();
m_vertices.clear();
m_updateCache = true;
}
void CoordsBuffer::addRect(const Rect& dest)
{
m_destRects << dest;
m_updateCache = true;
}
void CoordsBuffer::addRect(const Rect& dest, const Rect& src)
{
m_destRects << dest;
m_srcRects << src;
m_updateCache = true;
}
void CoordsBuffer::addBoudingRect(const Rect& dest, int innerLineWidth)
{
int left = dest.left();
int right = dest.right();
int top = dest.top();
int bottom = dest.bottom();
int width = dest.width();
int height = dest.height();
int w = innerLineWidth;
addRect(Rect(left, top, width - w, w)); // top
addRect(Rect(right - w + 1, top, w, height - w)); // right
addRect(Rect(left + w, bottom - w + 1, width - w, w)); // bottom
addRect(Rect(left, top + w, w, height - w)); // left
m_updateCache = true;
}
void CoordsBuffer::addRepeatedRects(const Rect& dest, const Rect& src)
{
if(dest.isEmpty() || src.isEmpty())
return;
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());
m_destRects << partialDest;
m_srcRects << partialSrc;
}
}
m_updateCache = true;
}
void CoordsBuffer::cacheVertexArrays()
{
if(!m_updateCache)
return;
int numDestRects = m_destRects.size();
int numSrcRects = m_srcRects.size();
m_vertices.clear();
m_textureCoords.clear();
for(int i=0;i<numDestRects;++i) {
m_vertices.addRect(m_destRects[i]);
if(numSrcRects == numDestRects)
m_textureCoords.addRect(m_srcRects[i]);
}
m_updateCache = false;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 COORDSBUFFER_H
#define COORDSBUFFER_H
#include "vertexarray.h"
class CoordsBuffer
{
public:
void clear();
// no texture
void addRect(const Rect& dest);
void addBoudingRect(const Rect& dest, int innerLineWidth);
// textured
void addRect(const Rect& dest, const Rect& src);
void addRepeatedRects(const Rect& dest, const Rect& src);
void cacheVertexArrays();
GLfloat *getVertices() const { return m_vertices.vertices(); }
GLfloat *getTextureCoords() const { return m_textureCoords.vertices(); }
int getVertexCount() const { return m_vertices.vertexCount(); }
int getTextureCoordsCount() const { return m_textureCoords.vertexCount(); }
private:
DataBuffer<Rect> m_destRects;
DataBuffer<Rect> m_srcRects;
VertexArray m_vertices;
VertexArray m_textureCoords;
Boolean<true> m_updateCache;
};
#endif

View File

@ -32,6 +32,9 @@ class Font;
class Image;
class BorderImage;
class FrameBuffer;
class Shader;
class ShaderProgram;
class PainterShaderProgram;
typedef std::weak_ptr<Texture> TextureWeakPtr;
@ -41,5 +44,9 @@ typedef std::shared_ptr<Font> FontPtr;
typedef std::shared_ptr<Image> ImagePtr;
typedef std::shared_ptr<BorderImage> BorderImagePtr;
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
typedef std::shared_ptr<Shader> ShaderPtr;
typedef std::shared_ptr<ShaderProgram> ShaderProgramPtr;
typedef std::shared_ptr<PainterShaderProgram> PainterShaderProgramPtr;
typedef std::vector<ShaderPtr> ShaderList;
#endif

View File

@ -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<Point>& 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<Point>& Font::calculateGlyphsPositions(const std::string& text,
@ -172,7 +168,7 @@ const std::vector<Point>& 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);
}
}

View File

@ -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);
if(!m_fbo)
logFatal("Unable to create framebuffer object");
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// attach 2D texture to this FBO
glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture->getId(), 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->getId(), 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
//ok
break;
default: // fallback to old implementation
m_fallbackOldImp = true;
break;
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
logFatal("Unable to create framebuffer object");
// 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;
}
if(m_fallbackOldImp)
logInfo("Framebuffers not supported, falling back to old implementation.");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
FrameBuffer::~FrameBuffer()
{
if(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
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glClear(GL_COLOR_BUFFER_BIT);
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);
glClear(GL_COLOR_BUFFER_BIT);
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);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 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();
// 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);
}
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);
}

View File

@ -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; }

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 "glbuffer.h"
GLBuffer::GLBuffer()
{
glGenBuffers(1, &m_id);
if(!m_id)
logFatal("Unable to create a simple GL buffer");
}
void GLBuffer::bind()
{
gl
}
void GLBuffer::release()
{
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 GLBUFFER_H
#define GLBUFFER_H
#include "declarations.h"
class GLBuffer
{
public:
GLBuffer();
~GLBuffer();
void write(const
void bind();
void release();
GLuint bufferId();
private:
GLuint m_id;
};
#endif

View File

@ -30,310 +30,47 @@ 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;
case Fw::BlendParticles:
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
break;
}
}
void Graphics::startDrawing()
{
assert(!m_drawing);
glBegin(GL_QUADS);
m_drawing = true;
}
void Graphics::stopDrawing()
{
assert(m_drawing);
glEnd();
m_drawing = false;
}

View File

@ -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;
};

View File

@ -52,7 +52,13 @@ void Image::loadFromOTML(const OTMLNodePtr& imageNode)
void Image::draw(const Rect& screenCoords)
{
if(m_texture) {
if(!m_texture)
return;
if(m_cachedScreenCoords != screenCoords) {
m_cachedScreenCoords = screenCoords;
m_coordsBuffer.clear();
if(m_fixedRatio) {
const Size& texSize = m_texture->getSize();
Size texCoordsSize = screenCoords.size();
@ -63,12 +69,14 @@ 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));
m_coordsBuffer.addRect(screenCoords, Rect(texCoordsOffset, texCoordsSize));
} else {
if(m_repeated)
g_graphics.drawRepeatedTexturedRect(screenCoords, m_texture, m_textureCoords);
m_coordsBuffer.addRepeatedRects(screenCoords, m_textureCoords);
else
g_graphics.drawTexturedRect(screenCoords, m_texture, m_textureCoords);
m_coordsBuffer.addRect(screenCoords, m_textureCoords);
}
}
g_painter.drawTextureCoords(m_coordsBuffer, m_texture);
}

View File

@ -24,6 +24,7 @@
#define IMAGE_H
#include "declarations.h"
#include "coordsbuffer.h"
#include <framework/otml/declarations.h>
@ -41,6 +42,9 @@ protected:
Rect m_textureCoords;
bool m_fixedRatio;
bool m_repeated;
Rect m_cachedScreenCoords;
CoordsBuffer m_coordsBuffer;
};
#endif

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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"
#include "vertexarray.h"
Painter g_painter;
void Painter::init()
{
setColor(Fw::white);
setOpacity(255);
setCompositionMode(CompositionMode_SourceOver);
m_drawTexturedProgram = PainterShaderProgramPtr(new PainterShaderProgram);
m_drawTexturedProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
m_drawTexturedProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslTextureSrcFragmentShader);
assert(m_drawTexturedProgram->link());
m_drawSolidColorProgram = PainterShaderProgramPtr(new PainterShaderProgram);
m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Vertex, glslMainVertexShader + glslPositionOnlyVertexShader);
m_drawSolidColorProgram->addShaderFromSourceCode(Shader::Fragment, glslMainFragmentShader + glslSolidColorFragmentShader);
assert(m_drawSolidColorProgram->link());
}
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::drawProgram(const PainterShaderProgramPtr& program, CoordsBuffer& coordsBuffer, PainterShaderProgram::DrawMode drawMode)
{
coordsBuffer.cacheVertexArrays();
if(coordsBuffer.getVertexCount() == 0)
return;
program->setProjectionMatrix(m_projectionMatrix);
program->setOpacity(m_currentOpacity);
program->setColor(m_currentColor);
program->draw(coordsBuffer, drawMode);
}
void Painter::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture)
{
PainterShaderProgramPtr program = m_customProgram ? m_customProgram : m_drawTexturedProgram;
program->setTexture(texture);
drawProgram(program, coordsBuffer);
}
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;
m_coordsBuffer.clear();
m_coordsBuffer.addRect(dest, src);
drawTextureCoords(m_coordsBuffer, texture);
}
void Painter::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
{
if(dest.isEmpty() || src.isEmpty() || !texture->getId())
return;
m_coordsBuffer.clear();
m_coordsBuffer.addRepeatedRects(dest, src);
drawTextureCoords(m_coordsBuffer, texture);
}
void Painter::drawFilledRect(const Rect& dest)
{
if(dest.isEmpty())
return;
m_coordsBuffer.clear();
m_coordsBuffer.addRect(dest);
drawProgram(m_customProgram ? m_customProgram : m_drawSolidColorProgram, m_coordsBuffer);
}
void Painter::drawBoundingRect(const Rect& dest, int innerLineWidth)
{
if(dest.isEmpty() || innerLineWidth == 0)
return;
m_coordsBuffer.clear();
m_coordsBuffer.addBoudingRect(dest, innerLineWidth);
drawProgram(m_customProgram ? m_customProgram : m_drawSolidColorProgram, m_coordsBuffer);
}
void Painter::setCustomProgram(PainterShaderProgramPtr program)
{
m_customProgram = program;
}
void Painter::setCompositionMode(Painter::CompositionMode compositionMode)
{
switch(compositionMode) {
case CompositionMode_SourceOver:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case CompositionMode_ColorizeSource:
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
break;
case CompositionMode_AdditiveSource:
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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"
#include <framework/util/databuffer.h>
#include "coordsbuffer.h"
#include "paintershaderprogram.h"
class Painter
{
public:
enum CompositionMode {
CompositionMode_SourceOver,
CompositionMode_ColorizeSource,
CompositionMode_AdditiveSource
};
void init();
void terminate();
void updateProjectionMatrix(const Size& viewportSize, bool inverseYAxis = false);
void drawProgram(const PainterShaderProgramPtr& program, CoordsBuffer& coordsBuffer, PainterShaderProgram::DrawMode drawMode = PainterShaderProgram::Triangles);
void drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture);
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 setCustomProgram(PainterShaderProgramPtr program);
void releaseCustomProgram() { m_customProgram = nullptr; }
void setCompositionMode(CompositionMode compositionMode);
GLfloat *getProjectionMatrix() { return (GLfloat*)m_projectionMatrix; }
private:
PainterShaderProgramPtr m_drawTexturedProgram;
PainterShaderProgramPtr m_drawSolidColorProgram;
PainterShaderProgramPtr m_customProgram;
GLfloat m_projectionMatrix[3][3];
Color m_currentColor;
GLfloat m_currentOpacity;
CoordsBuffer m_coordsBuffer;
};
extern Painter g_painter;
#endif

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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"
#include <framework/core/clock.h>
bool PainterShaderProgram::link()
{
bindAttributeLocation(VERTEX_COORDS_ATTR, "vertexCoord");
bindAttributeLocation(TEXTURE_COORDS_ATTR, "textureCoord");
if(ShaderProgram::link()) {
bindUniformLocation(PROJECTION_MATRIX_UNIFORM, "projectionMatrix");
bindUniformLocation(TEXTURE_TRANSFORM_MATRIX_UNIFORM, "textureTransformMatrix");
bindUniformLocation(COLOR_UNIFORM, "color");
bindUniformLocation(OPACITY_UNIFORM, "opacity");
bindUniformLocation(TEXTURE_UNIFORM, "texture");
bindUniformLocation(TICKS_UNIFORM, "ticks");
return true;
}
return false;
}
void PainterShaderProgram::setProjectionMatrix(float projectionMatrix[3][3])
{
bind();
setUniformValue(PROJECTION_MATRIX_UNIFORM, projectionMatrix, true);
}
void PainterShaderProgram::setColor(const Color& color)
{
bind();
setUniformValue(COLOR_UNIFORM, color);
}
void PainterShaderProgram::setOpacity(GLfloat opacity)
{
bind();
setUniformValue(OPACITY_UNIFORM, opacity);
}
void PainterShaderProgram::setUniformTexture(int location, const TexturePtr& texture, int index)
{
if(!texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture->getId());
setUniformValue(location, index);
}
void PainterShaderProgram::setTexture(const TexturePtr& texture)
{
if(!texture)
return;
float w = texture->getGlSize().width();
float h = texture->getGlSize().height();
GLfloat textureTransformMatrix[2][2] = {
{ 1.0f/w, 0.0f },
{ 0.0f, 1.0f/h }
};
bind();
setUniformTexture(TEXTURE_UNIFORM, texture, 0);
setUniformValue(TEXTURE_TRANSFORM_MATRIX_UNIFORM, textureTransformMatrix, true);
}
void PainterShaderProgram::draw(const CoordsBuffer& coordsBuffer, DrawMode drawMode)
{
assert(bind());
setUniformValue(TICKS_UNIFORM, (GLfloat)g_clock.ticks());
int numVertices = coordsBuffer.getVertexCount();
if(numVertices == 0)
return;
bool mustDisableVertexArray = false;
if(coordsBuffer.getVertexCount() > 0) {
enableAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR);
setAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR, coordsBuffer.getVertices(), 2);
mustDisableVertexArray = true;
}
bool mustDisableTexCoordsArray = false;
if(coordsBuffer.getTextureCoords() > 0) {
enableAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR);
setAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR, coordsBuffer.getTextureCoords(), 2);
mustDisableTexCoordsArray = true;
}
glDrawArrays(drawMode, 0, numVertices);
if(mustDisableVertexArray)
disableAttributeArray(PainterShaderProgram::VERTEX_COORDS_ATTR);
if(mustDisableTexCoordsArray)
disableAttributeArray(PainterShaderProgram::TEXTURE_COORDS_ATTR);
//release();
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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"
#include "coordsbuffer.h"
class PainterShaderProgram : public ShaderProgram
{
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,
TICKS_UNIFORM = 5
};
public:
enum DrawMode {
Triangles = GL_TRIANGLES,
TriangleStrip = GL_TRIANGLE_STRIP
};
bool link();
void setProjectionMatrix(GLfloat projectionMatrix[3][3]);
void setColor(const Color& color);
void setOpacity(GLfloat opacity);
void setTexture(const TexturePtr& texture);
void setUniformTexture(int location, const TexturePtr& texture, int index);
void draw(const CoordsBuffer& coordsBuffer, DrawMode drawMode = Triangles);
private:
DrawMode m_drawMode;
};
#endif

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 std::string glslMainVertexShader = "\n\
highp vec4 calculatePosition();\n\
void main() {\n\
gl_Position = calculatePosition();\n\
}\n";
static const std::string glslMainWithTexCoordsVertexShader = "\n\
attribute highp vec2 textureCoord;\n\
uniform highp mat2 textureTransformMatrix;\n\
varying highp vec2 textureCoords;\n\
highp vec4 calculatePosition();\n\
void main()\n\
{\n\
gl_Position = calculatePosition();\n\
textureCoords = textureTransformMatrix * textureCoord;\n\
}\n";
static std::string glslPositionOnlyVertexShader = "\n\
attribute highp vec2 vertexCoord;\n\
uniform highp mat3 projectionMatrix;\n\
highp vec4 calculatePosition() {\n\
return vec4(projectionMatrix * vec3(vertexCoord.xy, 1), 1);\n\
}\n";
static const std::string glslMainFragmentShader = "\n\
uniform lowp float opacity;\n\
lowp vec4 calculatePixel();\n\
void main()\n\
{\n\
gl_FragColor = calculatePixel() * opacity;\n\
}\n";
static const std::string glslTextureSrcFragmentShader = "\n\
varying mediump vec2 textureCoords;\n\
uniform lowp vec4 color;\n\
uniform sampler2D texture;\n\
lowp vec4 calculatePixel() {\n\
return texture2D(texture, textureCoords) * color;\n\
}\n";
static const std::string glslSolidColorFragmentShader = "\n\
uniform lowp vec4 color;\n\
lowp vec4 calculatePixel() {\n\
return color;\n\
}\n";

View File

@ -19,19 +19,19 @@ Particle::Particle(const Rect& rect, float vx, float vy, float ax, float ay, flo
Particle::~Particle()
{
dump << "deleted";
//dump << "deleted";
}
void Particle::render()
{
g_graphics.bindColor(m_color);
g_painter.setColor(m_color);
if(!m_texture)
g_graphics.drawFilledRect(m_rect);
g_painter.drawFilledRect(m_rect);
else {
g_graphics.bindBlendFunc(Fw::BlendParticles);
g_graphics.drawTexturedRect(m_rect, m_texture);
g_graphics.bindBlendFunc(Fw::BlendDefault);
g_painter.setCompositionMode(Painter::CompositionMode_AdditiveSource);
g_painter.drawTexturedRect(m_rect, m_texture);
g_painter.setCompositionMode(Painter::CompositionMode_SourceOver);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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"
#include <framework/core/resourcemanager.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)
{
#ifndef OPENGL_ES2
static const char *qualifierDefines =
"#define lowp\n"
"#define mediump\n"
"#define highp\n";
#else
static const char *qualifierDefines =
"#ifndef GL_FRAGMENT_PRECISION_HIGH\n"
"#define highp mediump\n"
"#endif\n";
#endif
std::string code = qualifierDefines;
code.append(sourceCode);
const char *c_source = code.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::string sourceCode = g_resources.loadFile(sourceFile);
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<char> buf(infoLogLength);
glGetShaderInfoLog(m_shaderId, infoLogLength-1, NULL, &buf[0]);
infoLog = &buf[0];
}
return infoLog;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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<char> 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 < MAX_UNIFORM_LOCATIONS);
m_uniformLocations[location] = glGetUniformLocation(m_programId, name);
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 = 30
};
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();
virtual 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, const Color& color) { glUniform4f(m_uniformLocations[location], color.r() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f); }
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, const Color& color) { glUniform4f(glGetUniformLocation(m_programId, name), color.r() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f); }
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<GLint, MAX_UNIFORM_LOCATIONS> m_uniformLocations;
};
#endif

View File

@ -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<uint8> 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;
}

View File

@ -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<uint8> 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;
};

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 "textureglyphcache.h"

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 TEXTUREGLYPHCACHE_H
#define TEXTUREGLYPHCACHE_H
class TextureGlyphCache
{
};
#endif

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 VERTEXARRAY_H
#define VERTEXARRAY_H
#include "declarations.h"
#include <framework/util/databuffer.h>
class VertexArray
{
public:
inline void addVertex(GLfloat x, GLfloat y) { m_buffer << x << y; }
inline void addRect(const Rect& rect) {
GLfloat top = rect.top();
GLfloat right = rect.right()+1;
GLfloat bottom = rect.bottom()+1;
GLfloat left = rect.left();
addVertex(left, top);
addVertex(right, top);
addVertex(left, bottom);
addVertex(left, bottom);
addVertex(right, top);
addVertex(right, bottom);
}
inline void addQuad(const Rect& rect) {
GLfloat top = rect.top();
GLfloat right = rect.right()+1;
GLfloat bottom = rect.bottom()+1;
GLfloat left = rect.left();
addVertex(left, top);
addVertex(right, top);
addVertex(left, bottom);
addVertex(right, bottom);
}
void clear() { m_buffer.reset(); }
GLfloat *vertices() const { return m_buffer.data(); }
int vertexCount() const { return m_buffer.size() / 2; }
private:
DataBuffer<GLfloat> m_buffer;
};
#endif

View File

@ -36,73 +36,110 @@ void Application::registerLuaFunctions()
// UIWidget
g_lua.registerClass<UIWidget>();
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create<UIWidget>);
g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId);
g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
g_lua.bindClassMemberFunction<UIWidget>("setEnabled", &UIWidget::setEnabled);
g_lua.bindClassMemberFunction<UIWidget>("isExplicitlyVisible", &UIWidget::isExplicitlyVisible);
g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy);
g_lua.bindClassMemberFunction<UIWidget>("setVisible", &UIWidget::setVisible);
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth);
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth);
g_lua.bindClassMemberFunction<UIWidget>("getHeight", &UIWidget::getHeight);
g_lua.bindClassMemberFunction<UIWidget>("setHeight", &UIWidget::setHeight);
g_lua.bindClassMemberFunction<UIWidget>("getSize", &UIWidget::getSize);
g_lua.bindClassMemberFunction<UIWidget>("setSize", &UIWidget::resize);
g_lua.bindClassMemberFunction<UIWidget>("getPosition", &UIWidget::getPosition);
g_lua.bindClassMemberFunction<UIWidget>("getX", &UIWidget::getX);
g_lua.bindClassMemberFunction<UIWidget>("getY", &UIWidget::getY);
g_lua.bindClassMemberFunction<UIWidget>("moveTo", &UIWidget::moveTo);
g_lua.bindClassMemberFunction<UIWidget>("moveChildToIndex", &UIWidget::moveChildToIndex);
g_lua.bindClassMemberFunction<UIWidget>("getParent", &UIWidget::getParent);
g_lua.bindClassMemberFunction<UIWidget>("setParent", &UIWidget::setParent);
g_lua.bindClassMemberFunction<UIWidget>("getBackgroundColor", &UIWidget::getBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setBackgroundColor", &UIWidget::setBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getForegroundColor", &UIWidget::getForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setForegroundColor", &UIWidget::setForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getOpacity", &UIWidget::getOpacity);
g_lua.bindClassMemberFunction<UIWidget>("setOpacity", &UIWidget::setOpacity);
g_lua.bindClassMemberFunction<UIWidget>("setEnabled", &UIWidget::setEnabled);
g_lua.bindClassMemberFunction<UIWidget>("setPressed", &UIWidget::setPressed);
g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
g_lua.bindClassMemberFunction<UIWidget>("setFocusable", &UIWidget::setFocusable);
g_lua.bindClassMemberFunction<UIWidget>("setPhantom", &UIWidget::setPhantom);
g_lua.bindClassMemberFunction<UIWidget>("setStyle", &UIWidget::setStyle);
g_lua.bindClassMemberFunction<UIWidget>("applyStyle", &UIWidget::applyStyle);
g_lua.bindClassMemberFunction<UIWidget>("getStyle", &UIWidget::getStyle);
g_lua.bindClassMemberFunction<UIWidget>("getMarginTop", &UIWidget::getMarginTop);
g_lua.bindClassMemberFunction<UIWidget>("setStyleFromNode", &UIWidget::setStyleFromNode);
//g_lua.bindClassMemberFunction<UIWidget>("setLayout", &UIWidget::setLayout);
g_lua.bindClassMemberFunction<UIWidget>("setParent", &UIWidget::setParent);
g_lua.bindClassMemberFunction<UIWidget>("setRect", &UIWidget::setRect);
g_lua.bindClassMemberFunction<UIWidget>("setX", &UIWidget::setX);
g_lua.bindClassMemberFunction<UIWidget>("setY", &UIWidget::setY);
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth);
g_lua.bindClassMemberFunction<UIWidget>("setHeight", &UIWidget::setHeight);
//g_lua.bindClassMemberFunction<UIWidget>("setImage", &UIWidget::setImage);
//g_lua.bindClassMemberFunction<UIWidget>("setFont", &UIWidget::setFont);
g_lua.bindClassMemberFunction<UIWidget>("setOpacity", &UIWidget::setOpacity);
g_lua.bindClassMemberFunction<UIWidget>("setBackgroundColor", &UIWidget::setBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setForegroundColor", &UIWidget::setForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setMarginTop", &UIWidget::setMarginTop);
g_lua.bindClassMemberFunction<UIWidget>("getMarginBottom", &UIWidget::getMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("setMarginBottom", &UIWidget::setMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("getMarginLeft", &UIWidget::getMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("setMarginLeft", &UIWidget::setMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("getMarginRight", &UIWidget::getMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("setMarginRight", &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible);
g_lua.bindClassMemberFunction<UIWidget>("isHidden", &UIWidget::isHidden);
g_lua.bindClassMemberFunction<UIWidget>("isHovered", &UIWidget::isHovered);
g_lua.bindClassMemberFunction<UIWidget>("isFocused", &UIWidget::isFocused);
g_lua.bindClassMemberFunction<UIWidget>("isPressed", &UIWidget::isPressed);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
g_lua.bindClassMemberFunction<UIWidget>("isDisabled", &UIWidget::isDisabled);
g_lua.bindClassMemberFunction<UIWidget>("isActive", &UIWidget::isActive);
g_lua.bindClassMemberFunction<UIWidget>("setMarginBottom", &UIWidget::setMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("setMarginLeft", &UIWidget::setMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("setSizeFixed", &UIWidget::setSizeFixed);
g_lua.bindClassMemberFunction<UIWidget>("setLastFocusReason", &UIWidget::setLastFocusReason);
g_lua.bindClassMemberFunction<UIWidget>("resize", &UIWidget::resize);
g_lua.bindClassMemberFunction<UIWidget>("moveTo", &UIWidget::moveTo);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show);
g_lua.bindClassMemberFunction<UIWidget>("disable", &UIWidget::disable);
g_lua.bindClassMemberFunction<UIWidget>("enable", &UIWidget::enable);
g_lua.bindClassMemberFunction<UIWidget>("lock", &UIWidget::lock);
g_lua.bindClassMemberFunction<UIWidget>("unlock", &UIWidget::unlock);
g_lua.bindClassMemberFunction<UIWidget>("focus", &UIWidget::focus);
g_lua.bindClassMemberFunction<UIWidget>("getChildren", &UIWidget::getChildren);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
g_lua.bindClassMemberFunction<UIWidget>("isActive", &UIWidget::isActive);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
g_lua.bindClassMemberFunction<UIWidget>("isDisabled", &UIWidget::isDisabled);
g_lua.bindClassMemberFunction<UIWidget>("isFocused", &UIWidget::isFocused);
g_lua.bindClassMemberFunction<UIWidget>("isHovered", &UIWidget::isHovered);
g_lua.bindClassMemberFunction<UIWidget>("isPressed", &UIWidget::isPressed);
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible);
g_lua.bindClassMemberFunction<UIWidget>("isHidden", &UIWidget::isHidden);
g_lua.bindClassMemberFunction<UIWidget>("isExplicitlyEnabled", &UIWidget::isExplicitlyEnabled);
g_lua.bindClassMemberFunction<UIWidget>("isExplicitlyVisible", &UIWidget::isExplicitlyVisible);
g_lua.bindClassMemberFunction<UIWidget>("isFocusable", &UIWidget::isFocusable);
g_lua.bindClassMemberFunction<UIWidget>("isPhantom", &UIWidget::isPhantom);
g_lua.bindClassMemberFunction<UIWidget>("isSizeFixed", &UIWidget::isSizeFixed);
g_lua.bindClassMemberFunction<UIWidget>("hasChildren", &UIWidget::hasChildren);
g_lua.bindClassMemberFunction<UIWidget>("hasChild", &UIWidget::hasChild);
g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId);
g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount);
//g_lua.bindClassMemberFunction<UIWidget>("getLayout", &UIWidget::getLayout);
g_lua.bindClassMemberFunction<UIWidget>("getParent", &UIWidget::getParent);
g_lua.bindClassMemberFunction<UIWidget>("getRootParent", &UIWidget::getRootParent);
g_lua.bindClassMemberFunction<UIWidget>("getPosition", &UIWidget::getPosition);
g_lua.bindClassMemberFunction<UIWidget>("getSize", &UIWidget::getSize);
g_lua.bindClassMemberFunction<UIWidget>("getRect", &UIWidget::getRect);
g_lua.bindClassMemberFunction<UIWidget>("getX", &UIWidget::getX);
g_lua.bindClassMemberFunction<UIWidget>("getY", &UIWidget::getY);
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth);
g_lua.bindClassMemberFunction<UIWidget>("getHeight", &UIWidget::getHeight);
//g_lua.bindClassMemberFunction<UIWidget>("getImage", &UIWidget::getImage);
//g_lua.bindClassMemberFunction<UIWidget>("getFont", &UIWidget::getFont);
g_lua.bindClassMemberFunction<UIWidget>("getForegroundColor", &UIWidget::getForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getBackgroundColor", &UIWidget::getBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getOpacity", &UIWidget::getOpacity);
g_lua.bindClassMemberFunction<UIWidget>("getMarginTop", &UIWidget::getMarginTop);
g_lua.bindClassMemberFunction<UIWidget>("getMarginRight", &UIWidget::getMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("getMarginBottom", &UIWidget::getMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("getMarginLeft", &UIWidget::getMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("getLastFocusReason", &UIWidget::getLastFocusReason);
g_lua.bindClassMemberFunction<UIWidget>("getStyle", &UIWidget::getStyle);
g_lua.bindClassMemberFunction<UIWidget>("getChildren", &UIWidget::getChildren);
g_lua.bindClassMemberFunction<UIWidget>("getFocusedChild", &UIWidget::getFocusedChild);
g_lua.bindClassMemberFunction<UIWidget>("getChildAfter", &UIWidget::getChildAfter);
g_lua.bindClassMemberFunction<UIWidget>("getChildBefore", &UIWidget::getChildBefore);
g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("getChildByPos", &UIWidget::getChildByPos);
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos);
g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild);
g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild);
g_lua.bindClassMemberFunction<UIWidget>("hasChild", &UIWidget::hasChild);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
g_lua.bindClassMemberFunction<UIWidget>("focusChild", &UIWidget::focusChild);
g_lua.bindClassMemberFunction<UIWidget>("focusNextChild", &UIWidget::focusNextChild);
g_lua.bindClassMemberFunction<UIWidget>("focusPreviousChild", &UIWidget::focusPreviousChild);
g_lua.bindClassMemberFunction<UIWidget>("moveChildToTop", &UIWidget::moveChildToTop);
g_lua.bindClassMemberFunction<UIWidget>("moveChildToIndex", &UIWidget::moveChildToIndex);
g_lua.bindClassMemberFunction<UIWidget>("lockChild", &UIWidget::lockChild);
g_lua.bindClassMemberFunction<UIWidget>("unlockChild", &UIWidget::unlockChild);
g_lua.bindClassMemberFunction<UIWidget>("updateLayout", &UIWidget::updateLayout);
g_lua.bindClassMemberFunction<UIWidget>("isChildLocked", &UIWidget::isChildLocked);
g_lua.bindClassMemberFunction<UIWidget>("getChildIndex", &UIWidget::getChildIndex);
g_lua.bindClassMemberFunction<UIWidget>("updateParentLayout", &UIWidget::updateParentLayout);
g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy);
g_lua.bindClassMemberFunction<UIWidget>("updateLayout", &UIWidget::updateLayout);
g_lua.bindClassMemberFunction<UIWidget>("updateStates", &UIWidget::updateStates);
g_lua.bindClassMemberFunction<UIWidget>("updateState", &UIWidget::updateState);
g_lua.bindClassMemberFunction<UIWidget>("setState", &UIWidget::setState);
g_lua.bindClassMemberFunction<UIWidget>("hasState", &UIWidget::hasState);
g_lua.bindClassMemberFunction<UIWidget>("updateStyle", &UIWidget::updateStyle);
g_lua.bindClassMemberFunction<UIWidget>("applyStyle", &UIWidget::applyStyle);
// UILabel
g_lua.registerClass<UILabel, UIWidget>();
@ -175,12 +212,27 @@ void Application::registerLuaFunctions()
g_lua.bindClassStaticFunction<Logger>("fireOldMessages", std::bind(&Logger::fireOldMessages, &g_logger));
g_lua.bindClassStaticFunction<Logger>("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));
}

View File

@ -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
};

View File

@ -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;

View File

@ -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);
}

View File

@ -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<textLength;++i)
g_graphics.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]);
g_painter.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]);
// render cursor
if(isExplicitlyEnabled() && (isActive() || m_alwaysActive) && m_cursorPos >= 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();
}

View File

@ -25,6 +25,7 @@
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
#include <framework/platform/platformwindow.h>
UIManager g_ui;
@ -33,7 +34,7 @@ void UIManager::init()
// creates root widget
m_rootWidget = UIWidget::create<UIWidget>();
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);
if(widget) {
widget->setStyleFromNode(styleNode);
for(const OTMLNodePtr& childNode : widgetNode->children()) {
if(!childNode->isUnique())
loadWidgetFromOTML(childNode, widget);
}
} else
logError("Unable to create widget of type '", widgetType, "'");
return widget;
}

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/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 DATABUFFER_H
#define DATABUFFER_H
template<class T>
class DataBuffer
{
public:
DataBuffer(int res = 64) {
m_capacity = res;
m_buffer = new T[m_capacity];
m_size = 0;
}
~DataBuffer() { delete[] m_buffer; }
inline void reset() { m_size = 0; }
inline bool isEmpty() const { return m_size == 0; }
inline int size() const { return m_size; }
inline T *data() const { return m_buffer; }
inline const T& at(int i) const { return m_buffer[i]; }
inline const T& last() const { return m_buffer[m_size-1]; }
inline const T& first() const { return m_buffer[0]; }
inline const T& operator[](int i) const { return m_buffer[i]; }
inline T& operator[](int i) { return m_buffer[i]; }
inline void add(const T &t) {
if(m_size >= m_capacity) {
m_capacity *= 2;
T *buffer = new T[m_capacity];
for(int i=0;i<m_size;++i)
buffer[i] = m_buffer[i];
delete[] m_buffer;
m_buffer = buffer;
}
m_buffer[m_size++] = t;
}
inline DataBuffer &operator<<(const T &t) { add(t); return *this; }
private:
int m_size;
int m_capacity;
T *m_buffer;
};
#endif

View File

@ -78,8 +78,8 @@ public:
void setBottomLeft(const TPoint<T> &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<T>& 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<T>& 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; }

View File

@ -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<T>& size)
{
T w, h;
in >> w >> h;
size.setSize(w, h);
size.resize(w, h);
return in;
}

View File

@ -30,6 +30,8 @@
#include <sstream>
#include <exception>
#include <cxxabi.h>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "types.h"
#include "exception.h"
@ -258,6 +260,16 @@ inline std::string ip2str(uint32 ip) {
return std::string(host);
}
template<typename T = std::string>
std::vector<T> split(const std::string& str, const std::string& separators = " ") {
std::vector<std::string> splitted;
boost::split(splitted, str, boost::is_any_of(std::string(separators)));
std::vector<T> results(splitted.size());
for(uint i=0;i<splitted.size();++i)
results[i] = Fw::safeCast<T>(splitted[i]);
return results;
}
template<typename... T>
void throwException(const T&... args) {
throw Exception(Fw::mkstr(args...));

View File

@ -25,9 +25,9 @@
int main(int argc, const char* argv[])
{
std::vector<std::string> args(argv, argv + argc);
OTClient otclient;
otclient.init(args);
otclient.run();
otclient.terminate();
OTClient app;
app.init(args);
app.run();
app.terminate();
return 0;
}

View File

@ -250,14 +250,6 @@ namespace Otc
ClientGetObjectInfo = 243
};
enum SpriteMask {
SpriteRedMask = 0,
SpriteGreenMask,
SpriteBlueMask,
SpriteYellowMask,
SpriteNoMask = 255
};
enum InventorySlots {
InventorySlotHead = 1,
InventorySlotNecklace,

View File

@ -31,6 +31,10 @@
#include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/paintershadersources.h>
#include "spritemanager.h"
Creature::Creature() : Thing()
{
m_healthPercent = 0;
@ -43,12 +47,31 @@ Creature::Creature() : Thing()
m_informationFont = g_fonts.getFont("verdana-11px-rounded");
}
PainterShaderProgramPtr outfitProgram;
int HEAD_COLOR_UNIFORM = 10;
int BODY_COLOR_UNIFORM = 11;
int LEGS_COLOR_UNIFORM = 12;
int FEET_COLOR_UNIFORM = 13;
int MASK_TEXTURE_UNIFORM = 14;
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);
}
if(!outfitProgram) {
outfitProgram = PainterShaderProgramPtr(new PainterShaderProgram);
outfitProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
outfitProgram->addShaderFromSourceFile(Shader::Fragment, "/outfit.frag");
assert(outfitProgram->link());
outfitProgram->bindUniformLocation(HEAD_COLOR_UNIFORM, "headColor");
outfitProgram->bindUniformLocation(BODY_COLOR_UNIFORM, "bodyColor");
outfitProgram->bindUniformLocation(LEGS_COLOR_UNIFORM, "legsColor");
outfitProgram->bindUniformLocation(FEET_COLOR_UNIFORM, "feetColor");
outfitProgram->bindUniformLocation(MASK_TEXTURE_UNIFORM, "maskTexture");
}
// Render creature
@ -58,35 +81,52 @@ void Creature::draw(const Point& p)
if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1))))
continue;
// draw white item
g_graphics.bindColor(Fw::white);
internalDraw(p + m_walkOffset, 0);
g_painter.setCustomProgram(outfitProgram);
// draw mask if exists
outfitProgram->bind();
outfitProgram->setUniformValue(HEAD_COLOR_UNIFORM, m_outfit.getHeadColor());
outfitProgram->setUniformValue(BODY_COLOR_UNIFORM, m_outfit.getBodyColor());
outfitProgram->setUniformValue(LEGS_COLOR_UNIFORM, m_outfit.getLegsColor());
outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor());
for(int yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) {
for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) {
int sprIndex = ((((((m_animation % m_type->dimensions[ThingType::AnimationPhases])
* m_type->dimensions[ThingType::PatternZ] + m_zPattern)
* m_type->dimensions[ThingType::PatternY] + m_yPattern)
* m_type->dimensions[ThingType::PatternX] + m_xPattern)
* m_type->dimensions[ThingType::Layers] + 0)
* m_type->dimensions[ThingType::Height] + yi)
* m_type->dimensions[ThingType::Width] + xi;
if(m_type->dimensions[ThingType::Layers] > 1) {
// switch to blend color mode
g_graphics.bindBlendFunc(Fw::BlendColorzing);
// head
g_graphics.bindColor(m_outfit.getHeadColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteYellowMask);
// body
g_graphics.bindColor(m_outfit.getBodyColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteRedMask);
// legs
g_graphics.bindColor(m_outfit.getLegsColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteGreenMask);
// feet
g_graphics.bindColor(m_outfit.getFeetColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteBlueMask);
// restore default blend func
g_graphics.bindBlendFunc(Fw::BlendDefault);
g_graphics.bindColor(Fw::white);
int maskIndex = ((((((m_animation % m_type->dimensions[ThingType::AnimationPhases])
* m_type->dimensions[ThingType::PatternZ] + m_zPattern)
* m_type->dimensions[ThingType::PatternY] + m_yPattern)
* m_type->dimensions[ThingType::PatternX] + m_xPattern)
* m_type->dimensions[ThingType::Layers] + 1)
* m_type->dimensions[ThingType::Height] + yi)
* m_type->dimensions[ThingType::Width] + xi;
int spriteId = m_type->sprites[maskIndex];
if(!spriteId)
continue;
TexturePtr maskTex = g_sprites.getSpriteTexture(spriteId);
outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1);
}
int spriteId = m_type->sprites[sprIndex];
if(!spriteId)
continue;
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
Rect drawRect(((p + m_walkOffset).x - xi*32) - m_type->parameters[ThingType::DisplacementX],
((p + m_walkOffset).y - yi*32) - m_type->parameters[ThingType::DisplacementY],
32, 32);
g_painter.drawTexturedRect(drawRect, spriteTex);
}
}
g_painter.releaseCustomProgram();
}
}
@ -115,11 +155,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);
}

View File

@ -28,7 +28,9 @@
#include "missile.h"
#include <framework/graphics/graphics.h>
#include <framework/graphics/framebuffer.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/paintershadersources.h>
#include <framework/graphics/texture.h>
Map g_map;
Map::Map()
@ -36,12 +38,20 @@ Map::Map()
setVisibleSize(Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT));
}
PainterShaderProgramPtr program;
void Map::draw(const Rect& rect)
{
if(!m_framebuffer)
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);
program = PainterShaderProgramPtr(new PainterShaderProgram);
program->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
program->addShaderFromSourceFile(Shader::Fragment, "/shadertest.frag");
assert(program->link());
}
g_painter.setColor(Fw::white);
m_framebuffer->bind();
// draw offsets
@ -80,10 +90,13 @@ void Map::draw(const Rect& rect)
}
}
m_framebuffer->unbind();
m_framebuffer->release();
g_graphics.bindColor(Fw::white);
g_painter.setCustomProgram(program);
g_painter.setColor(Fw::white);
m_framebuffer->draw(rect);
g_painter.releaseCustomProgram();
// calculate stretch factor
float horizontalStretchFactor = rect.width() / (float)(m_visibleSize.width() * NUM_TILE_PIXELS);

View File

@ -118,30 +118,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
return TexturePtr(new Texture(32, 32, 4, pixels));
}
TexturePtr SpriteManager::loadSpriteMask(TexturePtr spriteTex, Otc::SpriteMask mask)
{
auto pixels = spriteTex->getPixels();
static uint32 maskColors[4] = { Fw::red, Fw::green, Fw::blue, Fw::yellow };
uint32 maskColor = maskColors[mask];
uint32 whiteColor = Fw::white;
uint32 alphaColor = Fw::alpha;
// convert pixels
// masked color -> white color
// any other color -> alpha color
for(int i=0;i<4096;i+=4) {
uint32& currentColor = *(uint32*)&pixels[i];
if(currentColor == maskColor)
currentColor = whiteColor;
else
currentColor = alphaColor;
}
return TexturePtr(new Texture(32, 32, 4, &pixels[0]));
}
TexturePtr SpriteManager::getSpriteTexture(int id, Otc::SpriteMask mask)
TexturePtr SpriteManager::getSpriteTexture(int id)
{
if(id == 0)
return g_graphics.getEmptyTexture();
@ -149,17 +126,11 @@ TexturePtr SpriteManager::getSpriteTexture(int id, Otc::SpriteMask mask)
assert(id > 0 && id <= m_spritesCount);
// load sprites on demand
Sprite& sprite = m_sprites[id-1];
if(!sprite.texture)
sprite.texture = loadSpriteTexture(id);
TexturePtr& sprite = m_sprites[id-1];
if(!sprite)
sprite = loadSpriteTexture(id);
//TODO: release unused sprites textures after X seconds
// to avoid massive texture allocations
if(mask != Otc::SpriteNoMask) {
if(!sprite.masks[mask])
sprite.masks[mask] = loadSpriteMask(sprite.texture, mask);
return sprite.masks[mask];
} else
return sprite.texture;
return sprite;
}

View File

@ -26,11 +26,6 @@
#include "declarations.h"
#include <framework/graphics/texture.h>
struct Sprite {
TexturePtr texture;
TexturePtr masks[4];
};
class SpriteManager
{
public:
@ -42,16 +37,15 @@ public:
uint32 getSignature() { return m_signature; }
int getSpritesCount() { return m_spritesCount; }
TexturePtr getSpriteTexture(int id, Otc::SpriteMask mask = Otc::SpriteNoMask);
TexturePtr getSpriteTexture(int id);
private:
TexturePtr loadSpriteTexture(int id);
TexturePtr loadSpriteMask(TexturePtr spriteTex, Otc::SpriteMask mask);
uint32 m_signature;
uint16 m_spritesCount;
std::stringstream m_fin;
std::vector<Sprite> m_sprites;
std::vector<TexturePtr> m_sprites;
TexturePtr m_transparentSprite;
};

View File

@ -34,7 +34,7 @@ Thing::Thing() : m_id(0)
m_type = g_thingsType.getEmptyThingType();
}
void Thing::internalDraw(const Point& p, int layers, Otc::SpriteMask mask)
void Thing::internalDraw(const Point& p, int layers)
{
for(int yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) {
for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) {
@ -50,12 +50,12 @@ void Thing::internalDraw(const Point& p, int layers, Otc::SpriteMask mask)
if(!spriteId)
continue;
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId, mask);
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
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);
}
}
}

View File

@ -63,7 +63,7 @@ public:
virtual LocalPlayerPtr asLocalPlayer() { return nullptr; }
protected:
void internalDraw(const Point& p, int layers, Otc::SpriteMask mask = Otc::SpriteNoMask);
void internalDraw(const Point& p, int layers);
uint32 m_id;
Position m_position;

View File

@ -36,6 +36,5 @@ void OTClient::init(const std::vector<std::string>& args)
g_modules.discoverModules();
g_modules.autoLoadModules(100);
g_modules.ensureModuleLoaded("client");
g_modules.ensureModuleLoaded("game");
g_modules.autoLoadModules(1000);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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