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 todo display otclient icon in window bar
remake otui styles states system remake otui styles states system
padding padding
break UILabel lines
rename Game to g_game, etc rename Game to g_game, etc
implement Console key binding implement Console key binding
fatal error if sprite load fails
impl vertical sync, clipboard impl vertical sync, clipboard
crash handler crash handler
modify COnnection::poll() modify COnnection::poll()
@ -30,3 +29,12 @@ use metatable for Point,Rect,Color,Size lua classes
lua binder generator lua binder generator
restore win32 platform restore win32 platform
set special types for g_configs like lists/point/size 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() local cursorPos = commandLineEdit:getCursorPos()
if cursorPos == 0 then return end if cursorPos == 0 then return end
local commandBegin = string.sub(commandLineEdit:getText(), 1, cursorPos) local commandBegin = commandLineEdit:getText():sub(1, cursorPos)
local possibleCommands = {} local possibleCommands = {}
-- create a list containing all globals -- create a list containing all globals
@ -43,7 +43,7 @@ local function completeCommand()
-- match commands -- match commands
for k,v in pairs(allVars) do 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) table.insert(possibleCommands, k)
end end
end end
@ -63,9 +63,9 @@ local function completeCommand()
if #possibleCommands[1] < cursorPos then if #possibleCommands[1] < cursorPos then
break break
end end
expandedComplete = commandBegin .. string.sub(possibleCommands[1], cursorPos, cursorPos) expandedComplete = commandBegin .. possibleCommands[1]:sub(cursorPos, cursorPos)
for i,v in ipairs(possibleCommands) do for i,v in ipairs(possibleCommands) do
if string.sub(v, 1, #expandedComplete) ~= expandedComplete then if v:sub(1, #expandedComplete) ~= expandedComplete then
done = true done = true
end end
end end

View File

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

View File

@ -3,7 +3,7 @@ Client = { }
-- TODO: load and save configurations -- TODO: load and save configurations
function Client.init() function Client.init()
g_window.move({ x=220, y=220 }) 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.setTitle('OTClient')
g_window.setIcon('clienticon.png') g_window.setIcon('clienticon.png')
return true return true

View File

@ -23,8 +23,8 @@ local function onError(protocol, error)
end end
local function onMotd(protocol, motd) local function onMotd(protocol, motd)
motdNumber = tonumber(string.sub(motd, 0, string.find(motd, "\n"))) motdNumber = tonumber(motd:sub(0, motd:find("\n")))
motdMessage = string.sub(motd, string.find(motd, "\n") + 1, string.len(motd)) motdMessage = motd:sub(motd:find("\n") + 1, #motd)
TopMenu.getButton('motdButton'):show() TopMenu.getButton('motdButton'):show()
end end

View File

@ -7,7 +7,7 @@ local vsyncEnabled = false
function getConfig(name, default) function getConfig(name, default)
if g_configs.exists(name) then 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 if val == 'true' or val == 'false' then
return toboolean(val) return toboolean(val)
else else

View File

@ -1,4 +1,3 @@
-- AnchorEdge
AnchorNone = 0 AnchorNone = 0
AnchorTop = 1 AnchorTop = 1
AnchorBottom = 2 AnchorBottom = 2
@ -15,9 +14,6 @@ LogFatal = 4
ActiveFocusReason = 2 ActiveFocusReason = 2
EmptyFunction = function() end
-- KeyCodes
KeyUnknown = 0 KeyUnknown = 0
KeyEscape = 1 KeyEscape = 1
KeyTab = 2 KeyTab = 2
@ -57,7 +53,7 @@ KeyLeftParen = 40 -- (
KeyRightParen = 41 -- ) KeyRightParen = 41 -- )
KeyAsterisk = 42 -- * KeyAsterisk = 42 -- *
KeyPlus = 43 -- + KeyPlus = 43 -- +
KeyComma = 44 -- KeyComma = 44 -- ,
KeyMinus = 45 -- - KeyMinus = 45 -- -
KeyPeriod = 46 -- . KeyPeriod = 46 -- .
KeySlash = 47 -- / KeySlash = 47 -- /

View File

@ -7,10 +7,14 @@ Module
onLoad: | onLoad: |
require 'ext/table' require 'ext/table'
require 'ext/string' require 'ext/string'
require 'constants' require 'util/point'
require 'util/size'
require 'util/color'
require 'util/rect'
require 'const'
require 'util' require 'util'
require 'dispatcher' require 'dispatcher'
require 'widget' require 'widget'
require 'ui' require 'ui'
require 'gfx' require 'effects'
return true return true

View File

@ -1,43 +1,33 @@
local eventId = 0 local eventId = 0
local eventsTable = { } local eventList = {}
local orig = { scheduleEvent = scheduleEvent,
addEvent = addEvent }
-- fix original scheduleEvent
function scheduleEvent(func, delay) function scheduleEvent(func, delay)
eventId = eventId + 1 eventId = eventId + 1
local id = eventId local id = eventId
local function proxyFunc() local function proxyFunc()
if eventsTable[id] then if eventList[id] then
func() if eventList[id].active then
eventsTable[id] = nil func()
end
eventList[id] = nil
end end
end end
eventsTable[id] = proxyFunc eventList[id] = { func = proxyFunc, active = true }
orig.scheduleEvent(proxyFunc, delay) if delay and delay > 0 then
g_dispatcher.scheduleEvent(proxyFunc, delay)
else
g_dispatcher.addEvent(proxyFunc, false)
end
return id return id
end end
-- FIXME: the event function can be collected function addEvent(func)
-- and the dispatcher would call an invalid function, generating an warning return scheduleEvent(func, 0)
end
function removeEvent(id) function removeEvent(id)
if id and eventsTable[id] then if id and eventList[id] then
eventsTable[id] = nil eventList[id].active = false
return true return true
end end
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 elapsed then elapsed = 0 end
if not time then time = 250 end if not time then time = 250 end
widget:setOpacity(math.min((255*elapsed)/time, 255)) widget:setOpacity(math.min((255*elapsed)/time, 255))
@ -11,7 +11,7 @@ function GFX.fadeIn(widget, time, elapsed)
end end
end end
function GFX.fadeOut(widget, time, elapsed) function Effects.fadeOut(widget, time, elapsed)
if not elapsed then elapsed = 0 end if not elapsed then elapsed = 0 end
if not time then time = 250 end if not time then time = 250 end
widget:setOpacity((255*(time - elapsed))/time) widget:setOpacity((255*(time - elapsed))/time)

View File

@ -13,12 +13,12 @@ function string:starts(start)
return self:sub(1, #start) == start return self:sub(1, #start) == start
end end
function string.trim(str) function string:trim()
return str:match'^%s*(.*%S)' or '' return self:match('^%s*(.*%S)') or ''
end end
function toboolean(str) function toboolean(str)
str = string.trim(str) str = str:trim()
if str == '1' or str == 'true' then if str == '1' or str == 'true' then
return true return true
end end

View File

@ -1,7 +1,7 @@
function table.dump(t, depth) function table.dump(t, depth)
if not depth then depth = 0 end if not depth then depth = 0 end
for k,v in pairs(t) do for k,v in pairs(t) do
str = string.rep(' ', depth * 2) .. k .. ': ' str = (' '):rep(depth * 2) .. k .. ': '
if type(v) ~= "table" then if type(v) ~= "table" then
print(str .. tostring(v)) print(str .. tostring(v))
else else

View File

@ -6,10 +6,8 @@ function print(...)
Logger.log(LogInfo, msg) Logger.log(LogInfo, msg)
end end
function createEnvironment() function fatal(msg)
local env = { } Logger.log(LogFatal, msg)
setmetatable(env, { __index = _G} )
return env
end end
function connect(object, signalsAndSlots, pushFront) function connect(object, signalsAndSlots, pushFront)
@ -28,10 +26,10 @@ function connect(object, signalsAndSlots, pushFront)
end end
end end
function dumpWidgets() function createEnvironment()
for i=1,UI.root:getChildCount() do local env = { }
print(UI.root:getChildByIndex(i):getId()) setmetatable(env, { __index = _G} )
end return env
end end
function getCallingScriptSourcePath(depth) function getCallingScriptSourcePath(depth)

View File

@ -28,7 +28,7 @@ function MessageBox.create(title, text, flags)
if flags == MessageBoxOk then if flags == MessageBoxOk then
buttonRight:setText("Ok") buttonRight:setText("Ok")
box.onOk = EmptyFunction box.onOk = function() end
buttonRight.onClick = function() buttonRight.onClick = function()
box.onOk() box.onOk()
box:destroy() box:destroy()
@ -37,7 +37,7 @@ function MessageBox.create(title, text, flags)
window.onEscape = buttonRight.onClick window.onEscape = buttonRight.onClick
elseif flags == MessageBoxCancel then elseif flags == MessageBoxCancel then
buttonRight:setText("Cancel") buttonRight:setText("Cancel")
box.onCancel = EmptyFunction box.onCancel = function() end
buttonRight.onClick = function() buttonRight.onClick = function()
box.onCancel() box.onCancel()
box:destroy() box:destroy()

View File

@ -28,7 +28,7 @@ function ToolTip.display(text)
local size = label:getSize() local size = label:getSize()
size.width = size.width + 4 size.width = size.width + 4
size.height = size.height + 4 size.height = size.height + 4
currentToolTip:setSize(size) currentToolTip:resize(size)
moveToolTip(currentToolTip) moveToolTip(currentToolTip)
end end
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) ENDIF(NO_CONSOLE)
ELSE(WIN32) ELSE(WIN32)
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic") 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) SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp)
ENDIF(WIN32) ENDIF(WIN32)
@ -135,6 +135,7 @@ SET(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/font.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/font.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.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/texture.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffer.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/framebuffer.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.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/image.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/particlesmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/particlesmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/particlessystem.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 # framework otml
${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp ${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp

View File

@ -32,6 +32,7 @@
#include <framework/ui/uiwidget.h> #include <framework/ui/uiwidget.h>
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/graphics/particlesmanager.h> #include <framework/graphics/particlesmanager.h>
#include <framework/graphics/painter.h>
#include <framework/luascript/luainterface.h> #include <framework/luascript/luainterface.h>
Application *g_app = nullptr; Application *g_app = nullptr;
@ -135,7 +136,6 @@ void Application::terminate()
// terminate graphics // terminate graphics
if(m_appFlags & Fw::AppEnableGraphics) { if(m_appFlags & Fw::AppEnableGraphics) {
g_ui.terminate(); g_ui.terminate();
g_graphics.terminate();
g_window.terminate(); g_window.terminate();
} }
@ -222,8 +222,8 @@ void Application::render()
void Application::resize(const Size& size) void Application::resize(const Size& size)
{ {
g_graphics.resize(size);
g_ui.resize(size); g_ui.resize(size);
g_graphics.resize(size);
} }
void Application::inputEvent(const InputEvent& event) void Application::inputEvent(const InputEvent& event)

View File

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

View File

@ -79,15 +79,13 @@ bool Module::load()
} }
} }
if(m_loadCallback) { if(m_loadCallback && !m_loadCallback()) {
m_loaded = m_loadCallback(); logError("Unable to load module '", m_name, "' because its onLoad event returned false");
if(!m_loaded) { return false;
logError("Unable to load module '", m_name, "' because its onLoad event returned false");
return false;
}
} }
logInfo("Loaded module '", m_name, "'"); logInfo("Loaded module '", m_name, "'");
m_loaded = true;
return true; return true;
} }

View File

@ -29,7 +29,7 @@ AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFra
Texture(), Texture(),
m_numFrames(numFrames) m_numFrames(numFrames)
{ {
m_size.setSize(width, height); m_size.resize(width, height);
m_framesTextureId.resize(numFrames); m_framesTextureId.resize(numFrames);
m_framesDelay.resize(numFrames); m_framesDelay.resize(numFrames);

View File

@ -133,72 +133,72 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
void BorderImage::draw(const Rect& screenCoords) void BorderImage::draw(const Rect& screenCoords)
{ {
//TODO: borderimage drawing could be optimized by caching the render into a texture //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; Rect rectCoords;
Size centerSize = screenCoords.size() - m_bordersSize; Size centerSize = screenCoords.size() - m_bordersSize;
g_graphics.bindTexture(m_texture); // first the center
g_graphics.startDrawing(); if(centerSize.area() > 0) {
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(),
screenCoords.top() + m_topBorderTexCoords.height(),
centerSize);
m_coordsBuffer.addRepeatedRects(rectCoords, m_centerTexCoords);
}
// first the center // top left corner
if(centerSize.area() > 0) { rectCoords = Rect(screenCoords.topLeft(),
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(), m_topLeftCornerTexCoords.size());
screenCoords.top() + m_topBorderTexCoords.height(), m_coordsBuffer.addRepeatedRects(rectCoords, m_topLeftCornerTexCoords);
centerSize);
g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_centerTexCoords); // top
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width(),
screenCoords.topLeft().y,
centerSize.width(),
m_topBorderTexCoords.height());
m_coordsBuffer.addRepeatedRects(rectCoords, m_topBorderTexCoords);
// top right corner
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(),
screenCoords.top(),
m_topRightCornerTexCoords.size());
m_coordsBuffer.addRepeatedRects(rectCoords, m_topRightCornerTexCoords);
// left
rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topLeftCornerTexCoords.height(),
m_leftBorderTexCoords.width(),
centerSize.height());
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());
m_coordsBuffer.addRepeatedRects(rectCoords, m_rightBorderTexCoords);
// bottom left corner
rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topLeftCornerTexCoords.height() + centerSize.height(),
m_bottomLeftCornerTexCoords.size());
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());
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());
m_coordsBuffer.addRepeatedRects(rectCoords, m_bottomRightCornerTexCoords);
} }
g_painter.drawTextureCoords(m_coordsBuffer, m_texture);
// top left corner
rectCoords = Rect(screenCoords.topLeft(),
m_topLeftCornerTexCoords.size());
g_graphics.drawTexturedRect(rectCoords, m_texture, m_topLeftCornerTexCoords);
// top
rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width(),
screenCoords.topLeft().y,
centerSize.width(),
m_topBorderTexCoords.height());
g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_topBorderTexCoords);
// 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);
// left
rectCoords = Rect(screenCoords.left(),
screenCoords.top() + m_topLeftCornerTexCoords.height(),
m_leftBorderTexCoords.width(),
centerSize.height());
g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_leftBorderTexCoords);
// right
rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(),
screenCoords.top() + m_topRightCornerTexCoords.height(),
m_rightBorderTexCoords.width(),
centerSize.height());
g_graphics.drawRepeatedTexturedRect(rectCoords, m_texture, m_rightBorderTexCoords);
// 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);
// 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);
// 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();
} }

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 Image;
class BorderImage; class BorderImage;
class FrameBuffer; class FrameBuffer;
class Shader;
class ShaderProgram;
class PainterShaderProgram;
typedef std::weak_ptr<Texture> TextureWeakPtr; 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<Image> ImagePtr;
typedef std::shared_ptr<BorderImage> BorderImagePtr; typedef std::shared_ptr<BorderImage> BorderImagePtr;
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr; 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 #endif

View File

@ -64,7 +64,7 @@ void Font::renderText(const std::string& text,
const Point& startPos, const Point& startPos,
const Color& color) const Color& color)
{ {
Size boxSize = g_graphics.getScreenSize() - startPos.toSize(); Size boxSize = g_graphics.getViewportSize() - startPos.toSize();
Rect screenCoords(startPos, boxSize); Rect screenCoords(startPos, boxSize);
renderText(text, screenCoords, Fw::AlignTopLeft, color); renderText(text, screenCoords, Fw::AlignTopLeft, color);
} }
@ -85,9 +85,7 @@ void Font::renderText(const std::string& text,
Size textBoxSize; Size textBoxSize;
const std::vector<Point>& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize); const std::vector<Point>& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
g_graphics.bindColor(color); g_painter.setColor(color);
g_graphics.bindTexture(m_texture);
g_graphics.startDrawing();
for(int i = 0; i < textLenght; ++i) { for(int i = 0; i < textLenght; ++i) {
int glyph = (uchar)text[i]; int glyph = (uchar)text[i];
@ -149,10 +147,8 @@ void Font::renderText(const std::string& text,
} }
// render glyph // 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, 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 // return if there is no text
if(textLength == 0) { if(textLength == 0) {
if(textBoxSize) if(textBoxSize)
textBoxSize->setSize(0,m_glyphHeight); textBoxSize->resize(0,m_glyphHeight);
return glyphsPositions; return glyphsPositions;
} }
@ -280,6 +276,6 @@ void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
lastColumnFilledPixels = columnFilledPixels; lastColumnFilledPixels = columnFilledPixels;
} }
// store glyph size // 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) FrameBuffer::FrameBuffer(int width, int height)
{ {
m_fbo = 0;
// create FBO texture // create FBO texture
m_texture = TexturePtr(new Texture(width, height, 4)); m_texture = TexturePtr(new Texture(width, height, 4));
m_texture->enableBilinearFilter(); m_texture->enableBilinearFilter();
// use FBO ext only if supported // generate FBO
if(g_graphics.isExtensionSupported("GL_ARB_framebuffer_object")) { glGenFramebuffers(1, &m_fbo);
m_fallbackOldImp = false; if(!m_fbo)
logFatal("Unable to create framebuffer object");
// generate FBO glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
// attach 2D texture to this 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); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status) { if(status != GL_FRAMEBUFFER_COMPLETE)
case GL_FRAMEBUFFER_COMPLETE_EXT: logFatal("Unable to create framebuffer object");
//ok
break;
default: // fallback to old implementation
m_fallbackOldImp = true;
break;
}
// restore back buffer // restore back buffer
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 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.");
} }
FrameBuffer::~FrameBuffer() FrameBuffer::~FrameBuffer()
{ {
if(m_fbo) glDeleteFramebuffers(1, &m_fbo);
glDeleteFramebuffers(1, &m_fbo);
} }
void FrameBuffer::bind() void FrameBuffer::bind()
{ {
if(!m_fallbackOldImp) { glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// bind framebuffer
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
} else {
int screenWidth = g_graphics.getScreenSize().width();
int screenHeight = g_graphics.getScreenSize().height();
if(!m_screenBackup || m_screenBackup->getSize() != g_graphics.getScreenSize())
m_screenBackup = TexturePtr(new Texture(screenWidth, screenHeight, 4));
// save screen state
glBindTexture(GL_TEXTURE_2D, m_screenBackup->getId());
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight);
}
// setup framebuffer viewport
glViewport(0, 0, m_texture->getWidth(), m_texture->getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, m_texture->getWidth(), m_texture->getHeight(), 0, -1, 1);
// back to model view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// clear framebuffer
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, m_texture->getWidth(), m_texture->getHeight());
g_painter.updateProjectionMatrix(m_texture->getSize(), true);
} }
void FrameBuffer::unbind() void FrameBuffer::release()
{ {
if(!m_fallbackOldImp) { // bind back buffer again
// bind back buffer again glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);
glReadBuffer(GL_BACK);
// restore graphics viewport // restore graphics viewport
g_graphics.restoreViewport(); glViewport(0, 0, g_graphics.getViewportSize().width(), g_graphics.getViewportSize().height());
} else { g_painter.updateProjectionMatrix(g_graphics.getViewportSize());
// 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);
}
} }
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(); virtual ~FrameBuffer();
void bind(); void bind();
void unbind(); void release();
void draw(const Rect& screenCoords, const Rect& framebufferCoords = Rect()); void draw(const Rect& dest);
TexturePtr getTexture() { return m_texture; } 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() void Graphics::init()
{ {
// setup opengl // 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); 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("GPU ", glGetString(GL_RENDERER));
logInfo("OpenGL ", glGetString(GL_VERSION)); logInfo("OpenGL ", glGetString(GL_VERSION));
m_drawing = false; //if(!isExtensionSupported("GL_ARB_framebuffer_object"))
m_opacity = 255; // logFatal("Your graphics card is not supported.");
m_emptyTexture = TexturePtr(new Texture); m_emptyTexture = TexturePtr(new Texture);
bindColor(Fw::white); g_painter.init();
bindBlendFunc(Fw::BlendDefault);
} }
void Graphics::terminate() void Graphics::terminate()
{ {
g_fonts.releaseFonts(); g_fonts.releaseFonts();
g_painter.terminate();
m_emptyTexture.reset(); m_emptyTexture.reset();
} }
bool Graphics::isExtensionSupported(const char *extension) bool Graphics::isExtensionSupported(const char *extension)
{ {
const GLubyte *extensions = NULL; std::string extensionsString = (const char*)glGetString(GL_EXTENSIONS);
const GLubyte *start; auto extensions = Fw::split(extensionsString);
GLubyte *where, *terminator; return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();
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;
} }
void Graphics::resize(const Size& size) void Graphics::resize(const Size& size)
{ {
m_screenSize = size; glViewport(0, 0, size.width(), size.height());
restoreViewport(); g_painter.updateProjectionMatrix(size);
} m_viewportSize = size;
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();
} }
void Graphics::beginRender() void Graphics::beginRender()
{ {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
} }
void Graphics::endRender() 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 #define GRAPHICS_H
#include "declarations.h" #include "declarations.h"
#include "painter.h"
class Graphics class Graphics
{ {
public: public:
/// Initialize default OpenGL states
void init(); void init();
/// Termiante graphics
void terminate(); void terminate();
/// Check if a GL extension is supported
bool isExtensionSupported(const char *extension); bool isExtensionSupported(const char *extension);
/// Resizes OpenGL viewport
void resize(const Size& size); void resize(const Size& size);
/// Restore original viewport
void restoreViewport();
/// Called before every render
void beginRender(); void beginRender();
/// Called after every render
void endRender(); void endRender();
void bindColor(const Color& color); const Size& getViewportSize() const { return m_viewportSize; }
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; }
TexturePtr getEmptyTexture() { return m_emptyTexture; } TexturePtr getEmptyTexture() { return m_emptyTexture; }
private: private:
bool m_drawing; Size m_viewportSize;
int m_opacity;
Size m_screenSize;
TexturePtr m_emptyTexture; TexturePtr m_emptyTexture;
}; };

View File

@ -52,7 +52,13 @@ void Image::loadFromOTML(const OTMLNodePtr& imageNode)
void Image::draw(const Rect& screenCoords) 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) { if(m_fixedRatio) {
const Size& texSize = m_texture->getSize(); const Size& texSize = m_texture->getSize();
Size texCoordsSize = screenCoords.size(); Size texCoordsSize = screenCoords.size();
@ -63,12 +69,14 @@ void Image::draw(const Rect& screenCoords)
else if(texSize.width() > texCoordsSize.width()) else if(texSize.width() > texCoordsSize.width())
texCoordsOffset.x = (texSize.width() - texCoordsSize.width())/2; texCoordsOffset.x = (texSize.width() - texCoordsSize.width())/2;
g_graphics.drawTexturedRect(screenCoords, m_texture, Rect(texCoordsOffset, texCoordsSize)); m_coordsBuffer.addRect(screenCoords, Rect(texCoordsOffset, texCoordsSize));
} else { } else {
if(m_repeated) if(m_repeated)
g_graphics.drawRepeatedTexturedRect(screenCoords, m_texture, m_textureCoords); m_coordsBuffer.addRepeatedRects(screenCoords, m_textureCoords);
else 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 #define IMAGE_H
#include "declarations.h" #include "declarations.h"
#include "coordsbuffer.h"
#include <framework/otml/declarations.h> #include <framework/otml/declarations.h>
@ -41,6 +42,9 @@ protected:
Rect m_textureCoords; Rect m_textureCoords;
bool m_fixedRatio; bool m_fixedRatio;
bool m_repeated; bool m_repeated;
Rect m_cachedScreenCoords;
CoordsBuffer m_coordsBuffer;
}; };
#endif #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() Particle::~Particle()
{ {
dump << "deleted"; //dump << "deleted";
} }
void Particle::render() void Particle::render()
{ {
g_graphics.bindColor(m_color); g_painter.setColor(m_color);
if(!m_texture) if(!m_texture)
g_graphics.drawFilledRect(m_rect); g_painter.drawFilledRect(m_rect);
else { else {
g_graphics.bindBlendFunc(Fw::BlendParticles); g_painter.setCompositionMode(Painter::CompositionMode_AdditiveSource);
g_graphics.drawTexturedRect(m_rect, m_texture); g_painter.drawTexturedRect(m_rect, m_texture);
g_graphics.bindBlendFunc(Fw::BlendDefault); 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() Texture::~Texture()
{ {
assert(!g_graphics.isDrawing());
// free texture from gl memory // free texture from gl memory
if(m_textureId > 0) if(m_textureId > 0)
glDeleteTextures(1, &m_textureId); glDeleteTextures(1, &m_textureId);
@ -44,9 +43,7 @@ Texture::~Texture()
uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int height) uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int height)
{ {
assert(!g_graphics.isDrawing()); m_size.resize(width, height);
m_size.setSize(width, height);
// gets max texture size supported by the driver // gets max texture size supported by the driver
static GLint maxTexSize = -1; static GLint maxTexSize = -1;
@ -70,7 +67,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
std::vector<uint8> tmp; std::vector<uint8> tmp;
// old opengl drivers only accept power of two dimensions // 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; int glWidth = 1;
while(glWidth < width) while(glWidth < width)
glWidth = glWidth << 1; glWidth = glWidth << 1;
@ -88,7 +85,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
pixels = &tmp[0]; pixels = &tmp[0];
} }
m_glSize.setSize(glWidth, glHeight); m_glSize.resize(glWidth, glHeight);
//} else //} else
// m_glSize = m_size; // m_glSize = m_size;
@ -110,7 +107,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
} }
// load pixels into gl memory // 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 // disable texture border
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 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) // nearest filtering (non smooth)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return id; return id;
} }

View File

@ -37,22 +37,22 @@ public:
virtual void enableBilinearFilter(); virtual void enableBilinearFilter();
/// Get OpenGL texture id /// Get OpenGL texture id
uint getId() const { return m_textureId; } GLuint getId() { return m_textureId; }
/// Copy pixels from OpenGL texture /// Copy pixels from OpenGL texture
std::vector<uint8> getPixels(); std::vector<uint8> getPixels();
int getWidth() const { return m_size.width(); } int getWidth() { return m_size.width(); }
int getHeight() const { return m_size.height(); } int getHeight() { return m_size.height(); }
const Size& getSize() const { return m_size; } const Size& getSize() { return m_size; }
const Size& getGlSize() const { return m_glSize; } const Size& getGlSize() { return m_glSize; }
bool isEmpty() const { return m_textureId == 0; } bool isEmpty() const { return m_textureId == 0; }
protected: 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_size;
Size m_glSize; 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 // UIWidget
g_lua.registerClass<UIWidget>(); g_lua.registerClass<UIWidget>();
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create<UIWidget>); g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create<UIWidget>);
g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId); g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy);
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>("setVisible", &UIWidget::setVisible); g_lua.bindClassMemberFunction<UIWidget>("setVisible", &UIWidget::setVisible);
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth); g_lua.bindClassMemberFunction<UIWidget>("setEnabled", &UIWidget::setEnabled);
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth); g_lua.bindClassMemberFunction<UIWidget>("setPressed", &UIWidget::setPressed);
g_lua.bindClassMemberFunction<UIWidget>("getHeight", &UIWidget::getHeight); g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
g_lua.bindClassMemberFunction<UIWidget>("setHeight", &UIWidget::setHeight); g_lua.bindClassMemberFunction<UIWidget>("setFocusable", &UIWidget::setFocusable);
g_lua.bindClassMemberFunction<UIWidget>("getSize", &UIWidget::getSize); g_lua.bindClassMemberFunction<UIWidget>("setPhantom", &UIWidget::setPhantom);
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>("setStyle", &UIWidget::setStyle); g_lua.bindClassMemberFunction<UIWidget>("setStyle", &UIWidget::setStyle);
g_lua.bindClassMemberFunction<UIWidget>("applyStyle", &UIWidget::applyStyle); g_lua.bindClassMemberFunction<UIWidget>("setStyleFromNode", &UIWidget::setStyleFromNode);
g_lua.bindClassMemberFunction<UIWidget>("getStyle", &UIWidget::getStyle); //g_lua.bindClassMemberFunction<UIWidget>("setLayout", &UIWidget::setLayout);
g_lua.bindClassMemberFunction<UIWidget>("getMarginTop", &UIWidget::getMarginTop); 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>("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>("setMarginRight", &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible); g_lua.bindClassMemberFunction<UIWidget>("setMarginBottom", &UIWidget::setMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("isHidden", &UIWidget::isHidden); g_lua.bindClassMemberFunction<UIWidget>("setMarginLeft", &UIWidget::setMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("isHovered", &UIWidget::isHovered); g_lua.bindClassMemberFunction<UIWidget>("setSizeFixed", &UIWidget::setSizeFixed);
g_lua.bindClassMemberFunction<UIWidget>("isFocused", &UIWidget::isFocused); g_lua.bindClassMemberFunction<UIWidget>("setLastFocusReason", &UIWidget::setLastFocusReason);
g_lua.bindClassMemberFunction<UIWidget>("isPressed", &UIWidget::isPressed); g_lua.bindClassMemberFunction<UIWidget>("resize", &UIWidget::resize);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled); g_lua.bindClassMemberFunction<UIWidget>("moveTo", &UIWidget::moveTo);
g_lua.bindClassMemberFunction<UIWidget>("isDisabled", &UIWidget::isDisabled);
g_lua.bindClassMemberFunction<UIWidget>("isActive", &UIWidget::isActive);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide); g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show); 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>("lock", &UIWidget::lock);
g_lua.bindClassMemberFunction<UIWidget>("unlock", &UIWidget::unlock); g_lua.bindClassMemberFunction<UIWidget>("unlock", &UIWidget::unlock);
g_lua.bindClassMemberFunction<UIWidget>("focus", &UIWidget::focus); g_lua.bindClassMemberFunction<UIWidget>("focus", &UIWidget::focus);
g_lua.bindClassMemberFunction<UIWidget>("getChildren", &UIWidget::getChildren); g_lua.bindClassMemberFunction<UIWidget>("isActive", &UIWidget::isActive);
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById); g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById); g_lua.bindClassMemberFunction<UIWidget>("isDisabled", &UIWidget::isDisabled);
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex); 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>("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>("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>("insertChild", &UIWidget::insertChild);
g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild); 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>("focusChild", &UIWidget::focusChild);
g_lua.bindClassMemberFunction<UIWidget>("focusNextChild", &UIWidget::focusNextChild); g_lua.bindClassMemberFunction<UIWidget>("focusNextChild", &UIWidget::focusNextChild);
g_lua.bindClassMemberFunction<UIWidget>("focusPreviousChild", &UIWidget::focusPreviousChild); 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>("lockChild", &UIWidget::lockChild);
g_lua.bindClassMemberFunction<UIWidget>("unlockChild", &UIWidget::unlockChild); 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>("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 // UILabel
g_lua.registerClass<UILabel, UIWidget>(); 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>("fireOldMessages", std::bind(&Logger::fireOldMessages, &g_logger));
g_lua.bindClassStaticFunction<Logger>("setOnLog", std::bind(&Logger::setOnLog, &g_logger, _1)); 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 // global functions
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1)); 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("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));
g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _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("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1, _2));
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui)); 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); m_rootWindow = RootWindow(m_display, m_visual->screen);
#else #else
static int attrList[] = { static int attrList[] = {
EGL_BUFFER_SIZE, 16, //EGL_BUFFER_SIZE, 24,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE EGL_NONE
}; };

View File

@ -40,9 +40,9 @@ void UIButton::render()
if(m_icon) { if(m_icon) {
Rect iconRect; Rect iconRect;
iconRect.setSize(m_icon->getSize()); iconRect.resize(m_icon->getSize());
iconRect.moveCenter(m_rect.center()); iconRect.moveCenter(m_rect.center());
g_graphics.drawTexturedRect(iconRect, m_icon); g_painter.drawTexturedRect(iconRect, m_icon);
} }
Rect textRect = m_rect; Rect textRect = m_rect;

View File

@ -38,10 +38,10 @@ void UICheckBox::render()
{ {
if(m_image) { if(m_image) {
Rect boxRect; Rect boxRect;
boxRect.setSize(m_boxSize); boxRect.resize(m_boxSize);
boxRect.moveLeft(m_rect.left()); boxRect.moveLeft(m_rect.left());
boxRect.moveVerticalCenter(m_rect.verticalCenter()); boxRect.moveVerticalCenter(m_rect.verticalCenter());
g_graphics.bindColor(m_backgroundColor); g_painter.setColor(m_backgroundColor);
m_image->draw(boxRect); m_image->draw(boxRect);
} }

View File

@ -47,9 +47,9 @@ void UILineEdit::render()
int textLength = m_text.length(); int textLength = m_text.length();
const TexturePtr& texture = m_font->getTexture(); const TexturePtr& texture = m_font->getTexture();
g_graphics.bindColor(m_foregroundColor); g_painter.setColor(m_foregroundColor);
for(int i=0;i<textLength;++i) 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 // render cursor
if(isExplicitlyEnabled() && (isActive() || m_alwaysActive) && m_cursorPos >= 0) { 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()); cursorRect = Rect(m_drawArea.left()-1, m_drawArea.top(), 1, m_font->getGlyphHeight());
else else
cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight()); 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) { } else if(g_clock.ticksElapsed(m_cursorTicks) >= 2*delay) {
m_cursorTicks = g_clock.ticks(); m_cursorTicks = g_clock.ticks();
} }

View File

@ -25,6 +25,7 @@
#include <framework/otml/otml.h> #include <framework/otml/otml.h>
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/platform/platformwindow.h>
UIManager g_ui; UIManager g_ui;
@ -33,7 +34,7 @@ void UIManager::init()
// creates root widget // creates root widget
m_rootWidget = UIWidget::create<UIWidget>(); m_rootWidget = UIWidget::create<UIWidget>();
m_rootWidget->setId("root"); m_rootWidget->setId("root");
m_rootWidget->resize(g_graphics.getScreenSize()); m_rootWidget->resize(g_window.getSize());
} }
void UIManager::terminate() void UIManager::terminate()
@ -50,7 +51,7 @@ void UIManager::render()
void UIManager::resize(const Size& size) void UIManager::resize(const Size& size)
{ {
m_rootWidget->resize(g_graphics.getScreenSize()); m_rootWidget->resize(g_window.getSize());
} }
void UIManager::inputEvent(const InputEvent& event) void UIManager::inputEvent(const InputEvent& event)
@ -174,12 +175,15 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const U
if(parent) if(parent)
parent->addChild(widget); parent->addChild(widget);
widget->setStyleFromNode(styleNode); if(widget) {
widget->setStyleFromNode(styleNode);
for(const OTMLNodePtr& childNode : widgetNode->children()) { for(const OTMLNodePtr& childNode : widgetNode->children()) {
if(!childNode->isUnique()) if(!childNode->isUnique())
loadWidgetFromOTML(childNode, widget); loadWidgetFromOTML(childNode, widget);
} }
} else
logError("Unable to create widget of type '", widgetType, "'");
return widget; return widget;
} }

View File

@ -35,14 +35,14 @@ void UIProgressBar::render()
{ {
UIWidget::render(); UIWidget::render();
g_graphics.bindColor(m_foregroundColor); g_painter.setColor(m_foregroundColor);
g_graphics.drawBoundingRect(m_rect, 1); g_painter.drawBoundingRect(m_rect, 1);
Rect fillRect = m_rect.expanded(-1); Rect fillRect = m_rect.expanded(-1);
fillRect.setWidth(fillRect.width() * m_percent / 100.0); fillRect.setWidth(fillRect.width() * m_percent / 100.0);
g_graphics.bindColor(m_backgroundColor); g_painter.setColor(m_backgroundColor);
g_graphics.drawFilledRect(fillRect); g_painter.drawFilledRect(fillRect);
} }
void UIProgressBar::setPercent(double percent) void UIProgressBar::setPercent(double percent)

View File

@ -69,7 +69,7 @@ void UIWidget::renderSelf()
{ {
// draw background // draw background
if(m_image) { if(m_image) {
g_graphics.bindColor(m_backgroundColor); g_painter.setColor(m_backgroundColor);
m_image->draw(m_rect); m_image->draw(m_rect);
} }
} }
@ -81,20 +81,20 @@ void UIWidget::renderChildren()
// render only visible children with a valid rect inside our rect // render only visible children with a valid rect inside our rect
if(child->isExplicitlyVisible() && child->getRect().isValid() && child->getRect().intersects(m_rect)) { if(child->isExplicitlyVisible() && child->getRect().isValid() && child->getRect().intersects(m_rect)) {
// store current graphics opacity // store current graphics opacity
int oldOpacity = g_graphics.getOpacity(); int oldOpacity = g_painter.getOpacity();
// decrease to self opacity // decrease to self opacity
if(child->getOpacity() < oldOpacity) if(child->getOpacity() < oldOpacity)
g_graphics.setOpacity(child->getOpacity()); g_painter.setOpacity(child->getOpacity());
child->render(); child->render();
// debug draw box // debug draw box
//g_graphics.bindColor(Fw::green); //g_painter.setColor(Fw::green);
//g_graphics.drawBoundingRect(child->getRect()); //g_painter.drawBoundingRect(child->getRect());
//g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Fw::red); //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 setBottomLeft(const TPoint<T> &p) { x1 = p.x; y2 = p.y; }
void setWidth(T width) { x2 = x1 + width - 1; } void setWidth(T width) { x2 = x1 + width - 1; }
void setHeight(T height) { y2 = y1 + height- 1; } void setHeight(T height) { y2 = y1 + height- 1; }
void setSize(T width, T height) { x2 = x1 + width - 1; y2 = y1 + height - 1; } void resize(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(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 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; } 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 width() const { return wd; }
int height() const { return ht; } 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 setWidth(T w) { wd = w; }
void setHeight(T h) { ht = h; } void setHeight(T h) { ht = h; }
@ -115,7 +115,7 @@ std::istream& operator>>(std::istream& in, TSize<T>& size)
{ {
T w, h; T w, h;
in >> w >> h; in >> w >> h;
size.setSize(w, h); size.resize(w, h);
return in; return in;
} }

View File

@ -30,6 +30,8 @@
#include <sstream> #include <sstream>
#include <exception> #include <exception>
#include <cxxabi.h> #include <cxxabi.h>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "types.h" #include "types.h"
#include "exception.h" #include "exception.h"
@ -258,6 +260,16 @@ inline std::string ip2str(uint32 ip) {
return std::string(host); 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> template<typename... T>
void throwException(const T&... args) { void throwException(const T&... args) {
throw Exception(Fw::mkstr(args...)); throw Exception(Fw::mkstr(args...));

View File

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

View File

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

View File

@ -31,6 +31,10 @@
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h> #include <framework/core/clock.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/paintershadersources.h>
#include "spritemanager.h"
Creature::Creature() : Thing() Creature::Creature() : Thing()
{ {
m_healthPercent = 0; m_healthPercent = 0;
@ -43,12 +47,31 @@ Creature::Creature() : Thing()
m_informationFont = g_fonts.getFont("verdana-11px-rounded"); 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) void Creature::draw(const Point& p)
{ {
// TODO: activate on attack, follow, discover how 'attacked' works // TODO: activate on attack, follow, discover how 'attacked' works
if(m_showSquareColor) { if(m_showSquareColor) {
g_graphics.bindColor(Outfit::getColor(m_squareColor)); g_painter.setColor(Outfit::getColor(m_squareColor));
g_graphics.drawBoundingRect(Rect(p + m_walkOffset - 8, Size(32, 32)), 2); 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 // Render creature
@ -58,35 +81,52 @@ void Creature::draw(const Point& p)
if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1)))) if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1))))
continue; continue;
// draw white item g_painter.setCustomProgram(outfitProgram);
g_graphics.bindColor(Fw::white);
internalDraw(p + m_walkOffset, 0);
// draw mask if exists outfitProgram->bind();
if(m_type->dimensions[ThingType::Layers] > 1) { outfitProgram->setUniformValue(HEAD_COLOR_UNIFORM, m_outfit.getHeadColor());
// switch to blend color mode outfitProgram->setUniformValue(BODY_COLOR_UNIFORM, m_outfit.getBodyColor());
g_graphics.bindBlendFunc(Fw::BlendColorzing); outfitProgram->setUniformValue(LEGS_COLOR_UNIFORM, m_outfit.getLegsColor());
outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor());
// head for(int yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) {
g_graphics.bindColor(m_outfit.getHeadColor()); for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) {
internalDraw(p + m_walkOffset, 1, Otc::SpriteYellowMask); 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) {
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);
}
// body int spriteId = m_type->sprites[sprIndex];
g_graphics.bindColor(m_outfit.getBodyColor()); if(!spriteId)
internalDraw(p + m_walkOffset, 1, Otc::SpriteRedMask); continue;
// legs TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
g_graphics.bindColor(m_outfit.getLegsColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteGreenMask);
// feet Rect drawRect(((p + m_walkOffset).x - xi*32) - m_type->parameters[ThingType::DisplacementX],
g_graphics.bindColor(m_outfit.getFeetColor()); ((p + m_walkOffset).y - yi*32) - m_type->parameters[ThingType::DisplacementY],
internalDraw(p + m_walkOffset, 1, Otc::SpriteBlueMask); 32, 32);
g_painter.drawTexturedRect(drawRect, spriteTex);
// restore default blend func }
g_graphics.bindBlendFunc(Fw::BlendDefault);
g_graphics.bindColor(Fw::white);
} }
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); healthRect.setWidth((m_healthPercent / 100.0) * 25);
// draw // draw
g_graphics.bindColor(Fw::black); g_painter.setColor(Fw::black);
g_graphics.drawFilledRect(backgroundRect); g_painter.drawFilledRect(backgroundRect);
g_graphics.bindColor(fillColor); g_painter.setColor(fillColor);
g_graphics.drawFilledRect(healthRect); g_painter.drawFilledRect(healthRect);
m_informationFont->renderText(m_name, textRect, Fw::AlignTopCenter, fillColor); m_informationFont->renderText(m_name, textRect, Fw::AlignTopCenter, fillColor);
} }

View File

@ -28,7 +28,9 @@
#include "missile.h" #include "missile.h"
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/graphics/framebuffer.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 g_map;
Map::Map() Map::Map()
@ -36,12 +38,20 @@ Map::Map()
setVisibleSize(Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT)); setVisibleSize(Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT));
} }
PainterShaderProgramPtr program;
void Map::draw(const Rect& rect) 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)); 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(); m_framebuffer->bind();
// draw offsets // 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); m_framebuffer->draw(rect);
g_painter.releaseCustomProgram();
// calculate stretch factor // calculate stretch factor
float horizontalStretchFactor = rect.width() / (float)(m_visibleSize.width() * NUM_TILE_PIXELS); 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)); return TexturePtr(new Texture(32, 32, 4, pixels));
} }
TexturePtr SpriteManager::loadSpriteMask(TexturePtr spriteTex, Otc::SpriteMask mask) TexturePtr SpriteManager::getSpriteTexture(int id)
{
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)
{ {
if(id == 0) if(id == 0)
return g_graphics.getEmptyTexture(); return g_graphics.getEmptyTexture();
@ -149,17 +126,11 @@ TexturePtr SpriteManager::getSpriteTexture(int id, Otc::SpriteMask mask)
assert(id > 0 && id <= m_spritesCount); assert(id > 0 && id <= m_spritesCount);
// load sprites on demand // load sprites on demand
Sprite& sprite = m_sprites[id-1]; TexturePtr& sprite = m_sprites[id-1];
if(!sprite.texture) if(!sprite)
sprite.texture = loadSpriteTexture(id); sprite = loadSpriteTexture(id);
//TODO: release unused sprites textures after X seconds //TODO: release unused sprites textures after X seconds
// to avoid massive texture allocations // to avoid massive texture allocations
return sprite;
if(mask != Otc::SpriteNoMask) {
if(!sprite.masks[mask])
sprite.masks[mask] = loadSpriteMask(sprite.texture, mask);
return sprite.masks[mask];
} else
return sprite.texture;
} }

View File

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

View File

@ -34,7 +34,7 @@ Thing::Thing() : m_id(0)
m_type = g_thingsType.getEmptyThingType(); 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 yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) {
for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) { 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) if(!spriteId)
continue; 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], Rect drawRect((p.x - xi*32) - m_type->parameters[ThingType::DisplacementX],
(p.y - yi*32) - m_type->parameters[ThingType::DisplacementY], (p.y - yi*32) - m_type->parameters[ThingType::DisplacementY],
32, 32); 32, 32);
g_graphics.drawTexturedRect(drawRect, spriteTex); g_painter.drawTexturedRect(drawRect, spriteTex);
} }
} }
} }

View File

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

View File

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

View File

@ -34,7 +34,7 @@ void UICreature::render()
renderSelf(); renderSelf();
if(m_creature) { if(m_creature) {
g_graphics.bindColor(Fw::white); g_painter.setColor(Fw::white);
m_creature->draw(m_rect.bottomRight() - Point(32, 32) + m_creatureMargin); m_creature->draw(m_rect.bottomRight() - Point(32, 32) + m_creatureMargin);
} }

View File

@ -34,7 +34,7 @@ void UIItem::render()
renderSelf(); renderSelf();
if(m_item) { if(m_item) {
g_graphics.bindColor(Fw::white); g_painter.setColor(Fw::white);
m_item->draw(m_rect.bottomRight() - Point(32, 32) + m_itemMargin); m_item->draw(m_rect.bottomRight() - Point(32, 32) + m_itemMargin);
} }

View File

@ -35,8 +35,8 @@ void UIMap::render()
{ {
renderSelf(); renderSelf();
g_graphics.bindColor(Fw::black); g_painter.setColor(Fw::black);
g_graphics.drawBoundingRect(m_mapRect.expanded(1)); g_painter.drawBoundingRect(m_mapRect.expanded(1));
g_map.draw(m_mapRect); g_map.draw(m_mapRect);
renderChildren(); 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); Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS);
mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); mapSize.scale(mapRect.size(), Fw::KeepAspectRatio);
m_mapRect.setSize(mapSize); m_mapRect.resize(mapSize);
m_mapRect.moveCenter(newRect.center()); m_mapRect.moveCenter(newRect.center());
} }

View File

@ -15,16 +15,16 @@ if not io.open(cppclassheader, 'r') then
return false return false
end end
function string.matchcount(str, pattern) function string:matchcount(pattern)
local count = 0 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 return count
end end
function string.splitlines(str) function string:splitlines()
local t = {} local t = {}
local function helper(line) table.insert(t, line) return "" end local function helper(line) table.insert(t, line) return "" end
helper((str:gsub("(.-)\r?\n", helper))) helper((self:gsub("(.-)\r?\n", helper)))
return t return t
end end
@ -34,7 +34,7 @@ for line in io.lines(cppclassheader) do
foundclassname = line:match('^class ([%w_]+)') foundclassname = line:match('^class ([%w_]+)')
if foundclassname then if foundclassname then
if not cppclassname then if not cppclassname then
guessedclassname = cppclassheader:match('([%w_]+).h'):lower() guessedclassname = cppclassheader:match('([%w_]+)\.h$'):lower()
if foundclassname:lower() == guessedclassname then if foundclassname:lower() == guessedclassname then
cppclassname = foundclassname cppclassname = foundclassname
end end
@ -69,8 +69,9 @@ for line in io.lines(cppclassheader) do
elseif line:match('private:') or line:match('protected:') then elseif line:match('private:') or line:match('protected:') then
publicmethods = false publicmethods = false
elseif publicmethods then elseif publicmethods then
for funcname,args in line:gmatch(' *[%w :_]* ([%w_]+)%(([^%(]*%)) *[;{].*$') do funcname, args = line:match('^ *[%w <>&\*:_]* ([%w_]+)%(([^%)]*%))[%w ]*[;{].*$')
if funcname ~= cppclassname then if funcname then
if funcname ~= cppclassname and funcname ~= 'create' then
numargs = args:matchcount('[^,)]+[,)]') numargs = args:matchcount('[^,)]+[,)]')
if cppclassinstance then if cppclassinstance then