36 Commits

Author SHA1 Message Date
Eduardo Bart
b5911cf1de Use client version instead of entergame 2013-08-03 19:26:38 -03:00
BeniS
5fbb71157d Added enable/disable chat mode (allows for alphabetical key controls), battle window anchoring fixed (thank you River) & more:
* Added better walk key binding (for other uses, like the sample given WASD).
* Made string.ends part of the string meta table rather than parameter based.
2013-07-29 10:42:18 +12:00
Allan Ference
0ff36a1a0a Merge https://github.com/marksamman/otclient
* https://github.com/marksamman/otclient:
  Fix login with 9.83-10.10
2013-07-28 07:10:44 +02:00
Mark Samman
4a04a18835 Fix login with 9.83-10.10
This only adds protocol compatibility, the features aren't actually
implemented yet
2013-07-28 07:05:46 +02:00
Allan Ference
6fa9631d6a Merge https://github.com/marksamman/otclient
* https://github.com/marksamman/otclient:
  Fix compiling on OS X
2013-07-28 04:42:31 +02:00
Mark Samman
261642190b Fix compiling on OS X 2013-07-28 04:30:52 +02:00
BeniS
95abf2a1d2 Fix a bug with autowalking & add prompt param for tryLogout.
(We don't want to be prompted when pressing Ctrl + Q or  Ctrl + L).
2013-07-07 05:36:56 +12:00
Sam
c4adf2d817 Added whitelist
- Checkboxes to turn ignore/whitelist off
- Allow VIP messages
2013-07-04 18:03:21 +02:00
Sam
c7c259ef80 Game Menu / Attacking fixes
- No more "Attack" / "Follow" for creatures on different floor
- No rule violation for monsters, only players now
- Alt + Click to target works through roofs -> fixes #203
- Fixed battle list issue (check position when trying to attack)
2013-07-03 14:25:18 +02:00
Sam
987c6d6c91 Mount display issue
fixes #275
Not really needed but enables some cool stuff
2013-07-02 23:16:11 +02:00
Sam
c8185474de Implements battlelist sorting
Features:
Sort by age, name, health or distance
Sort ascending or descending
Button to toggle filters and sort options
http://i.imgur.com/cSCBwr4.png

closes 213
2013-07-02 22:43:52 +02:00
Sam
be071c7103 Fix deathwindow issue 2013-07-02 22:40:19 +02:00
Sam
2f9e2c3e33 Sorting VIP list by name
@ #209
What should sorting by type do?
2013-07-01 22:59:51 +02:00
Sam
b81590f297 Fixed Alt + F4 keycombo on Windows 2013-06-29 16:53:15 +02:00
BeniS
e062562888 Added sublime text 2 project file.
* Changed the order of the dofiles params.
2013-05-12 21:16:43 +12:00
BeniS
18d23653c4 Added some control params to dofiles lua method.
* File name contains string.
* Recursive file checking for deep searches.
2013-05-12 17:00:52 +12:00
Henrique Santiago
6c119627bb Merge pull request #330 from conde2/master
Improvement on styles
2013-04-30 13:26:56 -07:00
Joao Pasqualini Costa
d847a78a4d Improvement on styles
Added VerticalList
2013-04-30 17:21:04 -03:00
Eduardo Bart
0dccc870b5 Merge pull request #324 from TiagoTdA/master
Update/Refresh modules on unload
2013-04-13 18:11:47 -07:00
Tiago T. de Araujo
e4c7ca604b Fix update on unload module 2013-04-12 21:27:10 -03:00
Sam
d427560b98 Countwindow Fix [YAH]
Fixed typing amount in count window. Should be hidden again.
2013-04-12 19:15:28 +02:00
Sam
cc12db0d1f Reverted getTopMultiUseThing() change 2013-04-09 23:54:10 +02:00
Henrique Santiago
1ce6df99ac Merge pull request #318 from conde2/master
Fix #316
2013-04-09 14:21:15 -07:00
Joao Pasqualini Costa
57bb6ff974 Fix #315 by @pacmanis
Credits go to @pacmanis
2013-04-09 18:02:43 -03:00
Joao Pasqualini Costa
9bae1b9e25 Fix #316
It still have a bug when using string like this:

" teste {{}} teste"
2013-04-09 17:54:57 -03:00
Sam
1415de222c Merge pull request #313 from sn3ejk/sn3ejk
Fix extended opcodes for forgottenserver.
2013-04-05 18:50:02 -07:00
Kamil W
34ceb3c95e Fix extended opcodes for forgottenserver. 2013-04-05 22:03:17 +02:00
Eduardo Bart
b43a196eac Minor fixes and add auto resize for images 2013-03-15 21:59:22 -03:00
Eduardo Bart
a3a65d40ce Merge pull request #303 from conde2/master
Properly Fix #301
2013-03-15 08:35:04 -07:00
Joao Pasqualini Costa
6ef3508362 Properly Fix #301 2013-03-14 20:57:02 -03:00
Eduardo Bart
a71e07f063 Restore walk optimization 2013-03-14 00:16:57 -03:00
Eduardo Bart
4bdd1e79fd Fix compile error for win32 2013-03-13 21:18:17 -03:00
Eduardo Bart
e9e4dcd71b Improve walk when lagging 2013-03-13 20:55:20 -03:00
Eduardo Bart
0891e2b30a Add C++ traceback to errors 2013-03-12 01:36:36 -03:00
Eduardo Bart
24664714bd Fix rare but serious bug in Connection
* Implement output pooling for writing data in connection,
this should fix rare cases where sending would fail
2013-03-12 00:18:47 -03:00
Eduardo Bart
da51dd467e Minor fix 2013-03-11 15:00:31 -03:00
107 changed files with 2112 additions and 2244 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,3 @@
/modules/.project
build* build*
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
@@ -39,3 +38,4 @@ tags
Thumbs.db Thumbs.db
.directory .directory
src/framework/graphics/dx/ src/framework/graphics/dx/
modules/.project/modules.sublime-workspace

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
project(otclient) project(otclient)
set(VERSION "0.6.2") set(VERSION "0.6.3")
option(FRAMEWORK_SOUND "Use SOUND " ON) option(FRAMEWORK_SOUND "Use SOUND " ON)
option(FRAMEWORK_GRAPHICS "Use GRAPHICS " ON) option(FRAMEWORK_GRAPHICS "Use GRAPHICS " ON)

View File

@@ -11,3 +11,9 @@ HorizontalList < UIScrollArea
border-width: 1 border-width: 1
border-color: #1d222b border-color: #1d222b
background-color: #222833 background-color: #222833
VerticalList < UIScrollArea
layout: verticalBox
border-width: 1
border-color: #1d222b
background-color: #222833

View File

@@ -48,7 +48,7 @@ g_modules.ensureModuleLoaded("game_interface")
-- mods 1000-9999 -- mods 1000-9999
g_modules.autoLoadModules(9999) g_modules.autoLoadModules(9999)
local script = '/' .. g_app.getCompactName() .. 'rc.lua' local script = '/' .. g_app.getCompactName() .. 'rc'
if g_resources.fileExists(script) then if g_resources.fileExists(script) then
dofile(script) dofile(script)

View File

@@ -0,0 +1,10 @@
{
"folders":
[
{
"path": "..",
"folder_exclude_patterns": [".*", "*.*~"],
"file_exclude_patterns": [".*", "*.*~"]
}
]
}

View File

@@ -1,5 +1,5 @@
local musicFilename = "/sounds/startup" local musicFilename = "/sounds/startup"
local musicChannel = nil local musicChannel = g_sounds.getChannel(1)
function setMusic(filename) function setMusic(filename)
musicFilename = filename musicFilename = filename
@@ -57,14 +57,11 @@ function init()
onExit = exit }) onExit = exit })
g_window.setMinimumSize({ width = 600, height = 480 }) g_window.setMinimumSize({ width = 600, height = 480 })
musicChannel = g_sounds.getChannel(1)
g_sounds.preload(musicFilename) g_sounds.preload(musicFilename)
-- initialize in fullscreen mode on mobile devices -- initialize in fullscreen mode on mobile devices
if g_app.getOs() == "android" then if g_window.getPlatformType() == "X11-EGL" then
g_window.maximize() g_window.setFullscreen(true)
--g_window.setFullscreen(true)
else else
-- window size -- window size
local size = { width = 800, height = 600 } local size = { width = 800, height = 600 }
@@ -107,11 +104,6 @@ function terminate()
g_settings.set('window-size', g_window.getUnmaximizedSize()) g_settings.set('window-size', g_window.getUnmaximizedSize())
g_settings.set('window-pos', g_window.getUnmaximizedPos()) g_settings.set('window-pos', g_window.getUnmaximizedPos())
g_settings.set('window-maximized', g_window.isMaximized()) g_settings.set('window-maximized', g_window.isMaximized())
local protocolVersion = g_game.getProtocolVersion()
if protocolVersion ~= 0 then
g_settings.set('protocol-version', protocolVersion)
end
end end
function exit() function exit()

View File

@@ -19,4 +19,4 @@ Module
- client_terminal - client_terminal
- client_modulemanager - client_modulemanager
- client_serverlist - client_serverlist
//- client_stats - client_stats

View File

@@ -6,7 +6,7 @@ local enterGame
local motdWindow local motdWindow
local motdButton local motdButton
local enterGameButton local enterGameButton
local protocolBox local clientBox
local protocolLogin local protocolLogin
local motdEnabled = true local motdEnabled = true
@@ -73,11 +73,6 @@ local function onCharacterList(protocol, characters, account, otui)
end end
end end
local function onChangeProtocol(combobox, option)
local clients = g_game.getSupportedClients(option)
protocolBox:setTooltip("Supports Client" .. (#clients > 1 and "s" or "") .. ": " .. table.tostring(clients))
end
local function onUpdateNeeded(protocol, signature) local function onUpdateNeeded(protocol, signature)
loadBox:destroy() loadBox:destroy()
loadBox = nil loadBox = nil
@@ -109,7 +104,8 @@ function EnterGame.init()
local host = g_settings.get('host') local host = g_settings.get('host')
local port = g_settings.get('port') local port = g_settings.get('port')
local autologin = g_settings.getBoolean('autologin') local autologin = g_settings.getBoolean('autologin')
local protocolVersion = g_settings.getInteger('protocol-version') local clientVersion = g_settings.getInteger('client-version')
if clientVersion == 0 then clientVersion = 860 end
if port == nil or port == 0 then port = 7171 end if port == nil or port == 0 then port = 7171 end
@@ -120,11 +116,11 @@ function EnterGame.init()
enterGame:getChildById('serverPortTextEdit'):setText(port) enterGame:getChildById('serverPortTextEdit'):setText(port)
enterGame:getChildById('autoLoginBox'):setChecked(autologin) enterGame:getChildById('autoLoginBox'):setChecked(autologin)
protocolBox = enterGame:getChildById('protocolComboBox') clientBox = enterGame:getChildById('clientComboBox')
protocolBox.onOptionChange = onChangeProtocol for _, proto in pairs(g_game.getSupportedClients()) do
if protocolVersion then clientBox:addOption(proto)
protocolBox:setCurrentOption(protocolVersion)
end end
clientBox:setCurrentOption(clientVersion)
enterGame:hide() enterGame:hide()
@@ -154,7 +150,7 @@ function EnterGame.terminate()
enterGame = nil enterGame = nil
enterGameButton:destroy() enterGameButton:destroy()
enterGameButton = nil enterGameButton = nil
protocolBox = nil clientBox = nil
if motdWindow then if motdWindow then
motdWindow:destroy() motdWindow:destroy()
motdWindow = nil motdWindow = nil
@@ -218,8 +214,7 @@ function EnterGame.doLogin()
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText() G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
G.host = enterGame:getChildById('serverHostTextEdit'):getText() G.host = enterGame:getChildById('serverHostTextEdit'):getText()
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText()) G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
local protocolVersion = tonumber(protocolBox:getText()) local clientVersion = tonumber(clientBox:getText())
local clientVersions = g_game.getSupportedClients(protocolVersion)
EnterGame.hide() EnterGame.hide()
if g_game.isOnline() then if g_game.isOnline() then
@@ -230,6 +225,7 @@ function EnterGame.doLogin()
g_settings.set('host', G.host) g_settings.set('host', G.host)
g_settings.set('port', G.port) g_settings.set('port', G.port)
g_settings.set('client-version', clientVersion)
protocolLogin = ProtocolLogin.create() protocolLogin = ProtocolLogin.create()
protocolLogin.onLoginError = onError protocolLogin.onLoginError = onError
@@ -245,10 +241,8 @@ function EnterGame.doLogin()
end }) end })
g_game.chooseRsa(G.host) g_game.chooseRsa(G.host)
g_game.setProtocolVersion(protocolVersion) g_game.setClientVersion(clientVersion)
if #clientVersions > 0 then g_game.setProtocolVersion(g_game.getProtocolVersionForClient(clientVersion))
g_game.setClientVersion(clientVersions[#clientVersions])
end
if modules.game_things.isLoaded() then if modules.game_things.isLoaded() then
protocolLogin:login(G.host, G.port, G.account, G.password) protocolLogin:login(G.host, G.port, G.account, G.password)
@@ -269,14 +263,14 @@ end
function EnterGame.setDefaultServer(host, port, protocol) function EnterGame.setDefaultServer(host, port, protocol)
local hostTextEdit = enterGame:getChildById('serverHostTextEdit') local hostTextEdit = enterGame:getChildById('serverHostTextEdit')
local portTextEdit = enterGame:getChildById('serverPortTextEdit') local portTextEdit = enterGame:getChildById('serverPortTextEdit')
local protocolLabel = enterGame:getChildById('protocolLabel') local clientLabel = enterGame:getChildById('clientLabel')
local accountTextEdit = enterGame:getChildById('accountNameTextEdit') local accountTextEdit = enterGame:getChildById('accountNameTextEdit')
local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit') local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit')
if hostTextEdit:getText() ~= host then if hostTextEdit:getText() ~= host then
hostTextEdit:setText(host) hostTextEdit:setText(host)
portTextEdit:setText(port) portTextEdit:setText(port)
protocolBox:setCurrentOption(protocol) clientBox:setCurrentOption(protocol)
accountTextEdit:setText('') accountTextEdit:setText('')
passwordTextEdit:setText('') passwordTextEdit:setText('')
end end
@@ -292,9 +286,9 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
portTextEdit:setVisible(false) portTextEdit:setVisible(false)
portTextEdit:setHeight(0) portTextEdit:setHeight(0)
protocolBox:setCurrentOption(protocol) clientBox:setCurrentOption(protocol)
protocolBox:setVisible(false) clientBox:setVisible(false)
protocolBox:setHeight(0) clientBox:setHeight(0)
local serverLabel = enterGame:getChildById('serverLabel') local serverLabel = enterGame:getChildById('serverLabel')
serverLabel:setVisible(false) serverLabel:setVisible(false)
@@ -302,9 +296,9 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig
local portLabel = enterGame:getChildById('portLabel') local portLabel = enterGame:getChildById('portLabel')
portLabel:setVisible(false) portLabel:setVisible(false)
portLabel:setHeight(0) portLabel:setHeight(0)
local protocolLabel = enterGame:getChildById('protocolLabel') local clientLabel = enterGame:getChildById('clientLabel')
protocolLabel:setVisible(false) clientLabel:setVisible(false)
protocolLabel:setHeight(0) clientLabel:setHeight(0)
local serverListButton = enterGame:getChildById('serverListButton') local serverListButton = enterGame:getChildById('serverListButton')
serverListButton:setVisible(false) serverListButton:setVisible(false)

View File

@@ -68,7 +68,7 @@ EnterGameWindow
TextEdit TextEdit
id: serverHostTextEdit id: serverHostTextEdit
!tooltip: tr('Make sure that your client uses\nthe correct game protocol version') !tooltip: tr('Make sure that your client uses\nthe correct game client version')
anchors.left: parent.left anchors.left: parent.left
anchors.right: serverListButton.left anchors.right: serverListButton.left
anchors.top: serverLabel.bottom anchors.top: serverLabel.bottom
@@ -76,8 +76,8 @@ EnterGameWindow
margin-right: 4 margin-right: 4
MenuLabel MenuLabel
id: protocolLabel id: clientLabel
!text: tr('Protocol') !text: tr('Client Version')
anchors.left: parent.left anchors.left: parent.left
anchors.top: serverHostTextEdit.bottom anchors.top: serverHostTextEdit.bottom
text-auto-resize: true text-auto-resize: true
@@ -85,17 +85,13 @@ EnterGameWindow
margin-top: 8 margin-top: 8
ComboBox ComboBox
id: protocolComboBox id: clientComboBox
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.horizontalCenter anchors.right: parent.horizontalCenter
anchors.top: protocolLabel.bottom anchors.top: clientLabel.bottom
margin-top: 2 margin-top: 2
margin-right: 3 margin-right: 3
width: 90 width: 90
@onSetup: |
for _, proto in pairs(g_game.getSupportedProtocols()) do
self:addOption(proto)
end
MenuLabel MenuLabel
id: portLabel id: portLabel
@@ -110,7 +106,7 @@ EnterGameWindow
text: 7171 text: 7171
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.horizontalCenter anchors.left: parent.horizontalCenter
anchors.top: protocolComboBox.top anchors.top: clientComboBox.top
margin-left: 3 margin-left: 3
CheckBox CheckBox

View File

@@ -137,7 +137,7 @@ function unloadCurrentModule()
local module = g_modules.getModule(focusedChild:getText()) local module = g_modules.getModule(focusedChild:getText())
if module then if module then
module:unload() module:unload()
if ModuleManager == nil then return end if modules.client_modulemanager == nil then return end
updateModuleInfo(module:getName()) updateModuleInfo(module:getName())
refreshLoadedModules() refreshLoadedModules()
end end

View File

@@ -49,7 +49,7 @@ MainWindow
anchors.left: protocolLabel.left anchors.left: protocolLabel.left
anchors.right: port.right anchors.right: port.right
@onSetup: | @onSetup: |
for _, proto in pairs(g_game.getSupportedProtocols()) do for _, proto in pairs(g_game.getSupportedClients()) do
self:addOption(proto) self:addOption(proto)
end end

View File

@@ -257,10 +257,13 @@ function flushLines()
for _,line in pairs(cachedLines) do for _,line in pairs(cachedLines) do
-- delete old lines if needed -- delete old lines if needed
if numLines > MaxLogLines then if numLines > MaxLogLines then
local len = #terminalBuffer:getChildByIndex(1):getText() local firstChild = terminalBuffer:getChildByIndex(1)
terminalBuffer:getChildByIndex(1):destroy() if firstChild then
table.remove(allLines, 1) local len = #firstChild:getText()
fulltext = string.sub(fulltext, len) firstChild:destroy()
table.remove(allLines, 1)
fulltext = string.sub(fulltext, len)
end
end end
local label = g_ui.createWidget('TerminalLabel', terminalBuffer) local label = g_ui.createWidget('TerminalLabel', terminalBuffer)
@@ -285,6 +288,7 @@ function addLine(text, color)
flushEvent = scheduleEvent(flushLines, 10) flushEvent = scheduleEvent(flushLines, 10)
end end
text = string.gsub(text, '\t', ' ')
table.insert(cachedLines, {text=text, color=color}) table.insert(cachedLines, {text=text, color=color})
end end

View File

@@ -20,8 +20,8 @@ function string:starts(start)
return string.sub(self, 1, #start) == start return string.sub(self, 1, #start) == start
end end
function string.ends(s, test) function string:ends(test)
return test =='' or string.sub(s,-string.len(test)) == test return test =='' or string.sub(self,-string.len(test)) == test
end end
function string:trim() function string:trim()

View File

@@ -110,7 +110,9 @@ function UITabBar:selectTab(tab)
tab:setOn(false) tab:setOn(false)
local parent = tab:getParent() local parent = tab:getParent()
parent:focusChild(tab, MouseFocusReason) if parent then
parent:focusChild(tab, MouseFocusReason)
end
end end
function UITabBar:selectNextTab() function UITabBar:selectNextTab()

View File

@@ -1,11 +1,16 @@
battleWindow = nil battleWindow = nil
battleButton = nil battleButton = nil
battlePanel = nil battlePanel = nil
filterPanel = nil
toggleFilterButton = nil
lastBattleButtonSwitched = nil lastBattleButtonSwitched = nil
battleButtonsByCreaturesList = {} battleButtonsByCreaturesList = {}
creatureAgeList = {}
mouseWidget = nil mouseWidget = nil
sortTypeBox = nil
sortOrderBox = nil
hidePlayersButton = nil hidePlayersButton = nil
hideNPCsButton = nil hideNPCsButton = nil
hideMonstersButton = nil hideMonstersButton = nil
@@ -25,6 +30,15 @@ function init()
battlePanel = battleWindow:recursiveGetChildById('battlePanel') battlePanel = battleWindow:recursiveGetChildById('battlePanel')
filterPanel = battleWindow:recursiveGetChildById('filterPanel')
toggleFilterButton = battleWindow:recursiveGetChildById('toggleFilterButton')
if isHidingFilters() then
hideFilterPanel()
end
sortTypeBox = battleWindow:recursiveGetChildById('sortTypeBox')
sortOrderBox = battleWindow:recursiveGetChildById('sortOrderBox')
hidePlayersButton = battleWindow:recursiveGetChildById('hidePlayers') hidePlayersButton = battleWindow:recursiveGetChildById('hidePlayers')
hideNPCsButton = battleWindow:recursiveGetChildById('hideNPCs') hideNPCsButton = battleWindow:recursiveGetChildById('hideNPCs')
hideMonstersButton = battleWindow:recursiveGetChildById('hideMonsters') hideMonstersButton = battleWindow:recursiveGetChildById('hideMonsters')
@@ -38,6 +52,18 @@ function init()
battleWindow:setContentMinimumHeight(80) battleWindow:setContentMinimumHeight(80)
sortTypeBox:addOption('Name', 'name')
sortTypeBox:addOption('Distance', 'distance')
sortTypeBox:addOption('Age', 'age')
sortTypeBox:addOption('Health', 'health')
sortTypeBox:setCurrentOptionByData(getSortType())
sortTypeBox.onOptionChange = onChangeSortType
sortOrderBox:addOption('Asc.', 'asc')
sortOrderBox:addOption('Desc.', 'desc')
sortOrderBox:setCurrentOptionByData(getSortOrder())
sortOrderBox.onOptionChange = onChangeSortOrder
connect(Creature, { connect(Creature, {
onSkullChange = updateCreatureSkull, onSkullChange = updateCreatureSkull,
onEmblemChange = updateCreatureEmblem, onEmblemChange = updateCreatureEmblem,
@@ -47,6 +73,10 @@ function init()
onAppear = onCreatureAppear, onAppear = onCreatureAppear,
onDisappear = onCreatureDisappear onDisappear = onCreatureDisappear
}) })
connect(LocalPlayer, {
onPositionChange = onCreaturePositionChange
})
connect(g_game, { connect(g_game, {
onAttackingCreatureChange = onAttack, onAttackingCreatureChange = onAttack,
@@ -75,6 +105,10 @@ function terminate()
onDisappear = onCreatureDisappear onDisappear = onCreatureDisappear
}) })
disconnect(LocalPlayer, {
onPositionChange = onCreaturePositionChange
})
disconnect(g_game, { disconnect(g_game, {
onAttackingCreatureChange = onAttack, onAttackingCreatureChange = onAttack,
onFollowingCreatureChange = onFollow, onFollowingCreatureChange = onFollow,
@@ -96,6 +130,93 @@ function onMiniWindowClose()
battleButton:setOn(false) battleButton:setOn(false)
end end
function getSortType()
local settings = g_settings.getNode('BattleList')
if not settings then
return 'name'
end
return settings['sortType']
end
function setSortType(state)
settings = {}
settings['sortType'] = state
g_settings.mergeNode('BattleList', settings)
checkCreatures()
end
function getSortOrder()
local settings = g_settings.getNode('BattleList')
if not settings then
return 'asc'
end
return settings['sortOrder']
end
function setSortOrder(state)
settings = {}
settings['sortOrder'] = state
g_settings.mergeNode('BattleList', settings)
checkCreatures()
end
function isSortAsc()
return getSortOrder() == 'asc'
end
function isSortDesc()
return getSortOrder() == 'desc'
end
function isHidingFilters()
local settings = g_settings.getNode('BattleList')
if not settings then
return false
end
return settings['hidingFilters']
end
function setHidingFilters(state)
settings = {}
settings['hidingFilters'] = state
g_settings.mergeNode('BattleList', settings)
end
function hideFilterPanel()
filterPanel.originalHeight = filterPanel:getHeight()
filterPanel:setHeight(0)
toggleFilterButton:getParent():setMarginTop(0)
toggleFilterButton:setImageClip(torect("0 0 21 12"))
setHidingFilters(true)
filterPanel:setVisible(false)
end
function showFilterPanel()
toggleFilterButton:getParent():setMarginTop(5)
filterPanel:setHeight(filterPanel.originalHeight)
toggleFilterButton:setImageClip(torect("21 0 21 12"))
setHidingFilters(false)
filterPanel:setVisible(true)
end
function toggleFilterPanel()
if filterPanel:isVisible() then
hideFilterPanel()
else
showFilterPanel()
end
end
function onChangeSortType(comboBox, option)
setSortType(option:lower())
end
function onChangeSortOrder(comboBox, option)
setSortOrder(option:lower():gsub('[.]', '')) -- Replace dot in option name
end
function checkCreatures() function checkCreatures()
removeAllCreatures() removeAllCreatures()
@@ -151,15 +272,42 @@ end
function onCreatureHealthPercentChange(creature, health) function onCreatureHealthPercentChange(creature, health)
local battleButton = battleButtonsByCreaturesList[creature:getId()] local battleButton = battleButtonsByCreaturesList[creature:getId()]
if battleButton then if battleButton then
if getSortType() == 'health' then
removeCreature(creature)
addCreature(creature)
return
end
battleButton:setLifeBarPercent(creature:getHealthPercent()) battleButton:setLifeBarPercent(creature:getHealthPercent())
end end
end end
local function getDistanceBetween(p1, p2)
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
end
function onCreaturePositionChange(creature, newPos, oldPos) function onCreaturePositionChange(creature, newPos, oldPos)
if creature:isLocalPlayer() then if creature:isLocalPlayer() then
if oldPos and newPos and newPos.z ~= oldPos.z then if oldPos and newPos and newPos.z ~= oldPos.z then
checkCreatures() checkCreatures()
else else
-- Distance will change when moving, recalculate and move to correct index
if getSortType() == 'distance' then
local distanceList = {}
for id, creatureButton in pairs(battleButtonsByCreaturesList) do
table.insert(distanceList, {distance = getDistanceBetween(newPos, creatureButton.creature:getPosition()), widget = creatureButton})
end
if isSortAsc() then
table.sort(distanceList, function(a, b) return a.distance < b.distance end)
else
table.sort(distanceList, function(a, b) return a.distance > b.distance end)
end
for i = 1, #distanceList do
battlePanel:moveChildToIndex(distanceList[i].widget, i)
end
end
for id, creatureButton in pairs(battleButtonsByCreaturesList) do for id, creatureButton in pairs(battleButtonsByCreaturesList) do
addCreature(creatureButton.creature) addCreature(creatureButton.creature)
end end
@@ -170,6 +318,9 @@ function onCreaturePositionChange(creature, newPos, oldPos)
if has and not fit then if has and not fit then
removeCreature(creature) removeCreature(creature)
elseif fit then elseif fit then
if has and getSortType() == 'distance' then
removeCreature(creature)
end
addCreature(creature) addCreature(creature)
end end
end end
@@ -201,8 +352,13 @@ function addCreature(creature)
local creatureId = creature:getId() local creatureId = creature:getId()
local battleButton = battleButtonsByCreaturesList[creatureId] local battleButton = battleButtonsByCreaturesList[creatureId]
-- Register when creature is added to battlelist for the first time
if not creatureAgeList[creatureId] then
creatureAgeList[creatureId] = os.time()
end
if not battleButton then if not battleButton then
battleButton = g_ui.createWidget('BattleButton', battlePanel) battleButton = g_ui.createWidget('BattleButton')
battleButton:setup(creature) battleButton:setup(creature)
battleButton.onHoverChange = onBattleButtonHoverChange battleButton.onHoverChange = onBattleButtonHoverChange
@@ -217,6 +373,77 @@ function addCreature(creature)
if creature == g_game.getFollowingCreature() then if creature == g_game.getFollowingCreature() then
onFollow(creature) onFollow(creature)
end end
local inserted = false
local nameLower = creature:getName():lower()
local healthPercent = creature:getHealthPercent()
local playerPosition = g_game.getLocalPlayer():getPosition()
local distance = getDistanceBetween(playerPosition, creature:getPosition())
local age = creatureAgeList[creatureId]
local childCount = battlePanel:getChildCount()
for i = 1, childCount do
local child = battlePanel:getChildByIndex(i)
local childName = child:getCreature():getName():lower()
local equal = false
if getSortType() == 'age' then
local childAge = creatureAgeList[child:getCreature():getId()]
if (age < childAge and isSortAsc()) or (age > childAge and isSortDesc()) then
battlePanel:insertChild(i, battleButton)
inserted = true
break
elseif age == childAge then
equal = true
end
elseif getSortType() == 'distance' then
local childDistance = getDistanceBetween(child:getCreature():getPosition(), playerPosition)
if (distance < childDistance and isSortAsc()) or (distance > childDistance and isSortDesc()) then
battlePanel:insertChild(i, battleButton)
inserted = true
break
elseif childDistance == distance then
equal = true
end
elseif getSortType() == 'health' then
local childHealth = child:getCreature():getHealthPercent()
if (healthPercent < childHealth and isSortAsc()) or (healthPercent > childHealth and isSortDesc()) then
battlePanel:insertChild(i, battleButton)
inserted = true
break
elseif healthPercent == childHealth then
equal = true
end
end
-- If any other sort type is selected and values are equal, sort it by name also
if getSortType() == 'name' or equal then
local length = math.min(childName:len(), nameLower:len())
for j=1,length do
if (nameLower:byte(j) < childName:byte(j) and isSortAsc()) or (nameLower:byte(j) > childName:byte(j) and isSortDesc()) then
battlePanel:insertChild(i, battleButton)
inserted = true
break
elseif (nameLower:byte(j) > childName:byte(j) and isSortAsc()) or (nameLower:byte(j) < childName:byte(j) and isSortDesc()) then
break
elseif j == nameLower:len() and isSortAsc() then
battlePanel:insertChild(i, battleButton)
inserted = true
elseif j == childName:len() and isSortDesc() then
battlePanel:insertChild(i, battleButton)
inserted = true
end
end
end
if inserted then
break
end
end
-- Insert at the end if no other place is found
if not inserted then
battlePanel:insertChild(childCount + 1, battleButton)
end
else else
battleButton:setLifeBarPercent(creature:getHealthPercent()) battleButton:setLifeBarPercent(creature:getHealthPercent())
end end
@@ -226,6 +453,7 @@ function addCreature(creature)
end end
function removeAllCreatures() function removeAllCreatures()
creatureAgeList = {}
for i, v in pairs(battleButtonsByCreaturesList) do for i, v in pairs(battleButtonsByCreaturesList) do
removeCreature(v.creature) removeCreature(v.creature)
end end

View File

@@ -45,11 +45,12 @@ MiniWindow
&save: true &save: true
Panel Panel
id: filterPanel
margin-top: 26 margin-top: 26
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: miniwindowScrollBar.left anchors.right: miniwindowScrollBar.left
height: 20 height: 45
Panel Panel
anchors.top: parent.top anchors.top: parent.top
@@ -85,16 +86,56 @@ MiniWindow
!tooltip: tr('Hide party members') !tooltip: tr('Hide party members')
@onCheckChange: modules.game_battle.checkCreatures() @onCheckChange: modules.game_battle.checkCreatures()
HorizontalSeparator Panel
anchors.top: prev.bottom
anchors.horizontalCenter: parent.horizontalCenter
height: 20
width: 128
margin-top: 6
ComboBox
id: sortTypeBox
width: 74
anchors.top: parent.top
anchors.left: prev.right
anchors.horizontalCenter: parent.horizontalCenter
margin-left: -28
ComboBox
id: sortOrderBox
width: 54
anchors.top: parent.top
anchors.left: prev.right
margin-left: 4
Panel
height: 18
anchors.top: prev.bottom anchors.top: prev.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: miniwindowScrollBar.left anchors.right: miniwindowScrollBar.left
margin-right: 1 margin-top: 5
margin-top: 4
UIWidget
id: toggleFilterButton
anchors.top: prev.top
width: 21
anchors.horizontalCenter: parent.horizontalCenter
image-source: /images/ui/arrow_vertical
image-rect: 0 0 21 12
image-clip: 21 0 21 12
@onClick: modules.game_battle.toggleFilterPanel()
phantom: false
HorizontalSeparator
anchors.top: prev.top
anchors.left: parent.left
anchors.right: miniwindowScrollBar.left
margin-right: 1
margin-top: 11
MiniWindowContents MiniWindowContents
anchors.top: prev.bottom anchors.top: prev.bottom
margin-top: 0 margin-top: 6
Panel Panel
id: battlePanel id: battlePanel

View File

@@ -0,0 +1,206 @@
IgnoreListLabel < Label
font: verdana-11px-monochrome
background-color: alpha
text-offset: 2 0
focusable: true
phantom: false
$focus:
background-color: #ffffff22
color: #ffffff
WhiteListLabel < Label
font: verdana-11px-monochrome
background-color: alpha
text-offset: 2 0
focusable: true
phantom: false
$focus:
background-color: #ffffff22
color: #ffffff
MainWindow
id: communicationWindow
!text: tr('Ignore List')
size: 515 410
@onEscape: self:destroy()
CheckBox
id: checkboxUseIgnoreList
!text: tr('Activate ignorelist')
anchors.left: parent.left
anchors.top: parent.top
width: 180
Label
!text: tr('Ignored Players:')
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 10
TextList
id: ignoreList
vertical-scrollbar: ignoreListScrollBar
anchors.left: parent.left
anchors.top: prev.bottom
height: 150
width: 230
margin-bottom: 10
margin-top: 3
padding: 1
focusable: false
TextEdit
id: ignoreNameEdit
anchors.top: prev.bottom
anchors.left: parent.left
width: 110
margin-top: 5
Button
id: buttonIgnoreAdd
!text: tr('Add')
width: 48
height: 20
margin-left: 5
anchors.top: prev.top
anchors.left: prev.right
Button
id: buttonIgnoreRemove
!text: tr('Remove')
width: 64
height: 20
margin-left: 5
anchors.top: prev.top
anchors.left: prev.right
Label
!text: tr('Global ignore settings')
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 20
CheckBox
id: checkboxIgnorePrivateMessages
!text: tr('Ignore Private Messages')
anchors.left: parent.left
anchors.top: prev.bottom
width: 180
margin-top: 5
CheckBox
id: checkboxIgnoreYelling
!text: tr('Ignore Yelling')
anchors.left: parent.left
anchors.top: prev.bottom
width: 180
margin-top: 5
CheckBox
id: checkboxUseWhiteList
!text: tr('Activate whitelist')
anchors.top: parent.top
anchors.left: ignoreList.right
margin-left: 20
width: 180
Label
!text: tr('Allowed Players:')
anchors.top: prev.bottom
anchors.left: prev.left
margin-top: 10
TextList
id: whiteList
vertical-scrollbar: whiteListScrollBar
anchors.left: prev.left
anchors.top: prev.bottom
height: 150
width: 230
margin-bottom: 10
margin-top: 3
padding: 1
focusable: false
TextEdit
id: whitelistNameEdit
anchors.top: prev.bottom
anchors.left: prev.left
width: 110
margin-top: 5
Button
id: buttonWhitelistAdd
!text: tr('Add')
width: 48
height: 20
margin-left: 5
anchors.top: prev.top
anchors.left: prev.right
Button
id: buttonWhitelistRemove
!text: tr('Remove')
width: 64
height: 20
margin-left: 5
anchors.top: prev.top
anchors.left: prev.right
Label
!text: tr('Global whitelist settings')
anchors.left: whiteList.left
anchors.top: prev.bottom
margin-top: 20
CheckBox
id: checkboxAllowVIPs
!text: tr('Allow VIPs to message you')
anchors.left: prev.left
anchors.top: prev.bottom
width: 180
margin-top: 5
Panel
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 30
Panel
size: 160 30
anchors.horizontalCenter: parent.horizontalCenter
Button
id: buttonSave
!text: tr('Save')
width: 75
anchors.top: parent.top
anchors.left: parent.left
Button
id: buttonCancel
!text: tr('Cancel')
width: 75
anchors.top: parent.top
anchors.left: prev.right
margin-left: 10
VerticalScrollBar
id: ignoreListScrollBar
anchors.top: ignoreList.top
anchors.bottom: ignoreList.bottom
anchors.right: ignoreList.right
step: 14
pixels-scroll: true
VerticalScrollBar
id: whiteListScrollBar
anchors.top: whiteList.top
anchors.bottom: whiteList.bottom
anchors.right: whiteList.right
step: 14
pixels-scroll: true

View File

@@ -61,7 +61,7 @@ consoleTabBar = nil
consoleTextEdit = nil consoleTextEdit = nil
channels = nil channels = nil
channelsWindow = nil channelsWindow = nil
ignoreWindow = nil communicationWindow = nil
ownPrivateName = nil ownPrivateName = nil
messageHistory = {} messageHistory = {}
currentMessageIndex = 0 currentMessageIndex = 0
@@ -74,10 +74,14 @@ violationReportTab = nil
ignoredChannels = {} ignoredChannels = {}
filters = {} filters = {}
local ignoreSettings = { local communicationSettings = {
useIgnoreList = true,
useWhiteList = true,
privateMessages = false, privateMessages = false,
yelling = false, yelling = false,
players = {} allowVIPs = false,
ignoredPlayers = {},
whitelistedPlayers = {}
} }
function init() function init()
@@ -139,10 +143,59 @@ function init()
g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels) g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels)
g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab) g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab)
g_keyboard.bindKeyDown('Ctrl+H', openHelp) g_keyboard.bindKeyDown('Ctrl+H', openHelp)
consoleToggleChat = consolePanel:getChildById('toggleChat')
load() load()
end end
function toggleChat()
if consoleToggleChat:isChecked() then
disableChat()
else
enableChat()
end
end
function enableChat()
local gameInterface = modules.game_interface
consoleTextEdit:setVisible(true)
consoleTextEdit:setText("")
g_keyboard.unbindKeyUp("Space")
g_keyboard.unbindKeyUp("Enter")
gameInterface.unbindWalkKey("W")
gameInterface.unbindWalkKey("D")
gameInterface.unbindWalkKey("S")
gameInterface.unbindWalkKey("A")
consoleToggleChat:setTooltip(tr("Disable chat mode, allow to walk using ASDW"))
end
function disableChat()
local gameInterface = modules.game_interface
consoleTextEdit:setVisible(false)
consoleTextEdit:setText("")
local quickFunc = function()
if consoleToggleChat:isChecked() then
consoleToggleChat:setChecked(false)
end
enableChat()
end
g_keyboard.bindKeyUp("Space", quickFunc)
g_keyboard.bindKeyUp("Enter", quickFunc)
gameInterface.bindWalkKey("W", North)
gameInterface.bindWalkKey("D", East)
gameInterface.bindWalkKey("S", South)
gameInterface.bindWalkKey("A", West)
consoleToggleChat:setTooltip(tr("Enable chat mode"))
end
function terminate() function terminate()
save() save()
disconnect(g_game, { disconnect(g_game, {
@@ -166,14 +219,14 @@ function terminate()
g_keyboard.unbindKeyDown('Ctrl+E') g_keyboard.unbindKeyDown('Ctrl+E')
g_keyboard.unbindKeyDown('Ctrl+H') g_keyboard.unbindKeyDown('Ctrl+H')
saveIgnoreSettings() saveCommunicationSettings()
if channelsWindow then if channelsWindow then
channelsWindow:destroy() channelsWindow:destroy()
end end
if ignoreWindow then if communicationWindow then
ignoreWindow:destroy() communicationWindow:destroy()
end end
if violationWindow then if violationWindow then
@@ -197,7 +250,7 @@ function load()
if settings then if settings then
messageHistory = settings.messageHistory or {} messageHistory = settings.messageHistory or {}
end end
loadIgnoreSettings() loadCommunicationSettings()
end end
function onTabChange(tabBar, tab) function onTabChange(tabBar, tab)
@@ -466,7 +519,7 @@ function addTabText(text, speaktype, tab, creatureName)
-- Remove the curly braces -- Remove the curly braces
for i = 1, #highlightData / 3 do for i = 1, #highlightData / 3 do
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] } local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
text = text:gsub("{"..dataBlock.words.."}", dataBlock.words) text = text:gsub("%{(.-)%}", dataBlock.words, 1)
-- Recalculate positions as braces are removed -- Recalculate positions as braces are removed
highlightData[(i-1)*3+1] = dataBlock._start - ((i-1) * 2) highlightData[(i-1)*3+1] = dataBlock._start - ((i-1) * 2)
@@ -779,7 +832,11 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
return return
end end
if name ~= g_game.getCharacterName() then local localPlayer = g_game.getLocalPlayer()
if name ~= g_game.getCharacterName()
and isUsingIgnoreList()
and not(isUsingWhiteList()) or (isUsingWhiteList() and not(isWhitelisted(name)) and not(isAllowingVIPs() and localPlayer:hasVip(name))) then
if mode == MessageModes.Yell and isIgnoringYelling() then if mode == MessageModes.Yell and isIgnoringYelling() then
return return
elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then
@@ -957,107 +1014,221 @@ function onChannelList(channelList)
end end
end end
function loadIgnoreSettings() function loadCommunicationSettings()
communicationSettings.whitelistedPlayers = {}
communicationSettings.ignoredPlayers = {}
local ignoreNode = g_settings.getNode('IgnorePlayers') local ignoreNode = g_settings.getNode('IgnorePlayers')
if ignoreNode then if ignoreNode then
for i = 1, #ignoreNode do for i = 1, #ignoreNode do
table.insert(ignoreSettings.players, ignoreNode[i]) table.insert(communicationSettings.ignoredPlayers, ignoreNode[i])
end end
end end
ignoreSettings.privateMessages = g_settings.getBoolean('IgnorePrivateMessages')
ignoreSettings.yelling = g_settings.getBoolean('IgnoreYelling')
end
function saveIgnoreSettings() local whitelistNode = g_settings.getNode('WhitelistedPlayers')
local tmpSettings = {} if whitelistNode then
for i = 1, #ignoreSettings.players do for i = 1, #whitelistNode do
table.insert(tmpSettings, ignoreSettings.players[i]) table.insert(communicationSettings.whitelistedPlayers, whitelistNode[i])
end
end end
g_settings.set('IgnorePrivateMessages', ignoreSettings.privateMessages)
g_settings.set('IgnoreYelling', ignoreSettings.yelling) communicationSettings.useIgnoreList = g_settings.getBoolean('UseIgnoreList')
g_settings.setNode('IgnorePlayers', tmpSettings) communicationSettings.useWhiteList = g_settings.getBoolean('UseWhiteList')
communicationSettings.privateMessages = g_settings.getBoolean('IgnorePrivateMessages')
communicationSettings.yelling = g_settings.getBoolean('IgnoreYelling')
communicationSettings.allowVIPs = g_settings.getBoolean('AllowVIPs')
end end
function saveCommunicationSettings()
local tmpIgnoreList = {}
local ignoredPlayers = getIgnoredPlayers()
for i = 1, #ignoredPlayers do
table.insert(tmpIgnoreList, ignoredPlayers[i])
end
local tmpWhiteList = {}
local whitelistedPlayers = getWhitelistedPlayers()
for i = 1, #whitelistedPlayers do
table.insert(tmpWhiteList, whitelistedPlayers[i])
end
g_settings.set('UseIgnoreList', communicationSettings.useIgnoreList)
g_settings.set('UseWhiteList', communicationSettings.useWhiteList)
g_settings.set('IgnorePrivateMessages', communicationSettings.privateMessages)
g_settings.set('IgnoreYelling', communicationSettings.yelling)
g_settings.setNode('IgnorePlayers', tmpIgnoreList)
g_settings.setNode('WhitelistedPlayers', tmpWhiteList)
end
function getIgnoredPlayers()
return communicationSettings.ignoredPlayers
end
function getWhitelistedPlayers()
return communicationSettings.whitelistedPlayers
end
function isUsingIgnoreList()
return communicationSettings.useIgnoreList
end
function isUsingWhiteList()
return communicationSettings.useWhiteList
end
function isIgnored(name) function isIgnored(name)
return table.find(ignoreSettings.players, name, true) return table.find(communicationSettings.ignoredPlayers, name, true)
end end
function addIgnoredPlayer(name) function addIgnoredPlayer(name)
if not isIgnored(name) then if isIgnored(name) then return end
table.insert(ignoreSettings.players, name) table.insert(communicationSettings.ignoredPlayers, name)
end
end end
function removeIgnoredPlayer(name) function removeIgnoredPlayer(name)
table.removevalue(ignoreSettings.players, name) table.removevalue(communicationSettings.ignoredPlayers, name)
end
function isWhitelisted(name)
return table.find(communicationSettings.whitelistedPlayers, name, true)
end
function addWhitelistedPlayer(name)
if isWhitelisted(name) then return end
table.insert(communicationSettings.whitelistedPlayers, name)
end
function removeWhitelistedPlayer(name)
table.removevalue(communicationSettings.whitelistedPlayers, name)
end end
function isIgnoringPrivate() function isIgnoringPrivate()
return ignoreSettings.privateMessages return communicationSettings.privateMessages
end end
function isIgnoringYelling() function isIgnoringYelling()
return ignoreSettings.yelling return communicationSettings.yelling
end
function isAllowingVIPs()
return communicationSettings.allowVIPs
end end
function onClickIgnoreButton() function onClickIgnoreButton()
if ignoreWindow then return end if communicationWindow then return end
ignoreWindow = g_ui.displayUI('ignorewindow') communicationWindow = g_ui.displayUI('communicationwindow')
local ignoreListPanel = ignoreWindow:getChildById('ignoreList') local ignoreListPanel = communicationWindow:getChildById('ignoreList')
ignoreWindow.onDestroy = function() ignoreWindow = nil end local whiteListPanel = communicationWindow:getChildById('whiteList')
communicationWindow.onDestroy = function() communicationWindow = nil end
local removeButton = ignoreWindow:getChildById('buttonRemove') local useIgnoreListBox = communicationWindow:getChildById('checkboxUseIgnoreList')
removeButton:disable() useIgnoreListBox:setChecked(communicationSettings.useIgnoreList)
ignoreListPanel.onChildFocusChange = function() removeButton:enable() end local useWhiteListBox = communicationWindow:getChildById('checkboxUseWhiteList')
removeButton.onClick = function() useWhiteListBox:setChecked(communicationSettings.useWhiteList)
local removeIgnoreButton = communicationWindow:getChildById('buttonIgnoreRemove')
removeIgnoreButton:disable()
ignoreListPanel.onChildFocusChange = function() removeIgnoreButton:enable() end
removeIgnoreButton.onClick = function()
local selection = ignoreListPanel:getFocusedChild() local selection = ignoreListPanel:getFocusedChild()
if selection then if selection then
ignoreListPanel:removeChild(selection) ignoreListPanel:removeChild(selection)
selection:destroy() selection:destroy()
end end
if ignoreListPanel:getChildCount() == 0 then removeIgnoreButton:disable()
removeButton:disable() end
local removeWhitelistButton = communicationWindow:getChildById('buttonWhitelistRemove')
removeWhitelistButton:disable()
whiteListPanel.onChildFocusChange = function() removeWhitelistButton:enable() end
removeWhitelistButton.onClick = function()
local selection = whiteListPanel:getFocusedChild()
if selection then
whiteListPanel:removeChild(selection)
selection:destroy()
end end
removeWhitelistButton:disable()
end end
local newlyIgnoredPlayers = {} local newlyIgnoredPlayers = {}
local addName = ignoreWindow:getChildById('ignoreNameEdit') local addIgnoreName = communicationWindow:getChildById('ignoreNameEdit')
local addButton = ignoreWindow:getChildById('buttonAdd') local addIgnoreButton = communicationWindow:getChildById('buttonIgnoreAdd')
local addFunction = function() local addIgnoreFunction = function()
if addName:getText() == '' then return end local newEntry = addIgnoreName:getText()
if table.find(ignoreSettings.players, addName:getText()) then return end if newEntry == '' then return end
if table.find(newlyIgnoredPlayers, addName:getText()) then return end if table.find(getIgnoredPlayers(), newEntry) then return end
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel) if table.find(newlyIgnoredPlayers, newEntry) then return end
label:setText(addName:getText())
table.insert(newlyIgnoredPlayers, addName:getText())
label:setPhantom(false)
addName:setText('')
end
addButton.onClick = addFunction
ignoreWindow.onEnter = addFunction
local ignorePrivateMessageBox = ignoreWindow:getChildById('checkboxIgnorePrivateMessages')
ignorePrivateMessageBox:setChecked(ignoreSettings.privateMessages)
local ignoreYellingBox = ignoreWindow:getChildById('checkboxIgnoreYelling')
ignoreYellingBox:setChecked(ignoreSettings.yelling)
local saveButton = ignoreWindow:getChildById('buttonSave')
saveButton.onClick = function()
ignoreSettings.players = {}
for i = 1, ignoreListPanel:getChildCount() do
addIgnoredPlayer(ignoreListPanel:getChildByIndex(i):getText())
--table.insert(ignoreSettings.players, ignoreListPanel:getChildByIndex(i):getText())
end
ignoreSettings.yelling = ignoreYellingBox:isChecked()
ignoreSettings.privateMessages = ignorePrivateMessageBox:isChecked()
ignoreWindow:destroy()
end
for _, name in pairs(ignoreSettings.players) do
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel) local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
label:setText(name) label:setText(newEntry)
label:setPhantom(false) table.insert(newlyIgnoredPlayers, newEntry)
addIgnoreName:setText('')
end
addIgnoreButton.onClick = addIgnoreFunction
local newlyWhitelistedPlayers = {}
local addWhitelistName = communicationWindow:getChildById('whitelistNameEdit')
local addWhitelistButton = communicationWindow:getChildById('buttonWhitelistAdd')
local addWhitelistFunction = function()
local newEntry = addWhitelistName:getText()
if newEntry == '' then return end
if table.find(getWhitelistedPlayers(), newEntry) then return end
if table.find(newlyWhitelistedPlayers, newEntry) then return end
local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
label:setText(newEntry)
table.insert(newlyWhitelistedPlayers, newEntry)
addWhitelistName:setText('')
end
addWhitelistButton.onClick = addWhitelistFunction
communicationWindow.onEnter = function()
if addWhitelistName:isFocused() then
addWhitelistFunction()
elseif addIgnoreName:isFocused() then
addIgnoreFunction()
end
end
local ignorePrivateMessageBox = communicationWindow:getChildById('checkboxIgnorePrivateMessages')
ignorePrivateMessageBox:setChecked(communicationSettings.privateMessages)
local ignoreYellingBox = communicationWindow:getChildById('checkboxIgnoreYelling')
ignoreYellingBox:setChecked(communicationSettings.yelling)
local allowVIPsBox = communicationWindow:getChildById('checkboxAllowVIPs')
allowVIPsBox:setChecked(communicationSettings.allowVIPs)
local saveButton = communicationWindow:recursiveGetChildById('buttonSave')
saveButton.onClick = function()
communicationSettings.ignoredPlayers = {}
for i = 1, ignoreListPanel:getChildCount() do
addIgnoredPlayer(ignoreListPanel:getChildByIndex(i):getText())
end
communicationSettings.whitelistedPlayers = {}
for i = 1, whiteListPanel:getChildCount() do
addWhitelistedPlayer(whiteListPanel:getChildByIndex(i):getText())
end
communicationSettings.useIgnoreList = useIgnoreListBox:isChecked()
communicationSettings.useWhiteList = useWhiteListBox:isChecked()
communicationSettings.yelling = ignoreYellingBox:isChecked()
communicationSettings.privateMessages = ignorePrivateMessageBox:isChecked()
communicationSettings.allowVIPs = allowVIPsBox:isChecked()
communicationWindow:destroy()
end
local cancelButton = communicationWindow:recursiveGetChildById('buttonCancel')
cancelButton.onClick = function()
communicationWindow:destroy()
end
local ignoredPlayers = getIgnoredPlayers()
for i = 1, #ignoredPlayers do
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
label:setText(ignoredPlayers[i])
end
local whitelistedPlayers = getWhitelistedPlayers()
for i = 1, #whitelistedPlayers do
local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
label:setText(whitelistedPlayers[i])
end end
end end
@@ -1089,4 +1260,4 @@ function offline()
g_keyboard.unbindKeyDown('Ctrl+R') g_keyboard.unbindKeyDown('Ctrl+R')
end end
clear() clear()
end end

View File

@@ -56,12 +56,21 @@ Panel
id: consolePanel id: consolePanel
anchors.fill: parent anchors.fill: parent
CheckBox
id: toggleChat
!tooltip: tr('Disable chat mode, allow to walk using ASDW')
anchors.left: parent.left
anchors.top: parent.top
margin-left: 13
margin-top: 8
@onCheckChange: toggleChat()
TabButton TabButton
id: prevChannelButton id: prevChannelButton
icon: /images/game/console/leftarrow icon: /images/game/console/leftarrow
anchors.left: parent.left anchors.left: toggleChat.right
anchors.top: parent.top anchors.top: parent.top
margin-left: 6 margin-left: 3
margin-top: 6 margin-top: 6
ConsoleTabBar ConsoleTabBar

View File

@@ -1,98 +0,0 @@
IgnoreListLabel < Label
font: verdana-11px-monochrome
background-color: alpha
text-offset: 2 0
focusable: true
$focus:
background-color: #ffffff22
color: #ffffff
MainWindow
id: ignoreWindow
!text: tr('Ignore List')
size: 500 240
@onEscape: self:destroy()
Label
!text: tr('Ignored players:')
anchors.left: parent.left
anchors.top: parent.top
TextList
id: ignoreList
vertical-scrollbar: ignoreListScrollBar
anchors.left: parent.left
anchors.top: prev.bottom
height: 150
width: 230
margin-bottom: 10
margin-top: 3
padding: 1
focusable: false
Button
id: buttonRemove
!text: tr('Remove')
width: 64
anchors.right: prev.right
anchors.bottom: parent.bottom
TextEdit
id: ignoreNameEdit
anchors.left: ignoreList.right
anchors.top: ignoreList.top
width: 180
margin-left: 8
margin-right: 3
Button
id: buttonAdd
!text: tr('Add')
width: 48
height: 20
anchors.right: parent.right
anchors.top: prev.top
CheckBox
id: checkboxIgnorePrivateMessages
!text: tr('Ignore Private Messages')
anchors.left: ignoreList.right
anchors.top: ignoreList.top
width: 180
margin-top: 25
margin-left: 8
CheckBox
id: checkboxIgnoreYelling
!text: tr('Ignore Yelling')
anchors.left: ignoreList.right
anchors.top: prev.top
width: 180
margin-top: 25
margin-left: 8
Button
id: buttonSave
!text: tr('Save')
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin-right: 10
@onClick: self:getParent():onEnter()
Button
id: buttonCancel
!text: tr('Cancel')
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: self:getParent():destroy()
VerticalScrollBar
id: ignoreListScrollBar
anchors.top: ignoreList.top
anchors.bottom: ignoreList.bottom
anchors.right: ignoreList.right
step: 14
pixels-scroll: true

View File

@@ -42,7 +42,8 @@ function init()
gameBottomPanel = gameRootPanel:getChildById('gameBottomPanel') gameBottomPanel = gameRootPanel:getChildById('gameBottomPanel')
connect(gameLeftPanel, { onVisibilityChange = onLeftPanelVisibilityChange }) connect(gameLeftPanel, { onVisibilityChange = onLeftPanelVisibilityChange })
logoutButton = modules.client_topmenu.addLeftButton('logoutButton', tr('Exit'), '/images/topbuttons/logout', tryLogout, true) logoutButton = modules.client_topmenu.addLeftButton('logoutButton', tr('Exit'),
'/images/topbuttons/logout', tryLogout, true)
setupViewMode(0) setupViewMode(0)
@@ -56,42 +57,19 @@ end
function bindKeys() function bindKeys()
gameRootPanel:setAutoRepeatDelay(250) gameRootPanel:setAutoRepeatDelay(250)
g_keyboard.bindKeyDown('Up', function() changeWalkDir(North) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Right', function() changeWalkDir(East) end, gameRootPanel, true) bindWalkKey('Up', North)
g_keyboard.bindKeyDown('Down', function() changeWalkDir(South) end, gameRootPanel, true) bindWalkKey('Right', East)
g_keyboard.bindKeyDown('Left', function() changeWalkDir(West) end, gameRootPanel, true) bindWalkKey('Down', South)
g_keyboard.bindKeyDown('Numpad8', function() changeWalkDir(North) end, gameRootPanel, true) bindWalkKey('Left', West)
g_keyboard.bindKeyDown('Numpad9', function() changeWalkDir(NorthEast) end, gameRootPanel, true) bindWalkKey('Numpad8', North)
g_keyboard.bindKeyDown('Numpad6', function() changeWalkDir(East) end, gameRootPanel, true) bindWalkKey('Numpad9', NorthEast)
g_keyboard.bindKeyDown('Numpad3', function() changeWalkDir(SouthEast) end, gameRootPanel, true) bindWalkKey('Numpad6', East)
g_keyboard.bindKeyDown('Numpad2', function() changeWalkDir(South) end, gameRootPanel, true) bindWalkKey('Numpad3', SouthEast)
g_keyboard.bindKeyDown('Numpad1', function() changeWalkDir(SouthWest) end, gameRootPanel, true) bindWalkKey('Numpad2', South)
g_keyboard.bindKeyDown('Numpad4', function() changeWalkDir(West) end, gameRootPanel, true) bindWalkKey('Numpad1', SouthWest)
g_keyboard.bindKeyDown('Numpad7', function() changeWalkDir(NorthWest) end, gameRootPanel, true) bindWalkKey('Numpad4', West)
g_keyboard.bindKeyUp('Up', function() changeWalkDir(North, true) end, gameRootPanel, true) bindWalkKey('Numpad7', NorthWest)
g_keyboard.bindKeyUp('Right', function() changeWalkDir(East, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Down', function() changeWalkDir(South, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Left', function() changeWalkDir(West, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad8', function() changeWalkDir(North, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad9', function() changeWalkDir(NorthEast, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad6', function() changeWalkDir(East, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad3', function() changeWalkDir(SouthEast, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad2', function() changeWalkDir(South, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad1', function() changeWalkDir(SouthWest, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad4', function() changeWalkDir(West, true) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Numpad7', function() changeWalkDir(NorthWest, true) end, gameRootPanel, true)
g_keyboard.bindKeyPress('Up', function() smartWalk(North) end, gameRootPanel)
g_keyboard.bindKeyPress('Right', function() smartWalk(East) end, gameRootPanel)
g_keyboard.bindKeyPress('Down', function() smartWalk(South) end, gameRootPanel)
g_keyboard.bindKeyPress('Left', function() smartWalk(West) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad8', function() smartWalk(North) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad9', function() smartWalk(NorthEast) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad6', function() smartWalk(East) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad3', function() smartWalk(SouthEast) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad2', function() smartWalk(South) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad1', function() smartWalk(SouthWest) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad4', function() smartWalk(West) end, gameRootPanel)
g_keyboard.bindKeyPress('Numpad7', function() smartWalk(NorthWest) end, gameRootPanel)
g_keyboard.bindKeyPress('Ctrl+Up', function() g_game.turn(North) changeWalkDir(North) end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+Up', function() g_game.turn(North) changeWalkDir(North) end, gameRootPanel)
g_keyboard.bindKeyPress('Ctrl+Right', function() g_game.turn(East) changeWalkDir(East) end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+Right', function() g_game.turn(East) changeWalkDir(East) end, gameRootPanel)
@@ -104,12 +82,24 @@ function bindKeys()
g_keyboard.bindKeyPress('Escape', function() g_game.cancelAttackAndFollow() end, gameRootPanel) g_keyboard.bindKeyPress('Escape', function() g_game.cancelAttackAndFollow() end, gameRootPanel)
g_keyboard.bindKeyPress('Ctrl+=', function() gameMapPanel:zoomIn() end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+=', function() gameMapPanel:zoomIn() end, gameRootPanel)
g_keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel) g_keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+Q', logout, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+Q', function() tryLogout(false) end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+L', logout, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+L', function() tryLogout(false) end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() modules.game_textmessage.clearMessages() end, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() modules.game_textmessage.clearMessages() end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+.', nextViewMode, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+.', nextViewMode, gameRootPanel)
end end
function bindWalkKey(key, dir)
g_keyboard.bindKeyDown(key, function() changeWalkDir(dir) end)
g_keyboard.bindKeyUp(key, function() changeWalkDir(dir, true) end)
g_keyboard.bindKeyPress(key, function() smartWalk(dir) end)
end
function unbindWalkKey(key)
g_keyboard.unbindKeyDown(key)
g_keyboard.unbindKeyUp(key)
g_keyboard.unbindKeyPress(key)
end
function terminate() function terminate()
save() save()
hide() hide()
@@ -215,8 +205,8 @@ function tryExit()
return true return true
end end
local exitFunc = function() logout() forceExit() end local exitFunc = function() g_game.safeLogout() forceExit() end
local logoutFunc = function() logout() exitWindow:destroy() exitWindow = nil end local logoutFunc = function() g_game.safeLogout() exitWindow:destroy() exitWindow = nil end
local cancelFunc = function() exitWindow:destroy() exitWindow = nil end local cancelFunc = function() exitWindow:destroy() exitWindow = nil end
exitWindow = displayGeneralBox(tr('Exit'), tr("If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."), exitWindow = displayGeneralBox(tr('Exit'), tr("If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."),
@@ -228,14 +218,10 @@ function tryExit()
return true return true
end end
function logout() function tryLogout(prompt)
if g_game.isOnline() then if type(prompt) ~= "boolean" then
g_game.safeLogout() prompt = true
return true
end end
end
function tryLogout()
if not g_game.isOnline() then if not g_game.isOnline() then
exit() exit()
return return
@@ -245,13 +231,42 @@ function tryLogout()
return return
end end
local yesCallback = function() logout() logoutWindow:destroy() logoutWindow=nil end local msg, yesCallback
local noCallback = function() logoutWindow:destroy() logoutWindow=nil end if not g_game.isConnectionOk() then
msg = 'Your connection is failing, if you logout now your character will be still online, do you want to force logout?'
logoutWindow = displayGeneralBox(tr('Logout'), tr('Are you sure you want to logout?'), { yesCallback = function()
{ text=tr('Yes'), callback=yesCallback }, g_game.forceLogout()
{ text=tr('No'), callback=noCallback }, if logoutWindow then
anchor=AnchorHorizontalCenter}, yesCallback, noCallback) logoutWindow:destroy()
logoutWindow=nil
end
end
else
msg = 'Are you sure you want to logout?'
yesCallback = function()
g_game.safeLogout()
if logoutWindow then
logoutWindow:destroy()
logoutWindow=nil
end
end
end
local noCallback = function()
logoutWindow:destroy()
logoutWindow=nil
end
if prompt then
logoutWindow = displayGeneralBox(tr('Logout'), tr(msg), {
{ text=tr('Yes'), callback=yesCallback },
{ text=tr('No'), callback=noCallback },
anchor=AnchorHorizontalCenter}, yesCallback, noCallback)
else
yesCallback()
end
end end
function stopSmartWalk() function stopSmartWalk()
@@ -463,17 +478,20 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
end end
else else
local localPosition = localPlayer:getPosition()
if not classic then shortcut = '(Alt)' else shortcut = nil end if not classic then shortcut = '(Alt)' else shortcut = nil end
if g_game.getAttackingCreature() ~= creatureThing then if creatureThing:getPosition().z == localPosition.z then
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end, shortcut) if g_game.getAttackingCreature() ~= creatureThing then
else menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end, shortcut)
menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end, shortcut) else
end menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end, shortcut)
end
if g_game.getFollowingCreature() ~= creatureThing then
menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end) if g_game.getFollowingCreature() ~= creatureThing then
else menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end)
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end) else
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
end
end end
if creatureThing:isPlayer() then if creatureThing:isPlayer() then
@@ -519,7 +537,7 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
end end
end end
if modules.game_ruleviolation.hasWindowAccess() then if modules.game_ruleviolation.hasWindowAccess() and creatureThing:isPlayer() then
menu:addSeparator() menu:addSeparator()
menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureThing:getName()) end) menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureThing:getName()) end)
end end
@@ -531,7 +549,7 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
menu:display(menuPosition) menu:display(menuPosition)
end end
function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing) function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, attackCreature)
local keyboardModifiers = g_keyboard.getModifiers() local keyboardModifiers = g_keyboard.getModifiers()
if not modules.client_options.getOption('classicControl') then if not modules.client_options.getOption('classicControl') then
@@ -557,7 +575,10 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
return true return true
end end
return true return true
elseif creatureThing and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then elseif attackCreature and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(attackCreature)
return true
elseif creatureThing and creatureThing:getPosition().z == autoWalkPos.z and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(creatureThing) g_game.attack(creatureThing)
return true return true
end end
@@ -566,7 +587,10 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
else else
if useThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then if useThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
if creatureThing and creatureThing ~= player then if attackCreature and attackCreature ~= player then
g_game.attack(attackCreature)
return true
elseif creatureThing and creatureThing ~= player and creatureThing:getPosition().z == autoWalkPos.z then
g_game.attack(creatureThing) g_game.attack(creatureThing)
return true return true
elseif useThing:isContainer() then elseif useThing:isContainer() then
@@ -594,7 +618,10 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
createThingMenu(menuPosition, lookThing, useThing, creatureThing) createThingMenu(menuPosition, lookThing, useThing, creatureThing)
return true return true
elseif creatureThing and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then elseif attackCreature and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(attackCreature)
return true
elseif creatureThing and creatureThing:getPosition().z == autoWalkPos.z and g_keyboard.isAltPressed() and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(creatureThing) g_game.attack(creatureThing)
return true return true
end end
@@ -655,6 +682,8 @@ function moveStackableItem(item, toPos)
end end
g_keyboard.bindKeyPress("Up", function() check() spinbox:up() end, spinbox) g_keyboard.bindKeyPress("Up", function() check() spinbox:up() end, spinbox)
g_keyboard.bindKeyPress("Down", function() check() spinbox:down() end, spinbox) g_keyboard.bindKeyPress("Down", function() check() spinbox:down() end, spinbox)
g_keyboard.bindKeyPress("Right", function() check() spinbox:up() end, spinbox)
g_keyboard.bindKeyPress("Left", function() check() spinbox:down() end, spinbox)
g_keyboard.bindKeyPress("PageUp", function() check() spinbox:setValue(spinbox:getValue()+10) end, spinbox) g_keyboard.bindKeyPress("PageUp", function() check() spinbox:setValue(spinbox:getValue()+10) end, spinbox)
g_keyboard.bindKeyPress("PageDown", function() check() spinbox:setValue(spinbox:getValue()-10) end, spinbox) g_keyboard.bindKeyPress("PageDown", function() check() spinbox:setValue(spinbox:getValue()-10) end, spinbox)
@@ -747,7 +776,6 @@ function setupViewMode(mode)
gameMapPanel:setVisibleDimension({ width = 15, height = 11 }) gameMapPanel:setVisibleDimension({ width = 15, height = 11 })
elseif mode == 2 then elseif mode == 2 then
local limit = limitZoom and not g_game.isGM() local limit = limitZoom and not g_game.isGM()
gameMapPanel:setKeepAspectRatio(false)
gameMapPanel:setLimitVisibleRange(limit) gameMapPanel:setLimitVisibleRange(limit)
gameMapPanel:setZoom(11) gameMapPanel:setZoom(11)
gameMapPanel:setVisibleDimension({ width = 15, height = 11 }) gameMapPanel:setVisibleDimension({ width = 15, height = 11 })

View File

@@ -6,11 +6,11 @@ CountWindow < MainWindow
SpinBox SpinBox
id: spinBox id: spinBox
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.bottom anchors.top: parent.top
width: 0 width: 1
height: 0 height: 1
phantom: true phantom: true
padding-bottom: -40 margin-top: 2
focusable: true focusable: true
Item Item

View File

@@ -78,15 +78,21 @@ function UIGameMap:onMouseRelease(mousePosition, mouseButton)
local useThing local useThing
local creatureThing local creatureThing
local multiUseThing local multiUseThing
local attackCreature
local tile = self:getTile(mousePosition) local tile = self:getTile(mousePosition)
if tile then if tile then
lookThing = tile:getTopLookThing() lookThing = tile:getTopLookThing()
useThing = tile:getTopUseThing() useThing = tile:getTopUseThing()
creatureThing = tile:getTopCreature() creatureThing = tile:getTopCreature()
end
local autoWalkTile = g_map.getTile(autoWalkPos)
if autoWalkTile then
attackCreature = autoWalkTile:getTopCreature()
end end
local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing) local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, attackCreature)
if ret then if ret then
self.allowNextRelease = false self.allowNextRelease = false
end end

View File

@@ -86,7 +86,7 @@ function UIItem:onMouseRelease(mousePosition, mouseButton)
g_game.look(item) g_game.look(item)
self.cancelNextRelease = true self.cancelNextRelease = true
return true return true
elseif modules.game_interface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item) then elseif modules.game_interface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, nil) then
return true return true
end end
return false return false

View File

@@ -151,8 +151,7 @@ function onTradeTypeChange(radioTabs, selected, deselected)
ignoreCapacity:setVisible(currentTradeType == BUY) ignoreCapacity:setVisible(currentTradeType == BUY)
ignoreEquipped:setVisible(currentTradeType == SELL) ignoreEquipped:setVisible(currentTradeType == SELL)
showAllItems:setVisible(currentTradeType == SELL) showAllItems:setVisible(currentTradeType == SELL)
sellAllButton:setVisible(false) sellAllButton:setVisible(currentTradeType == SELL)
--sellAllButton:setVisible(currentTradeType == SELL)
refreshTradeItems() refreshTradeItems()
refreshPlayerGoods() refreshPlayerGoods()

View File

@@ -252,7 +252,6 @@ MainWindow
margin-right: 10 margin-right: 10
visible: false visible: false
@onClick: modules.game_npctrade.sellAll() @onClick: modules.game_npctrade.sellAll()
visible: false
Button Button
id: tradeButton id: tradeButton

View File

@@ -47,7 +47,7 @@ function openWindow()
deathWindow = nil deathWindow = nil
end end
local cancelFunc = function() local cancelFunc = function()
modules.game_interface.logout() g_game.safeLogout()
cancelButton:getParent():destroy() cancelButton:getParent():destroy()
deathWindow = nil deathWindow = nil
end end

View File

@@ -18,7 +18,7 @@ function isLoaded()
end end
function load() function load()
local version = g_game.getProtocolVersion() local version = g_game.getClientVersion()
local datPath, sprPath local datPath, sprPath
if filename then if filename then

View File

@@ -88,6 +88,23 @@ function isHiddingOffline()
return settings['hideOffline'] return settings['hideOffline']
end end
function getSortedBy()
local settings = g_settings.getNode('VipList')
if not settings then
return 'status'
end
return settings['sortedBy']
end
function sortBy(state)
settings = {}
settings['sortedBy'] = state
g_settings.mergeNode('VipList', settings)
refresh()
end
function onAddVip(id, name, state) function onAddVip(id, name, state)
local vipList = vipWindow:getChildById('contentsPanel') local vipList = vipWindow:getChildById('contentsPanel')
@@ -118,13 +135,13 @@ function onAddVip(id, name, state)
for i=1,childrenCount do for i=1,childrenCount do
local child = vipList:getChildByIndex(i) local child = vipList:getChildByIndex(i)
if state == VipState.Online and child.vipState ~= VipState.Online then if state == VipState.Online and child.vipState ~= VipState.Online and getSortedBy() == 'status' then
vipList:insertChild(i, label) vipList:insertChild(i, label)
return return
end end
if (state ~= VipState.Online and child.vipState ~= VipState.Online) if ((state ~= VipState.Online and child.vipState ~= VipState.Online)
or (state == VipState.Online and child.vipState == VipState.Online) then or (state == VipState.Online and child.vipState == VipState.Online)) or getSortedBy() == 'name' then
local childText = child:getText():lower() local childText = child:getText():lower()
local length = math.min(childText:len(), nameLower:len()) local length = math.min(childText:len(), nameLower:len())
@@ -167,6 +184,14 @@ function onVipListMousePress(widget, mousePos, mouseButton)
else else
menu:addOption(tr('Show Offline'), function() hideOffline(false) end) menu:addOption(tr('Show Offline'), function() hideOffline(false) end)
end end
if not(getSortedBy() == 'name') then
menu:addOption(tr('Sort by name'), function() sortBy('name') end)
end
if not(getSortedBy() == 'status') then
menu:addOption(tr('Sort by status'), function() sortBy('status') end)
end
menu:display(mousePos) menu:display(mousePos)
@@ -196,6 +221,15 @@ function onVipListLabelMousePress(widget, mousePos, mouseButton)
else else
menu:addOption(tr('Show Offline'), function() hideOffline(false) end) menu:addOption(tr('Show Offline'), function() hideOffline(false) end)
end end
if not(getSortedBy() == 'name') then
menu:addOption(tr('Sort by name'), function() sortBy('name') end)
end
if not(getSortedBy() == 'status') then
menu:addOption(tr('Sort by status'), function() sortBy('status') end)
end
menu:display(mousePos) menu:display(mousePos)
return true return true

View File

@@ -6,7 +6,7 @@ end
function g_game.chooseRsa(host) function g_game.chooseRsa(host)
if currentRsa ~= CIPSOFT_RSA and currentRsa ~= OTSERV_RSA then return end if currentRsa ~= CIPSOFT_RSA and currentRsa ~= OTSERV_RSA then return end
if string.ends(host, '.tibia.com') or string.ends(host, '.cipsoft.com') then if host:ends('.tibia.com') or host:ends('.cipsoft.com') then
g_game.setRsa(CIPSOFT_RSA) g_game.setRsa(CIPSOFT_RSA)
if g_app.getOs() == 'windows' then if g_app.getOs() == 'windows' then
@@ -32,22 +32,29 @@ function g_game.isOfficialTibia()
return currentRsa == CIPSOFT_RSA return currentRsa == CIPSOFT_RSA
end end
function g_game.getSupportedProtocols() function g_game.getSupportedClients()
return { return {
810, 811, 840, 842, 850, 853, 854, 810, 811, 840, 842, 850, 853, 854,
860, 861, 862, 870, 910, 940, 944, 860, 861, 862, 870, 910, 940, 944,
953, 954, 960, 961, 963, 970, 971, 953, 954, 960, 961, 963, 970, 980,
973, 974 981, 982, 983, 984, 985, 986, 1001,
1002, 1010
} }
end end
function g_game.getSupportedClients(protocol) function g_game.getProtocolVersionForClient(client)
clients = { clients = {
[971] = {980}, [980] = 971,
[973] = {981}, [981] = 973,
[974] = {982} [982] = 974,
[983] = 975,
[984] = 976,
[985] = 977,
[986] = 978,
[1001] = 979,
[1002] = 980,
} }
return clients[protocol] or {protocol} return clients[client] or client
end end
g_game.setRsa(OTSERV_RSA) g_game.setRsa(OTSERV_RSA)

View File

@@ -2,3 +2,4 @@
-- you can place any custom user code here -- you can place any custom user code here
print 'Startup done :]' print 'Startup done :]'

View File

@@ -353,6 +353,8 @@ namespace Otc
GameForceFirstAutoWalkStep = 37, GameForceFirstAutoWalkStep = 37,
GameMinimapRemove = 38, GameMinimapRemove = 38,
GameDoubleShopSellAmount = 39, GameDoubleShopSellAmount = 39,
GameContainerPagination = 40,
GameThingMarks = 41,
// 51-100 reserved to be defined in lua // 51-100 reserved to be defined in lua
LastGameFeature = 101 LastGameFeature = 101
}; };

View File

@@ -128,7 +128,7 @@ void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWal
dest -= datType->getDisplacement() * scaleFactor; dest -= datType->getDisplacement() * scaleFactor;
datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView); datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
dest += getDisplacement() * scaleFactor; dest += getDisplacement() * scaleFactor;
zPattern = 1; zPattern = std::min(1, getNumPatternZ() - 1);
} }
PointF jumpOffset = m_jumpOffset * scaleFactor; PointF jumpOffset = m_jumpOffset * scaleFactor;

View File

@@ -99,6 +99,11 @@ void Game::resetGameStates()
m_walkEvent = nullptr; m_walkEvent = nullptr;
} }
if(m_checkConnectionEvent) {
m_checkConnectionEvent->cancel();
m_checkConnectionEvent = nullptr;
}
m_containers.clear(); m_containers.clear();
m_vips.clear(); m_vips.clear();
m_gmActions.clear(); m_gmActions.clear();
@@ -183,6 +188,16 @@ void Game::processGameStart()
g_game.ping(); g_game.ping();
}, m_pingDelay); }, m_pingDelay);
} }
m_checkConnectionEvent = g_dispatcher.cycleEvent([this] {
if(!g_game.isConnectionOk() && !m_connectionFailWarned) {
g_lua.callGlobalField("g_game", "onConnectionFailing", true);
m_connectionFailWarned = true;
} else if(g_game.isConnectionOk() && m_connectionFailWarned) {
g_lua.callGlobalField("g_game", "onConnectionFailing", false);
m_connectionFailWarned = false;
}
}, 1000);
} }
void Game::processGameEnd() void Game::processGameEnd()
@@ -190,6 +205,11 @@ void Game::processGameEnd()
m_online = false; m_online = false;
g_lua.callGlobalField("g_game", "onGameEnd"); g_lua.callGlobalField("g_game", "onGameEnd");
if(m_connectionFailWarned) {
g_lua.callGlobalField("g_game", "onConnectionFailing", false);
m_connectionFailWarned = false;
}
// reset game state // reset game state
resetGameStates(); resetGameStates();
@@ -554,7 +574,7 @@ bool Game::walk(Otc::Direction direction)
if(m_lastWalkDir != direction) { if(m_lastWalkDir != direction) {
// must add a new walk event // must add a new walk event
float ticks = m_localPlayer->getStepTicksLeft(); float ticks = m_localPlayer->getStepTicksLeft();
if(ticks < 0) { ticks = 0; } if(ticks <= 0) { ticks = 1; }
if(m_walkEvent) { if(m_walkEvent) {
m_walkEvent->cancel(); m_walkEvent->cancel();
@@ -697,15 +717,16 @@ void Game::autoWalk(std::vector<Otc::Direction> dirs)
auto it = dirs.begin(); auto it = dirs.begin();
Otc::Direction direction = *it; Otc::Direction direction = *it;
if(m_localPlayer->canWalk(direction)) { if(!m_localPlayer->canWalk(direction))
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction)); return;
if(toTile && toTile->isWalkable() && !m_localPlayer->isServerWalking()) {
m_localPlayer->preWalk(direction);
if(getFeature(Otc::GameForceFirstAutoWalkStep)) { TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
forceWalk(direction); if(toTile && toTile->isWalkable() && !m_localPlayer->isServerWalking()) {
dirs.erase(it); m_localPlayer->preWalk(direction);
}
if(getFeature(Otc::GameForceFirstAutoWalkStep)) {
forceWalk(direction);
dirs.erase(it);
} }
} }
@@ -1129,7 +1150,7 @@ void Game::removeVip(int playerId)
{ {
if(!canPerformGameAction()) if(!canPerformGameAction())
return; return;
auto it = m_vips.find(playerId); auto it = m_vips.find(playerId);
if(it == m_vips.end()) if(it == m_vips.end())
return; return;
@@ -1379,7 +1400,7 @@ void Game::setProtocolVersion(int version)
if(isOnline()) if(isOnline())
stdext::throw_exception("Unable to change protocol version while online"); stdext::throw_exception("Unable to change protocol version while online");
if(version != 0 && (version < 810 || version > 974)) if(version != 0 && (version < 810 || version > 1010))
stdext::throw_exception(stdext::format("Protocol version %d not supported", version)); stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
m_features.reset(); m_features.reset();
@@ -1443,6 +1464,14 @@ void Game::setProtocolVersion(int version)
enableFeature(Otc::GameNewSpeedLaw); enableFeature(Otc::GameNewSpeedLaw);
} }
if(version >= 976) {
enableFeature(Otc::GameContainerPagination);
}
if(version >= 979) {
enableFeature(Otc::GameThingMarks);
}
m_protocolVersion = version; m_protocolVersion = version;
Proto::buildMessageModesMap(version); Proto::buildMessageModesMap(version);
@@ -1458,7 +1487,7 @@ void Game::setClientVersion(int version)
if(isOnline()) if(isOnline())
stdext::throw_exception("Unable to change client version while online"); stdext::throw_exception("Unable to change client version while online");
if(version != 0 && (version < 810 || version > 982)) if(version != 0 && (version < 810 || version > 1010))
stdext::throw_exception(stdext::format("Client version %d not supported", version)); stdext::throw_exception(stdext::format("Client version %d not supported", version));
m_clientVersion = version; m_clientVersion = version;

View File

@@ -231,7 +231,7 @@ public:
void openRuleViolation(const std::string& reporter); void openRuleViolation(const std::string& reporter);
void closeRuleViolation(const std::string& reporter); void closeRuleViolation(const std::string& reporter);
void cancelRuleViolation(); void cancelRuleViolation();
// reports // reports
void reportBug(const std::string& comment); void reportBug(const std::string& comment);
void reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment); void reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment);
@@ -281,6 +281,7 @@ public:
bool isDead() { return m_dead; } bool isDead() { return m_dead; }
bool isAttacking() { return !!m_attackingCreature; } bool isAttacking() { return !!m_attackingCreature; }
bool isFollowing() { return !!m_followingCreature; } bool isFollowing() { return !!m_followingCreature; }
bool isConnectionOk() { return m_protocolGame && m_protocolGame->getElapsedTicksSinceLastRead() < 5000; }
int getPing() { return m_ping >= 0 ? std::max(m_ping, m_pingTimer.elapsed_millis()) : -1; } int getPing() { return m_ping >= 0 ? std::max(m_ping, m_pingTimer.elapsed_millis()) : -1; }
ContainerPtr getContainer(int index) { return m_containers[index]; } ContainerPtr getContainer(int index) { return m_containers[index]; }
@@ -340,6 +341,8 @@ private:
std::bitset<Otc::LastGameFeature> m_features; std::bitset<Otc::LastGameFeature> m_features;
ScheduledEventPtr m_pingEvent; ScheduledEventPtr m_pingEvent;
ScheduledEventPtr m_walkEvent; ScheduledEventPtr m_walkEvent;
ScheduledEventPtr m_checkConnectionEvent;
bool m_connectionFailWarned;
int m_protocolVersion; int m_protocolVersion;
int m_clientVersion; int m_clientVersion;
std::string m_clientSignature; std::string m_clientSignature;

View File

@@ -26,7 +26,6 @@
#include <framework/graphics/framebuffermanager.h> #include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/painter.h> #include <framework/graphics/painter.h>
#include <framework/graphics/image.h> #include <framework/graphics/image.h>
#include <framework/graphics/ogl/textureogl.h>
enum { enum {
MAX_LIGHT_INTENSITY = 8, MAX_LIGHT_INTENSITY = 8,
@@ -62,7 +61,7 @@ TexturePtr LightView::generateLightBubble(float centerFactor)
} }
} }
TexturePtr tex = TexturePtr(new TextureOGL(lightImage, true)); TexturePtr tex = TexturePtr(new Texture(lightImage, true));
tex->setSmooth(true); tex->setSmooth(true);
return tex; return tex;
} }

View File

@@ -72,7 +72,7 @@ bool LocalPlayer::canWalk(Otc::Direction direction)
return false; return false;
// last walk is not done yet // last walk is not done yet
if(m_walkTimer.ticksElapsed() < getStepDuration()) if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
return false; return false;
// prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
@@ -83,7 +83,7 @@ bool LocalPlayer::canWalk(Otc::Direction direction)
return false; return false;
// cannot walk while already walking // cannot walk while already walking
if(m_walking && !prewalkTimeouted) if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
return false; return false;
return true; return true;
@@ -95,6 +95,7 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
if(m_preWalking) { if(m_preWalking) {
// switch to normal walking // switch to normal walking
m_preWalking = false; m_preWalking = false;
m_secondPreWalk = false;
m_lastPrewalkDone = true; m_lastPrewalkDone = true;
// if is to the last prewalk destination, updates the walk preserving the animation // if is to the last prewalk destination, updates the walk preserving the animation
if(newPos == m_lastPrewalkDestination) { if(newPos == m_lastPrewalkDestination) {
@@ -118,7 +119,8 @@ void LocalPlayer::preWalk(Otc::Direction direction)
Position newPos = m_position.translatedToDirection(direction); Position newPos = m_position.translatedToDirection(direction);
// avoid reanimating prewalks // avoid reanimating prewalks
if(m_preWalking && m_lastPrewalkDestination == newPos) { if(m_preWalking) {
m_secondPreWalk = true;
return; return;
} }
@@ -277,6 +279,7 @@ void LocalPlayer::terminateWalk()
{ {
Creature::terminateWalk(); Creature::terminateWalk();
m_preWalking = false; m_preWalking = false;
m_secondPreWalk = false;
m_idleTimer.restart(); m_idleTimer.restart();
auto self = asLocalPlayer(); auto self = asLocalPlayer();

View File

@@ -126,6 +126,7 @@ private:
ticks_t m_walkLockExpiration; ticks_t m_walkLockExpiration;
stdext::boolean<false> m_preWalking; stdext::boolean<false> m_preWalking;
stdext::boolean<true> m_lastPrewalkDone; stdext::boolean<true> m_lastPrewalkDone;
stdext::boolean<false> m_secondPreWalk;
stdext::boolean<false> m_serverWalking; stdext::boolean<false> m_serverWalking;
stdext::boolean<false> m_knownCompletePath; stdext::boolean<false> m_knownCompletePath;

View File

@@ -230,6 +230,7 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "isDead", &Game::isDead, &g_game); g_lua.bindSingletonFunction("g_game", "isDead", &Game::isDead, &g_game);
g_lua.bindSingletonFunction("g_game", "isAttacking", &Game::isAttacking, &g_game); g_lua.bindSingletonFunction("g_game", "isAttacking", &Game::isAttacking, &g_game);
g_lua.bindSingletonFunction("g_game", "isFollowing", &Game::isFollowing, &g_game); g_lua.bindSingletonFunction("g_game", "isFollowing", &Game::isFollowing, &g_game);
g_lua.bindSingletonFunction("g_game", "isConnectionOk", &Game::isConnectionOk, &g_game);
g_lua.bindSingletonFunction("g_game", "getPing", &Game::getPing, &g_game); g_lua.bindSingletonFunction("g_game", "getPing", &Game::getPing, &g_game);
g_lua.bindSingletonFunction("g_game", "getContainer", &Game::getContainer, &g_game); g_lua.bindSingletonFunction("g_game", "getContainer", &Game::getContainer, &g_game);
g_lua.bindSingletonFunction("g_game", "getContainers", &Game::getContainers, &g_game); g_lua.bindSingletonFunction("g_game", "getContainers", &Game::getContainers, &g_game);

View File

@@ -608,21 +608,21 @@ int MapView::calcFirstVisibleFloor()
Position pos = cameraPosition.translated(ix, iy); Position pos = cameraPosition.translated(ix, iy);
// process tiles that we can look through, e.g. windows, doors // process tiles that we can look through, e.g. windows, doors
if((ix == 0 && iy == 0) || (/*(std::abs(ix) != std::abs(iy)) && */g_map.isLookPossible(pos))) { if((ix == 0 && iy == 0) || ((std::abs(ix) != std::abs(iy)) && g_map.isLookPossible(pos))) {
Position upperPos = pos; Position upperPos = pos;
Position coveredPos = pos; Position coveredPos = pos;
while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) { while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
// check tiles physically above // check tiles physically above
TilePtr tile = g_map.getTile(upperPos); TilePtr tile = g_map.getTile(upperPos);
if(tile && tile->limitsFloorsView()) { if(tile && tile->limitsFloorsView(!g_map.isLookPossible(pos))) {
firstFloor = upperPos.z + 1; firstFloor = upperPos.z + 1;
break; break;
} }
// check tiles geometrically above // check tiles geometrically above
tile = g_map.getTile(coveredPos); tile = g_map.getTile(coveredPos);
if(tile && tile->limitsFloorsView()) { if(tile && tile->limitsFloorsView(g_map.isLookPossible(pos))) {
firstFloor = coveredPos.z + 1; firstFloor = coveredPos.z + 1;
break; break;
} }

View File

@@ -29,7 +29,6 @@
#include <framework/graphics/painter.h> #include <framework/graphics/painter.h>
#include <framework/graphics/image.h> #include <framework/graphics/image.h>
#include <framework/graphics/framebuffermanager.h> #include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/ogl/textureogl.h>
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h> #include <framework/core/filestream.h>
#include <zlib.h> #include <zlib.h>
@@ -66,7 +65,7 @@ void MinimapBlock::update()
if(shouldDraw) { if(shouldDraw) {
if(!m_texture) { if(!m_texture) {
m_texture = TexturePtr(new TextureOGL(image, true)); m_texture = TexturePtr(new Texture(image, true));
} else { } else {
m_texture->uploadPixels(image, true); m_texture->uploadPixels(image, true);
} }

View File

@@ -603,6 +603,14 @@ void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
std::string name = msg->getString(); std::string name = msg->getString();
int capacity = msg->getU8(); int capacity = msg->getU8();
bool hasParent = (msg->getU8() != 0); bool hasParent = (msg->getU8() != 0);
if(g_game.getFeature(Otc::GameContainerPagination)) {
msg->getU8(); // drag and drop
msg->getU8(); // pagination
msg->getU16(); // container size
msg->getU16(); // first index
}
int itemCount = msg->getU8(); int itemCount = msg->getU8();
std::vector<ItemPtr> items(itemCount); std::vector<ItemPtr> items(itemCount);
@@ -622,13 +630,21 @@ void ProtocolGame::parseContainerAddItem(const InputMessagePtr& msg)
{ {
int containerId = msg->getU8(); int containerId = msg->getU8();
ItemPtr item = getItem(msg); ItemPtr item = getItem(msg);
if(g_game.getFeature(Otc::GameContainerPagination)) {
msg->getU16(); // slot
}
g_game.processContainerAddItem(containerId, item); g_game.processContainerAddItem(containerId, item);
} }
void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg) void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
{ {
int containerId = msg->getU8(); int containerId = msg->getU8();
int slot = msg->getU8(); int slot;
if(g_game.getFeature(Otc::GameContainerPagination)) {
slot = msg->getU16();
} else {
slot = msg->getU8();
}
ItemPtr item = getItem(msg); ItemPtr item = getItem(msg);
g_game.processContainerUpdateItem(containerId, slot, item); g_game.processContainerUpdateItem(containerId, slot, item);
} }
@@ -636,7 +652,13 @@ void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg) void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
{ {
int containerId = msg->getU8(); int containerId = msg->getU8();
int slot = msg->getU8(); int slot;
if(g_game.getFeature(Otc::GameContainerPagination)) {
slot = msg->getU16();
getItem(msg);
} else {
slot = msg->getU8();
}
g_game.processContainerRemoveItem(containerId, slot); g_game.processContainerRemoveItem(containerId, slot);
} }
@@ -1808,6 +1830,12 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known) if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
emblem = msg->getU8(); emblem = msg->getU8();
if(g_game.getFeature(Otc::GameThingMarks)) {
msg->getU8(); // creature type for summons
msg->getU8(); // mark
msg->getU16(); // helpers
}
if(g_game.getProtocolVersion() >= 854) if(g_game.getProtocolVersion() >= 854)
unpass = msg->getU8(); unpass = msg->getU8();
@@ -1860,6 +1888,10 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
if(item->getId() == 0) if(item->getId() == 0)
stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id)); stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
if(g_game.getFeature(Otc::GameThingMarks)) {
msg->getU8(); // mark
}
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable()) if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
item->setCountOrSubType(msg->getU8()); item->setCountOrSubType(msg->getU8());

View File

@@ -48,11 +48,9 @@ bool SpriteManager::loadSpr(std::string file)
file = g_resources.guessFilePath(file, "spr"); file = g_resources.guessFilePath(file, "spr");
m_spritesFile = g_resources.openFile(file); m_spritesFile = g_resources.openFile(file);
// cache file buffer to avoid lags from hard drive // cache file buffer to avoid lags from hard drive
#ifndef MOBILE
m_spritesFile->cache(); m_spritesFile->cache();
#endif
m_signature = m_spritesFile->getU32(); m_signature = m_spritesFile->getU32();
m_spritesCount = g_game.getFeature(Otc::GameSpritesU32) ? m_spritesFile->getU32() : m_spritesFile->getU16(); m_spritesCount = g_game.getFeature(Otc::GameSpritesU32) ? m_spritesFile->getU32() : m_spritesFile->getU16();
m_spritesOffset = m_spritesFile->tell(); m_spritesOffset = m_spritesFile->tell();

View File

@@ -28,7 +28,6 @@
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/graphics/texture.h> #include <framework/graphics/texture.h>
#include <framework/graphics/image.h> #include <framework/graphics/image.h>
#include <framework/graphics/ogl/textureogl.h>
#include <framework/graphics/texturemanager.h> #include <framework/graphics/texturemanager.h>
#include <framework/core/filestream.h> #include <framework/core/filestream.h>
#include <framework/otml/otml.h> #include <framework/otml/otml.h>
@@ -68,6 +67,17 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
attr -= 1; attr -= 1;
} }
if(g_game.getProtocolVersion() >= 1010) {
/* In 10.10 all attributes from 16 and up were
* incremented by 1 to make space for 16 as
* "No Movement Animation" flag.
*/
if(attr == 16)
attr = ThingAttrNoMoveAnimation;
else if(attr > 16)
attr -= 1;
}
switch(attr) { switch(attr) {
case ThingAttrDisplacement: { case ThingAttrDisplacement: {
m_displacement.x = fin->getU16(); m_displacement.x = fin->getU16();
@@ -127,8 +137,8 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases; int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
if(totalSprites == 0) // if(totalSprites == 0)
stdext::throw_exception("a thing type has no sprites"); // stdext::throw_exception("a thing type has no sprites");
if(totalSprites > 4096) if(totalSprites > 4096)
stdext::throw_exception("a thing type has more than 4096 sprites"); stdext::throw_exception("a thing type has more than 4096 sprites");
@@ -284,7 +294,7 @@ const TexturePtr& ThingType::getTexture(int animationPhase)
} }
} }
} }
animationPhaseTexture = TexturePtr(new TextureOGL(fullImage)); animationPhaseTexture = TexturePtr(new Texture(fullImage, true));
animationPhaseTexture->setSmooth(true); animationPhaseTexture->setSmooth(true);
} }
return animationPhaseTexture; return animationPhaseTexture;

View File

@@ -81,6 +81,7 @@ enum ThingAttr : uint8 {
ThingAttrOpacity = 100, ThingAttrOpacity = 100,
ThingAttrNotPreWalkable = 101, ThingAttrNotPreWalkable = 101,
ThingAttrNoMoveAnimation = 253, // real value is 16, but we need to do this for backwards compatibility
ThingAttrChargeable = 254, // deprecated ThingAttrChargeable = 254, // deprecated
ThingLastAttr = 255 ThingLastAttr = 255
}; };

View File

@@ -457,7 +457,7 @@ ThingPtr Tile::getTopMultiUseThing()
if(thing->isForceUse()) if(thing->isForceUse())
return thing; return thing;
} }
for(uint i = 0; i < m_things.size(); ++i) { for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i]; ThingPtr thing = m_things[i];
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()) { if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()) {
@@ -590,15 +590,24 @@ bool Tile::hasCreature()
return false; return false;
} }
bool Tile::limitsFloorsView() bool Tile::limitsFloorsView(bool isFreeView)
{ {
// ground and walls limits the view // ground and walls limits the view
ThingPtr firstThing = getThing(0); ThingPtr firstThing = getThing(0);
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
return true; if(isFreeView){
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
return true;
}
else
{
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || (firstThing->isOnBottom() && firstThing->blockProjectile())))
return true;
}
return false; return false;
} }
bool Tile::canErase() bool Tile::canErase()
{ {
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty() && m_flags == 0 && m_minimapColor == 0; return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty() && m_flags == 0 && m_minimapColor == 0;

View File

@@ -48,7 +48,7 @@ enum tileflags_t
TILESTATE_TRASHHOLDER = 1 << 20, TILESTATE_TRASHHOLDER = 1 << 20,
TILESTATE_BED = 1 << 21, TILESTATE_BED = 1 << 21,
TILESTATE_DEPOT = 1 << 22, TILESTATE_DEPOT = 1 << 22,
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23 TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
}; };
class Tile : public LuaObject class Tile : public LuaObject
@@ -105,7 +105,7 @@ public:
bool mustHookSouth(); bool mustHookSouth();
bool mustHookEast(); bool mustHookEast();
bool hasCreature(); bool hasCreature();
bool limitsFloorsView(); bool limitsFloorsView(bool isFreeView = false);
bool canErase(); bool canErase();
bool hasElevation(int elevation = 1); bool hasElevation(int elevation = 1);
void overwriteMinimapColor(uint8 color) { m_minimapColor = color; } void overwriteMinimapColor(uint8 color) { m_minimapColor = color; }

View File

@@ -123,20 +123,15 @@ set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/otml/otmlparser.h ${CMAKE_CURRENT_LIST_DIR}/otml/otmlparser.h
# crash handler # crash handler
${CMAKE_CURRENT_LIST_DIR}/platform/crashhandler.h
${CMAKE_CURRENT_LIST_DIR}/platform/unixcrashhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/win32crashhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/win32platform.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/unixplatform.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/platform.cpp ${CMAKE_CURRENT_LIST_DIR}/platform/platform.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/platform.h ${CMAKE_CURRENT_LIST_DIR}/platform/platform.h
) )
if(WIN32)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/win32platform.cpp
)
else()
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/unixplatform.cpp
)
endif()
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/luafunctions.cpp set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/luafunctions.cpp
PROPERTIES LANGUAGE CXX COMPILE_FLAGS "-g0 -Os") PROPERTIES LANGUAGE CXX COMPILE_FLAGS "-g0 -Os")
@@ -263,15 +258,6 @@ if(CRASH_HANDLER)
message(STATUS "Crash handler: ON") message(STATUS "Crash handler: ON")
if(WIN32) if(WIN32)
set(framework_LIBRARIES ${framework_LIBRARIES} imagehlp) set(framework_LIBRARIES ${framework_LIBRARIES} imagehlp)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/crashhandler.h
${CMAKE_CURRENT_LIST_DIR}/platform/win32crashhandler.cpp
)
else()
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/crashhandler.h
${CMAKE_CURRENT_LIST_DIR}/platform/unixcrashhandler.cpp
)
endif() endif()
else() else()
message(STATUS "Crash handler: OFF") message(STATUS "Crash handler: OFF")
@@ -304,24 +290,18 @@ endif()
if(FRAMEWORK_GRAPHICS) if(FRAMEWORK_GRAPHICS)
set(OPENGLES "OFF" CACHE "Use OpenGL ES 1.0 or 2.0 (for mobiles devices)" STRING) set(OPENGLES "OFF" CACHE "Use OpenGL ES 1.0 or 2.0 (for mobiles devices)" STRING)
if(OPENGLES) if(OPENGLES STREQUAL "2.0")
set(framework_SOURCES ${framework_SOURCES} find_package(OpenGLES2 REQUIRED)
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextegl.cpp find_package(EGL REQUIRED)
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextegl.h set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=2)
) set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR})
if(OPENGLES STREQUAL "2.0") set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES2_LIBRARY})
find_package(OpenGLES2 REQUIRED) ELSEif(OPENGLES STREQUAL "1.0")
find_package(EGL REQUIRED) find_package(OpenGLES1 REQUIRED)
set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=2) find_package(EGL REQUIRED)
set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR}) set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=1)
set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES2_LIBRARY}) set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES1_INCLUDE_DIR})
elseif(OPENGLES STREQUAL "1.0") set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES1_LIBRARY})
find_package(OpenGLES1 REQUIRED)
find_package(EGL REQUIRED)
set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=1)
set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES1_INCLUDE_DIR})
set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES1_LIBRARY})
endif()
else() else()
## TODO: CMake Documentation says that this is not the right ## TODO: CMake Documentation says that this is not the right
# Thing for Mac OS X, but it works for now. # Thing for Mac OS X, but it works for now.
@@ -356,8 +336,6 @@ if(FRAMEWORK_GRAPHICS)
set(framework_SOURCES ${framework_SOURCES} set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/dx/painterdx9.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/dx/painterdx9.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/dx/painterdx9.h ${CMAKE_CURRENT_LIST_DIR}/graphics/dx/painterdx9.h
${CMAKE_CURRENT_LIST_DIR}/graphics/dx/graphicscontextdx9.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/dx/graphicscontextdx9.h
) )
endif() endif()
@@ -365,44 +343,6 @@ if(FRAMEWORK_GRAPHICS)
set(framework_LIBRARIES ${framework_LIBRARIES} X11) set(framework_LIBRARIES ${framework_LIBRARIES} X11)
endif() endif()
option(SDL "Use SDL 2.0 support" OFF)
if(SDL)
find_package(SDL2 REQUIRED)
set(framework_DEFINITIONS ${framework_DEFINITIONS} -DSDL)
set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR})
set(framework_LIBRARIES ${framework_LIBRARIES} ${SDL2_LIBRARY})
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/sdl/paintersdl.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/sdl/paintersdl.h
${CMAKE_CURRENT_LIST_DIR}/platform/sdlwindow.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/sdlwindow.h
)
else()
if(WIN32)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/win32window.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/win32window.h
)
if(NOT OPENGLES)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextwgl.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextwgl.h
)
endif()
else()
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/x11window.h
)
if(NOT OPENGLES)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextglx.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextglx.h
)
endif()
endif()
endif()
set(framework_SOURCES ${framework_SOURCES} set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.h ${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.h
@@ -422,8 +362,6 @@ if(FRAMEWORK_GRAPHICS)
${CMAKE_CURRENT_LIST_DIR}/graphics/glutil.h ${CMAKE_CURRENT_LIST_DIR}/graphics/glutil.h
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.h ${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.h
${CMAKE_CURRENT_LIST_DIR}/graphics/graphicscontext.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/graphicscontext.h
${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.h ${CMAKE_CURRENT_LIST_DIR}/graphics/hardwarebuffer.h
${CMAKE_CURRENT_LIST_DIR}/graphics/image.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/image.cpp
@@ -459,8 +397,6 @@ if(FRAMEWORK_GRAPHICS)
${CMAKE_CURRENT_LIST_DIR}/graphics/shaderprogram.h ${CMAKE_CURRENT_LIST_DIR}/graphics/shaderprogram.h
${CMAKE_CURRENT_LIST_DIR}/graphics/texture.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/texture.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/texture.h ${CMAKE_CURRENT_LIST_DIR}/graphics/texture.h
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/textureogl.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/textureogl.h
${CMAKE_CURRENT_LIST_DIR}/graphics/texturemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/texturemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/texturemanager.h ${CMAKE_CURRENT_LIST_DIR}/graphics/texturemanager.h
${CMAKE_CURRENT_LIST_DIR}/graphics/vertexarray.h ${CMAKE_CURRENT_LIST_DIR}/graphics/vertexarray.h
@@ -499,6 +435,10 @@ if(FRAMEWORK_GRAPHICS)
# platform window # platform window
${CMAKE_CURRENT_LIST_DIR}/platform/platformwindow.cpp ${CMAKE_CURRENT_LIST_DIR}/platform/platformwindow.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/platformwindow.h ${CMAKE_CURRENT_LIST_DIR}/platform/platformwindow.h
${CMAKE_CURRENT_LIST_DIR}/platform/win32window.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/win32window.h
${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp
${CMAKE_CURRENT_LIST_DIR}/platform/x11window.h
# window input # window input
${CMAKE_CURRENT_LIST_DIR}/input/mouse.cpp ${CMAKE_CURRENT_LIST_DIR}/input/mouse.cpp

View File

@@ -1,16 +0,0 @@
# Try to find the SDL2 library
# SDL2_FOUND - system has SDL2
# SDL2_INCLUDE_DIR - the SDL2 include directory
# SDL2_LIBRARY - the SDL2 library
FIND_PATH(SDL2_INCLUDE_DIR PATH_SUFFIXES SDL2 SDL NAMES SDL.h)
SET(_SDL2_STATIC_LIBS libSDL2.a libSDL.a)
SET(_SDL2_SHARED_LIBS libSDL2.dll.a SDL2 SDL libSDL.dll.a SDL)
IF(USE_STATIC_LIBS)
FIND_LIBRARY(SDL2_LIBRARY NAMES ${_SDL2_STATIC_LIBS} ${_SDL2_SHARED_LIBS})
ELSE()
FIND_LIBRARY(SDL2_LIBRARY NAMES ${_SDL2_SHARED_LIBS} ${_SDL2_STATIC_LIBS})
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 DEFAULT_MSG SDL2_LIBRARY SDL2_INCLUDE_DIR)
MARK_AS_ADVANCED(SDL2_LIBRARY SDL2_INCLUDE_DIR)

View File

@@ -33,7 +33,6 @@
#include <framework/platform/platform.h> #include <framework/platform/platform.h>
#include <locale> #include <locale>
#include <boost/concept_check.hpp>
#ifdef FW_NET #ifdef FW_NET
#include <framework/net/connection.h> #include <framework/net/connection.h>
@@ -164,14 +163,10 @@ void Application::close()
std::string Application::getOs() std::string Application::getOs()
{ {
#if defined(ANDROID) #if defined(WIN32)
return "android";
#elif defined(IOS)
return "ios";
#elif defined(WIN32)
return "windows"; return "windows";
#elif defined(__APPLE__) #elif defined(__APPLE__)
return "macos"; return "mac";
#elif __linux #elif __linux
return "linux"; return "linux";
#else #else

View File

@@ -24,14 +24,12 @@
#include "graphicalapplication.h" #include "graphicalapplication.h"
#include <framework/core/clock.h> #include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include <framework/input/mouse.h>
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
#include <framework/ui/uimanager.h> #include <framework/ui/uimanager.h>
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/graphics/particlemanager.h> #include <framework/graphics/particlemanager.h>
#include <framework/graphics/texturemanager.h> #include <framework/graphics/texturemanager.h>
#include <framework/graphics/painter.h> #include <framework/graphics/painter.h>
#include <framework/graphics/ogl/textureogl.h>
#ifdef FW_SOUND #ifdef FW_SOUND
#include <framework/sound/soundmanager.h> #include <framework/sound/soundmanager.h>
@@ -234,7 +232,7 @@ void GraphicalApplication::resize(const Size& size)
m_onInputEvent = false; m_onInputEvent = false;
if(g_graphics.canCacheBackbuffer()) { if(g_graphics.canCacheBackbuffer()) {
m_foreground = TexturePtr(new TextureOGL(size)); m_foreground = TexturePtr(new Texture(size));
m_foreground->setUpsideDown(true); m_foreground->setUpsideDown(true);
} }
m_mustRepaint = true; m_mustRepaint = true;

View File

@@ -31,7 +31,7 @@
class GraphicalApplication : public Application class GraphicalApplication : public Application
{ {
enum { enum {
POLL_CYCLE_DELAY = 1000 POLL_CYCLE_DELAY = 10
}; };
public: public:

View File

@@ -25,30 +25,24 @@
//#include <boost/regex.hpp> //#include <boost/regex.hpp>
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include "application.h"
#ifdef FW_GRAPHICS #ifdef FW_GRAPHICS
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
#include <framework/platform/platform.h>
#include <framework/luaengine/luainterface.h> #include <framework/luaengine/luainterface.h>
#endif #endif
#ifdef MOBILE
#include <android/log.h>
#endif
Logger g_logger; Logger g_logger;
void Logger::log(Fw::LogLevel level, const std::string& message) void Logger::log(Fw::LogLevel level, const std::string& message)
{ {
std::lock_guard<std::recursive_mutex> lock(m_mutex); std::lock_guard<std::recursive_mutex> lock(m_mutex);
/*
>>>>>>> Progress in SDL platform
#ifdef NDEBUG #ifdef NDEBUG
if(level == Fw::LogDebug) if(level == Fw::LogDebug)
return; return;
#endif #endif
*/
static bool ignoreLogs = false; static bool ignoreLogs = false;
if(ignoreLogs) if(ignoreLogs)
return; return;
@@ -73,11 +67,7 @@ void Logger::log(Fw::LogLevel level, const std::string& message)
#endif #endif
*/ */
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, g_app.getCompactName().c_str(), outmsg.c_str());
#else
std::cout << outmsg << std::endl; std::cout << outmsg << std::endl;
#endif
if(m_outFile.good()) { if(m_outFile.good()) {
m_outFile << outmsg << std::endl; m_outFile << outmsg << std::endl;
@@ -115,16 +105,16 @@ void Logger::logFunc(Fw::LogLevel level, const std::string& message, std::string
prettyFunction = prettyFunction.substr(prettyFunction.find_last_of(' ') + 1); prettyFunction = prettyFunction.substr(prettyFunction.find_last_of(' ') + 1);
std::string out = message; std::stringstream ss;
ss << message;
if(!prettyFunction.empty()) { if(!prettyFunction.empty()) {
if(g_lua.isInCppCallback()) if(g_lua.isInCppCallback())
out = g_lua.traceback(out, 1); ss << g_lua.traceback("", 1);
else ss << g_platform.traceback(prettyFunction, 1, 8);
out += "\nat:\t[C++]: " + prettyFunction;
} }
log(level, out); log(level, ss.str());
} }
void Logger::fireOldMessages() void Logger::fireOldMessages()

View File

@@ -29,10 +29,6 @@
#include <physfs.h> #include <physfs.h>
#ifdef MOBILE
#include <SDL.h>
#endif
ResourceManager g_resources; ResourceManager g_resources;
void ResourceManager::init(const char *argv0) void ResourceManager::init(const char *argv0)
@@ -49,15 +45,10 @@ void ResourceManager::terminate()
bool ResourceManager::discoverWorkDir(const std::string& existentFile) bool ResourceManager::discoverWorkDir(const std::string& existentFile)
{ {
// search for modules directory // search for modules directory
#ifdef ANDROID std::string possiblePaths[] = { g_platform.getCurrentDir(),
std::string possiblePaths[] = { std::string("/sdcard/") + g_app.getCompactName() + "/" };
#else
std::string possiblePaths[] = { "./",
g_platform.getCurrentDir(),
g_resources.getBaseDir(), g_resources.getBaseDir(),
g_resources.getBaseDir() + "../", g_resources.getBaseDir() + "../",
g_resources.getBaseDir() + "../share/" + g_app.getCompactName() + "/" }; g_resources.getBaseDir() + "../share/" + g_app.getCompactName() + "/" };
#endif
bool found = false; bool found = false;
for(const std::string& dir : possiblePaths) { for(const std::string& dir : possiblePaths) {
@@ -318,11 +309,7 @@ std::string ResourceManager::getBaseDir()
std::string ResourceManager::getUserDir() std::string ResourceManager::getUserDir()
{ {
#ifdef ANDROID
return std::string("/sdcard/");
#else
return PHYSFS_getUserDir(); return PHYSFS_getUserDir();
#endif
} }
std::string ResourceManager::guessFilePath(const std::string& filename, const std::string& type) std::string ResourceManager::guessFilePath(const std::string& filename, const std::string& type)

View File

@@ -24,15 +24,14 @@
#include "graphics.h" #include "graphics.h"
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include "ogl/textureogl.h"
AnimatedTexture::AnimatedTexture(const Size& size, std::vector<ImagePtr> frames, std::vector<int> framesDelay, bool buildMipmaps) AnimatedTexture::AnimatedTexture(const Size& size, std::vector<ImagePtr> frames, std::vector<int> framesDelay, bool buildMipmaps, bool compress)
{ {
if(!setupSize(size, buildMipmaps)) if(!setupSize(size, buildMipmaps))
return; return;
for(uint i=0;i<frames.size();++i) { for(uint i=0;i<frames.size();++i) {
m_frames.push_back(new TextureOGL(frames[i], buildMipmaps)); m_frames.push_back(new Texture(frames[i], buildMipmaps, compress));
} }
m_framesDelay = framesDelay; m_framesDelay = framesDelay;

View File

@@ -29,7 +29,7 @@
class AnimatedTexture : public Texture class AnimatedTexture : public Texture
{ {
public: public:
AnimatedTexture(const Size& size, std::vector<ImagePtr> frames, std::vector<int> framesDelay, bool buildMipmaps = false); AnimatedTexture(const Size& size, std::vector<ImagePtr> frames, std::vector<int> framesDelay, bool buildMipmaps = false, bool compress = false);
virtual ~AnimatedTexture(); virtual ~AnimatedTexture();
virtual bool buildHardwareMipmaps(); virtual bool buildHardwareMipmaps();

View File

@@ -33,15 +33,15 @@
#include <fstream> #include <fstream>
#if defined(_MSC_VER) && _MSC_VER >= 1300 #if defined(_MSC_VER) && _MSC_VER >= 1300
#define lswap16(data) _byteswap_ushort(data) #define swap16(data) _byteswap_ushort(data)
#define lswap32(data) _byteswap_ulong(data) #define swap32(data) _byteswap_ulong(data)
#elif __linux__ #elif __linux__
#include <byteswap.h> #include <byteswap.h>
#define lswap16(data) bswap_16(data) #define swap16(data) bswap_16(data)
#define lswap32(data) bswap_32(data) #define swap32(data) bswap_32(data)
#else #else
#define lswap16(data) (((data >> 8) & 255) | ((data & 255) << 8)) #define swap16(data) (((data >> 8) & 255) | ((data & 255) << 8))
#define lswap32(data) ((swap16(data) << 16) | swap16(data >> 16)) #define swap32(data) ((swap16(data) << 16) | swap16(data >> 16))
#endif #endif
#define PNG_ZBUF_SIZE 32768 #define PNG_ZBUF_SIZE 32768
@@ -865,7 +865,7 @@ int load_apng(std::stringstream& file, struct apng_data *apng)
void write_chunk(std::ostream& f, const char* name, unsigned char* data, unsigned int length) void write_chunk(std::ostream& f, const char* name, unsigned char* data, unsigned int length)
{ {
unsigned int crc = crc32(0, Z_NULL, 0); unsigned int crc = crc32(0, Z_NULL, 0);
unsigned int len = lswap32(length); unsigned int len = swap32(length);
f.write((char*)&len, 4); f.write((char*)&len, 4);
f.write(name, 4); f.write(name, 4);
@@ -876,7 +876,7 @@ void write_chunk(std::ostream& f, const char* name, unsigned char* data, unsigne
crc = crc32(crc, data, length); crc = crc32(crc, data, length);
} }
crc = lswap32(crc); crc = swap32(crc);
f.write((char*)&crc, 4); f.write((char*)&crc, 4);
} }
@@ -937,7 +937,7 @@ void save_png(std::stringstream& f, unsigned int width, unsigned int height, int
unsigned char mCompression; unsigned char mCompression;
unsigned char mFilterMethod; unsigned char mFilterMethod;
unsigned char mInterlaceMethod; unsigned char mInterlaceMethod;
} ihdr = { lswap32(width), lswap32(height), 8, coltype, 0, 0, 0 }; } ihdr = { swap32(width), swap32(height), 8, coltype, 0, 0, 0 };
z_stream zstream1; z_stream zstream1;
z_stream zstream2; z_stream zstream2;

View File

@@ -34,7 +34,6 @@ class BitmapFont;
class CachedText; class CachedText;
class FrameBuffer; class FrameBuffer;
class FrameBufferManager; class FrameBufferManager;
class GraphicsContext;
class Shader; class Shader;
class ShaderProgram; class ShaderProgram;
class PainterShaderProgram; class PainterShaderProgram;
@@ -52,7 +51,6 @@ typedef stdext::shared_object_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef stdext::shared_object_ptr<BitmapFont> BitmapFontPtr; typedef stdext::shared_object_ptr<BitmapFont> BitmapFontPtr;
typedef stdext::shared_object_ptr<CachedText> CachedTextPtr; typedef stdext::shared_object_ptr<CachedText> CachedTextPtr;
typedef stdext::shared_object_ptr<FrameBuffer> FrameBufferPtr; typedef stdext::shared_object_ptr<FrameBuffer> FrameBufferPtr;
typedef stdext::shared_object_ptr<GraphicsContext> GraphicsContextPtr;
typedef stdext::shared_object_ptr<Shader> ShaderPtr; typedef stdext::shared_object_ptr<Shader> ShaderPtr;
typedef stdext::shared_object_ptr<ShaderProgram> ShaderProgramPtr; typedef stdext::shared_object_ptr<ShaderProgram> ShaderProgramPtr;
typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr; typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr;

View File

@@ -26,7 +26,6 @@
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
#include <framework/core/application.h> #include <framework/core/application.h>
#include <framework/graphics/ogl/textureogl.h>
uint FrameBuffer::boundFbo = 0; uint FrameBuffer::boundFbo = 0;
@@ -62,7 +61,7 @@ void FrameBuffer::resize(const Size& size)
if(m_texture && m_texture->getSize() == size) if(m_texture && m_texture->getSize() == size)
return; return;
m_texture = TexturePtr(new TextureOGL(size)); m_texture = TexturePtr(new Texture(size));
m_texture->setSmooth(m_smooth); m_texture->setSmooth(m_smooth);
m_texture->setUpsideDown(true); m_texture->setUpsideDown(true);
@@ -76,7 +75,7 @@ void FrameBuffer::resize(const Size& size)
internalRelease(); internalRelease();
} else { } else {
if(m_backuping) { if(m_backuping) {
m_screenBackup = TexturePtr(new TextureOGL(size)); m_screenBackup = TexturePtr(new Texture(size));
m_screenBackup->setUpsideDown(true); m_screenBackup->setUpsideDown(true);
} }
} }

View File

@@ -44,7 +44,6 @@
typedef char GLchar; typedef char GLchar;
// define OpenGL ES 2.0 API just to make compile, it wont actually be used // define OpenGL ES 2.0 API just to make compile, it wont actually be used
inline void glBlendEquation (GLenum mode) { }
inline void glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { } inline void glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { }
inline void glBindFramebuffer (GLenum target, GLuint framebuffer) { } inline void glBindFramebuffer (GLenum target, GLuint framebuffer) { }
inline void glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers) { } inline void glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers) { }

View File

@@ -184,16 +184,14 @@ bool Graphics::isPainterEngineAvailable(Graphics::PainterEngine painterEngine)
bool Graphics::selectPainterEngine(PainterEngine painterEngine) bool Graphics::selectPainterEngine(PainterEngine painterEngine)
{ {
// TODO: remove this
#ifdef DIRECTX
painterEngine = Painter_DirectX9;
#endif
Painter *painter = nullptr; Painter *painter = nullptr;
Painter *fallbackPainter = nullptr; Painter *fallbackPainter = nullptr;
PainterEngine fallbackPainterEngine = Painter_Any; PainterEngine fallbackPainterEngine = Painter_Any;
#ifdef PAINTER_DX9 #ifdef PAINTER_DX9
// use this to force directx if its enabled (avoid changes in options module, etc, will be removed)
painterEngine = Painter_DirectX9;
// always prefer DirectX9 on Windows // always prefer DirectX9 on Windows
if(g_painterDX9) { if(g_painterDX9) {
if(!painter && (painterEngine == Painter_DirectX9 || painterEngine == Painter_Any)) { if(!painter && (painterEngine == Painter_DirectX9 || painterEngine == Painter_Any)) {
@@ -240,7 +238,6 @@ bool Graphics::selectPainterEngine(PainterEngine painterEngine)
if(g_painter) if(g_painter)
g_painter->unbind(); g_painter->unbind();
painter->bind(); painter->bind();
g_window.setGraphicsContext(painter->getGraphicsContext());
g_painter = painter; g_painter = painter;
} }
@@ -256,11 +253,6 @@ bool Graphics::selectPainterEngine(PainterEngine painterEngine)
void Graphics::resize(const Size& size) void Graphics::resize(const Size& size)
{ {
m_viewportSize = size; m_viewportSize = size;
#ifdef PAINTER_DX9
if(g_painterDX9)
g_painterDX9->setResolution(size);
#endif
#ifdef PAINTER_OGL1 #ifdef PAINTER_OGL1
if(g_painterOGL1) if(g_painterOGL1)
g_painterOGL1->setResolution(size); g_painterOGL1->setResolution(size);

View File

@@ -1,28 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "graphicscontext.h"
GraphicsContext::GraphicsContext(const std::string& name) :
m_name(name)
{
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2010-2013 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 GRAPHICSCONTEXT_H
#define GRAPHICSCONTEXT_H
#include "declarations.h"
class GraphicsContext : public stdext::shared_object
{
public:
GraphicsContext(const std::string& name);
virtual ~GraphicsContext() {}
std::string getName() { return m_name; }
virtual void create() {}
virtual void destroy() {}
virtual void restore() {}
virtual void swapBuffers() {}
virtual void setVerticalSync(bool enable) {}
protected:
std::string m_name;
};
#endif

View File

@@ -1,150 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "graphicscontextegl.h"
#ifdef WIN32
#include <framework/platform/win32window.h>
#else
#include <framework/platform/x11window.h>
#endif
GraphicsContextEGL::GraphicsContextEGL() :
GraphicsContext("EGL")
{
m_eglConfig = 0;
m_eglContext = 0;
m_eglDisplay = 0;
m_eglSurface = 0;
}
void GraphicsContextEGL::create()
{
#ifdef WIN32
HDC display = g_win32Window.getDisplay();
#else
Display *display = g_x11Window.getDisplay();
#endif
m_eglDisplay = eglGetDisplay(display);
if(m_eglDisplay == EGL_NO_DISPLAY)
g_logger.fatal("EGL not supported");
if(!eglInitialize(m_eglDisplay, NULL, NULL))
g_logger.fatal("Unable to initialize EGL");
static int configList[] = {
#if OPENGL_ES==2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 4,
EGL_BLUE_SIZE, 4,
EGL_ALPHA_SIZE, 4,
EGL_NONE
};
EGLint numConfig;
if(!eglChooseConfig(m_eglDisplay, configList, &m_eglConfig, 1, &numConfig))
g_logger.fatal("Failed to choose EGL config");
if(numConfig != 1)
g_logger.warning("Didn't got the exact EGL config");
#ifndef WIN32
EGLint vid;
if(!eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_NATIVE_VISUAL_ID, &vid))
g_logger.fatal("Unable to get visual EGL visual id");
XVisualInfo visTemplate;
int numVisuals;
memset(&visTemplate, 0, sizeof(visTemplate));
visTemplate.visualid = vid;
g_x11Window.setVisual(XGetVisualInfo(display, VisualIDMask, &visTemplate, &numVisuals));
if(!g_x11Window.getVisual())
g_logger.fatal("Couldn't choose RGBA, double buffered visual");
g_x11Window.setRootWindow(DefaultRootWindow(display));
#endif
EGLint contextAtrrList[] = {
#if OPENGL_ES==2
EGL_CONTEXT_CLIENT_VERSION, 2,
#else
EGL_CONTEXT_CLIENT_VERSION, 1,
#endif
EGL_NONE
};
#ifdef WIN32
HWND window = g_win32Window.getWindow();
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, window, NULL);
if(m_eglSurface == EGL_NO_SURFACE)
g_logger.fatal(stdext::format("Unable to create EGL surface: %s", eglGetError()));
#endif
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAtrrList);
if(m_eglContext == EGL_NO_CONTEXT )
g_logger.fatal(stdext::format("Unable to create EGL context: %s", eglGetError()));
}
void GraphicsContextEGL::destroy()
{
if(m_eglDisplay) {
if(m_eglContext) {
eglDestroyContext(m_eglDisplay, m_eglContext);
m_eglContext = 0;
}
if(m_eglSurface) {
eglDestroySurface(m_eglDisplay, m_eglSurface);
m_eglSurface = 0;
}
eglTerminate(m_eglDisplay);
m_eglDisplay = 0;
}
}
void GraphicsContextEGL::restore()
{
#ifndef WIN32
Window window = g_x11Window.getWindow();
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, window, NULL);
if(m_eglSurface == EGL_NO_SURFACE)
g_logger.fatal(stdext::format("Unable to create EGL surface: %s", eglGetError()));
#endif
if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))
g_logger.fatal("Unable to make current EGL context");
}
void GraphicsContextEGL::swapBuffers()
{
eglSwapBuffers(m_eglDisplay, m_eglSurface);
}
void GraphicsContextEGL::setVerticalSync(bool enable)
{
eglSwapInterval(m_eglDisplay, enable ? 1 : 0);
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2010-2013 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 GRAPHICSCONTEXTEGL_H
#define GRAPHICSCONTEXTEGL_H
#include <framework/graphics/graphicscontext.h>
#include <EGL/egl.h>
class GraphicsContextEGL : public GraphicsContext
{
public:
GraphicsContextEGL();
void create();
void destroy();
void restore();
void swapBuffers();
void setVerticalSync(bool enable);
private:
EGLConfig m_eglConfig;
EGLContext m_eglContext;
EGLDisplay m_eglDisplay;
EGLSurface m_eglSurface;
};
#endif

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "graphicscontextglx.h"
GraphicsContextGLX::GraphicsContextGLX() :
GraphicsContext("GLX"), m_window(dynamic_cast<X11Window&>(g_window))
{
m_fbConfig = 0;
m_glxContext = 0;
}
void GraphicsContextGLX::create()
{
if(!glXQueryExtension(m_window.getDisplay(), NULL, NULL))
g_logger.fatal("GLX not supported");
static int attrList[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
None
};
int nelements;
m_fbConfig = glXChooseFBConfig(m_window.getDisplay(), m_window.getScreen(), attrList, &nelements);
if(!m_fbConfig)
g_logger.fatal("Couldn't choose RGBA, double buffered fbconfig");
m_window.setVisual(glXGetVisualFromFBConfig(m_window.getDisplay(), *m_fbConfig));
if(!m_window.getDisplay())
g_logger.fatal("Couldn't choose RGBA, double buffered visual");
m_window.setRootWindow(RootWindow(m_window.getDisplay(), m_window.getVisual()->screen));
m_glxContext = glXCreateContext(m_window.getDisplay(), m_window.getVisual(), NULL, True);
if(!m_glxContext)
g_logger.fatal("Unable to create GLX context");
if(!glXIsDirect(m_window.getDisplay(), m_glxContext))
g_logger.warning("GL direct rendering is not possible");
}
void GraphicsContextGLX::destroy()
{
if(m_glxContext) {
glXMakeCurrent(m_window.getDisplay(), None, NULL);
glXDestroyContext(m_window.getDisplay(), m_glxContext);
m_glxContext = 0;
}
}
void GraphicsContextGLX::restore()
{
if(!glXMakeCurrent(m_window.getDisplay(), m_window.getWindow(), m_glxContext))
g_logger.fatal("Unable to set GLX context on X11 window");
}
bool GraphicsContextGLX::isExtensionSupported(const char *ext)
{
const char *exts = glXQueryExtensionsString(m_window.getDisplay(), m_window.getScreen());
if(strstr(exts, ext))
return true;
return false;
}
void *GraphicsContextGLX::getExtensionProcAddress(const char *ext)
{
return (void *)glXGetProcAddressARB((const GLubyte*)ext);
}
void GraphicsContextGLX::swapBuffers()
{
glXSwapBuffers(m_window.getDisplay(), m_window.getWindow());
}
void GraphicsContextGLX::setVerticalSync(bool enable)
{
typedef GLint (*glSwapIntervalProc)(GLint);
glSwapIntervalProc glSwapInterval = NULL;
if(isExtensionSupported("GLX_MESA_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
else if(isExtensionSupported("GLX_SGI_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
if(glSwapInterval)
glSwapInterval(enable ? 1 : 0);
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright (c) 2010-2013 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 GRAPHICSCONTEXTGLX_H
#define GRAPHICSCONTEXTGLX_H
#include <framework/graphics/graphicscontext.h>
#include <framework/platform/x11window.h>
#include <GL/glx.h>
class GraphicsContextGLX : public GraphicsContext
{
public:
GraphicsContextGLX();
void create();
void destroy();
void restore();
bool isExtensionSupported(const char *ext);
void *getExtensionProcAddress(const char *ext);
void swapBuffers();
void setVerticalSync(bool enable);
private:
X11Window& m_window;
GLXContext m_glxContext;
GLXFBConfig *m_fbConfig;
};
#endif

View File

@@ -1,117 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "graphicscontextwgl.h"
#include <framework/platform/win32window.h>
GraphicsContextWGL::GraphicsContextWGL() :
GraphicsContext("WGL")
{
m_wglContext = 0;
}
void GraphicsContextWGL::create()
{
HDC display = g_win32Window.getDisplay();
uint pixelFormat;
static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, // Select Our Color Depth
8, 0, 8, 0, 8, 0, // Color Bits Ignored
8, // Alpha Buffer Bits
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
0, // Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 }; // Layer Masks Ignored
pixelFormat = ChoosePixelFormat(display, &pfd);
if(!pixelFormat)
g_logger.fatal("Could not find a suitable pixel format");
if(!SetPixelFormat(display, pixelFormat, &pfd))
g_logger.fatal("Could not set the pixel format");
if(!(m_wglContext = wglCreateContext(display)))
g_logger.fatal("Unable to create GL context");
}
void GraphicsContextWGL::destroy()
{
if(m_wglContext) {
if(!wglMakeCurrent(NULL, NULL))
g_logger.error("Release of dc and rc failed.");
if(!wglDeleteContext(m_wglContext))
g_logger.error("Release rendering context failed.");
m_wglContext = NULL;
}
}
void GraphicsContextWGL::restore()
{
if(!wglMakeCurrent(g_win32Window.getDisplay(), m_wglContext))
g_logger.fatal("Unable to make current WGL context");
}
bool GraphicsContextWGL::isExtensionSupported(const char *ext)
{
typedef const char* (WINAPI * wglGetExtensionsStringProc)();
wglGetExtensionsStringProc wglGetExtensionsString = (wglGetExtensionsStringProc)getExtensionProcAddress("wglGetExtensionsStringEXT");
if(!wglGetExtensionsString)
return false;
const char *exts = wglGetExtensionsString();
if(exts && strstr(exts, ext))
return true;
return false;
}
void *GraphicsContextWGL::getExtensionProcAddress(const char *ext)
{
return (void*)wglGetProcAddress(ext);
}
void GraphicsContextWGL::swapBuffers()
{
SwapBuffers(g_win32Window.getDisplay());
}
void GraphicsContextWGL::setVerticalSync(bool enable)
{
if(!isExtensionSupported("WGL_EXT_swap_control"))
return;
typedef BOOL (WINAPI * wglSwapIntervalProc)(int);
wglSwapIntervalProc wglSwapInterval = (wglSwapIntervalProc)getExtensionProcAddress("wglSwapIntervalEXT");
if(!wglSwapInterval)
return;
wglSwapInterval(enable ? 1 : 0);
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2010-2013 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 GRAPHICSCONTEXTWGL_H
#define GRAPHICSCONTEXTWGL_H
#include <framework/graphics/graphicscontext.h>
#include <windows.h>
class GraphicsContextWGL : public GraphicsContext
{
public:
GraphicsContextWGL();
void create();
void destroy();
void restore();
bool isExtensionSupported(const char *ext);
void *getExtensionProcAddress(const char *ext);
void swapBuffers();
void setVerticalSync(bool enable);
private:
HGLRC m_wglContext;
};
#endif

View File

@@ -24,26 +24,8 @@
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
#ifdef OPENGL_ES
#include <framework/graphics/ogl/graphicscontextegl.h>
#elif WIN32
#include <framework/graphics/ogl/graphicscontextwgl.h>
#else
#include <framework/graphics/ogl/graphicscontextglx.h>
#endif
PainterOGL::PainterOGL() PainterOGL::PainterOGL()
{ {
#ifdef SDL
m_graphicsContext = GraphicsContextPtr(new GraphicsContext("null"));
#elif OPENGL_ES
m_graphicsContext = GraphicsContextPtr(new GraphicsContextEGL);
#elif WIN32
m_graphicsContext = GraphicsContextPtr(new GraphicsContextWGL);
#else
m_graphicsContext = GraphicsContextPtr(new GraphicsContextGLX);
#endif
m_glTextureId = 0; m_glTextureId = 0;
m_oldStateIndex = 0; m_oldStateIndex = 0;
m_color = Color::white; m_color = Color::white;
@@ -53,7 +35,6 @@ PainterOGL::PainterOGL()
m_shaderProgram = nullptr; m_shaderProgram = nullptr;
m_texture = nullptr; m_texture = nullptr;
m_alphaWriting = false; m_alphaWriting = false;
setResolution(g_window.getSize()); setResolution(g_window.getSize());
} }
@@ -305,7 +286,6 @@ void PainterOGL::updateGlBlendEquation()
{ {
if(!g_graphics.canUseBlendEquation()) if(!g_graphics.canUseBlendEquation())
return; return;
if(m_blendEquation == BlendEquation_Add) if(m_blendEquation == BlendEquation_Add)
glBlendEquation(0x8006); // GL_FUNC_ADD glBlendEquation(0x8006); // GL_FUNC_ADD
else if(m_blendEquation == BlendEquation_Max) else if(m_blendEquation == BlendEquation_Max)

View File

@@ -1,229 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "textureogl.h"
#include <framework/graphics/image.h>
#include <framework/core/application.h>
#include <framework/graphics/graphics.h>
TextureOGL::TextureOGL()
{
m_id = 0;
}
TextureOGL::TextureOGL(const Size& size)
{
m_id = 0;
if(!setupSize(size))
return;
createTexture();
bind();
setupPixels(0, m_glSize, nullptr, 4);
setupWrap();
setupFilters();
}
TextureOGL::TextureOGL(const ImagePtr& image, bool buildMipmaps)
{
m_id = 0;
if(!setupSize(image->getSize(), buildMipmaps))
return;
createTexture();
uploadPixels(image, buildMipmaps);
}
TextureOGL::~TextureOGL()
{
#ifndef NDEBUG
assert(!g_app.isTerminated());
#endif
// free texture from gl memory
if(g_graphics.ok() && m_id != 0)
glDeleteTextures(1, &m_id);
}
void TextureOGL::uploadPixels(const ImagePtr& image, bool buildMipmaps)
{
ImagePtr glImage = image;
if(m_size != m_glSize) {
glImage = ImagePtr(new Image(m_glSize, image->getBpp()));
glImage->paste(image);
} else
glImage = image;
bind();
if(buildMipmaps) {
int level = 0;
do {
setupPixels(level++, glImage->getSize(), glImage->getPixelData(), glImage->getBpp());
} while(glImage->nextMipmap());
m_hasMipmaps = true;
} else
setupPixels(0, glImage->getSize(), glImage->getPixelData(), glImage->getBpp());
setupWrap();
setupFilters();
}
void TextureOGL::bind()
{
// must reset painter texture state
g_painter->setTexture(this);
glBindTexture(GL_TEXTURE_2D, m_id);
}
void TextureOGL::copyFromScreen(const Rect& screenRect)
{
bind();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, screenRect.x(), screenRect.y(), screenRect.width(), screenRect.height());
}
bool TextureOGL::buildHardwareMipmaps()
{
if(!g_graphics.canUseHardwareMipmaps())
return false;
bind();
if(!m_hasMipmaps) {
m_hasMipmaps = true;
setupFilters();
}
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void TextureOGL::setSmooth(bool smooth)
{
if(smooth && !g_graphics.canUseBilinearFiltering())
return;
if(smooth == m_smooth)
return;
m_smooth = smooth;
bind();
setupFilters();
}
void TextureOGL::setRepeat(bool repeat)
{
if(m_repeat == repeat)
return;
m_repeat = repeat;
bind();
setupWrap();
}
void TextureOGL::setUpsideDown(bool upsideDown)
{
if(m_upsideDown == upsideDown)
return;
m_upsideDown = upsideDown;
setupTranformMatrix(m_glSize, m_size);
}
void TextureOGL::createTexture()
{
glGenTextures(1, &m_id);
assert(m_id != 0);
}
bool TextureOGL::setupSize(const Size& size, bool forcePowerOfTwo)
{
Size glSize;
if(!g_graphics.canUseNonPowerOfTwoTextures() || forcePowerOfTwo)
glSize.resize(stdext::to_power_of_two(size.width()), stdext::to_power_of_two(size.height()));
else
glSize = size;
// checks texture max size
if(std::max(glSize.width(), glSize.height()) > g_graphics.getMaxTextureSize()) {
g_logger.error(stdext::format("loading texture with size %dx%d failed, "
"the maximum size allowed by the graphics card is %dx%d,"
"to prevent crashes the texture will be displayed as a blank texture",
size.width(), size.height(), g_graphics.getMaxTextureSize(), g_graphics.getMaxTextureSize()));
return false;
}
m_size = size;
m_glSize = glSize;
setupTranformMatrix(m_glSize, m_size);
return true;
}
void TextureOGL::setupWrap()
{
int texParam;
if(!m_repeat && g_graphics.canUseClampToEdge())
texParam = GL_CLAMP_TO_EDGE;
else
texParam = GL_REPEAT;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParam);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParam);
}
void TextureOGL::setupFilters()
{
int minFilter;
int magFilter;
if(m_smooth) {
minFilter = m_hasMipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
magFilter = GL_LINEAR;
} else {
minFilter = m_hasMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
magFilter = GL_NEAREST;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
}
void TextureOGL::setupPixels(int level, const Size& size, uchar* pixels, int channels)
{
GLenum format = 0;
switch(channels) {
case 4:
format = GL_RGBA;
break;
case 3:
format = GL_RGB;
break;
case 2:
format = GL_LUMINANCE_ALPHA;
break;
case 1:
format = GL_LUMINANCE;
break;
}
GLenum internalFormat = GL_RGBA;
//TODO: compression support
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, pixels);
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (c) 2010-2013 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 TEXTUREOGL_H
#define TEXTUREOGL_H
#include <framework/graphics/texture.h>
class TextureOGL : public Texture
{
public:
TextureOGL();
TextureOGL(const Size& size);
TextureOGL(const ImagePtr& image, bool buildMipmaps = false);
virtual ~TextureOGL();
void uploadPixels(const ImagePtr& image, bool buildMipmaps = false);
void bind();
void copyFromScreen(const Rect& screenRect);
virtual bool buildHardwareMipmaps();
virtual void setSmooth(bool smooth);
virtual void setRepeat(bool repeat);
void setUpsideDown(bool upsideDown);
protected:
void createTexture();
bool setupSize(const Size& size, bool forcePowerOfTwo = false);
void setupWrap();
void setupFilters();
void setupPixels(int level, const Size& size, uchar *pixels, int channels = 4);
};
#endif

View File

@@ -25,7 +25,6 @@
#include <framework/graphics/declarations.h> #include <framework/graphics/declarations.h>
#include <framework/graphics/coordsbuffer.h> #include <framework/graphics/coordsbuffer.h>
#include <framework/graphics/graphicscontext.h>
#include <framework/graphics/paintershaderprogram.h> #include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/texture.h> #include <framework/graphics/texture.h>
@@ -51,7 +50,7 @@ public:
Painter(); Painter();
virtual ~Painter() {} virtual ~Painter() { }
virtual void bind() { } virtual void bind() { }
virtual void unbind() { } virtual void unbind() { }
@@ -96,7 +95,6 @@ public:
float getOpacity() { return m_opacity; } float getOpacity() { return m_opacity; }
Rect getClipRect() { return m_clipRect; } Rect getClipRect() { return m_clipRect; }
CompositionMode getCompositionMode() { return m_compositionMode; } CompositionMode getCompositionMode() { return m_compositionMode; }
GraphicsContextPtr getGraphicsContext() { return m_graphicsContext; }
virtual void setCompositionMode(CompositionMode compositionMode) = 0; virtual void setCompositionMode(CompositionMode compositionMode) = 0;
@@ -118,7 +116,6 @@ protected:
Size m_resolution; Size m_resolution;
float m_opacity; float m_opacity;
Rect m_clipRect; Rect m_clipRect;
GraphicsContextPtr m_graphicsContext;
}; };
extern Painter *g_painter; extern Painter *g_painter;

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2010-2013 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 GRAPHICSCONTEXTEGL_H
#define GRAPHICSCONTEXTEGL_H
#include <framework/graphics/graphicscontext.h>
#include <EGL/egl.h>
class GraphicsContextEGL : public GraphicsContext
{
public:
GraphicsContextEGL();
void create(WindowType window, DisplayType display);
void destroy();
void restore();
void swapBuffers();
void setVerticalSync(bool enable);
private:
EGLConfig m_eglConfig;
EGLContext m_eglContext;
EGLDisplay m_eglDisplay;
EGLSurface m_eglSurface;
};
#endif

View File

@@ -1,21 +0,0 @@
/*
* Copyright (c) 2010-2013 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.
*/

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2010-2013 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 PAINTERSDL_H
#define PAINTERSDL_H
#include <framework/graphics/painter.h>
class PainterSDL: public Painter
{
public:
};
#endif

View File

@@ -33,29 +33,223 @@ Texture::Texture()
m_time = 0; m_time = 0;
} }
Texture::Texture(const Size& size)
{
m_id = 0;
m_time = 0;
if(!setupSize(size))
return;
createTexture();
bind();
setupPixels(0, m_glSize, nullptr, 4);
setupWrap();
setupFilters();
}
Texture::Texture(const ImagePtr& image, bool buildMipmaps, bool compress)
{
m_id = 0;
m_time = 0;
createTexture();
uploadPixels(image, buildMipmaps, compress);
}
Texture::~Texture() Texture::~Texture()
{ {
#ifndef NDEBUG #ifndef NDEBUG
assert(!g_app.isTerminated()); assert(!g_app.isTerminated());
#endif #endif
// free texture from gl memory
if(g_graphics.ok() && m_id != 0)
glDeleteTextures(1, &m_id);
} }
bool Texture::setupSize(const Size& size, bool) void Texture::uploadPixels(const ImagePtr& image, bool buildMipmaps, bool compress)
{ {
m_size = size; if(!setupSize(image->getSize(), buildMipmaps))
setupTranformMatrix(size, size); return;
ImagePtr glImage = image;
if(m_size != m_glSize) {
glImage = ImagePtr(new Image(m_glSize, image->getBpp()));
glImage->paste(image);
} else
glImage = image;
bind();
if(buildMipmaps) {
int level = 0;
do {
setupPixels(level++, glImage->getSize(), glImage->getPixelData(), glImage->getBpp(), compress);
} while(glImage->nextMipmap());
m_hasMipmaps = true;
} else
setupPixels(0, glImage->getSize(), glImage->getPixelData(), glImage->getBpp(), compress);
setupWrap();
setupFilters();
}
void Texture::bind()
{
// must reset painter texture state
g_painter->setTexture(this);
glBindTexture(GL_TEXTURE_2D, m_id);
}
void Texture::copyFromScreen(const Rect& screenRect)
{
bind();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, screenRect.x(), screenRect.y(), screenRect.width(), screenRect.height());
}
bool Texture::buildHardwareMipmaps()
{
if(!g_graphics.canUseHardwareMipmaps())
return false;
bind();
if(!m_hasMipmaps) {
m_hasMipmaps = true;
setupFilters();
}
glGenerateMipmap(GL_TEXTURE_2D);
return true; return true;
} }
void Texture::setupTranformMatrix(const Size& textureSize, const Size& realSize) void Texture::setSmooth(bool smooth)
{
if(smooth && !g_graphics.canUseBilinearFiltering())
return;
if(smooth == m_smooth)
return;
m_smooth = smooth;
bind();
setupFilters();
}
void Texture::setRepeat(bool repeat)
{
if(m_repeat == repeat)
return;
m_repeat = repeat;
bind();
setupWrap();
}
void Texture::setUpsideDown(bool upsideDown)
{
if(m_upsideDown == upsideDown)
return;
m_upsideDown = upsideDown;
setupTranformMatrix();
}
void Texture::createTexture()
{
glGenTextures(1, &m_id);
assert(m_id != 0);
}
bool Texture::setupSize(const Size& size, bool forcePowerOfTwo)
{
Size glSize;
if(!g_graphics.canUseNonPowerOfTwoTextures() || forcePowerOfTwo)
glSize.resize(stdext::to_power_of_two(size.width()), stdext::to_power_of_two(size.height()));
else
glSize = size;
// checks texture max size
if(std::max(glSize.width(), glSize.height()) > g_graphics.getMaxTextureSize()) {
g_logger.error(stdext::format("loading texture with size %dx%d failed, "
"the maximum size allowed by the graphics card is %dx%d,"
"to prevent crashes the texture will be displayed as a blank texture",
size.width(), size.height(), g_graphics.getMaxTextureSize(), g_graphics.getMaxTextureSize()));
return false;
}
m_size = size;
m_glSize = glSize;
setupTranformMatrix();
return true;
}
void Texture::setupWrap()
{
int texParam;
if(!m_repeat && g_graphics.canUseClampToEdge())
texParam = GL_CLAMP_TO_EDGE;
else
texParam = GL_REPEAT;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParam);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParam);
}
void Texture::setupFilters()
{
int minFilter;
int magFilter;
if(m_smooth) {
minFilter = m_hasMipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
magFilter = GL_LINEAR;
} else {
minFilter = m_hasMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
magFilter = GL_NEAREST;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
}
void Texture::setupTranformMatrix()
{ {
if(m_upsideDown) { if(m_upsideDown) {
m_transformMatrix = { 1.0f/textureSize.width(), 0.0f, 0.0f, m_transformMatrix = { 1.0f/m_glSize.width(), 0.0f, 0.0f,
0.0f, -1.0f/textureSize.height(), 0.0f, 0.0f, -1.0f/m_glSize.height(), 0.0f,
0.0f, realSize.height()/(float)textureSize.height(), 1.0f }; 0.0f, m_size.height()/(float)m_glSize.height(), 1.0f };
} else { } else {
m_transformMatrix = { 1.0f/textureSize.width(), 0.0f, 0.0f, m_transformMatrix = { 1.0f/m_glSize.width(), 0.0f, 0.0f,
0.0f, 1.0f/textureSize.height(), 0.0f, 0.0f, 1.0f/m_glSize.height(), 0.0f,
0.0f, 0.0f, 1.0f }; 0.0f, 0.0f, 1.0f };
} }
} }
void Texture::setupPixels(int level, const Size& size, uchar* pixels, int channels, bool compress)
{
GLenum format = 0;
switch(channels) {
case 4:
format = GL_RGBA;
break;
case 3:
format = GL_RGB;
break;
case 2:
format = GL_LUMINANCE_ALPHA;
break;
case 1:
format = GL_LUMINANCE;
break;
}
GLenum internalFormat = GL_RGBA;
#ifdef OPENGL_ES
//TODO
#else
if(compress)
internalFormat = GL_COMPRESSED_RGBA;
#endif
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, pixels);
}

View File

@@ -29,25 +29,26 @@ class Texture : public stdext::shared_object
{ {
public: public:
Texture(); Texture();
Texture(const Size& size);
Texture(const ImagePtr& image, bool buildMipmaps = false, bool compress = false);
virtual ~Texture(); virtual ~Texture();
virtual void setSmooth(bool) {} void uploadPixels(const ImagePtr& image, bool buildMipmaps = false, bool compress = false);
virtual void setRepeat(bool) {} void bind();
virtual void setUpsideDown(bool) {} void copyFromScreen(const Rect& screenRect);
virtual bool buildHardwareMipmaps();
virtual bool setupSize(const Size& size, bool);
virtual void copyFromScreen(const Rect&) {}
virtual bool buildHardwareMipmaps() { return false; }
virtual void uploadPixels(const ImagePtr&, bool) {}
virtual void setSmooth(bool smooth);
virtual void setRepeat(bool repeat);
void setUpsideDown(bool upsideDown);
void setTime(ticks_t time) { m_time = time; } void setTime(ticks_t time) { m_time = time; }
void setupTranformMatrix(const Size& textureSize, const Size& realSize);
uint getId() { return m_id; } uint getId() { return m_id; }
ticks_t getTime() { return m_time; } ticks_t getTime() { return m_time; }
int getWidth() { return m_size.width(); } int getWidth() { return m_size.width(); }
int getHeight() { return m_size.height(); } int getHeight() { return m_size.height(); }
const Size& getSize() { return m_size; } const Size& getSize() { return m_size; }
const Size& getGlSize() { return m_glSize; }
const Matrix3& getTransformMatrix() { return m_transformMatrix; } const Matrix3& getTransformMatrix() { return m_transformMatrix; }
bool isEmpty() { return m_id == 0; } bool isEmpty() { return m_id == 0; }
bool hasRepeat() { return m_repeat; } bool hasRepeat() { return m_repeat; }
@@ -55,6 +56,13 @@ public:
virtual bool isAnimatedTexture() { return false; } virtual bool isAnimatedTexture() { return false; }
protected: protected:
void createTexture();
bool setupSize(const Size& size, bool forcePowerOfTwo = false);
void setupWrap();
void setupFilters();
void setupTranformMatrix();
void setupPixels(int level, const Size& size, uchar *pixels, int channels = 4, bool compress = false);
uint m_id; uint m_id;
ticks_t m_time; ticks_t m_time;
Size m_size; Size m_size;

View File

@@ -29,7 +29,6 @@
#include <framework/core/clock.h> #include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include <framework/graphics/apngloader.h> #include <framework/graphics/apngloader.h>
#include "ogl/textureogl.h"
TextureManager g_textures; TextureManager g_textures;
@@ -147,7 +146,7 @@ TexturePtr TextureManager::loadTexture(std::stringstream& file)
texture = animatedTexture; texture = animatedTexture;
} else { } else {
ImagePtr image = ImagePtr(new Image(imageSize, apng.bpp, apng.pdata)); ImagePtr image = ImagePtr(new Image(imageSize, apng.bpp, apng.pdata));
texture = TexturePtr(new TextureOGL(image)); texture = TexturePtr(new Texture(image));
} }
free_apng(&apng); free_apng(&apng);
} }

View File

@@ -20,9 +20,6 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef MOUSE_H
#define MOUSE_H
#include <framework/global.h> #include <framework/global.h>
class Mouse class Mouse
@@ -46,5 +43,3 @@ private:
}; };
extern Mouse g_mouse; extern Mouse g_mouse;
#endif

View File

@@ -577,20 +577,19 @@ int LuaInterface::lua_dofile(lua_State* L)
int LuaInterface::lua_dofiles(lua_State* L) int LuaInterface::lua_dofiles(lua_State* L)
{ {
std::string directory = g_lua.popString(); std::string contains = "";
if(g_lua.getTop() > 2) {
for(const std::string& fileName : g_resources.listDirectoryFiles(directory)) { contains = g_lua.popString();
if(!g_resources.isFileType(fileName, "lua"))
continue;
try {
g_lua.loadScript(directory + "/" + fileName);
g_lua.call(0, 0);
} catch(stdext::exception& e) {
g_lua.pushString(e.what());
g_lua.error();
}
} }
bool recursive = false;
if(g_lua.getTop() > 1) {
recursive = g_lua.popBoolean();
}
std::string directory = g_lua.popString();
g_lua.loadFiles(directory, recursive, contains);
return 0; return 0;
} }
@@ -1247,3 +1246,29 @@ int LuaInterface::getTop()
{ {
return lua_gettop(L); return lua_gettop(L);
} }
void LuaInterface::loadFiles(std::string directory, bool recursive, std::string contains)
{
for(const std::string& fileName : g_resources.listDirectoryFiles(directory)) {
std::string fullPath = directory + "/" + fileName;
if(recursive && g_resources.directoryExists(fullPath)) {
loadFiles(fullPath, true, contains);
continue;
}
if(!g_resources.isFileType(fileName, "lua"))
continue;
if(!contains.empty() && fileName.find(contains) == std::string::npos)
continue;
try {
g_lua.loadScript(fullPath);
g_lua.call(0, 0);
} catch(stdext::exception& e) {
g_lua.pushString(e.what());
g_lua.error();
}
}
}

View File

@@ -321,6 +321,8 @@ public:
void clearStack() { pop(stackSize()); } void clearStack() { pop(stackSize()); }
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); } bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); }
void loadFiles(std::string directory, bool recursive = false, std::string contains = "");
/// Pushes any type onto the stack /// Pushes any type onto the stack
template<typename T, typename... Args> template<typename T, typename... Args>
int polymorphicPush(const T& v, const Args&... args); int polymorphicPush(const T& v, const Args&... args);

View File

@@ -569,6 +569,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("setImageFixedRatio", &UIWidget::setImageFixedRatio); g_lua.bindClassMemberFunction<UIWidget>("setImageFixedRatio", &UIWidget::setImageFixedRatio);
g_lua.bindClassMemberFunction<UIWidget>("setImageRepeated", &UIWidget::setImageRepeated); g_lua.bindClassMemberFunction<UIWidget>("setImageRepeated", &UIWidget::setImageRepeated);
g_lua.bindClassMemberFunction<UIWidget>("setImageSmooth", &UIWidget::setImageSmooth); g_lua.bindClassMemberFunction<UIWidget>("setImageSmooth", &UIWidget::setImageSmooth);
g_lua.bindClassMemberFunction<UIWidget>("setImageAutoResize", &UIWidget::setImageAutoResize);
g_lua.bindClassMemberFunction<UIWidget>("setImageBorderTop", &UIWidget::setImageBorderTop); g_lua.bindClassMemberFunction<UIWidget>("setImageBorderTop", &UIWidget::setImageBorderTop);
g_lua.bindClassMemberFunction<UIWidget>("setImageBorderRight", &UIWidget::setImageBorderRight); g_lua.bindClassMemberFunction<UIWidget>("setImageBorderRight", &UIWidget::setImageBorderRight);
g_lua.bindClassMemberFunction<UIWidget>("setImageBorderBottom", &UIWidget::setImageBorderBottom); g_lua.bindClassMemberFunction<UIWidget>("setImageBorderBottom", &UIWidget::setImageBorderBottom);
@@ -585,6 +586,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("getImageColor", &UIWidget::getImageColor); g_lua.bindClassMemberFunction<UIWidget>("getImageColor", &UIWidget::getImageColor);
g_lua.bindClassMemberFunction<UIWidget>("isImageFixedRatio", &UIWidget::isImageFixedRatio); g_lua.bindClassMemberFunction<UIWidget>("isImageFixedRatio", &UIWidget::isImageFixedRatio);
g_lua.bindClassMemberFunction<UIWidget>("isImageSmooth", &UIWidget::isImageSmooth); g_lua.bindClassMemberFunction<UIWidget>("isImageSmooth", &UIWidget::isImageSmooth);
g_lua.bindClassMemberFunction<UIWidget>("isImageAutoResize", &UIWidget::isImageAutoResize);
g_lua.bindClassMemberFunction<UIWidget>("getImageBorderTop", &UIWidget::getImageBorderTop); g_lua.bindClassMemberFunction<UIWidget>("getImageBorderTop", &UIWidget::getImageBorderTop);
g_lua.bindClassMemberFunction<UIWidget>("getImageBorderRight", &UIWidget::getImageBorderRight); g_lua.bindClassMemberFunction<UIWidget>("getImageBorderRight", &UIWidget::getImageBorderRight);
g_lua.bindClassMemberFunction<UIWidget>("getImageBorderBottom", &UIWidget::getImageBorderBottom); g_lua.bindClassMemberFunction<UIWidget>("getImageBorderBottom", &UIWidget::getImageBorderBottom);

View File

@@ -27,16 +27,17 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
asio::io_service g_ioService; asio::io_service g_ioService;
std::list<std::shared_ptr<asio::streambuf>> Connection::m_outputStreams;
Connection::Connection() : Connection::Connection() :
m_readTimer(g_ioService), m_readTimer(g_ioService),
m_writeTimer(g_ioService), m_writeTimer(g_ioService),
m_delayedWriteTimer(g_ioService),
m_resolver(g_ioService), m_resolver(g_ioService),
m_socket(g_ioService) m_socket(g_ioService)
{ {
m_connected = false; m_connected = false;
m_connecting = false; m_connecting = false;
m_sendBufferSize = 0;
} }
Connection::~Connection() Connection::~Connection()
@@ -56,34 +57,7 @@ void Connection::poll()
void Connection::terminate() void Connection::terminate()
{ {
g_ioService.stop(); g_ioService.stop();
} m_outputStreams.clear();
void Connection::connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback)
{
m_connected = false;
m_connecting = true;
m_error.clear();
m_connectCallback = connectCallback;
asio::ip::tcp::resolver::query query(host, stdext::unsafe_cast<std::string>(port));
auto self = asConnection();
m_resolver.async_resolve(query, [=](const boost::system::error_code& error, asio::ip::tcp::resolver::iterator endpointIterator) {
if(self.is_unique())
return;
m_readTimer.cancel();
if(!error) {
m_socket.async_connect(*endpointIterator, std::bind(&Connection::onConnect, asConnection(), std::placeholders::_1));
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} else
handleError(error);
});
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} }
void Connection::close() void Connection::close()
@@ -92,8 +66,8 @@ void Connection::close()
return; return;
// flush send data before disconnecting on clean connections // flush send data before disconnecting on clean connections
if(m_connected && !m_error && m_sendBufferSize > 0 && m_sendEvent) if(m_connected && !m_error && m_outputStream)
m_sendEvent->execute(); internal_write();
m_connecting = false; m_connecting = false;
m_connected = false; m_connected = false;
@@ -104,6 +78,7 @@ void Connection::close()
m_resolver.cancel(); m_resolver.cancel();
m_readTimer.cancel(); m_readTimer.cancel();
m_writeTimer.cancel(); m_writeTimer.cancel();
m_delayedWriteTimer.cancel();
if(m_socket.is_open()) { if(m_socket.is_open()) {
boost::system::error_code ec; boost::system::error_code ec;
@@ -112,94 +87,138 @@ void Connection::close()
} }
} }
void Connection::write(uint8* buffer, uint16 size) void Connection::connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback)
{
m_connected = false;
m_connecting = true;
m_error.clear();
m_connectCallback = connectCallback;
asio::ip::tcp::resolver::query query(host, stdext::unsafe_cast<std::string>(port));
m_resolver.async_resolve(query, std::bind(&Connection::onResolve, asConnection(), std::placeholders::_1, std::placeholders::_2));
m_readTimer.cancel();
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
}
void Connection::internal_connect(asio::ip::basic_resolver<asio::ip::tcp>::iterator endpointIterator)
{
m_socket.async_connect(*endpointIterator, std::bind(&Connection::onConnect, asConnection(), std::placeholders::_1));
m_readTimer.cancel();
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
}
void Connection::write(uint8* buffer, size_t size)
{ {
if(!m_connected) if(!m_connected)
return; return;
// send old buffer if we can't add more data
if(m_sendBufferSize + size >= SEND_BUFFER_SIZE && m_sendEvent)
m_sendEvent->execute();
// we can't send the data right away, otherwise we could create tcp congestion // we can't send the data right away, otherwise we could create tcp congestion
memcpy(m_sendBuffer + m_sendBufferSize, buffer, size); if(!m_outputStream) {
m_sendBufferSize += size; if(!m_outputStreams.empty()) {
m_outputStream = m_outputStreams.front();
m_outputStreams.pop_front();
} else
m_outputStream = std::shared_ptr<asio::streambuf>(new asio::streambuf);
if(!m_sendEvent || m_sendEvent->isExecuted() || m_sendEvent->isCanceled()) { m_delayedWriteTimer.cancel();
auto self = asConnection(); m_delayedWriteTimer.expires_from_now(boost::posix_time::milliseconds(10));
m_delayedWriteTimer.async_wait(std::bind(&Connection::onCanWrite, asConnection(), std::placeholders::_1));
// wait 1 ms to do the real send
m_sendEvent = g_dispatcher.scheduleEvent([=] {
if(self.is_unique())
return;
//m_writeTimer.cancel();
asio::async_write(m_socket,
asio::buffer(m_sendBuffer, m_sendBufferSize),
std::bind(&Connection::onWrite, asConnection(), std::placeholders::_1, std::placeholders::_2));
m_writeTimer.expires_from_now(boost::posix_time::seconds(WRITE_TIMEOUT));
m_writeTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
m_sendBufferSize = 0;
}, SEND_INTERVAL);
} }
std::ostream os(m_outputStream.get());
os.write((const char*)buffer, size);
os.flush();
}
void Connection::internal_write()
{
if(!m_connected)
return;
std::shared_ptr<asio::streambuf> outputStream = m_outputStream;
m_outputStream = nullptr;
asio::async_write(m_socket,
*outputStream,
std::bind(&Connection::onWrite, asConnection(), std::placeholders::_1, std::placeholders::_2, outputStream));
m_writeTimer.cancel();
m_writeTimer.expires_from_now(boost::posix_time::seconds(WRITE_TIMEOUT));
m_writeTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} }
void Connection::read(uint16 bytes, const RecvCallback& callback) void Connection::read(uint16 bytes, const RecvCallback& callback)
{ {
m_readTimer.cancel();
if(!m_connected) if(!m_connected)
return; return;
m_recvCallback = callback; m_recvCallback = callback;
asio::async_read(m_socket, asio::async_read(m_socket,
asio::buffer(m_streamBuffer.prepare(bytes)), asio::buffer(m_inputStream.prepare(bytes)),
std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, bytes)); std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, std::placeholders::_2));
m_readTimer.cancel();
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT)); m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1)); m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} }
void Connection::read_until(const std::string& what, const RecvCallback& callback) void Connection::read_until(const std::string& what, const RecvCallback& callback)
{ {
m_readTimer.cancel();
if(!m_connected) if(!m_connected)
return; return;
m_recvCallback = callback; m_recvCallback = callback;
asio::async_read_until(m_socket, asio::async_read_until(m_socket,
m_streamBuffer, m_inputStream,
what.c_str(), what.c_str(),
std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, std::placeholders::_2)); std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, std::placeholders::_2));
m_readTimer.cancel();
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT)); m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1)); m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} }
void Connection::read_some(const RecvCallback& callback) void Connection::read_some(const RecvCallback& callback)
{ {
m_readTimer.cancel();
if(!m_connected) if(!m_connected)
return; return;
m_recvCallback = callback; m_recvCallback = callback;
m_socket.async_read_some(asio::buffer(m_streamBuffer.prepare(RECV_BUFFER_SIZE)), m_socket.async_read_some(asio::buffer(m_inputStream.prepare(RECV_BUFFER_SIZE)),
std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, std::placeholders::_2)); std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, std::placeholders::_2));
m_readTimer.cancel();
m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT)); m_readTimer.expires_from_now(boost::posix_time::seconds(READ_TIMEOUT));
m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1)); m_readTimer.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
} }
void Connection::onResolve(const boost::system::error_code& error, asio::ip::basic_resolver<asio::ip::tcp>::iterator endpointIterator)
{
m_readTimer.cancel();
if(error == asio::error::operation_aborted)
return;
if(!error)
internal_connect(endpointIterator);
else
handleError(error);
}
void Connection::onConnect(const boost::system::error_code& error) void Connection::onConnect(const boost::system::error_code& error)
{ {
m_readTimer.cancel(); m_readTimer.cancel();
m_activityTimer.restart();
if(error == asio::error::operation_aborted)
return;
if(!error) { if(!error) {
m_connected = true; m_connected = true;
@@ -216,51 +235,72 @@ void Connection::onConnect(const boost::system::error_code& error)
m_connecting = false; m_connecting = false;
} }
void Connection::onWrite(const boost::system::error_code& error, size_t) void Connection::onCanWrite(const boost::system::error_code& error)
{
m_delayedWriteTimer.cancel();
if(error == asio::error::operation_aborted)
return;
if(m_connected)
internal_write();
}
void Connection::onWrite(const boost::system::error_code& error, size_t writeSize, std::shared_ptr<asio::streambuf> outputStream)
{ {
m_writeTimer.cancel(); m_writeTimer.cancel();
if(!m_connected) if(error == asio::error::operation_aborted)
return; return;
if(error) // free output stream and store for using it again later
outputStream->consume(outputStream->size());
m_outputStreams.push_back(outputStream);
if(m_connected && error)
handleError(error); handleError(error);
} }
void Connection::onRecv(const boost::system::error_code& error, size_t recvSize) void Connection::onRecv(const boost::system::error_code& error, size_t recvSize)
{ {
m_readTimer.cancel(); m_readTimer.cancel();
m_activityTimer.restart();
if(!m_connected) if(error == asio::error::operation_aborted)
return; return;
if(!error) { if(m_connected) {
if(m_recvCallback) { if(!error) {
const char* header = boost::asio::buffer_cast<const char*>(m_streamBuffer.data()); if(m_recvCallback) {
m_recvCallback((uint8*)header, recvSize); const char* header = boost::asio::buffer_cast<const char*>(m_inputStream.data());
} m_recvCallback((uint8*)header, recvSize);
}
} else
handleError(error);
} }
else
handleError(error);
m_streamBuffer.consume(recvSize); if(!error)
m_inputStream.consume(recvSize);
} }
void Connection::onTimeout(const boost::system::error_code& error) void Connection::onTimeout(const boost::system::error_code& error)
{ {
if(error != asio::error::operation_aborted) if(error == asio::error::operation_aborted)
handleError(asio::error::timed_out); return;
handleError(asio::error::timed_out);
} }
void Connection::handleError(const boost::system::error_code& error) void Connection::handleError(const boost::system::error_code& error)
{ {
if(error != asio::error::operation_aborted) { if(error == asio::error::operation_aborted)
m_error = error; return;
if(m_errorCallback)
m_errorCallback(error); m_error = error;
if(m_connected || m_connecting) if(m_errorCallback)
close(); m_errorCallback(error);
} if(m_connected || m_connecting)
close();
} }
int Connection::getIp() int Connection::getIp()

View File

@@ -36,7 +36,6 @@ class Connection : public LuaObject
enum { enum {
READ_TIMEOUT = 30, READ_TIMEOUT = 30,
WRITE_TIMEOUT = 30, WRITE_TIMEOUT = 30,
SEND_INTERVAL = 1,
SEND_BUFFER_SIZE = 65536, SEND_BUFFER_SIZE = 65536,
RECV_BUFFER_SIZE = 65536 RECV_BUFFER_SIZE = 65536
}; };
@@ -51,7 +50,7 @@ public:
void connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback); void connect(const std::string& host, uint16 port, const std::function<void()>& connectCallback);
void close(); void close();
void write(uint8* buffer, uint16 size); void write(uint8* buffer, size_t size);
void read(uint16 bytes, const RecvCallback& callback); void read(uint16 bytes, const RecvCallback& callback);
void read_until(const std::string& what, const RecvCallback& callback); void read_until(const std::string& what, const RecvCallback& callback);
void read_some(const RecvCallback& callback); void read_some(const RecvCallback& callback);
@@ -62,11 +61,17 @@ public:
boost::system::error_code getError() { return m_error; } boost::system::error_code getError() { return m_error; }
bool isConnecting() { return m_connecting; } bool isConnecting() { return m_connecting; }
bool isConnected() { return m_connected; } bool isConnected() { return m_connected; }
ticks_t getElapsedTicksSinceLastRead() { return m_connected ? m_activityTimer.elapsed_millis() : -1; }
ConnectionPtr asConnection() { return static_self_cast<Connection>(); } ConnectionPtr asConnection() { return static_self_cast<Connection>(); }
protected: protected:
void internal_connect(asio::ip::basic_resolver<asio::ip::tcp>::iterator endpointIterator);
void internal_write();
void onResolve(const boost::system::error_code& error, asio::ip::tcp::resolver::iterator endpointIterator);
void onConnect(const boost::system::error_code& error); void onConnect(const boost::system::error_code& error);
void onWrite(const boost::system::error_code& error, size_t); void onCanWrite(const boost::system::error_code& error);
void onWrite(const boost::system::error_code& error, size_t writeSize, std::shared_ptr<asio::streambuf> outputStream);
void onRecv(const boost::system::error_code& error, size_t recvSize); void onRecv(const boost::system::error_code& error, size_t recvSize);
void onTimeout(const boost::system::error_code& error); void onTimeout(const boost::system::error_code& error);
void handleError(const boost::system::error_code& error); void handleError(const boost::system::error_code& error);
@@ -77,17 +82,17 @@ protected:
asio::deadline_timer m_readTimer; asio::deadline_timer m_readTimer;
asio::deadline_timer m_writeTimer; asio::deadline_timer m_writeTimer;
asio::deadline_timer m_delayedWriteTimer;
asio::ip::tcp::resolver m_resolver; asio::ip::tcp::resolver m_resolver;
asio::ip::tcp::socket m_socket; asio::ip::tcp::socket m_socket;
uint8 m_sendBuffer[SEND_BUFFER_SIZE]; static std::list<std::shared_ptr<asio::streambuf>> m_outputStreams;
asio::streambuf m_streamBuffer; std::shared_ptr<asio::streambuf> m_outputStream;
asio::streambuf m_inputStream;
bool m_connected; bool m_connected;
bool m_connecting; bool m_connecting;
boost::system::error_code m_error; boost::system::error_code m_error;
int m_sendBufferSize; stdext::timer m_activityTimer;
Timer m_sendTimer;
ScheduledEventPtr m_sendEvent;
friend class Server; friend class Server;
}; };

View File

@@ -42,6 +42,8 @@ public:
bool isConnected(); bool isConnected();
bool isConnecting(); bool isConnecting();
ticks_t getElapsedTicksSinceLastRead() { return m_connection ? m_connection->getElapsedTicksSinceLastRead() : -1; }
ConnectionPtr getConnection() { return m_connection; } ConnectionPtr getConnection() { return m_connection; }
void setConnection(const ConnectionPtr& connection) { m_connection = connection; } void setConnection(const ConnectionPtr& connection) { m_connection = connection; }

View File

@@ -23,6 +23,8 @@
#ifndef CRASHHANDLER_H #ifndef CRASHHANDLER_H
#define CRASHHANDLER_H #define CRASHHANDLER_H
#ifdef CRASH_HANDLER
void installCrashHandler(); void installCrashHandler();
#endif
#endif #endif

View File

@@ -45,6 +45,7 @@ public:
std::string getCPUName(); std::string getCPUName();
double getTotalSystemMemory(); double getTotalSystemMemory();
std::string getOSName(); std::string getOSName();
std::string traceback(const std::string& where, int level = 1, int maxDepth = 32);
}; };
extern Platform g_platform; extern Platform g_platform;

View File

@@ -22,20 +22,13 @@
#include "platformwindow.h" #include "platformwindow.h"
#ifdef SDL
#include "sdlwindow.h"
SDLWindow window;
#else
#ifdef WIN32 #ifdef WIN32
#include "win32window.h" #include "win32window.h"
WIN32Window window; WIN32Window window;
WIN32Window& g_win32Window = window;
#else #else
#include "x11window.h" #include "x11window.h"
#include <framework/core/clock.h> #include <framework/core/clock.h>
X11Window window; X11Window window;
X11Window& g_x11Window = window;
#endif
#endif #endif
#include <framework/core/clock.h> #include <framework/core/clock.h>
@@ -65,19 +58,6 @@ int PlatformWindow::loadMouseCursor(const std::string& file, const Point& hotSpo
return internalLoadMouseCursor(image, hotSpot); return internalLoadMouseCursor(image, hotSpot);
} }
void PlatformWindow::setGraphicsContext(const GraphicsContextPtr& graphicsContext)
{
if(m_graphicsContext && m_graphicsContext->getName() == graphicsContext->getName())
return;
if(m_graphicsContext)
m_graphicsContext->destroy();
m_graphicsContext = graphicsContext;
m_graphicsContext->create();
m_graphicsContext->restore();
}
void PlatformWindow::updateUnmaximizedCoords() void PlatformWindow::updateUnmaximizedCoords()
{ {
if(!isMaximized() && !isFullscreen()) { if(!isMaximized() && !isFullscreen()) {

View File

@@ -27,13 +27,12 @@
#include <framework/core/inputevent.h> #include <framework/core/inputevent.h>
#include <framework/core/timer.h> #include <framework/core/timer.h>
#include <framework/graphics/declarations.h> #include <framework/graphics/declarations.h>
#include <framework/graphics/graphicscontext.h>
//@bindsingleton g_window //@bindsingleton g_window
class PlatformWindow class PlatformWindow
{ {
enum { enum {
KEY_PRESS_REPEAT_INTERVAL = 30 KEY_PRESS_REPEAT_INTERVAL = 30,
}; };
typedef std::function<void(const Size&)> OnResizeCallback; typedef std::function<void(const Size&)> OnResizeCallback;
@@ -58,16 +57,12 @@ public:
virtual void setMouseCursor(int cursorId) = 0; virtual void setMouseCursor(int cursorId) = 0;
virtual void restoreMouseCursor() = 0; virtual void restoreMouseCursor() = 0;
virtual void showTextInput() { }
virtual void hideTextInput() { }
virtual void setTitle(const std::string& title) = 0; virtual void setTitle(const std::string& title) = 0;
virtual void setMinimumSize(const Size& minimumSize) = 0; virtual void setMinimumSize(const Size& minimumSize) = 0;
virtual void setFullscreen(bool fullscreen) = 0; virtual void setFullscreen(bool fullscreen) = 0;
virtual void setVerticalSync(bool enable) = 0; virtual void setVerticalSync(bool enable) = 0;
virtual void setIcon(const std::string& iconFile) = 0; virtual void setIcon(const std::string& iconFile) = 0;
virtual void setClipboardText(const std::string& text) = 0; virtual void setClipboardText(const std::string& text) = 0;
void setGraphicsContext(const GraphicsContextPtr& graphicsContext);
virtual Size getDisplaySize() = 0; virtual Size getDisplaySize() = 0;
virtual std::string getClipboardText() = 0; virtual std::string getClipboardText() = 0;
@@ -132,8 +127,6 @@ protected:
std::function<void()> m_onClose; std::function<void()> m_onClose;
OnResizeCallback m_onResize; OnResizeCallback m_onResize;
OnInputEventCallback m_onInputEvent; OnInputEventCallback m_onInputEvent;
GraphicsContextPtr m_graphicsContext;
}; };
extern PlatformWindow& g_window; extern PlatformWindow& g_window;

View File

@@ -1,385 +0,0 @@
/*
* Copyright (c) 2010-2013 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 "sdlwindow.h"
#include <framework/graphics/image.h>
#include <framework/core/graphicalapplication.h>
SDLWindow::SDLWindow()
{
m_window = NULL;
m_renderer = NULL;
m_minimumSize = Size(600,480);
m_size = Size(600,480);
}
void SDLWindow::init()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 4);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 4);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 4);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 4);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
#ifdef OPENGL_ES
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_ES);
#endif
#ifdef MOBILE
int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_SHOWN;
#else
int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
#endif
m_window = SDL_CreateWindow(g_app.getName().c_str(),
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
m_size.width(), m_size.height(),
flags);
if(!m_window)
g_logger.fatal("Unable to create SDL window");
int w, h;
SDL_GetWindowSize(m_window, &w, &h);
m_size = Size(w,h);
m_context = SDL_GL_CreateContext(m_window);
if(!m_context)
g_logger.fatal("Unable to create SDL GL context");
SDL_GL_MakeCurrent(m_window, m_context);
}
void SDLWindow::terminate()
{
SDL_GL_DeleteContext(m_context);
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
void SDLWindow::move(const Point& pos)
{
if(pos.x < 0 || pos.y < 0)
return;
SDL_SetWindowPosition(m_window, pos.x, pos.y);
}
void SDLWindow::resize(const Size& size)
{
if(!size.isValid())
return;
m_size = size;
SDL_SetWindowSize(m_window, m_size.width(), m_size.height());
if(m_onResize)
m_onResize(m_size);
}
void SDLWindow::show()
{
SDL_ShowWindow(m_window);
}
void SDLWindow::hide()
{
SDL_HideWindow(m_window);
}
void SDLWindow::maximize()
{
SDL_MaximizeWindow(m_window);
}
Fw::MouseButton translateMouseButton(uint8 sdlButton)
{
switch(sdlButton) {
case SDL_BUTTON_LEFT:
return Fw::MouseLeftButton;
break;
case SDL_BUTTON_MIDDLE:
return Fw::MouseMidButton;
break;
case SDL_BUTTON_RIGHT:
return Fw::MouseRightButton;
}
return Fw::MouseNoButton;
}
void SDLWindow::poll()
{
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_WINDOWEVENT: {
switch(event.window.event) {
case SDL_WINDOWEVENT_SHOWN:
m_visible = true;
break;
case SDL_WINDOWEVENT_HIDDEN:
m_visible = false;
break;
case SDL_WINDOWEVENT_MOVED:
m_position = Point(event.window.data1, event.window.data2);
break;
case SDL_WINDOWEVENT_RESIZED:
g_logger.info(stdext::format("resize %d %d", event.window.data1, event.window.data2));
m_size = Size(event.window.data1, event.window.data2);
if(m_onResize)
m_onResize(m_size);
break;
case SDL_WINDOWEVENT_MINIMIZED:
m_maximized = false;
m_visible = false;
break;
case SDL_WINDOWEVENT_MAXIMIZED:
m_maximized = true;
m_visible = true;
break;
case SDL_WINDOWEVENT_RESTORED:
m_maximized = false;
m_visible = true;
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
m_focused = true;
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
m_focused = false;
break;
case SDL_WINDOWEVENT_CLOSE:
break;
}
break;
}
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
break;
case SDL_TEXTINPUT:
m_inputEvent.reset(Fw::KeyTextInputEvent);
m_inputEvent.keyText = event.text.text;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
case SDL_MOUSEMOTION:
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseMoveInputEvent;
m_inputEvent.mouseMoved = Point(event.motion.xrel, event.motion.yrel);
m_inputEvent.mousePos = Point(event.motion.x, event.motion.y);
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
case SDL_MOUSEBUTTONDOWN: {
Fw::MouseButton button = translateMouseButton(event.button.button);
if(button != Fw::MouseNoButton) {
m_inputEvent.reset();
m_inputEvent.type = Fw::MousePressInputEvent;
m_inputEvent.mouseButton = button;
m_mouseButtonStates[button] = true;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
}
break;
}
case SDL_MOUSEBUTTONUP: {
Fw::MouseButton button = translateMouseButton(event.button.button);
if(button == Fw::MouseNoButton)
break;
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseReleaseInputEvent;
m_inputEvent.mouseButton = button;
m_mouseButtonStates[button] = false;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
}
case SDL_MOUSEWHEEL: {
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseWheelInputEvent;
m_inputEvent.mouseButton = Fw::MouseMidButton;
if(event.wheel.y > 0)
m_inputEvent.wheelDirection = Fw::MouseWheelUp;
else if(event.wheel.y < 0)
m_inputEvent.wheelDirection = Fw::MouseWheelUp;
else
break;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
}
case SDL_FINGERDOWN: {
Fw::MouseButton button;
if(event.tfinger.fingerId == 0)
button = Fw::MouseLeftButton;
else if(event.tfinger.fingerId == 1)
button = Fw::MouseRightButton;
else
break;
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseReleaseInputEvent;
m_inputEvent.mouseButton = button;
m_mouseButtonStates[button] = true;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
}
case SDL_FINGERUP: {
Fw::MouseButton button;
if(event.tfinger.fingerId == 0)
button = Fw::MouseLeftButton;
else if(event.tfinger.fingerId == 1)
button = Fw::MouseRightButton;
else
break;
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseReleaseInputEvent;
m_inputEvent.mouseButton = button;
m_mouseButtonStates[button] = false;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
}
case SDL_FINGERMOTION: {
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseMoveInputEvent;
m_inputEvent.mouseMoved = Point(event.tfinger.dx, event.tfinger.dy);
m_inputEvent.mousePos = Point(event.tfinger.x, event.tfinger.y);
//g_logger.info(stdext::format("motion %d %d", event.tfinger.x, event.tfinger.y));
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
}
case SDL_QUIT:
if(m_onClose)
m_onClose();
break;
}
}
if(!m_maximized)
updateUnmaximizedCoords();
}
void SDLWindow::swapBuffers()
{
SDL_GL_SwapWindow(m_window);
}
void SDLWindow::showMouse()
{
SDL_ShowCursor(1);
}
void SDLWindow::hideMouse()
{
SDL_ShowCursor(0);
}
void SDLWindow::setMouseCursor(int cursorId)
{
//TODO
}
void SDLWindow::restoreMouseCursor()
{
//TODO
}
void SDLWindow::showTextInput()
{
SDL_StartTextInput();
}
void SDLWindow::hideTextInput()
{
SDL_StopTextInput();
}
void SDLWindow::setTitle(const std::string& title)
{
SDL_SetWindowTitle(m_window, title.c_str());
}
void SDLWindow::setMinimumSize(const Size& minimumSize)
{
SDL_SetWindowMinimumSize(m_window, minimumSize.width(), minimumSize.height());
}
void SDLWindow::setFullscreen(bool fullscreen)
{
if(m_fullscreen == fullscreen)
return;
SDL_SetWindowFullscreen(m_window, fullscreen);
m_fullscreen = fullscreen;
}
void SDLWindow::setVerticalSync(bool enable)
{
SDL_GL_SetSwapInterval(enable);
}
void SDLWindow::setIcon(const std::string& file)
{
ImagePtr image = Image::load(file);
if(!image) {
g_logger.traceError(stdext::format("unable to load icon file %s", file));
return;
}
if(image->getBpp() != 4) {
g_logger.error("the app icon must have 4 channels");
return;
}
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(image->getPixelData(), image->getWidth(), image->getHeight(), 32, image->getWidth()*4, 0xff0000, 0xff00, 0xff, 0xff000000);
SDL_SetWindowIcon(m_window, surface);
SDL_FreeSurface(surface);
}
void SDLWindow::setClipboardText(const std::string& text)
{
SDL_SetClipboardText(text.c_str());
}
Size SDLWindow::getDisplaySize()
{
//TODO
return getSize();
}
std::string SDLWindow::getClipboardText()
{
return SDL_GetClipboardText();
}
std::string SDLWindow::getPlatformType()
{
return "SDL";
}
int SDLWindow::internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot)
{
//TODO
return 0;
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2010-2013 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 SDLWINDOW_H
#define SDLWINDOW_H
#include "platformwindow.h"
#include <SDL.h>
#include <framework/graphics/glutil.h>
class SDLWindow : public PlatformWindow
{
public:
SDLWindow();
void init();
void terminate();
void move(const Point& pos);
void resize(const Size& size);
void show();
void hide();
void maximize();
void poll();
void swapBuffers();
void showMouse();
void hideMouse();
void setMouseCursor(int cursorId);
void restoreMouseCursor();
void showTextInput();
void hideTextInput();
void setTitle(const std::string& title);
void setMinimumSize(const Size& minimumSize);
void setFullscreen(bool fullscreen);
void setVerticalSync(bool enable);
void setIcon(const std::string& file);
void setClipboardText(const std::string& text);
Size getDisplaySize();
std::string getClipboardText();
std::string getPlatformType();
protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
private:
SDL_Window *m_window;
SDL_Renderer *m_renderer;
SDL_GLContext m_context;
};
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#if !defined(WIN32) && defined(CRASH_HANDLER)
#include "crashhandler.h" #include "crashhandler.h"
#include <framework/global.h> #include <framework/global.h>
#include <framework/core/application.h> #include <framework/core/application.h>
@@ -131,3 +133,5 @@ void installCrashHandler()
sigaction(SIGFPE, &sa, NULL); // floating-point exception sigaction(SIGFPE, &sa, NULL); // floating-point exception
sigaction(SIGABRT, &sa, NULL); // process aborted (asserts) sigaction(SIGABRT, &sa, NULL); // process aborted (asserts)
} }
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef WIN32
#include "platform.h" #include "platform.h"
#include <fstream> #include <fstream>
#include <unistd.h> #include <unistd.h>
@@ -27,16 +29,17 @@
#include <framework/stdext/stdext.h> #include <framework/stdext/stdext.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <execinfo.h>
void Platform::processArgs(std::vector<std::string>& args) void Platform::processArgs(std::vector<std::string>& args)
{ {
//nothing to do, linux args are already utf8 encoded //nothing todo, linux args are already utf8 encoded
} }
bool Platform::spawnProcess(std::string process, const std::vector<std::string>& args) bool Platform::spawnProcess(std::string process, const std::vector<std::string>& args)
{ {
struct stat sts; struct stat sts;
if(stat(process.c_str(), &sts) == -1) if(stat(process.c_str(), &sts) == -1 && errno == ENOENT)
return false; return false;
pid_t pid = fork(); pid_t pid = fork();
@@ -165,3 +168,36 @@ std::string Platform::getOSName()
} }
return std::string(); return std::string();
} }
std::string Platform::traceback(const std::string& where, int level, int maxDepth)
{
std::stringstream ss;
ss << "\nC++ stack traceback:";
if(!where.empty())
ss << "\n\t[C++]: " << where;
void* buffer[maxDepth + level + 1];
int numLevels = backtrace(buffer, maxDepth + level + 1);
char **tracebackBuffer = backtrace_symbols(buffer, numLevels);
if(tracebackBuffer) {
for(int i = 1 + level; i < numLevels; i++) {
std::string line = tracebackBuffer[i];
if(line.find("__libc_start_main") != std::string::npos)
break;
std::size_t demanglePos = line.find("(_Z");
if(demanglePos != std::string::npos) {
demanglePos++;
int len = std::min(line.find_first_of("+", demanglePos), line.find_first_of(")", demanglePos)) - demanglePos;
std::string funcName = line.substr(demanglePos, len);
line.replace(demanglePos, len, stdext::demangle_name(funcName.c_str()));
}
ss << "\n\t" << line;
}
free(tracebackBuffer);
}
return ss.str();
}
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#if defined(WIN32) && defined(CRASH_HANDLER)
#include "crashhandler.h" #include "crashhandler.h"
#include <framework/global.h> #include <framework/global.h>
#include <framework/core/application.h> #include <framework/core/application.h>
@@ -156,3 +158,5 @@ void installCrashHandler()
{ {
SetUnhandledExceptionFilter(ExceptionHandler); SetUnhandledExceptionFilter(ExceptionHandler);
} }
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifdef WIN32
#include "platform.h" #include "platform.h"
#include <windows.h> #include <windows.h>
#include <framework/stdext/stdext.h> #include <framework/stdext/stdext.h>
@@ -411,3 +413,14 @@ std::string Platform::getOSName()
} }
return ret; return ret;
} }
std::string Platform::traceback(const std::string& where, int level, int maxDepth)
{
std::stringstream ss;
ss << "\nat:";
ss << "\n\t[C++]: " << where;
return ss.str();
}
#endif

View File

@@ -20,33 +20,32 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifdef WIN32
#include "win32window.h" #include "win32window.h"
#include <framework/graphics/image.h> #include <framework/graphics/image.h>
#include <framework/core/application.h> #include <framework/core/application.h>
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#ifndef OPENGL_ES
#include <framework/graphics/ogl/graphicscontextwgl.h>
#else
#include <framework/graphics/ogl/graphicscontextegl.h>
#endif
#define HSB_BIT_SET(p, n) (p[(n)/8] |= (128 >>((n)%8))) #define HSB_BIT_SET(p, n) (p[(n)/8] |= (128 >>((n)%8)))
WIN32Window::WIN32Window() WIN32Window::WIN32Window()
{ {
m_window = 0; m_window = 0;
m_instance = 0; m_instance = 0;
m_deviceContext = 0;
m_cursor = 0; m_cursor = 0;
m_minimumSize = Size(600,480); m_minimumSize = Size(600,480);
m_size = Size(600,480); m_size = Size(600,480);
m_hidden = true; m_hidden = true;
m_deviceContext = 0;
#ifndef OPENGL_ES #ifdef OPENGL_ES
m_graphicsContext = GraphicsContextPtr(new GraphicsContextWGL); m_eglConfig = 0;
m_eglContext = 0;
m_eglDisplay = 0;
m_eglSurface = 0;
#else #else
m_graphicsContext = GraphicsContextPtr(new GraphicsContextEGL); m_wglContext = 0;
#endif #endif
m_keyMap[VK_ESCAPE] = Fw::KeyEscape; m_keyMap[VK_ESCAPE] = Fw::KeyEscape;
@@ -204,9 +203,30 @@ WIN32Window::WIN32Window()
void WIN32Window::init() void WIN32Window::init()
{ {
m_instance = GetModuleHandle(NULL); m_instance = GetModuleHandle(NULL);
#ifdef DIRECTX
m_d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information
ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = m_window; // set the window to be used by Direct3D
// create a device class using this information and information from the d3dpp stuct
m_d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
m_window,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&m_d3ddev);
#endif
internalCreateWindow(); internalCreateWindow();
m_graphicsContext->create(); internalCreateGLContext();
m_graphicsContext->restore(); internalRestoreGLContext();
} }
void WIN32Window::terminate() void WIN32Window::terminate()
@@ -221,7 +241,7 @@ void WIN32Window::terminate()
DestroyCursor(cursor); DestroyCursor(cursor);
m_cursors.clear(); m_cursors.clear();
m_graphicsContext->destroy(); internalDestroyGLContext();
if(m_deviceContext) { if(m_deviceContext) {
if(!ReleaseDC(m_window, m_deviceContext)) if(!ReleaseDC(m_window, m_deviceContext))
@@ -298,6 +318,154 @@ void WIN32Window::internalCreateWindow()
g_logger.fatal("GetDC failed"); g_logger.fatal("GetDC failed");
} }
void WIN32Window::internalCreateGLContext()
{
#ifdef OPENGL_ES
m_eglDisplay = eglGetDisplay(m_deviceContext);
if(m_eglDisplay == EGL_NO_DISPLAY)
g_logger.fatal("EGL not supported");
if(!eglInitialize(m_eglDisplay, NULL, NULL))
g_logger.fatal("Unable to initialize EGL");
static int configList[] = {
#if OPENGL_ES==2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 4,
EGL_BLUE_SIZE, 4,
EGL_ALPHA_SIZE, 4,
EGL_NONE
};
EGLint numConfig;
if(!eglGetConfigs(m_eglDisplay, NULL, 0, &numConfig))
g_logger.fatal("No valid GL configurations");
if(!eglChooseConfig(m_eglDisplay, configList, &m_eglConfig, 1, &numConfig))
g_logger.fatal("Failed to choose EGL config");
if(numConfig != 1)
g_logger.warning("Didn't got the exact EGL config");
EGLint contextAtrrList[] = {
#if OPENGL_ES==2
EGL_CONTEXT_CLIENT_VERSION, 2,
#else
EGL_CONTEXT_CLIENT_VERSION, 1,
#endif
EGL_NONE
};
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_window, NULL);
if(m_eglSurface == EGL_NO_SURFACE)
g_logger.fatal(stdext::format("Unable to create EGL surface: %s", eglGetError()));
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAtrrList);
if(m_eglContext == EGL_NO_CONTEXT )
g_logger.fatal(stdext::format("Unable to create EGL context: %s", eglGetError()));
#else
uint pixelFormat;
static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, // Select Our Color Depth
8, 0, 8, 0, 8, 0, // Color Bits Ignored
8, // Alpha Buffer Bits
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
0, // Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 }; // Layer Masks Ignored
pixelFormat = ChoosePixelFormat(m_deviceContext, &pfd);
if(!pixelFormat)
g_logger.fatal("Could not find a suitable pixel format");
if(!SetPixelFormat(m_deviceContext, pixelFormat, &pfd))
g_logger.fatal("Could not set the pixel format");
if(!(m_wglContext = wglCreateContext(m_deviceContext)))
g_logger.fatal("Unable to create GL context");
#endif
}
void WIN32Window::internalDestroyGLContext()
{
#ifdef OPENGL_ES
if(m_eglDisplay) {
if(m_eglContext) {
eglDestroyContext(m_eglDisplay, m_eglContext);
m_eglContext = 0;
}
if(m_eglSurface) {
eglDestroySurface(m_eglDisplay, m_eglSurface);
m_eglSurface = 0;
}
eglTerminate(m_eglDisplay);
m_eglDisplay = 0;
}
#else
if(m_wglContext) {
if(!wglMakeCurrent(NULL, NULL))
g_logger.error("Release of dc and rc failed.");
if(!wglDeleteContext(m_wglContext))
g_logger.error("Release rendering context failed.");
m_wglContext = NULL;
}
#endif
}
void WIN32Window::internalRestoreGLContext()
{
#ifdef OPENGL_ES
if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))
g_logger.fatal("Unable to make current EGL context");
#else
if(!wglMakeCurrent(m_deviceContext, m_wglContext))
g_logger.fatal("Unable to make current WGL context");
#endif
}
bool WIN32Window::isExtensionSupported(const char *ext)
{
#ifdef OPENGL_ES
//TODO
return false;
#else
typedef const char* (WINAPI * wglGetExtensionsStringProc)();
wglGetExtensionsStringProc wglGetExtensionsString = (wglGetExtensionsStringProc)getExtensionProcAddress("wglGetExtensionsStringEXT");
if(!wglGetExtensionsString)
return false;
const char *exts = wglGetExtensionsString();
if(exts && strstr(exts, ext))
return true;
return false;
#endif
}
void *WIN32Window::getExtensionProcAddress(const char *ext)
{
#ifdef OPENGL_ES
//TODO
return NULL;
#else
return (void*)wglGetProcAddress(ext);
#endif
}
void WIN32Window::move(const Point& pos) void WIN32Window::move(const Point& pos)
{ {
Rect clientRect(pos, getClientRect().size()); Rect clientRect(pos, getClientRect().size());
@@ -456,6 +624,9 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
break; break;
} }
case WM_SYSKEYDOWN: { case WM_SYSKEYDOWN: {
if(wParam == VK_F4 && m_inputEvent.keyboardModifiers & Fw::KeyboardAltModifier)
return DefWindowProc(hWnd, uMsg, wParam, lParam);
processKeyDown(retranslateVirtualKey(wParam, lParam)); processKeyDown(retranslateVirtualKey(wParam, lParam));
break; break;
} }
@@ -571,8 +742,8 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
break; break;
} }
if(m_visible) if(m_visible && m_deviceContext)
m_graphicsContext->restore(); internalRestoreGLContext();
Size size = Size(LOWORD(lParam), HIWORD(lParam)); Size size = Size(LOWORD(lParam), HIWORD(lParam));
size.setWidth(std::max(std::min(size.width(), 7680), 32)); size.setWidth(std::max(std::min(size.width(), 7680), 32));
@@ -594,7 +765,11 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
void WIN32Window::swapBuffers() void WIN32Window::swapBuffers()
{ {
m_graphicsContext->swapBuffers(); #ifdef OPENGL_ES
eglSwapBuffers(m_eglDisplay, m_eglSurface);
#else
SwapBuffers(m_deviceContext);
#endif
} }
void WIN32Window::showMouse() void WIN32Window::showMouse()
@@ -690,7 +865,19 @@ void WIN32Window::setFullscreen(bool fullscreen)
void WIN32Window::setVerticalSync(bool enable) void WIN32Window::setVerticalSync(bool enable)
{ {
m_graphicsContext->setVerticalSync(enable); #ifdef OPENGL_ES
eglSwapInterval(m_eglDisplay, enable ? 1 : 0);
#else
if(!isExtensionSupported("WGL_EXT_swap_control"))
return;
typedef BOOL (WINAPI * wglSwapIntervalProc)(int);
wglSwapIntervalProc wglSwapInterval = (wglSwapIntervalProc)getExtensionProcAddress("wglSwapIntervalEXT");
if(!wglSwapInterval)
return;
wglSwapInterval(enable ? 1 : 0);
#endif
} }
void WIN32Window::setIcon(const std::string& file) void WIN32Window::setIcon(const std::string& file)
@@ -783,7 +970,11 @@ std::string WIN32Window::getClipboardText()
std::string WIN32Window::getPlatformType() std::string WIN32Window::getPlatformType()
{ {
return stdext::format("WIN32-%s", m_graphicsContext->getName()); #ifndef OPENGL_ES
return "WIN32-WGL";
#else
return "WIN32-EGL";
#endif
} }
Rect WIN32Window::getClientRect() Rect WIN32Window::getClientRect()
@@ -831,3 +1022,5 @@ Rect WIN32Window::adjustWindowRect(const Rect& clientRect)
} }
return rect; return rect;
} }
#endif

View File

@@ -24,13 +24,28 @@
#define WIN32WINDOW_H #define WIN32WINDOW_H
#include "platformwindow.h" #include "platformwindow.h"
#include <windows.h> #include <windows.h>
#ifdef OPENGL_ES
#include <EGL/egl.h>
#endif
#ifdef DIRECTX
#include <d3d9.h>
#endif
struct WindowProcProxy; struct WindowProcProxy;
class WIN32Window : public PlatformWindow class WIN32Window : public PlatformWindow
{ {
void internalCreateWindow(); void internalCreateWindow();
void internalCreateGLContext();
void internalDestroyGLContext();
void internalRestoreGLContext();
void *getExtensionProcAddress(const char *ext);
bool isExtensionSupported(const char *ext);
LRESULT windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
friend class WindowProcProxy; friend class WindowProcProxy;
@@ -67,8 +82,6 @@ public:
Size getDisplaySize(); Size getDisplaySize();
std::string getClipboardText(); std::string getClipboardText();
std::string getPlatformType(); std::string getPlatformType();
HWND getWindow() { return m_window; }
HDC getDisplay() { return m_deviceContext; }
protected: protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot); int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
@@ -79,14 +92,26 @@ private:
Rect adjustWindowRect(const Rect& rect); Rect adjustWindowRect(const Rect& rect);
std::vector<HCURSOR> m_cursors; std::vector<HCURSOR> m_cursors;
HDC m_deviceContext;
HWND m_window; HWND m_window;
HINSTANCE m_instance; HINSTANCE m_instance;
HDC m_deviceContext;
HCURSOR m_cursor; HCURSOR m_cursor;
HCURSOR m_defaultCursor; HCURSOR m_defaultCursor;
bool m_hidden; bool m_hidden;
#ifdef DIRECTX
LPDIRECT3D9 m_d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 m_d3ddev; // the pointer to the device class
#endif
#ifdef OPENGL_ES
EGLConfig m_eglConfig;
EGLContext m_eglContext;
EGLDisplay m_eglDisplay;
EGLSurface m_eglSurface;
#else
HGLRC m_wglContext;
#endif
}; };
extern WIN32Window& g_win32Window;
#endif #endif

View File

@@ -20,17 +20,13 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef WIN32
#include "x11window.h" #include "x11window.h"
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <framework/graphics/image.h> #include <framework/graphics/image.h>
#include <unistd.h> #include <unistd.h>
#ifndef OPENGL_ES
#include <framework/graphics/ogl/graphicscontextglx.h>
#else
#include <framework/graphics/ogl/graphicscontextegl.h>
#endif
#define LSB_BIT_SET(p, n) (p[(n)/8] |= (1 <<((n)%8))) #define LSB_BIT_SET(p, n) (p[(n)/8] |= (1 <<((n)%8)))
X11Window::X11Window() X11Window::X11Window()
@@ -48,10 +44,15 @@ X11Window::X11Window()
m_wmDelete = 0; m_wmDelete = 0;
m_minimumSize = Size(600,480); m_minimumSize = Size(600,480);
m_size = Size(600,480); m_size = Size(600,480);
#ifndef OPENGL_ES
m_graphicsContext = GraphicsContextPtr(new GraphicsContextGLX); #ifdef OPENGL_ES
m_eglConfig = 0;
m_eglContext = 0;
m_eglDisplay = 0;
m_eglSurface = 0;
#else #else
m_graphicsContext = GraphicsContextPtr(new GraphicsContextEGL); m_fbConfig = 0;
m_glxContext = 0;
#endif #endif
m_keyMap[XK_Escape] = Fw::KeyEscape; m_keyMap[XK_Escape] = Fw::KeyEscape;
@@ -210,7 +211,9 @@ X11Window::X11Window()
void X11Window::init() void X11Window::init()
{ {
internalOpenDisplay(); internalOpenDisplay();
m_graphicsContext->create(); internalCheckGL();
internalChooseGLVisual();
internalCreateGLContext();
internalCreateWindow(); internalCreateWindow();
} }
@@ -240,7 +243,7 @@ void X11Window::terminate()
m_colormap = 0; m_colormap = 0;
} }
m_graphicsContext->destroy(); internalDestroyGLContext();
if(m_visual) { if(m_visual) {
XFree(m_visual); XFree(m_visual);
@@ -328,7 +331,7 @@ void X11Window::internalCreateWindow()
if(!internalSetupWindowInput()) if(!internalSetupWindowInput())
g_logger.warning("Input of special keys may be messed up, because window input initialization failed"); g_logger.warning("Input of special keys may be messed up, because window input initialization failed");
m_graphicsContext->restore(); internalConnectGLContext();
} }
bool X11Window::internalSetupWindowInput() bool X11Window::internalSetupWindowInput()
@@ -355,6 +358,169 @@ bool X11Window::internalSetupWindowInput()
return true; return true;
} }
void X11Window::internalCheckGL()
{
#ifdef OPENGL_ES
m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)m_display);
if(m_eglDisplay == EGL_NO_DISPLAY)
g_logger.fatal("EGL not supported");
if(!eglInitialize(m_eglDisplay, NULL, NULL))
g_logger.fatal("Unable to initialize EGL");
#else
if(!glXQueryExtension(m_display, NULL, NULL))
g_logger.fatal("GLX not supported");
#endif
}
void X11Window::internalChooseGLVisual()
{
#ifdef OPENGL_ES
static int attrList[] = {
#if OPENGL_ES==2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 4,
EGL_BLUE_SIZE, 4,
EGL_ALPHA_SIZE, 4,
EGL_NONE
};
EGLint numConfig;
XVisualInfo visTemplate;
int numVisuals;
if(!eglChooseConfig(m_eglDisplay, attrList, &m_eglConfig, 1, &numConfig))
g_logger.fatal("Failed to choose EGL config");
if(numConfig != 1)
g_logger.warning("Didn't got the exact EGL config");
EGLint vid;
if(!eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_NATIVE_VISUAL_ID, &vid))
g_logger.fatal("Unable to get visual EGL visual id");
memset(&visTemplate, 0, sizeof(visTemplate));
visTemplate.visualid = vid;
m_visual = XGetVisualInfo(m_display, VisualIDMask, &visTemplate, &numVisuals);
if(!m_visual)
g_logger.fatal("Couldn't choose RGBA, double buffered visual");
m_rootWindow = DefaultRootWindow(m_display);
#else
static int attrList[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
None
};
int nelements;
m_fbConfig = glXChooseFBConfig(m_display, m_screen, attrList, &nelements);
if(!m_fbConfig)
g_logger.fatal("Couldn't choose RGBA, double buffered fbconfig");
m_visual = glXGetVisualFromFBConfig(m_display, *m_fbConfig);
if(!m_visual)
g_logger.fatal("Couldn't choose RGBA, double buffered visual");
m_rootWindow = RootWindow(m_display, m_visual->screen);
#endif
}
void X11Window::internalCreateGLContext()
{
#ifdef OPENGL_ES
EGLint attrList[] = {
#if OPENGL_ES==2
EGL_CONTEXT_CLIENT_VERSION, 2,
#else
EGL_CONTEXT_CLIENT_VERSION, 1,
#endif
EGL_NONE
};
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, attrList);
if(m_eglContext == EGL_NO_CONTEXT )
g_logger.fatal(stdext::format("Unable to create EGL context: %s", eglGetError()));
#else
m_glxContext = glXCreateContext(m_display, m_visual, NULL, True);
if(!m_glxContext)
g_logger.fatal("Unable to create GLX context");
if(!glXIsDirect(m_display, m_glxContext))
g_logger.warning("GL direct rendering is not possible");
#endif
}
void X11Window::internalDestroyGLContext()
{
#ifdef OPENGL_ES
if(m_eglDisplay) {
if(m_eglContext) {
eglDestroyContext(m_eglDisplay, m_eglContext);
m_eglContext = 0;
}
if(m_eglSurface) {
eglDestroySurface(m_eglDisplay, m_eglSurface);
m_eglSurface = 0;
}
eglTerminate(m_eglDisplay);
m_eglDisplay = 0;
}
#else
if(m_glxContext) {
glXMakeCurrent(m_display, None, NULL);
glXDestroyContext(m_display, m_glxContext);
m_glxContext = 0;
}
#endif
}
void X11Window::internalConnectGLContext()
{
#ifdef OPENGL_ES
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_window, NULL);
if(m_eglSurface == EGL_NO_SURFACE)
g_logger.fatal(stdext::format("Unable to create EGL surface: %s", eglGetError()));
if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))
g_logger.fatal("Unable to connect EGL context into X11 window");
#else
if(!glXMakeCurrent(m_display, m_window, m_glxContext))
g_logger.fatal("Unable to set GLX context on X11 window");
#endif
}
void *X11Window::getExtensionProcAddress(const char *ext)
{
#ifdef OPENGL_ES
//TODO
return NULL;
#else
return (void *)glXGetProcAddressARB((const GLubyte*)ext);
#endif
}
bool X11Window::isExtensionSupported(const char *ext)
{
#ifdef OPENGL_ES
//TODO
return false;
#else
const char *exts = glXQueryExtensionsString(m_display, m_screen);
if(strstr(exts, ext))
return true;
#endif
return false;
}
void X11Window::move(const Point& pos) void X11Window::move(const Point& pos)
{ {
m_position = pos; m_position = pos;
@@ -674,7 +840,11 @@ void X11Window::poll()
void X11Window::swapBuffers() void X11Window::swapBuffers()
{ {
m_graphicsContext->swapBuffers(); #ifdef OPENGL_ES
eglSwapBuffers(m_eglDisplay, m_eglSurface);
#else
glXSwapBuffers(m_display, m_window);
#endif
} }
void X11Window::showMouse() void X11Window::showMouse()
@@ -798,7 +968,20 @@ void X11Window::setFullscreen(bool fullscreen)
void X11Window::setVerticalSync(bool enable) void X11Window::setVerticalSync(bool enable)
{ {
m_graphicsContext->setVerticalSync(enable); #ifdef OPENGL_ES
//TODO
#else
typedef GLint (*glSwapIntervalProc)(GLint);
glSwapIntervalProc glSwapInterval = NULL;
if(isExtensionSupported("GLX_MESA_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
else if(isExtensionSupported("GLX_SGI_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
if(glSwapInterval)
glSwapInterval(enable ? 1 : 0);
#endif
} }
void X11Window::setIcon(const std::string& file) void X11Window::setIcon(const std::string& file)
@@ -886,5 +1069,11 @@ std::string X11Window::getClipboardText()
std::string X11Window::getPlatformType() std::string X11Window::getPlatformType()
{ {
return stdext::format("X11-%s", m_graphicsContext->getName()); #ifndef OPENGL_ES
return "X11-GLX";
#else
return "X11-EGL";
#endif
} }
#endif

View File

@@ -28,9 +28,12 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h>
typedef Window WindowType; #ifdef OPENGL_ES
#include <EGL/egl.h>
#else
#include <GL/glx.h>
#endif
class X11Window : public PlatformWindow class X11Window : public PlatformWindow
{ {
@@ -38,6 +41,15 @@ class X11Window : public PlatformWindow
void internalCreateWindow(); void internalCreateWindow();
bool internalSetupWindowInput(); bool internalSetupWindowInput();
void internalCheckGL();
void internalChooseGLVisual();
void internalCreateGLContext();
void internalDestroyGLContext();
void internalConnectGLContext();
void *getExtensionProcAddress(const char *ext);
bool isExtensionSupported(const char *ext);
public: public:
X11Window(); X11Window();
@@ -63,16 +75,10 @@ public:
void setVerticalSync(bool enable); void setVerticalSync(bool enable);
void setIcon(const std::string& file); void setIcon(const std::string& file);
void setClipboardText(const std::string& text); void setClipboardText(const std::string& text);
void setVisual(XVisualInfo *visual) { m_visual = visual; }
void setRootWindow(const Window& window) { m_rootWindow = window; }
Size getDisplaySize(); Size getDisplaySize();
std::string getClipboardText(); std::string getClipboardText();
std::string getPlatformType(); std::string getPlatformType();
Window getWindow() { return m_window; }
Display *getDisplay() { return m_display; }
int getScreen() { return m_screen; }
XVisualInfo *getVisual() { return m_visual; }
protected: protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot); int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
@@ -91,9 +97,17 @@ private:
int m_screen; int m_screen;
Atom m_wmDelete; Atom m_wmDelete;
std::string m_clipboardText; std::string m_clipboardText;
};
extern X11Window& g_x11Window; #ifndef OPENGL_ES
GLXContext m_glxContext;
GLXFBConfig *m_fbConfig;
#else
EGLConfig m_eglConfig;
EGLContext m_eglContext;
EGLDisplay m_eglDisplay;
EGLSurface m_eglSurface;
#endif
};
#endif #endif

Some files were not shown because too many files have changed in this diff Show More