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*
CMakeCache.txt
CMakeFiles
@@ -39,3 +38,4 @@ tags
Thumbs.db
.directory
src/framework/graphics/dx/
modules/.project/modules.sublime-workspace

View File

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

View File

@@ -11,3 +11,9 @@ HorizontalList < UIScrollArea
border-width: 1
border-color: #1d222b
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
g_modules.autoLoadModules(9999)
local script = '/' .. g_app.getCompactName() .. 'rc.lua'
local script = '/' .. g_app.getCompactName() .. 'rc'
if g_resources.fileExists(script) then
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 musicChannel = nil
local musicChannel = g_sounds.getChannel(1)
function setMusic(filename)
musicFilename = filename
@@ -57,14 +57,11 @@ function init()
onExit = exit })
g_window.setMinimumSize({ width = 600, height = 480 })
musicChannel = g_sounds.getChannel(1)
g_sounds.preload(musicFilename)
-- initialize in fullscreen mode on mobile devices
if g_app.getOs() == "android" then
g_window.maximize()
--g_window.setFullscreen(true)
if g_window.getPlatformType() == "X11-EGL" then
g_window.setFullscreen(true)
else
-- window size
local size = { width = 800, height = 600 }
@@ -107,11 +104,6 @@ function terminate()
g_settings.set('window-size', g_window.getUnmaximizedSize())
g_settings.set('window-pos', g_window.getUnmaximizedPos())
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
function exit()

View File

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

View File

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

View File

@@ -68,7 +68,7 @@ EnterGameWindow
TextEdit
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.right: serverListButton.left
anchors.top: serverLabel.bottom
@@ -76,8 +76,8 @@ EnterGameWindow
margin-right: 4
MenuLabel
id: protocolLabel
!text: tr('Protocol')
id: clientLabel
!text: tr('Client Version')
anchors.left: parent.left
anchors.top: serverHostTextEdit.bottom
text-auto-resize: true
@@ -85,17 +85,13 @@ EnterGameWindow
margin-top: 8
ComboBox
id: protocolComboBox
id: clientComboBox
anchors.left: parent.left
anchors.right: parent.horizontalCenter
anchors.top: protocolLabel.bottom
anchors.top: clientLabel.bottom
margin-top: 2
margin-right: 3
width: 90
@onSetup: |
for _, proto in pairs(g_game.getSupportedProtocols()) do
self:addOption(proto)
end
MenuLabel
id: portLabel
@@ -110,7 +106,7 @@ EnterGameWindow
text: 7171
anchors.right: parent.right
anchors.left: parent.horizontalCenter
anchors.top: protocolComboBox.top
anchors.top: clientComboBox.top
margin-left: 3
CheckBox

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,16 @@
battleWindow = nil
battleButton = nil
battlePanel = nil
filterPanel = nil
toggleFilterButton = nil
lastBattleButtonSwitched = nil
battleButtonsByCreaturesList = {}
creatureAgeList = {}
mouseWidget = nil
sortTypeBox = nil
sortOrderBox = nil
hidePlayersButton = nil
hideNPCsButton = nil
hideMonstersButton = nil
@@ -25,6 +30,15 @@ function init()
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')
hideNPCsButton = battleWindow:recursiveGetChildById('hideNPCs')
hideMonstersButton = battleWindow:recursiveGetChildById('hideMonsters')
@@ -38,6 +52,18 @@ function init()
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, {
onSkullChange = updateCreatureSkull,
onEmblemChange = updateCreatureEmblem,
@@ -47,6 +73,10 @@ function init()
onAppear = onCreatureAppear,
onDisappear = onCreatureDisappear
})
connect(LocalPlayer, {
onPositionChange = onCreaturePositionChange
})
connect(g_game, {
onAttackingCreatureChange = onAttack,
@@ -75,6 +105,10 @@ function terminate()
onDisappear = onCreatureDisappear
})
disconnect(LocalPlayer, {
onPositionChange = onCreaturePositionChange
})
disconnect(g_game, {
onAttackingCreatureChange = onAttack,
onFollowingCreatureChange = onFollow,
@@ -96,6 +130,93 @@ function onMiniWindowClose()
battleButton:setOn(false)
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()
removeAllCreatures()
@@ -151,15 +272,42 @@ end
function onCreatureHealthPercentChange(creature, health)
local battleButton = battleButtonsByCreaturesList[creature:getId()]
if battleButton then
if getSortType() == 'health' then
removeCreature(creature)
addCreature(creature)
return
end
battleButton:setLifeBarPercent(creature:getHealthPercent())
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)
if creature:isLocalPlayer() then
if oldPos and newPos and newPos.z ~= oldPos.z then
checkCreatures()
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
addCreature(creatureButton.creature)
end
@@ -170,6 +318,9 @@ function onCreaturePositionChange(creature, newPos, oldPos)
if has and not fit then
removeCreature(creature)
elseif fit then
if has and getSortType() == 'distance' then
removeCreature(creature)
end
addCreature(creature)
end
end
@@ -201,8 +352,13 @@ function addCreature(creature)
local creatureId = creature:getId()
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
battleButton = g_ui.createWidget('BattleButton', battlePanel)
battleButton = g_ui.createWidget('BattleButton')
battleButton:setup(creature)
battleButton.onHoverChange = onBattleButtonHoverChange
@@ -217,6 +373,77 @@ function addCreature(creature)
if creature == g_game.getFollowingCreature() then
onFollow(creature)
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
battleButton:setLifeBarPercent(creature:getHealthPercent())
end
@@ -226,6 +453,7 @@ function addCreature(creature)
end
function removeAllCreatures()
creatureAgeList = {}
for i, v in pairs(battleButtonsByCreaturesList) do
removeCreature(v.creature)
end

View File

@@ -45,11 +45,12 @@ MiniWindow
&save: true
Panel
id: filterPanel
margin-top: 26
anchors.top: parent.top
anchors.left: parent.left
anchors.right: miniwindowScrollBar.left
height: 20
height: 45
Panel
anchors.top: parent.top
@@ -85,16 +86,56 @@ MiniWindow
!tooltip: tr('Hide party members')
@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.left: parent.left
anchors.right: miniwindowScrollBar.left
margin-right: 1
margin-top: 4
margin-top: 5
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
anchors.top: prev.bottom
margin-top: 0
margin-top: 6
Panel
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
channels = nil
channelsWindow = nil
ignoreWindow = nil
communicationWindow = nil
ownPrivateName = nil
messageHistory = {}
currentMessageIndex = 0
@@ -74,10 +74,14 @@ violationReportTab = nil
ignoredChannels = {}
filters = {}
local ignoreSettings = {
local communicationSettings = {
useIgnoreList = true,
useWhiteList = true,
privateMessages = false,
yelling = false,
players = {}
allowVIPs = false,
ignoredPlayers = {},
whitelistedPlayers = {}
}
function init()
@@ -139,10 +143,59 @@ function init()
g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels)
g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab)
g_keyboard.bindKeyDown('Ctrl+H', openHelp)
consoleToggleChat = consolePanel:getChildById('toggleChat')
load()
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()
save()
disconnect(g_game, {
@@ -166,14 +219,14 @@ function terminate()
g_keyboard.unbindKeyDown('Ctrl+E')
g_keyboard.unbindKeyDown('Ctrl+H')
saveIgnoreSettings()
saveCommunicationSettings()
if channelsWindow then
channelsWindow:destroy()
end
if ignoreWindow then
ignoreWindow:destroy()
if communicationWindow then
communicationWindow:destroy()
end
if violationWindow then
@@ -197,7 +250,7 @@ function load()
if settings then
messageHistory = settings.messageHistory or {}
end
loadIgnoreSettings()
loadCommunicationSettings()
end
function onTabChange(tabBar, tab)
@@ -466,7 +519,7 @@ function addTabText(text, speaktype, tab, creatureName)
-- Remove the curly braces
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] }
text = text:gsub("{"..dataBlock.words.."}", dataBlock.words)
text = text:gsub("%{(.-)%}", dataBlock.words, 1)
-- Recalculate positions as braces are removed
highlightData[(i-1)*3+1] = dataBlock._start - ((i-1) * 2)
@@ -779,7 +832,11 @@ function onTalk(name, level, mode, message, channelId, creaturePos)
return
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
return
elseif speaktype.private and isIgnoringPrivate() and mode ~= MessageModes.NpcFrom then
@@ -957,107 +1014,221 @@ function onChannelList(channelList)
end
end
function loadIgnoreSettings()
function loadCommunicationSettings()
communicationSettings.whitelistedPlayers = {}
communicationSettings.ignoredPlayers = {}
local ignoreNode = g_settings.getNode('IgnorePlayers')
if ignoreNode then
for i = 1, #ignoreNode do
table.insert(ignoreSettings.players, ignoreNode[i])
table.insert(communicationSettings.ignoredPlayers, ignoreNode[i])
end
end
ignoreSettings.privateMessages = g_settings.getBoolean('IgnorePrivateMessages')
ignoreSettings.yelling = g_settings.getBoolean('IgnoreYelling')
end
function saveIgnoreSettings()
local tmpSettings = {}
for i = 1, #ignoreSettings.players do
table.insert(tmpSettings, ignoreSettings.players[i])
local whitelistNode = g_settings.getNode('WhitelistedPlayers')
if whitelistNode then
for i = 1, #whitelistNode do
table.insert(communicationSettings.whitelistedPlayers, whitelistNode[i])
end
end
g_settings.set('IgnorePrivateMessages', ignoreSettings.privateMessages)
g_settings.set('IgnoreYelling', ignoreSettings.yelling)
g_settings.setNode('IgnorePlayers', tmpSettings)
communicationSettings.useIgnoreList = g_settings.getBoolean('UseIgnoreList')
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
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)
return table.find(ignoreSettings.players, name, true)
return table.find(communicationSettings.ignoredPlayers, name, true)
end
function addIgnoredPlayer(name)
if not isIgnored(name) then
table.insert(ignoreSettings.players, name)
end
if isIgnored(name) then return end
table.insert(communicationSettings.ignoredPlayers, name)
end
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
function isIgnoringPrivate()
return ignoreSettings.privateMessages
return communicationSettings.privateMessages
end
function isIgnoringYelling()
return ignoreSettings.yelling
return communicationSettings.yelling
end
function isAllowingVIPs()
return communicationSettings.allowVIPs
end
function onClickIgnoreButton()
if ignoreWindow then return end
ignoreWindow = g_ui.displayUI('ignorewindow')
local ignoreListPanel = ignoreWindow:getChildById('ignoreList')
ignoreWindow.onDestroy = function() ignoreWindow = nil end
if communicationWindow then return end
communicationWindow = g_ui.displayUI('communicationwindow')
local ignoreListPanel = communicationWindow:getChildById('ignoreList')
local whiteListPanel = communicationWindow:getChildById('whiteList')
communicationWindow.onDestroy = function() communicationWindow = nil end
local removeButton = ignoreWindow:getChildById('buttonRemove')
removeButton:disable()
ignoreListPanel.onChildFocusChange = function() removeButton:enable() end
removeButton.onClick = function()
local useIgnoreListBox = communicationWindow:getChildById('checkboxUseIgnoreList')
useIgnoreListBox:setChecked(communicationSettings.useIgnoreList)
local useWhiteListBox = communicationWindow:getChildById('checkboxUseWhiteList')
useWhiteListBox:setChecked(communicationSettings.useWhiteList)
local removeIgnoreButton = communicationWindow:getChildById('buttonIgnoreRemove')
removeIgnoreButton:disable()
ignoreListPanel.onChildFocusChange = function() removeIgnoreButton:enable() end
removeIgnoreButton.onClick = function()
local selection = ignoreListPanel:getFocusedChild()
if selection then
ignoreListPanel:removeChild(selection)
selection:destroy()
ignoreListPanel:removeChild(selection)
selection:destroy()
end
if ignoreListPanel:getChildCount() == 0 then
removeButton:disable()
removeIgnoreButton: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
removeWhitelistButton:disable()
end
local newlyIgnoredPlayers = {}
local addName = ignoreWindow:getChildById('ignoreNameEdit')
local addButton = ignoreWindow:getChildById('buttonAdd')
local addFunction = function()
if addName:getText() == '' then return end
if table.find(ignoreSettings.players, addName:getText()) then return end
if table.find(newlyIgnoredPlayers, addName:getText()) then return end
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
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 addIgnoreName = communicationWindow:getChildById('ignoreNameEdit')
local addIgnoreButton = communicationWindow:getChildById('buttonIgnoreAdd')
local addIgnoreFunction = function()
local newEntry = addIgnoreName:getText()
if newEntry == '' then return end
if table.find(getIgnoredPlayers(), newEntry) then return end
if table.find(newlyIgnoredPlayers, newEntry) then return end
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
label:setText(name)
label:setPhantom(false)
label:setText(newEntry)
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
@@ -1089,4 +1260,4 @@ function offline()
g_keyboard.unbindKeyDown('Ctrl+R')
end
clear()
end
end

View File

@@ -56,12 +56,21 @@ Panel
id: consolePanel
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
id: prevChannelButton
icon: /images/game/console/leftarrow
anchors.left: parent.left
anchors.left: toggleChat.right
anchors.top: parent.top
margin-left: 6
margin-left: 3
margin-top: 6
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')
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)
@@ -56,42 +57,19 @@ end
function bindKeys()
gameRootPanel:setAutoRepeatDelay(250)
g_keyboard.bindKeyDown('Up', function() changeWalkDir(North) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Right', function() changeWalkDir(East) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Down', function() changeWalkDir(South) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Left', function() changeWalkDir(West) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad8', function() changeWalkDir(North) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad9', function() changeWalkDir(NorthEast) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad6', function() changeWalkDir(East) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad3', function() changeWalkDir(SouthEast) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad2', function() changeWalkDir(South) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad1', function() changeWalkDir(SouthWest) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad4', function() changeWalkDir(West) end, gameRootPanel, true)
g_keyboard.bindKeyDown('Numpad7', function() changeWalkDir(NorthWest) end, gameRootPanel, true)
g_keyboard.bindKeyUp('Up', function() changeWalkDir(North, true) end, gameRootPanel, true)
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)
bindWalkKey('Up', North)
bindWalkKey('Right', East)
bindWalkKey('Down', South)
bindWalkKey('Left', West)
bindWalkKey('Numpad8', North)
bindWalkKey('Numpad9', NorthEast)
bindWalkKey('Numpad6', East)
bindWalkKey('Numpad3', SouthEast)
bindWalkKey('Numpad2', South)
bindWalkKey('Numpad1', SouthWest)
bindWalkKey('Numpad4', West)
bindWalkKey('Numpad7', NorthWest)
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)
@@ -104,12 +82,24 @@ function bindKeys()
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:zoomOut() end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+Q', logout, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+L', logout, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+Q', function() tryLogout(false) end, 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+.', nextViewMode, gameRootPanel)
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()
save()
hide()
@@ -215,8 +205,8 @@ function tryExit()
return true
end
local exitFunc = function() logout() forceExit() end
local logoutFunc = function() logout() exitWindow:destroy() exitWindow = nil end
local exitFunc = function() g_game.safeLogout() forceExit() end
local logoutFunc = function() g_game.safeLogout() 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."),
@@ -228,14 +218,10 @@ function tryExit()
return true
end
function logout()
if g_game.isOnline() then
g_game.safeLogout()
return true
function tryLogout(prompt)
if type(prompt) ~= "boolean" then
prompt = true
end
end
function tryLogout()
if not g_game.isOnline() then
exit()
return
@@ -245,13 +231,42 @@ function tryLogout()
return
end
local yesCallback = function() logout() logoutWindow:destroy() logoutWindow=nil end
local noCallback = function() logoutWindow:destroy() logoutWindow=nil end
local msg, yesCallback
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?'), {
{ text=tr('Yes'), callback=yesCallback },
{ text=tr('No'), callback=noCallback },
anchor=AnchorHorizontalCenter}, yesCallback, noCallback)
yesCallback = function()
g_game.forceLogout()
if logoutWindow then
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
function stopSmartWalk()
@@ -463,17 +478,20 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
end
else
local localPosition = localPlayer:getPosition()
if not classic then shortcut = '(Alt)' else shortcut = nil end
if g_game.getAttackingCreature() ~= creatureThing then
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end, shortcut)
else
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)
else
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
if creatureThing:getPosition().z == localPosition.z then
if g_game.getAttackingCreature() ~= creatureThing then
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end, shortcut)
else
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)
else
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
end
end
if creatureThing:isPlayer() then
@@ -519,7 +537,7 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
end
end
if modules.game_ruleviolation.hasWindowAccess() then
if modules.game_ruleviolation.hasWindowAccess() and creatureThing:isPlayer() then
menu:addSeparator()
menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureThing:getName()) end)
end
@@ -531,7 +549,7 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
menu:display(menuPosition)
end
function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing)
function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, attackCreature)
local keyboardModifiers = g_keyboard.getModifiers()
if not modules.client_options.getOption('classicControl') then
@@ -557,7 +575,10 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
return true
end
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)
return true
end
@@ -566,7 +587,10 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
else
if useThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
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)
return true
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
createThingMenu(menuPosition, lookThing, useThing, creatureThing)
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)
return true
end
@@ -655,6 +682,8 @@ function moveStackableItem(item, toPos)
end
g_keyboard.bindKeyPress("Up", function() check() spinbox:up() 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("PageDown", function() check() spinbox:setValue(spinbox:getValue()-10) end, spinbox)
@@ -747,7 +776,6 @@ function setupViewMode(mode)
gameMapPanel:setVisibleDimension({ width = 15, height = 11 })
elseif mode == 2 then
local limit = limitZoom and not g_game.isGM()
gameMapPanel:setKeepAspectRatio(false)
gameMapPanel:setLimitVisibleRange(limit)
gameMapPanel:setZoom(11)
gameMapPanel:setVisibleDimension({ width = 15, height = 11 })

View File

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

View File

@@ -78,15 +78,21 @@ function UIGameMap:onMouseRelease(mousePosition, mouseButton)
local useThing
local creatureThing
local multiUseThing
local attackCreature
local tile = self:getTile(mousePosition)
if tile then
lookThing = tile:getTopLookThing()
useThing = tile:getTopUseThing()
creatureThing = tile:getTopCreature()
end
local autoWalkTile = g_map.getTile(autoWalkPos)
if autoWalkTile then
attackCreature = autoWalkTile:getTopCreature()
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
self.allowNextRelease = false
end

View File

@@ -86,7 +86,7 @@ function UIItem:onMouseRelease(mousePosition, mouseButton)
g_game.look(item)
self.cancelNextRelease = 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
end
return false

View File

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

View File

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

View File

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

View File

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

View File

@@ -88,6 +88,23 @@ function isHiddingOffline()
return settings['hideOffline']
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)
local vipList = vipWindow:getChildById('contentsPanel')
@@ -118,13 +135,13 @@ function onAddVip(id, name, state)
for i=1,childrenCount do
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)
return
end
if (state ~= VipState.Online and child.vipState ~= VipState.Online)
or (state == VipState.Online and child.vipState == VipState.Online) then
if ((state ~= VipState.Online and child.vipState ~= VipState.Online)
or (state == VipState.Online and child.vipState == VipState.Online)) or getSortedBy() == 'name' then
local childText = child:getText():lower()
local length = math.min(childText:len(), nameLower:len())
@@ -167,6 +184,14 @@ function onVipListMousePress(widget, mousePos, mouseButton)
else
menu:addOption(tr('Show Offline'), function() hideOffline(false) 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)
@@ -196,6 +221,15 @@ function onVipListLabelMousePress(widget, mousePos, mouseButton)
else
menu:addOption(tr('Show Offline'), function() hideOffline(false) 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)
return true

View File

@@ -6,7 +6,7 @@ end
function g_game.chooseRsa(host)
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)
if g_app.getOs() == 'windows' then
@@ -32,22 +32,29 @@ function g_game.isOfficialTibia()
return currentRsa == CIPSOFT_RSA
end
function g_game.getSupportedProtocols()
function g_game.getSupportedClients()
return {
810, 811, 840, 842, 850, 853, 854,
860, 861, 862, 870, 910, 940, 944,
953, 954, 960, 961, 963, 970, 971,
973, 974
953, 954, 960, 961, 963, 970, 980,
981, 982, 983, 984, 985, 986, 1001,
1002, 1010
}
end
function g_game.getSupportedClients(protocol)
function g_game.getProtocolVersionForClient(client)
clients = {
[971] = {980},
[973] = {981},
[974] = {982}
[980] = 971,
[981] = 973,
[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
g_game.setRsa(OTSERV_RSA)

View File

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

View File

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

View File

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

View File

@@ -99,6 +99,11 @@ void Game::resetGameStates()
m_walkEvent = nullptr;
}
if(m_checkConnectionEvent) {
m_checkConnectionEvent->cancel();
m_checkConnectionEvent = nullptr;
}
m_containers.clear();
m_vips.clear();
m_gmActions.clear();
@@ -183,6 +188,16 @@ void Game::processGameStart()
g_game.ping();
}, 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()
@@ -190,6 +205,11 @@ void Game::processGameEnd()
m_online = false;
g_lua.callGlobalField("g_game", "onGameEnd");
if(m_connectionFailWarned) {
g_lua.callGlobalField("g_game", "onConnectionFailing", false);
m_connectionFailWarned = false;
}
// reset game state
resetGameStates();
@@ -554,7 +574,7 @@ bool Game::walk(Otc::Direction direction)
if(m_lastWalkDir != direction) {
// must add a new walk event
float ticks = m_localPlayer->getStepTicksLeft();
if(ticks < 0) { ticks = 0; }
if(ticks <= 0) { ticks = 1; }
if(m_walkEvent) {
m_walkEvent->cancel();
@@ -697,15 +717,16 @@ void Game::autoWalk(std::vector<Otc::Direction> dirs)
auto it = dirs.begin();
Otc::Direction direction = *it;
if(m_localPlayer->canWalk(direction)) {
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
if(toTile && toTile->isWalkable() && !m_localPlayer->isServerWalking()) {
m_localPlayer->preWalk(direction);
if(!m_localPlayer->canWalk(direction))
return;
if(getFeature(Otc::GameForceFirstAutoWalkStep)) {
forceWalk(direction);
dirs.erase(it);
}
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
if(toTile && toTile->isWalkable() && !m_localPlayer->isServerWalking()) {
m_localPlayer->preWalk(direction);
if(getFeature(Otc::GameForceFirstAutoWalkStep)) {
forceWalk(direction);
dirs.erase(it);
}
}
@@ -1129,7 +1150,7 @@ void Game::removeVip(int playerId)
{
if(!canPerformGameAction())
return;
auto it = m_vips.find(playerId);
if(it == m_vips.end())
return;
@@ -1379,7 +1400,7 @@ void Game::setProtocolVersion(int version)
if(isOnline())
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));
m_features.reset();
@@ -1443,6 +1464,14 @@ void Game::setProtocolVersion(int version)
enableFeature(Otc::GameNewSpeedLaw);
}
if(version >= 976) {
enableFeature(Otc::GameContainerPagination);
}
if(version >= 979) {
enableFeature(Otc::GameThingMarks);
}
m_protocolVersion = version;
Proto::buildMessageModesMap(version);
@@ -1458,7 +1487,7 @@ void Game::setClientVersion(int version)
if(isOnline())
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));
m_clientVersion = version;

View File

@@ -231,7 +231,7 @@ public:
void openRuleViolation(const std::string& reporter);
void closeRuleViolation(const std::string& reporter);
void cancelRuleViolation();
// reports
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);
@@ -281,6 +281,7 @@ public:
bool isDead() { return m_dead; }
bool isAttacking() { return !!m_attackingCreature; }
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; }
ContainerPtr getContainer(int index) { return m_containers[index]; }
@@ -340,6 +341,8 @@ private:
std::bitset<Otc::LastGameFeature> m_features;
ScheduledEventPtr m_pingEvent;
ScheduledEventPtr m_walkEvent;
ScheduledEventPtr m_checkConnectionEvent;
bool m_connectionFailWarned;
int m_protocolVersion;
int m_clientVersion;
std::string m_clientSignature;

View File

@@ -26,7 +26,6 @@
#include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/painter.h>
#include <framework/graphics/image.h>
#include <framework/graphics/ogl/textureogl.h>
enum {
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);
return tex;
}

View File

@@ -72,7 +72,7 @@ bool LocalPlayer::canWalk(Otc::Direction direction)
return false;
// last walk is not done yet
if(m_walkTimer.ticksElapsed() < getStepDuration())
if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
return false;
// 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;
// cannot walk while already walking
if(m_walking && !prewalkTimeouted)
if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
return false;
return true;
@@ -95,6 +95,7 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
if(m_preWalking) {
// switch to normal walking
m_preWalking = false;
m_secondPreWalk = false;
m_lastPrewalkDone = true;
// if is to the last prewalk destination, updates the walk preserving the animation
if(newPos == m_lastPrewalkDestination) {
@@ -118,7 +119,8 @@ void LocalPlayer::preWalk(Otc::Direction direction)
Position newPos = m_position.translatedToDirection(direction);
// avoid reanimating prewalks
if(m_preWalking && m_lastPrewalkDestination == newPos) {
if(m_preWalking) {
m_secondPreWalk = true;
return;
}
@@ -277,6 +279,7 @@ void LocalPlayer::terminateWalk()
{
Creature::terminateWalk();
m_preWalking = false;
m_secondPreWalk = false;
m_idleTimer.restart();
auto self = asLocalPlayer();

View File

@@ -126,6 +126,7 @@ private:
ticks_t m_walkLockExpiration;
stdext::boolean<false> m_preWalking;
stdext::boolean<true> m_lastPrewalkDone;
stdext::boolean<false> m_secondPreWalk;
stdext::boolean<false> m_serverWalking;
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", "isAttacking", &Game::isAttacking, &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", "getContainer", &Game::getContainer, &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);
// 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 coveredPos = pos;
while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
// check tiles physically above
TilePtr tile = g_map.getTile(upperPos);
if(tile && tile->limitsFloorsView()) {
if(tile && tile->limitsFloorsView(!g_map.isLookPossible(pos))) {
firstFloor = upperPos.z + 1;
break;
}
// check tiles geometrically above
tile = g_map.getTile(coveredPos);
if(tile && tile->limitsFloorsView()) {
if(tile && tile->limitsFloorsView(g_map.isLookPossible(pos))) {
firstFloor = coveredPos.z + 1;
break;
}

View File

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

View File

@@ -603,6 +603,14 @@ void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
std::string name = msg->getString();
int capacity = msg->getU8();
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();
std::vector<ItemPtr> items(itemCount);
@@ -622,13 +630,21 @@ void ProtocolGame::parseContainerAddItem(const InputMessagePtr& msg)
{
int containerId = msg->getU8();
ItemPtr item = getItem(msg);
if(g_game.getFeature(Otc::GameContainerPagination)) {
msg->getU16(); // slot
}
g_game.processContainerAddItem(containerId, item);
}
void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
{
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);
g_game.processContainerUpdateItem(containerId, slot, item);
}
@@ -636,7 +652,13 @@ void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
{
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);
}
@@ -1808,6 +1830,12 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
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)
unpass = msg->getU8();
@@ -1860,6 +1888,10 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
if(item->getId() == 0)
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())
item->setCountOrSubType(msg->getU8());

View File

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

View File

@@ -28,7 +28,6 @@
#include <framework/graphics/graphics.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/image.h>
#include <framework/graphics/ogl/textureogl.h>
#include <framework/graphics/texturemanager.h>
#include <framework/core/filestream.h>
#include <framework/otml/otml.h>
@@ -68,6 +67,17 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
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) {
case ThingAttrDisplacement: {
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;
if(totalSprites == 0)
stdext::throw_exception("a thing type has no sprites");
// if(totalSprites == 0)
// stdext::throw_exception("a thing type has no sprites");
if(totalSprites > 4096)
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);
}
return animationPhaseTexture;

View File

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

View File

@@ -457,7 +457,7 @@ ThingPtr Tile::getTopMultiUseThing()
if(thing->isForceUse())
return thing;
}
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()) {
@@ -590,15 +590,24 @@ bool Tile::hasCreature()
return false;
}
bool Tile::limitsFloorsView()
bool Tile::limitsFloorsView(bool isFreeView)
{
// ground and walls limits the view
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;
}
bool Tile::canErase()
{
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_BED = 1 << 21,
TILESTATE_DEPOT = 1 << 22,
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
};
class Tile : public LuaObject
@@ -105,7 +105,7 @@ public:
bool mustHookSouth();
bool mustHookEast();
bool hasCreature();
bool limitsFloorsView();
bool limitsFloorsView(bool isFreeView = false);
bool canErase();
bool hasElevation(int elevation = 1);
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
# 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.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
PROPERTIES LANGUAGE CXX COMPILE_FLAGS "-g0 -Os")
@@ -263,15 +258,6 @@ if(CRASH_HANDLER)
message(STATUS "Crash handler: ON")
if(WIN32)
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()
else()
message(STATUS "Crash handler: OFF")
@@ -304,24 +290,18 @@ endif()
if(FRAMEWORK_GRAPHICS)
set(OPENGLES "OFF" CACHE "Use OpenGL ES 1.0 or 2.0 (for mobiles devices)" STRING)
if(OPENGLES)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextegl.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/ogl/graphicscontextegl.h
)
if(OPENGLES STREQUAL "2.0")
find_package(OpenGLES2 REQUIRED)
find_package(EGL REQUIRED)
set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=2)
set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR})
set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES2_LIBRARY})
elseif(OPENGLES STREQUAL "1.0")
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()
if(OPENGLES STREQUAL "2.0")
find_package(OpenGLES2 REQUIRED)
find_package(EGL REQUIRED)
set(framework_DEFINITIONS ${framework_DEFINITIONS} -DOPENGL_ES=2)
set(framework_INCLUDE_DIRS ${framework_INCLUDE_DIRS} ${EGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR})
set(framework_LIBRARIES ${framework_LIBRARIES} ${EGL_LIBRARY} ${OPENGLES2_LIBRARY})
ELSEif(OPENGLES STREQUAL "1.0")
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})
else()
## TODO: CMake Documentation says that this is not the right
# Thing for Mac OS X, but it works for now.
@@ -356,8 +336,6 @@ if(FRAMEWORK_GRAPHICS)
set(framework_SOURCES ${framework_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/graphics/dx/painterdx9.cpp
${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()
@@ -365,44 +343,6 @@ if(FRAMEWORK_GRAPHICS)
set(framework_LIBRARIES ${framework_LIBRARIES} X11)
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}
${CMAKE_CURRENT_LIST_DIR}/graphics/animatedtexture.cpp
${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/graphics.cpp
${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.h
${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/texture.cpp
${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.h
${CMAKE_CURRENT_LIST_DIR}/graphics/vertexarray.h
@@ -499,6 +435,10 @@ if(FRAMEWORK_GRAPHICS)
# platform window
${CMAKE_CURRENT_LIST_DIR}/platform/platformwindow.cpp
${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
${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 <locale>
#include <boost/concept_check.hpp>
#ifdef FW_NET
#include <framework/net/connection.h>
@@ -164,14 +163,10 @@ void Application::close()
std::string Application::getOs()
{
#if defined(ANDROID)
return "android";
#elif defined(IOS)
return "ios";
#elif defined(WIN32)
#if defined(WIN32)
return "windows";
#elif defined(__APPLE__)
return "macos";
return "mac";
#elif __linux
return "linux";
#else

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,15 +24,14 @@
#include "graphics.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))
return;
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;

View File

@@ -29,7 +29,7 @@
class AnimatedTexture : public Texture
{
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 bool buildHardwareMipmaps();

View File

@@ -33,15 +33,15 @@
#include <fstream>
#if defined(_MSC_VER) && _MSC_VER >= 1300
#define lswap16(data) _byteswap_ushort(data)
#define lswap32(data) _byteswap_ulong(data)
#define swap16(data) _byteswap_ushort(data)
#define swap32(data) _byteswap_ulong(data)
#elif __linux__
#include <byteswap.h>
#define lswap16(data) bswap_16(data)
#define lswap32(data) bswap_32(data)
#define swap16(data) bswap_16(data)
#define swap32(data) bswap_32(data)
#else
#define lswap16(data) (((data >> 8) & 255) | ((data & 255) << 8))
#define lswap32(data) ((swap16(data) << 16) | swap16(data >> 16))
#define swap16(data) (((data >> 8) & 255) | ((data & 255) << 8))
#define swap32(data) ((swap16(data) << 16) | swap16(data >> 16))
#endif
#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)
{
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(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 = lswap32(crc);
crc = swap32(crc);
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 mFilterMethod;
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 zstream2;

View File

@@ -34,7 +34,6 @@ class BitmapFont;
class CachedText;
class FrameBuffer;
class FrameBufferManager;
class GraphicsContext;
class Shader;
class ShaderProgram;
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<CachedText> CachedTextPtr;
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<ShaderProgram> ShaderProgramPtr;
typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr;

View File

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

View File

@@ -44,7 +44,6 @@
typedef char GLchar;
// 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 glBindFramebuffer (GLenum target, GLuint framebuffer) { }
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)
{
// TODO: remove this
#ifdef DIRECTX
painterEngine = Painter_DirectX9;
#endif
Painter *painter = nullptr;
Painter *fallbackPainter = nullptr;
PainterEngine fallbackPainterEngine = Painter_Any;
#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
if(g_painterDX9) {
if(!painter && (painterEngine == Painter_DirectX9 || painterEngine == Painter_Any)) {
@@ -240,7 +238,6 @@ bool Graphics::selectPainterEngine(PainterEngine painterEngine)
if(g_painter)
g_painter->unbind();
painter->bind();
g_window.setGraphicsContext(painter->getGraphicsContext());
g_painter = painter;
}
@@ -256,11 +253,6 @@ bool Graphics::selectPainterEngine(PainterEngine painterEngine)
void Graphics::resize(const Size& size)
{
m_viewportSize = size;
#ifdef PAINTER_DX9
if(g_painterDX9)
g_painterDX9->setResolution(size);
#endif
#ifdef PAINTER_OGL1
if(g_painterOGL1)
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/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()
{
#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_oldStateIndex = 0;
m_color = Color::white;
@@ -53,7 +35,6 @@ PainterOGL::PainterOGL()
m_shaderProgram = nullptr;
m_texture = nullptr;
m_alphaWriting = false;
setResolution(g_window.getSize());
}
@@ -305,7 +286,6 @@ void PainterOGL::updateGlBlendEquation()
{
if(!g_graphics.canUseBlendEquation())
return;
if(m_blendEquation == BlendEquation_Add)
glBlendEquation(0x8006); // GL_FUNC_ADD
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/coordsbuffer.h>
#include <framework/graphics/graphicscontext.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/texture.h>
@@ -51,7 +50,7 @@ public:
Painter();
virtual ~Painter() {}
virtual ~Painter() { }
virtual void bind() { }
virtual void unbind() { }
@@ -96,7 +95,6 @@ public:
float getOpacity() { return m_opacity; }
Rect getClipRect() { return m_clipRect; }
CompositionMode getCompositionMode() { return m_compositionMode; }
GraphicsContextPtr getGraphicsContext() { return m_graphicsContext; }
virtual void setCompositionMode(CompositionMode compositionMode) = 0;
@@ -118,7 +116,6 @@ protected:
Size m_resolution;
float m_opacity;
Rect m_clipRect;
GraphicsContextPtr m_graphicsContext;
};
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;
}
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()
{
#ifndef NDEBUG
assert(!g_app.isTerminated());
#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;
setupTranformMatrix(size, size);
if(!setupSize(image->getSize(), buildMipmaps))
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;
}
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) {
m_transformMatrix = { 1.0f/textureSize.width(), 0.0f, 0.0f,
0.0f, -1.0f/textureSize.height(), 0.0f,
0.0f, realSize.height()/(float)textureSize.height(), 1.0f };
m_transformMatrix = { 1.0f/m_glSize.width(), 0.0f, 0.0f,
0.0f, -1.0f/m_glSize.height(), 0.0f,
0.0f, m_size.height()/(float)m_glSize.height(), 1.0f };
} else {
m_transformMatrix = { 1.0f/textureSize.width(), 0.0f, 0.0f,
0.0f, 1.0f/textureSize.height(), 0.0f,
0.0f, 0.0f, 1.0f };
m_transformMatrix = { 1.0f/m_glSize.width(), 0.0f, 0.0f,
0.0f, 1.0f/m_glSize.height(), 0.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:
Texture();
Texture(const Size& size);
Texture(const ImagePtr& image, bool buildMipmaps = false, bool compress = false);
virtual ~Texture();
virtual void setSmooth(bool) {}
virtual void setRepeat(bool) {}
virtual void setUpsideDown(bool) {}
virtual bool setupSize(const Size& size, bool);
virtual void copyFromScreen(const Rect&) {}
virtual bool buildHardwareMipmaps() { return false; }
virtual void uploadPixels(const ImagePtr&, bool) {}
void uploadPixels(const ImagePtr& image, bool buildMipmaps = false, bool compress = 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);
void setTime(ticks_t time) { m_time = time; }
void setupTranformMatrix(const Size& textureSize, const Size& realSize);
uint getId() { return m_id; }
ticks_t getTime() { return m_time; }
int getWidth() { return m_size.width(); }
int getHeight() { return m_size.height(); }
const Size& getSize() { return m_size; }
const Size& getGlSize() { return m_glSize; }
const Matrix3& getTransformMatrix() { return m_transformMatrix; }
bool isEmpty() { return m_id == 0; }
bool hasRepeat() { return m_repeat; }
@@ -55,6 +56,13 @@ public:
virtual bool isAnimatedTexture() { return false; }
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;
ticks_t m_time;
Size m_size;

View File

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

View File

@@ -20,9 +20,6 @@
* THE SOFTWARE.
*/
#ifndef MOUSE_H
#define MOUSE_H
#include <framework/global.h>
class Mouse
@@ -46,5 +43,3 @@ private:
};
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)
{
std::string directory = g_lua.popString();
for(const std::string& fileName : g_resources.listDirectoryFiles(directory)) {
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();
}
std::string contains = "";
if(g_lua.getTop() > 2) {
contains = g_lua.popString();
}
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;
}
@@ -1247,3 +1246,29 @@ int LuaInterface::getTop()
{
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()); }
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
template<typename T, typename... 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>("setImageRepeated", &UIWidget::setImageRepeated);
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>("setImageBorderRight", &UIWidget::setImageBorderRight);
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>("isImageFixedRatio", &UIWidget::isImageFixedRatio);
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>("getImageBorderRight", &UIWidget::getImageBorderRight);
g_lua.bindClassMemberFunction<UIWidget>("getImageBorderBottom", &UIWidget::getImageBorderBottom);

View File

@@ -27,16 +27,17 @@
#include <boost/asio.hpp>
asio::io_service g_ioService;
std::list<std::shared_ptr<asio::streambuf>> Connection::m_outputStreams;
Connection::Connection() :
m_readTimer(g_ioService),
m_writeTimer(g_ioService),
m_delayedWriteTimer(g_ioService),
m_resolver(g_ioService),
m_socket(g_ioService)
{
m_connected = false;
m_connecting = false;
m_sendBufferSize = 0;
}
Connection::~Connection()
@@ -56,34 +57,7 @@ void Connection::poll()
void Connection::terminate()
{
g_ioService.stop();
}
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));
m_outputStreams.clear();
}
void Connection::close()
@@ -92,8 +66,8 @@ void Connection::close()
return;
// flush send data before disconnecting on clean connections
if(m_connected && !m_error && m_sendBufferSize > 0 && m_sendEvent)
m_sendEvent->execute();
if(m_connected && !m_error && m_outputStream)
internal_write();
m_connecting = false;
m_connected = false;
@@ -104,6 +78,7 @@ void Connection::close()
m_resolver.cancel();
m_readTimer.cancel();
m_writeTimer.cancel();
m_delayedWriteTimer.cancel();
if(m_socket.is_open()) {
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)
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
memcpy(m_sendBuffer + m_sendBufferSize, buffer, size);
m_sendBufferSize += size;
if(!m_outputStream) {
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()) {
auto self = asConnection();
// 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);
m_delayedWriteTimer.cancel();
m_delayedWriteTimer.expires_from_now(boost::posix_time::milliseconds(10));
m_delayedWriteTimer.async_wait(std::bind(&Connection::onCanWrite, asConnection(), std::placeholders::_1));
}
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)
{
m_readTimer.cancel();
if(!m_connected)
return;
m_recvCallback = callback;
asio::async_read(m_socket,
asio::buffer(m_streamBuffer.prepare(bytes)),
std::bind(&Connection::onRecv, asConnection(), std::placeholders::_1, bytes));
asio::buffer(m_inputStream.prepare(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.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
}
void Connection::read_until(const std::string& what, const RecvCallback& callback)
{
m_readTimer.cancel();
if(!m_connected)
return;
m_recvCallback = callback;
asio::async_read_until(m_socket,
m_streamBuffer,
m_inputStream,
what.c_str(),
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.async_wait(std::bind(&Connection::onTimeout, asConnection(), std::placeholders::_1));
}
void Connection::read_some(const RecvCallback& callback)
{
m_readTimer.cancel();
if(!m_connected)
return;
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));
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::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)
{
m_readTimer.cancel();
m_activityTimer.restart();
if(error == asio::error::operation_aborted)
return;
if(!error) {
m_connected = true;
@@ -216,51 +235,72 @@ void Connection::onConnect(const boost::system::error_code& error)
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();
if(!m_connected)
if(error == asio::error::operation_aborted)
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);
}
void Connection::onRecv(const boost::system::error_code& error, size_t recvSize)
{
m_readTimer.cancel();
m_activityTimer.restart();
if(!m_connected)
if(error == asio::error::operation_aborted)
return;
if(!error) {
if(m_recvCallback) {
const char* header = boost::asio::buffer_cast<const char*>(m_streamBuffer.data());
m_recvCallback((uint8*)header, recvSize);
}
if(m_connected) {
if(!error) {
if(m_recvCallback) {
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)
{
if(error != asio::error::operation_aborted)
handleError(asio::error::timed_out);
if(error == asio::error::operation_aborted)
return;
handleError(asio::error::timed_out);
}
void Connection::handleError(const boost::system::error_code& error)
{
if(error != asio::error::operation_aborted) {
m_error = error;
if(m_errorCallback)
m_errorCallback(error);
if(m_connected || m_connecting)
close();
}
if(error == asio::error::operation_aborted)
return;
m_error = error;
if(m_errorCallback)
m_errorCallback(error);
if(m_connected || m_connecting)
close();
}
int Connection::getIp()

View File

@@ -36,7 +36,6 @@ class Connection : public LuaObject
enum {
READ_TIMEOUT = 30,
WRITE_TIMEOUT = 30,
SEND_INTERVAL = 1,
SEND_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 close();
void write(uint8* buffer, uint16 size);
void write(uint8* buffer, size_t size);
void read(uint16 bytes, const RecvCallback& callback);
void read_until(const std::string& what, const RecvCallback& callback);
void read_some(const RecvCallback& callback);
@@ -62,11 +61,17 @@ public:
boost::system::error_code getError() { return m_error; }
bool isConnecting() { return m_connecting; }
bool isConnected() { return m_connected; }
ticks_t getElapsedTicksSinceLastRead() { return m_connected ? m_activityTimer.elapsed_millis() : -1; }
ConnectionPtr asConnection() { return static_self_cast<Connection>(); }
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 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 onTimeout(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_writeTimer;
asio::deadline_timer m_delayedWriteTimer;
asio::ip::tcp::resolver m_resolver;
asio::ip::tcp::socket m_socket;
uint8 m_sendBuffer[SEND_BUFFER_SIZE];
asio::streambuf m_streamBuffer;
static std::list<std::shared_ptr<asio::streambuf>> m_outputStreams;
std::shared_ptr<asio::streambuf> m_outputStream;
asio::streambuf m_inputStream;
bool m_connected;
bool m_connecting;
boost::system::error_code m_error;
int m_sendBufferSize;
Timer m_sendTimer;
ScheduledEventPtr m_sendEvent;
stdext::timer m_activityTimer;
friend class Server;
};

View File

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

View File

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

View File

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

View File

@@ -22,20 +22,13 @@
#include "platformwindow.h"
#ifdef SDL
#include "sdlwindow.h"
SDLWindow window;
#else
#ifdef WIN32
#include "win32window.h"
WIN32Window window;
WIN32Window& g_win32Window = window;
#else
#include "x11window.h"
#include <framework/core/clock.h>
X11Window window;
X11Window& g_x11Window = window;
#endif
#endif
#include <framework/core/clock.h>
@@ -65,19 +58,6 @@ int PlatformWindow::loadMouseCursor(const std::string& file, const Point& hotSpo
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()
{
if(!isMaximized() && !isFullscreen()) {

View File

@@ -27,13 +27,12 @@
#include <framework/core/inputevent.h>
#include <framework/core/timer.h>
#include <framework/graphics/declarations.h>
#include <framework/graphics/graphicscontext.h>
//@bindsingleton g_window
class PlatformWindow
{
enum {
KEY_PRESS_REPEAT_INTERVAL = 30
KEY_PRESS_REPEAT_INTERVAL = 30,
};
typedef std::function<void(const Size&)> OnResizeCallback;
@@ -58,16 +57,12 @@ public:
virtual void setMouseCursor(int cursorId) = 0;
virtual void restoreMouseCursor() = 0;
virtual void showTextInput() { }
virtual void hideTextInput() { }
virtual void setTitle(const std::string& title) = 0;
virtual void setMinimumSize(const Size& minimumSize) = 0;
virtual void setFullscreen(bool fullscreen) = 0;
virtual void setVerticalSync(bool enable) = 0;
virtual void setIcon(const std::string& iconFile) = 0;
virtual void setClipboardText(const std::string& text) = 0;
void setGraphicsContext(const GraphicsContextPtr& graphicsContext);
virtual Size getDisplaySize() = 0;
virtual std::string getClipboardText() = 0;
@@ -132,8 +127,6 @@ protected:
std::function<void()> m_onClose;
OnResizeCallback m_onResize;
OnInputEventCallback m_onInputEvent;
GraphicsContextPtr m_graphicsContext;
};
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.
*/
#if !defined(WIN32) && defined(CRASH_HANDLER)
#include "crashhandler.h"
#include <framework/global.h>
#include <framework/core/application.h>
@@ -131,3 +133,5 @@ void installCrashHandler()
sigaction(SIGFPE, &sa, NULL); // floating-point exception
sigaction(SIGABRT, &sa, NULL); // process aborted (asserts)
}
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE.
*/
#ifndef WIN32
#include "platform.h"
#include <fstream>
#include <unistd.h>
@@ -27,16 +29,17 @@
#include <framework/stdext/stdext.h>
#include <sys/stat.h>
#include <execinfo.h>
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)
{
struct stat sts;
if(stat(process.c_str(), &sts) == -1)
if(stat(process.c_str(), &sts) == -1 && errno == ENOENT)
return false;
pid_t pid = fork();
@@ -165,3 +168,36 @@ std::string Platform::getOSName()
}
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.
*/
#if defined(WIN32) && defined(CRASH_HANDLER)
#include "crashhandler.h"
#include <framework/global.h>
#include <framework/core/application.h>
@@ -156,3 +158,5 @@ void installCrashHandler()
{
SetUnhandledExceptionFilter(ExceptionHandler);
}
#endif

View File

@@ -20,6 +20,8 @@
* THE SOFTWARE.
*/
#ifdef WIN32
#include "platform.h"
#include <windows.h>
#include <framework/stdext/stdext.h>
@@ -411,3 +413,14 @@ std::string Platform::getOSName()
}
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.
*/
#ifdef WIN32
#include "win32window.h"
#include <framework/graphics/image.h>
#include <framework/core/application.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)))
WIN32Window::WIN32Window()
{
m_window = 0;
m_instance = 0;
m_deviceContext = 0;
m_cursor = 0;
m_minimumSize = Size(600,480);
m_size = Size(600,480);
m_hidden = true;
m_deviceContext = 0;
#ifndef OPENGL_ES
m_graphicsContext = GraphicsContextPtr(new GraphicsContextWGL);
#ifdef OPENGL_ES
m_eglConfig = 0;
m_eglContext = 0;
m_eglDisplay = 0;
m_eglSurface = 0;
#else
m_graphicsContext = GraphicsContextPtr(new GraphicsContextEGL);
m_wglContext = 0;
#endif
m_keyMap[VK_ESCAPE] = Fw::KeyEscape;
@@ -204,9 +203,30 @@ WIN32Window::WIN32Window()
void WIN32Window::init()
{
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();
m_graphicsContext->create();
m_graphicsContext->restore();
internalCreateGLContext();
internalRestoreGLContext();
}
void WIN32Window::terminate()
@@ -221,7 +241,7 @@ void WIN32Window::terminate()
DestroyCursor(cursor);
m_cursors.clear();
m_graphicsContext->destroy();
internalDestroyGLContext();
if(m_deviceContext) {
if(!ReleaseDC(m_window, m_deviceContext))
@@ -298,6 +318,154 @@ void WIN32Window::internalCreateWindow()
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)
{
Rect clientRect(pos, getClientRect().size());
@@ -456,6 +624,9 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
break;
}
case WM_SYSKEYDOWN: {
if(wParam == VK_F4 && m_inputEvent.keyboardModifiers & Fw::KeyboardAltModifier)
return DefWindowProc(hWnd, uMsg, wParam, lParam);
processKeyDown(retranslateVirtualKey(wParam, lParam));
break;
}
@@ -571,8 +742,8 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
break;
}
if(m_visible)
m_graphicsContext->restore();
if(m_visible && m_deviceContext)
internalRestoreGLContext();
Size size = Size(LOWORD(lParam), HIWORD(lParam));
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()
{
m_graphicsContext->swapBuffers();
#ifdef OPENGL_ES
eglSwapBuffers(m_eglDisplay, m_eglSurface);
#else
SwapBuffers(m_deviceContext);
#endif
}
void WIN32Window::showMouse()
@@ -690,7 +865,19 @@ void WIN32Window::setFullscreen(bool fullscreen)
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)
@@ -783,7 +970,11 @@ std::string WIN32Window::getClipboardText()
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()
@@ -831,3 +1022,5 @@ Rect WIN32Window::adjustWindowRect(const Rect& clientRect)
}
return rect;
}
#endif

View File

@@ -24,13 +24,28 @@
#define WIN32WINDOW_H
#include "platformwindow.h"
#include <windows.h>
#ifdef OPENGL_ES
#include <EGL/egl.h>
#endif
#ifdef DIRECTX
#include <d3d9.h>
#endif
struct WindowProcProxy;
class WIN32Window : public PlatformWindow
{
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);
friend class WindowProcProxy;
@@ -67,8 +82,6 @@ public:
Size getDisplaySize();
std::string getClipboardText();
std::string getPlatformType();
HWND getWindow() { return m_window; }
HDC getDisplay() { return m_deviceContext; }
protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
@@ -79,14 +92,26 @@ private:
Rect adjustWindowRect(const Rect& rect);
std::vector<HCURSOR> m_cursors;
HDC m_deviceContext;
HWND m_window;
HINSTANCE m_instance;
HDC m_deviceContext;
HCURSOR m_cursor;
HCURSOR m_defaultCursor;
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

View File

@@ -20,17 +20,13 @@
* THE SOFTWARE.
*/
#ifndef WIN32
#include "x11window.h"
#include <framework/core/resourcemanager.h>
#include <framework/graphics/image.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)))
X11Window::X11Window()
@@ -48,10 +44,15 @@ X11Window::X11Window()
m_wmDelete = 0;
m_minimumSize = 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
m_graphicsContext = GraphicsContextPtr(new GraphicsContextEGL);
m_fbConfig = 0;
m_glxContext = 0;
#endif
m_keyMap[XK_Escape] = Fw::KeyEscape;
@@ -210,7 +211,9 @@ X11Window::X11Window()
void X11Window::init()
{
internalOpenDisplay();
m_graphicsContext->create();
internalCheckGL();
internalChooseGLVisual();
internalCreateGLContext();
internalCreateWindow();
}
@@ -240,7 +243,7 @@ void X11Window::terminate()
m_colormap = 0;
}
m_graphicsContext->destroy();
internalDestroyGLContext();
if(m_visual) {
XFree(m_visual);
@@ -328,7 +331,7 @@ void X11Window::internalCreateWindow()
if(!internalSetupWindowInput())
g_logger.warning("Input of special keys may be messed up, because window input initialization failed");
m_graphicsContext->restore();
internalConnectGLContext();
}
bool X11Window::internalSetupWindowInput()
@@ -355,6 +358,169 @@ bool X11Window::internalSetupWindowInput()
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)
{
m_position = pos;
@@ -674,7 +840,11 @@ void X11Window::poll()
void X11Window::swapBuffers()
{
m_graphicsContext->swapBuffers();
#ifdef OPENGL_ES
eglSwapBuffers(m_eglDisplay, m_eglSurface);
#else
glXSwapBuffers(m_display, m_window);
#endif
}
void X11Window::showMouse()
@@ -798,7 +968,20 @@ void X11Window::setFullscreen(bool fullscreen)
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)
@@ -886,5 +1069,11 @@ std::string X11Window::getClipboardText()
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/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
{
@@ -38,6 +41,15 @@ class X11Window : public PlatformWindow
void internalCreateWindow();
bool internalSetupWindowInput();
void internalCheckGL();
void internalChooseGLVisual();
void internalCreateGLContext();
void internalDestroyGLContext();
void internalConnectGLContext();
void *getExtensionProcAddress(const char *ext);
bool isExtensionSupported(const char *ext);
public:
X11Window();
@@ -63,16 +75,10 @@ public:
void setVerticalSync(bool enable);
void setIcon(const std::string& file);
void setClipboardText(const std::string& text);
void setVisual(XVisualInfo *visual) { m_visual = visual; }
void setRootWindow(const Window& window) { m_rootWindow = window; }
Size getDisplaySize();
std::string getClipboardText();
std::string getPlatformType();
Window getWindow() { return m_window; }
Display *getDisplay() { return m_display; }
int getScreen() { return m_screen; }
XVisualInfo *getVisual() { return m_visual; }
protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
@@ -91,9 +97,17 @@ private:
int m_screen;
Atom m_wmDelete;
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

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