Merge branch 'master' into pr-downloader

This commit is contained in:
oy 2018-12-30 17:48:36 +01:00 committed by GitHub
commit a86c661651
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
280 changed files with 17299 additions and 9099 deletions

19
.circleci/config.yml Normal file
View file

@ -0,0 +1,19 @@
version: 2
jobs:
build:
docker:
- image: buildpack-deps:stretch
steps:
- checkout
- run:
name: Build bam
command: |
apt-get update -y
apt-get install libsdl2-dev libfreetype6-dev -y
git clone https://github.com/matricks/bam.git ~/bam
cd ~/bam/
git reset --hard f012dd9a3e38295b8a45af5a101d29573381f169
./make_unix.sh
- run:
name: Build teeworlds
command: ~/bam/bam conf=release all

3
.gitignore vendored
View file

@ -2,6 +2,8 @@
/.bam
/config.lua
/build
/other/*/lib
/other/*/include
__pycache__/
*.pyc
*.pyo
@ -11,3 +13,4 @@ scripts/work/
/autoexec.cfg
other/freetype
other/sdl
_test.exe

2
.gitmodules vendored
View file

@ -1,6 +1,8 @@
[submodule "datasrc/languages"]
path = datasrc/languages
url = git://github.com/teeworlds/teeworlds-translation.git
branch = master
[submodule "datasrc/maps"]
path = datasrc/maps
url = git://github.com/teeworlds/teeworlds-maps.git
branch = master

77
bam.lua
View file

@ -1,4 +1,4 @@
CheckVersion("0.4")
CheckVersion("0.5")
Import("configure.lua")
Import("other/sdl/sdl.lua")
@ -8,7 +8,7 @@ Import("other/freetype/freetype.lua")
config = NewConfig()
config:Add(OptCCompiler("compiler"))
config:Add(OptTestCompileC("stackprotector", "int main(){return 0;}", "-fstack-protector -fstack-protector-all"))
config:Add(OptTestCompileC("minmacosxsdk", "int main(){return 0;}", "-mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk"))
config:Add(OptTestCompileC("minmacosxsdk", "int main(){return 0;}", "-mmacosx-version-min=10.7 -isysroot /Developer/SDKs/MacOSX10.7.sdk"))
config:Add(OptLibrary("zlib", "zlib.h", false))
config:Add(SDL.OptFind("sdl", true))
config:Add(FreeType.OptFind("freetype", true))
@ -76,7 +76,7 @@ function ContentCompile(action, output)
end
function GenerateCommonSettings(settings)
function GenerateCommonSettings(settings, conf, arch, compiler)
if compiler == "gcc" or compiler == "clang" then
settings.cc.flags:Add("-Wall", "-fno-exceptions")
end
@ -93,15 +93,16 @@ function GenerateCommonSettings(settings)
zlib = Compile(settings, Collect("src/engine/external/zlib/*.c"))
end
local md5 = Compile(settings, Collect("src/engine/external/md5/*.c"))
local wavpack = Compile(settings, Collect("src/engine/external/wavpack/*.c"))
local png = Compile(settings, Collect("src/engine/external/pnglite/*.c"))
local json = Compile(settings, Collect("src/engine/external/json-parser/*.c"))
-- globally available libs
libs = {zlib=zlib, wavpack=wavpack, png=png, json=json}
libs = {zlib=zlib, wavpack=wavpack, png=png, md5=md5, json=json}
end
function GenerateMacOSXSettings(settings, conf, arch)
function GenerateMacOSXSettings(settings, conf, arch, compiler)
if arch == "x86" then
settings.cc.flags:Add("-arch i386")
settings.link.flags:Add("-arch i386")
@ -119,17 +120,23 @@ function GenerateMacOSXSettings(settings, conf, arch)
os.exit(1)
end
settings.cc.flags:Add("-mmacosx-version-min=10.5")
settings.link.flags:Add("-mmacosx-version-min=10.5")
-- c++ stdlib needed
settings.cc.flags:Add("--stdlib=libc++")
settings.link.flags:Add("--stdlib=libc++")
-- this also needs the macOS min SDK version to be at least 10.7
settings.cc.flags:Add("-mmacosx-version-min=10.7")
settings.link.flags:Add("-mmacosx-version-min=10.7")
if config.minmacosxsdk.value == 1 then
settings.cc.flags:Add("-isysroot /Developer/SDKs/MacOSX10.5.sdk")
settings.link.flags:Add("-isysroot /Developer/SDKs/MacOSX10.5.sdk")
settings.cc.flags:Add("-isysroot /Developer/SDKs/MacOSX10.7.sdk")
settings.link.flags:Add("-isysroot /Developer/SDKs/MacOSX10.7.sdk")
end
settings.link.frameworks:Add("Carbon")
settings.link.frameworks:Add("AppKit")
GenerateCommonSettings(settings, conf, arch)
GenerateCommonSettings(settings, conf, arch, compiler)
-- Build server launcher before adding game stuff
local serverlaunch = Link(settings, "serverlaunch", Compile(settings, "src/osxlaunch/server.m"))
@ -160,20 +167,23 @@ function GenerateMacOSXSettings(settings, conf, arch)
BuildContent(settings)
end
function GenerateLinuxSettings(settings, conf, arch)
function GenerateLinuxSettings(settings, conf, arch, compiler)
if arch == "x86" then
settings.cc.flags:Add("-msse2") -- for the _mm_pause call
settings.cc.flags:Add("-m32")
settings.link.flags:Add("-m32")
elseif arch == "x86_64" then
settings.cc.flags:Add("-m64")
settings.link.flags:Add("-m64")
elseif arch == "armv7l" then
-- arm 32 bit
else
print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64")
os.exit(1)
end
settings.link.libs:Add("pthread")
GenerateCommonSettings(settings, conf, arch)
GenerateCommonSettings(settings, conf, arch, compiler)
-- Master server, version server and tools
BuildEngineCommon(settings)
@ -197,29 +207,23 @@ function GenerateLinuxSettings(settings, conf, arch)
BuildContent(settings)
end
function GenerateSolarisSettings(settings, conf, arch)
function GenerateSolarisSettings(settings, conf, arch, compiler)
settings.link.libs:Add("socket")
settings.link.libs:Add("nsl")
GenerateLinuxSettings(settings, conf, arch)
GenerateLinuxSettings(settings, conf, arch, compiler)
end
function GenerateWindowsSettings(settings, conf, target_arch, compiler)
if compiler == "cl" then
if (target_arch == "x86" and arch ~= "ia32") or
(target_arch == "x86_64" and arch ~= "x64" and arch ~= "x86_64") then
(target_arch == "x86_64" and arch ~= "ia64" and arch ~= "amd64") then
print("Cross compiling is unsupported on Windows.")
os.exit(1)
end
settings.cc.flags:Add("/wd4244")
settings.cc.flags:Add("/wd4244", "/wd4577")
elseif compiler == "gcc" or config.compiler.driver == "clang" then
if target_arch == "x86" then
settings.cc.flags:Add("-m32")
settings.link.flags:Add("-m32")
elseif target_arch == "x86_64" then
settings.cc.flags:Add("-m64")
settings.link.flags:Add("-m64")
else
if target_arch ~= "x86" and target_arch ~= "x86_64" then
print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64")
os.exit(1)
end
@ -237,8 +241,9 @@ function GenerateWindowsSettings(settings, conf, target_arch, compiler)
settings.link.libs:Add("ws2_32")
settings.link.libs:Add("ole32")
settings.link.libs:Add("shell32")
settings.link.libs:Add("advapi32")
GenerateCommonSettings(settings, conf, target_arch)
GenerateCommonSettings(settings, conf, target_arch, compiler)
-- Master server, version server and tools
BuildEngineCommon(settings)
@ -271,7 +276,7 @@ function SharedCommonFiles()
if not shared_common_files then
local network_source = ContentCompile("network_source", "generated/protocol.cpp")
local network_header = ContentCompile("network_header", "generated/protocol.h")
AddDependency(network_source, network_header)
AddDependency(network_source, network_header, "src/engine/shared/protocol.h")
local nethash = CHash("generated/nethash.cpp", "src/engine/shared/protocol.h", "src/game/tuning.h", "src/game/gamecore.cpp", network_header)
shared_common_files = {network_source, nethash}
@ -334,7 +339,7 @@ function BuildClient(settings, family, platform)
local game_client = Compile(settings, CollectRecursive("src/game/client/*.cpp"), SharedClientFiles())
local game_editor = Compile(settings, Collect("src/game/editor/*.cpp"))
Link(settings, "teeworlds", libs["zlib"], libs["wavpack"], libs["png"], libs["json"], client, game_client, game_editor)
Link(settings, "teeworlds", libs["zlib"], libs["md5"], libs["wavpack"], libs["png"], libs["json"], client, game_client, game_editor)
end
function BuildServer(settings, family, platform)
@ -342,24 +347,24 @@ function BuildServer(settings, family, platform)
local game_server = Compile(settings, CollectRecursive("src/game/server/*.cpp"), SharedServerFiles())
return Link(settings, "teeworlds_srv", libs["zlib"], server, game_server)
return Link(settings, "teeworlds_srv", libs["zlib"], libs["md5"], server, game_server)
end
function BuildTools(settings)
local tools = {}
for i,v in ipairs(Collect("src/tools/*.cpp", "src/tools/*.c")) do
local toolname = PathFilename(PathBase(v))
tools[i] = Link(settings, toolname, Compile(settings, v), libs["zlib"], libs["wavpack"], libs["png"])
tools[i] = Link(settings, toolname, Compile(settings, v), libs["zlib"], libs["md5"], libs["wavpack"], libs["png"])
end
PseudoTarget(settings.link.Output(settings, "pseudo_tools") .. settings.link.extension, tools)
end
function BuildMasterserver(settings)
return Link(settings, "mastersrv", Compile(settings, Collect("src/mastersrv/*.cpp")), libs["zlib"])
return Link(settings, "mastersrv", Compile(settings, Collect("src/mastersrv/*.cpp")), libs["zlib"], libs["md5"])
end
function BuildVersionserver(settings)
return Link(settings, "versionsrv", Compile(settings, Collect("src/versionsrv/*.cpp")), libs["zlib"])
return Link(settings, "versionsrv", Compile(settings, Collect("src/versionsrv/*.cpp")), libs["zlib"], libs["md5"])
end
function BuildContent(settings)
@ -380,6 +385,8 @@ function GenerateSettings(conf, arch, builddir, compiler)
elseif compiler == "cl" then
SetDriversCL(settings)
else
-- apply compiler settings
config.compiler:Apply(settings)
compiler = config.compiler.driver
end
@ -413,11 +420,11 @@ function GenerateSettings(conf, arch, builddir, compiler)
GenerateWindowsSettings(settings, conf, arch, compiler)
elseif family == "unix" then
if platform == "macosx" then
GenerateMacOSXSettings(settings, conf, arch)
elseif platform == "linux" then
GenerateLinuxSettings(settings, conf, arch)
GenerateMacOSXSettings(settings, conf, arch, compiler)
elseif platform == "solaris" then
GenerateSolarisSettings(settings, conf, arch)
GenerateSolarisSettings(settings, conf, arch, compiler)
else -- Linux, BSD
GenerateLinuxSettings(settings, conf, arch, compiler)
end
end
@ -452,7 +459,7 @@ if ScriptArgs['arch'] then
else
if arch == "ia32" then
archs = {"x86"}
elseif arch == "x64" or arch == "amd64" then
elseif arch == "ia64" or arch == "amd64" then
archs = {"x86_64"}
else
archs = {arch}

View file

@ -72,13 +72,13 @@ function NewConfig(on_configured_callback)
end
config.Load = function(self, filename)
local options_func = loadfile(filename)
local options_table = {}
local options_func = loadfile(filename, nil, options_table)
if not options_func then
print("auto configuration")
self:Config(filename)
options_func = loadfile(filename)
options_func = loadfile(filename, nil, options_table)
end
if options_func then
@ -86,7 +86,6 @@ function NewConfig(on_configured_callback)
for k,v in pairs(self.options) do
options_table[v.name] = {}
end
setfenv(options_func, options_table)
-- this is to make sure that we get nice error messages when
-- someone sets an option that isn't valid.
@ -360,10 +359,10 @@ function OptCCompiler(name, default_driver, default_c, default_cxx, desc)
-- no need todo anything if we have a driver
-- TODO: test if we can find the compiler
else
if ExecuteSilent("cl") == 0 then
option.driver = "cl"
elseif ExecuteSilent("g++ -v") == 0 then
if ExecuteSilent("g++ -v") == 0 then
option.driver = "gcc"
elseif ExecuteSilent("cl") == 0 then
option.driver = "cl"
else
error("no c/c++ compiler found")
end

View file

@ -1,4 +1,5 @@
import os, imp, sys
import os
import sys
from datatypes import *
import content
import network
@ -127,11 +128,11 @@ if gen_network_header:
class CNetObjHandler
{
const char *m_pMsgFailedOn;
const char *m_pObjCorrectedOn;
char m_aMsgData[1024];
int m_NumObjCorrections;
int ClampInt(const char *pErrorMsg, int Value, int Min, int Max);
int ClampFlag(const char *pErrorMsg, int Value, int Mask);
const char *m_pObjFailedOn;
int m_NumObjFailures;
bool CheckInt(const char *pErrorMsg, int Value, int Min, int Max);
bool CheckFlag(const char *pErrorMsg, int Value, int Mask);
static const char *ms_apObjNames[];
static int ms_aObjSizes[];
@ -143,8 +144,8 @@ public:
int ValidateObj(int Type, const void *pData, int Size);
const char *GetObjName(int Type) const;
int GetObjSize(int Type) const;
int NumObjCorrections() const;
const char *CorrectedObjOn() const;
const char *FailedObjOn() const;
int NumObjFailures() const;
const char *GetMsgName(int Type) const;
void *SecureUnpackMsg(int Type, CUnpacker *pUnpacker);
@ -167,34 +168,32 @@ if gen_network_source:
lines += ['CNetObjHandler::CNetObjHandler()']
lines += ['{']
lines += ['\tm_pMsgFailedOn = "";']
lines += ['\tm_pObjCorrectedOn = "";']
lines += ['\tm_NumObjCorrections = 0;']
lines += ['\tm_pObjFailedOn = "";']
lines += ['\tm_NumObjFailures = 0;']
lines += ['}']
lines += ['']
lines += ['int CNetObjHandler::NumObjCorrections() const { return m_NumObjCorrections; }']
lines += ['const char *CNetObjHandler::CorrectedObjOn() const { return m_pObjCorrectedOn; }']
lines += ['const char *CNetObjHandler::FailedObjOn() const { return m_pObjFailedOn; }']
lines += ['int CNetObjHandler::NumObjFailures() const { return m_NumObjFailures; }']
lines += ['const char *CNetObjHandler::FailedMsgOn() const { return m_pMsgFailedOn; }']
lines += ['']
lines += ['']
lines += ['']
lines += ['']
lines += ['']
lines += ['static const int max_int = 0x7fffffff;']
lines += ['']
lines += ['int CNetObjHandler::ClampInt(const char *pErrorMsg, int Value, int Min, int Max)']
lines += ['bool CNetObjHandler::CheckInt(const char *pErrorMsg, int Value, int Min, int Max)']
lines += ['{']
lines += ['\tif(Value < Min) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Min; }']
lines += ['\tif(Value > Max) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Max; }']
lines += ['\treturn Value;']
lines += ['\tif(Value < Min || Value > Max) { m_pObjFailedOn = pErrorMsg; m_NumObjFailures++; return false; }']
lines += ['\treturn true;']
lines += ['}']
lines += ['']
lines += ['int CNetObjHandler::ClampFlag(const char *pErrorMsg, int Value, int Mask)']
lines += ['bool CNetObjHandler::CheckFlag(const char *pErrorMsg, int Value, int Mask)']
lines += ['{']
lines += ['\tif((Value&Mask) != Value) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return (Value&Mask); }']
lines += ['\treturn Value;']
lines += ['\tif((Value&Mask) != Value) { m_pObjFailedOn = pErrorMsg; m_NumObjFailures++; return false; }']
lines += ['\treturn true;']
lines += ['}']
lines += ['']
@ -300,6 +299,7 @@ if gen_network_source:
lines += ['void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)']
lines += ['{']
lines += ['\tm_pMsgFailedOn = 0;']
lines += ['\tm_pObjFailedOn = 0;']
lines += ['\tswitch(Type)']
lines += ['\t{']
@ -317,9 +317,15 @@ if gen_network_source:
lines += ['\tif(pUnpacker->Error())']
lines += ['\t\tm_pMsgFailedOn = "(unpack error)";']
lines += ['\t']
lines += ['\tif(m_pMsgFailedOn)']
lines += ['\tif(m_pMsgFailedOn || m_pObjFailedOn) {']
lines += ['\t\tif(!m_pMsgFailedOn)']
lines += ['\t\t\tm_pMsgFailedOn = "";']
lines += ['\t\tif(!m_pObjFailedOn)']
lines += ['\t\t\tm_pObjFailedOn = "";']
lines += ['\t\treturn 0;']
lines += ['\t}']
lines += ['\tm_pMsgFailedOn = "";']
lines += ['\tm_pObjFailedOn = "";']
lines += ['\treturn m_aMsgData;']
lines += ['};']
lines += ['']

View file

@ -17,10 +17,11 @@ class SoundSet(Struct):
self.sounds.Add(Sound(name))
class Image(Struct):
def __init__(self, name="", filename=""):
def __init__(self, name="", filename="", linear_mapping=0):
Struct.__init__(self, "CDataImage")
self.name = String(name)
self.filename = String(filename)
self.flag = Int(linear_mapping)
self.id = TextureHandle()
class SpriteSet(Struct):
@ -233,15 +234,20 @@ container.sounds.Add(SoundSet("menu", ["audio/music_menu.wv"]))
image_null = Image("null", "")
image_particles = Image("particles", "particles.png")
image_game = Image("game", "game.png")
image_browseicons = Image("browseicons", "ui/icons/browse.png")
image_browseicons = Image("browseicons", "ui/icons/browse.png", 1)
image_emoticons = Image("emoticons", "emoticons.png")
image_demobuttons = Image("demobuttons", "ui/demo_buttons.png")
image_fileicons = Image("fileicons", "ui/file_icons.png")
image_guibuttons = Image("guibuttons", "ui/gui_buttons.png")
image_guiicons = Image("guiicons", "ui/gui_icons.png")
image_menuicons = Image("menuicons", "ui/icons/menu.png")
image_toolicons = Image("toolicons", "ui/icons/tools.png")
image_infoicons = Image("infoicons", "ui/icons/info.png")
image_demobuttons = Image("demobuttons", "ui/demo_buttons.png", 1)
image_fileicons = Image("fileicons", "ui/file_icons.png", 1)
image_guibuttons = Image("guibuttons", "ui/gui_buttons.png", 1)
image_guiicons = Image("guiicons", "ui/gui_icons.png", 1)
image_menuicons = Image("menuicons", "ui/icons/menu.png", 1)
image_toolicons = Image("toolicons", "ui/icons/tools.png", 1)
image_arrowicons = Image("arrowicons", "ui/icons/arrows.png", 1)
image_friendicons = Image("friendicons", "ui/icons/friend.png", 1)
image_infoicons = Image("infoicons", "ui/icons/info.png", 1)
image_levelicons = Image("levelicons", "ui/icons/level.png", 1)
image_sidebaricons = Image("sidebaricons", "ui/icons/sidebar.png", 1)
image_chatwhisper = Image("chatwhisper", "ui/icons/chat_whisper.png", 1)
container.images.Add(image_null)
container.images.Add(image_game)
@ -260,7 +266,12 @@ container.images.Add(image_guiicons)
container.images.Add(Image("no_skinpart", "ui/no_skinpart.png"))
container.images.Add(image_menuicons)
container.images.Add(image_toolicons)
container.images.Add(image_arrowicons)
container.images.Add(image_friendicons)
container.images.Add(image_infoicons)
container.images.Add(image_levelicons)
container.images.Add(image_sidebaricons)
container.images.Add(image_chatwhisper)
container.pickups.Add(Pickup("health"))
container.pickups.Add(Pickup("armor"))
@ -277,6 +288,7 @@ set_tee_decoration = SpriteSet("tee_decoration", image_null, 2, 1)
set_tee_hands = SpriteSet("tee_hands", image_null, 2, 1)
set_tee_feet = SpriteSet("tee_feet", image_null, 2, 1)
set_tee_eyes = SpriteSet("tee_eyes", image_null, 2, 4)
set_tee_hats = SpriteSet("tee_hats", image_null, 1, 4)
set_browseicons = SpriteSet("browseicons", image_browseicons, 4, 2)
set_emoticons = SpriteSet("emoticons", image_emoticons, 4, 4)
set_demobuttons = SpriteSet("demobuttons", image_demobuttons, 5, 1)
@ -285,7 +297,11 @@ set_guibuttons = SpriteSet("guibuttons", image_guibuttons, 12, 4)
set_guiicons = SpriteSet("guiicons", image_guiicons, 8, 2)
set_menuicons = SpriteSet("menuicons", image_menuicons, 2, 2)
set_toolicons = SpriteSet("toolicons", image_toolicons, 4, 2)
set_arrowicons = SpriteSet("arrowicons", image_arrowicons, 4, 3)
set_friendicons = SpriteSet("friendicons", image_friendicons, 2, 2)
set_infoicons = SpriteSet("infoicons", image_infoicons, 1, 2)
set_levelicons = SpriteSet("levelicons", image_levelicons, 4, 4)
set_sidebaricons = SpriteSet("sidebaricons", image_sidebaricons, 4, 2)
container.spritesets.Add(set_particles)
container.spritesets.Add(set_game)
@ -295,6 +311,7 @@ container.spritesets.Add(set_tee_decoration)
container.spritesets.Add(set_tee_hands)
container.spritesets.Add(set_tee_feet)
container.spritesets.Add(set_tee_eyes)
container.spritesets.Add(set_tee_hats)
container.spritesets.Add(set_browseicons)
container.spritesets.Add(set_emoticons)
container.spritesets.Add(set_demobuttons)
@ -303,7 +320,12 @@ container.spritesets.Add(set_guibuttons)
container.spritesets.Add(set_guiicons)
container.spritesets.Add(set_menuicons)
container.spritesets.Add(set_toolicons)
container.spritesets.Add(set_arrowicons)
container.spritesets.Add(set_friendicons)
container.spritesets.Add(set_infoicons)
container.spritesets.Add(set_levelicons)
container.spritesets.Add(set_sidebaricons)
container.sprites.Add(Sprite("part_slice", set_particles, 0,0,1,1))
container.sprites.Add(Sprite("part_ball", set_particles, 1,0,1,1))
@ -383,6 +405,11 @@ container.sprites.Add(Sprite("pickup_ninja", set_game, 2,10,8,2))
container.sprites.Add(Sprite("flag_blue", set_game, 12,8,4,8))
container.sprites.Add(Sprite("flag_red", set_game, 16,8,4,8))
container.sprites.Add(Sprite("ninja_bar_full_left", set_game, 21,4,1,2))
container.sprites.Add(Sprite("ninja_bar_full", set_game, 22,4,1,2))
container.sprites.Add(Sprite("ninja_bar_empty", set_game, 23,4,1,2))
container.sprites.Add(Sprite("ninja_bar_empty_right", set_game, 24,4,1,2))
container.sprites.Add(Sprite("tee_body_outline", set_tee_body, 0,0,1,1))
container.sprites.Add(Sprite("tee_body", set_tee_body, 1,0,1,1))
container.sprites.Add(Sprite("tee_body_shadow", set_tee_body, 0,1,1,1))
@ -405,6 +432,11 @@ container.sprites.Add(Sprite("tee_eyes_pain", set_tee_eyes, 0,1,1,1))
container.sprites.Add(Sprite("tee_eyes_happy", set_tee_eyes, 1,1,1,1))
container.sprites.Add(Sprite("tee_eyes_surprise", set_tee_eyes, 0,2,1,1))
container.sprites.Add(Sprite("tee_hats_top1", set_tee_hats, 0,0,1,1))
container.sprites.Add(Sprite("tee_hats_top2", set_tee_hats, 0,1,1,1))
container.sprites.Add(Sprite("tee_hats_side1", set_tee_hats, 0,2,1,1))
container.sprites.Add(Sprite("tee_hats_side2", set_tee_hats, 0,3,1,1))
container.sprites.Add(Sprite("oop", set_emoticons, 0, 0, 1, 1))
container.sprites.Add(Sprite("exclamation", set_emoticons, 1, 0, 1, 1))
container.sprites.Add(Sprite("hearts", set_emoticons, 2, 0, 1, 1))
@ -468,9 +500,45 @@ container.sprites.Add(Sprite("tool_edit_b", set_toolicons, 2,1,1,1))
container.sprites.Add(Sprite("tool_x_a", set_toolicons, 3,0,1,1))
container.sprites.Add(Sprite("tool_x_b", set_toolicons, 3,1,1,1))
container.sprites.Add(Sprite("arrow_left_a", set_arrowicons, 0,0,1,1))
container.sprites.Add(Sprite("arrow_left_b", set_arrowicons, 0,1,1,1))
container.sprites.Add(Sprite("arrow_left_c", set_arrowicons, 0,2,1,1))
container.sprites.Add(Sprite("arrow_up_a", set_arrowicons, 1,0,1,1))
container.sprites.Add(Sprite("arrow_up_b", set_arrowicons, 1,1,1,1))
container.sprites.Add(Sprite("arrow_up_c", set_arrowicons, 1,2,1,1))
container.sprites.Add(Sprite("arrow_right_a", set_arrowicons, 2,0,1,1))
container.sprites.Add(Sprite("arrow_right_b", set_arrowicons, 2,1,1,1))
container.sprites.Add(Sprite("arrow_right_c", set_arrowicons, 2,2,1,1))
container.sprites.Add(Sprite("arrow_down_a", set_arrowicons, 3,0,1,1))
container.sprites.Add(Sprite("arrow_down_b", set_arrowicons, 3,1,1,1))
container.sprites.Add(Sprite("arrow_down_c", set_arrowicons, 3,2,1,1))
container.sprites.Add(Sprite("friend_plus_a", set_friendicons, 0,0,1,1))
container.sprites.Add(Sprite("friend_plus_b", set_friendicons, 0,1,1,1))
container.sprites.Add(Sprite("friend_x_a", set_friendicons, 1,0,1,1))
container.sprites.Add(Sprite("friend_x_b", set_friendicons, 1,1,1,1))
container.sprites.Add(Sprite("info_a", set_infoicons, 0,0,1,1))
container.sprites.Add(Sprite("info_b", set_infoicons, 0,1,1,1))
container.sprites.Add(Sprite("level_a_on", set_levelicons, 0,0,1,1))
container.sprites.Add(Sprite("level_a_a", set_levelicons, 0,1,1,1))
container.sprites.Add(Sprite("level_a_b", set_levelicons, 0,2,1,1))
container.sprites.Add(Sprite("level_b_on", set_levelicons, 1,0,1,1))
container.sprites.Add(Sprite("level_b_a", set_levelicons, 1,1,1,1))
container.sprites.Add(Sprite("level_b_b", set_levelicons, 1,2,1,1))
container.sprites.Add(Sprite("level_c_on", set_levelicons, 2,0,1,1))
container.sprites.Add(Sprite("level_c_a", set_levelicons, 2,1,1,1))
container.sprites.Add(Sprite("level_c_b", set_levelicons, 2,2,1,1))
container.sprites.Add(Sprite("sidebar_refresh_a", set_sidebaricons, 0,0,1,1))
container.sprites.Add(Sprite("sidebar_refresh_b", set_sidebaricons, 0,1,1,1))
container.sprites.Add(Sprite("sidebar_friend_a", set_sidebaricons, 1,0,1,1))
container.sprites.Add(Sprite("sidebar_friend_b", set_sidebaricons, 1,1,1,1))
container.sprites.Add(Sprite("sidebar_filter_a", set_sidebaricons, 2,0,1,1))
container.sprites.Add(Sprite("sidebar_filter_b", set_sidebaricons, 2,1,1,1))
container.sprites.Add(Sprite("sidebar_info_a", set_sidebaricons, 3,0,1,1))
container.sprites.Add(Sprite("sidebar_info_b", set_sidebaricons, 3,1,1,1))
anim = Animation("base")
anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0))
@ -543,7 +611,7 @@ weapon.damage.Set(1)
weapon.ammoregentime.Set(500)
weapon.visual_size.Set(64)
weapon.offsetx.Set(32)
weapon.offsety.Set(4)
weapon.offsety.Set(-4)
weapon.muzzleoffsetx.Set(50)
weapon.muzzleoffsety.Set(6)
container.weapons.gun.base.Set(weapon)

BIN
datasrc/countryflags/PS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -20,6 +20,26 @@
"id": "XWA",
"code": 904
},
{
"id": "XBZ",
"code": 950,
"blocked": true
},
{
"id": "XCA",
"code": 951,
"blocked": true
},
{
"id": "XES",
"code": 952,
"blocked": true
},
{
"id": "XGA",
"code": 953,
"blocked": true
},
{
"id": "default",
"code": -1
@ -738,6 +758,10 @@
"id": "PR",
"code": 630
},
{
"id": "PS",
"code": 275
},
{
"id": "PT",
"code": 620

View file

@ -147,7 +147,7 @@ class Float(BaseType):
def Set(self, value):
self.value = value
def EmitDefinition(self, name):
return ["%f"%self.value]
return ["%ff"%self.value]
#return ["%d /* %s */"%(self.value, self._target_name)]
class String(BaseType):
@ -328,9 +328,9 @@ class NetIntRange(NetIntAny):
self.min = str(min)
self.max = str(max)
def emit_validate(self):
return ["ClampInt(\"%s\", pObj->%s, %s, %s);"%(self.name,self.name, self.min, self.max)]
return ["if(!CheckInt(\"%s\", pObj->%s, %s, %s)) return -1;"%(self.name, self.name, self.min, self.max)]
def emit_unpack_check(self):
return ["if(pMsg->%s < %s || pMsg->%s > %s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.min, self.name, self.max, self.name)]
return ["if(!CheckInt(\"%s\", pMsg->%s, %s, %s)) break;"%(self.name, self.name, self.min, self.max)]
class NetEnum(NetIntRange):
def __init__(self, name, enum):
@ -346,9 +346,9 @@ class NetFlag(NetIntAny):
else:
self.mask = "0"
def emit_validate(self):
return ["ClampFlag(\"%s\", pObj->%s, %s);"%(self.name, self.name, self.mask)]
return ["if(!CheckFlag(\"%s\", pObj->%s, %s)) return -1;"%(self.name, self.name, self.mask)]
def emit_unpack_check(self):
return ["if((pMsg->%s & (%s)) != pMsg->%s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.mask, self.name, self.name)]
return ["if(!CheckFlag(\"%s\", pMsg->%s, %s)) break;"%(self.name, self.name, self.mask)]
class NetBool(NetIntRange):
def __init__(self, name):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 137 KiB

@ -1 +1 @@
Subproject commit 68c3ccfe095d88028bfe1e2f27f44983a244c7d7
Subproject commit d5143007d8492481b687d4adab04b1968107196b

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 B

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

@ -1 +1 @@
Subproject commit 7673ace6ac831f3496870fe3c4c79e8423307c0d
Subproject commit 7fefdb4c643f4e623f179460b8e68cd51f4d5e9d

View file

@ -3,9 +3,10 @@ from datatypes import *
Pickups = Enum("PICKUP", ["HEALTH", "ARMOR", "GRENADE", "SHOTGUN", "LASER", "NINJA"])
Emotes = Enum("EMOTE", ["NORMAL", "PAIN", "HAPPY", "SURPRISE", "ANGRY", "BLINK"])
Emoticons = Enum("EMOTICON", ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"])
Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"])
Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"]) # todo: add RUN_OP, RUN_KICK, RUN_SPEC; rem UNKNOWN
ChatModes = Enum("CHAT", ["NONE", "ALL", "TEAM", "WHISPER"])
PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING"])
PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING", "BOT"])
GameFlags = Flags("GAMEFLAG", ["TEAMS", "FLAGS", "SURVIVAL"])
GameStateFlags = Flags("GAMESTATEFLAG", ["WARMUP", "SUDDENDEATH", "ROUNDOVER", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"])
CoreEventFlags = Flags("COREEVENTFLAG", ["GROUND_JUMP", "AIR_JUMP", "HOOK_ATTACH_PLAYER", "HOOK_ATTACH_GROUND", "HOOK_HIT_NOHOOK"])
@ -37,7 +38,11 @@ enum
FLAG_ATSTAND,
FLAG_TAKEN,
SPEC_FREEVIEW=-1,
SPEC_FREEVIEW=0,
SPEC_PLAYER,
SPEC_FLAGRED,
SPEC_FLAGBLUE,
NUM_SPECMODES,
};
'''
@ -51,6 +56,7 @@ Enums = [
Emotes,
Emoticons,
Votes,
ChatModes,
GameMsgIDs,
]
@ -147,6 +153,8 @@ Objects = [
NetIntAny("m_HookX"),
NetIntAny("m_HookY"),
NetIntAny("m_HookDx"),
NetIntAny("m_HookDy"),
]),
NetObject("Character:CharacterCore", [
@ -166,7 +174,8 @@ Objects = [
]),
NetObject("SpectatorInfo", [
NetIntRange("m_SpectatorID", 'SPEC_FREEVIEW', 'MAX_CLIENTS-1'),
NetIntRange("m_SpecMode", 0, 'NUM_SPECMODES-1'),
NetIntRange("m_SpectatorID", -1, 'MAX_CLIENTS-1'),
NetIntAny("m_X"),
NetIntAny("m_Y"),
]),
@ -199,7 +208,7 @@ Objects = [
NetObject("De_TuneParams", [
# todo: should be done differently
NetArray(NetIntAny("m_aTuneParams"), 33),
NetArray(NetIntAny("m_aTuneParams"), 32),
]),
## Events
@ -222,8 +231,12 @@ Objects = [
NetIntRange("m_SoundID", 0, 'NUM_SOUNDS-1'),
]),
NetEvent("DamageInd:Common", [
NetEvent("Damage:Common", [ # Unused yet
NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'),
NetIntAny("m_Angle"),
NetIntRange("m_HealthAmount", 0, 9),
NetIntRange("m_ArmorAmount", 0, 9),
NetBool("m_Self"),
]),
]
@ -234,9 +247,14 @@ Messages = [
NetString("m_pMessage"),
]),
NetMessage("Sv_Broadcast", [
NetString("m_pMessage"),
]),
NetMessage("Sv_Chat", [
NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'),
NetIntRange("m_Mode", 0, 'NUM_CHATS-1'),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetIntRange("m_TargetID", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pMessage"),
]),
@ -313,6 +331,7 @@ Messages = [
NetArray(NetStringStrict("m_apSkinPartNames"), 6),
NetArray(NetBool("m_aUseCustomColors"), 6),
NetArray(NetIntAny("m_aSkinPartColors"), 6),
NetBool("m_Silent"),
]),
NetMessage("Sv_GameInfo", [
@ -328,6 +347,7 @@ Messages = [
NetMessage("Sv_ClientDrop", [
NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'),
NetStringStrict("m_pReason"),
NetBool("m_Silent"),
]),
NetMessage("Sv_GameMsg", []),
@ -335,17 +355,20 @@ Messages = [
## Demo messages
NetMessage("De_ClientEnter", [
NetStringStrict("m_pName"),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'),
]),
NetMessage("De_ClientLeave", [
NetStringStrict("m_pName"),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pReason"),
]),
### Client messages
NetMessage("Cl_Say", [
NetBool("m_Team"),
NetIntRange("m_Mode", 0, 'NUM_CHATS-1'),
NetIntRange("m_Target", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pMessage"),
]),
@ -354,7 +377,8 @@ Messages = [
]),
NetMessage("Cl_SetSpectatorMode", [
NetIntRange("m_SpectatorID", 'SPEC_FREEVIEW', 'MAX_CLIENTS-1'),
NetIntRange("m_SpecMode", 0, 'NUM_SPECMODES-1'),
NetIntRange("m_SpectatorID", -1, 'MAX_CLIENTS-1'),
]),
NetMessage("Cl_StartInfo", [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -11,8 +11,8 @@
"custom_colors": "true",
"hue": 0,
"sat": 0,
"lgt": 255,
"alp": 127
"lgt": 64,
"alp": 255
},
"hands": {
"filename": "standard",

BIN
datasrc/skins/xmas_hat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
datasrc/ui/gametypes/dm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
datasrc/ui/icons/arrows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
datasrc/ui/icons/friend.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
datasrc/ui/icons/level.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

BIN
datasrc/ui/themes/none.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

View file

@ -1,4 +1,4 @@
Copyright (C) 2007-2014 Magnus Auvinen
Copyright (C) 2007-2018 Magnus Auvinen
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -18,9 +18,14 @@ freely, subject to the following restrictions:
------------------------------------------------------------------------
All content under 'data' except the font (which has its own license) is
All content under 'data' and 'datasrc' except the font (which has its own license) is
released under CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/).
Authors: android272, Chi11y (chi1), Crises, Daniel, Echchouik, Fisico,
Landil, Lappi, LordSk, maikka, matricks, Pocram, red_com,
serpis, SkizZ, somerunce, Sonix, Stephanator, teetow, Ubu,
Zatline
------------------------------------------------------------------------
IMPORTANT NOTE! The source under src/engine/external are stripped

View file

@ -4,11 +4,15 @@ FreeType = {
OptFind = function (name, required)
local check = function(option, settings)
option.value = false
option.use_pkgconfig = false
option.use_ftconfig = false
option.use_winlib = 0
option.lib_path = nil
if ExecuteSilent("freetype-config") > 0 and ExecuteSilent("freetype-config --cflags") == 0 then
if ExecuteSilent("pkg-config freetype2") == 0 then
option.value = true
option.use_pkgconfig = true
elseif ExecuteSilent("freetype-config") > 0 and ExecuteSilent("freetype-config --cflags") == 0 then
option.value = true
option.use_ftconfig = true
end
@ -23,15 +27,18 @@ FreeType = {
end
local apply = function(option, settings)
if option.use_ftconfig == true then
if option.use_pkgconfig == true then
settings.cc.flags:Add("`pkg-config --cflags freetype2`")
settings.link.flags:Add("`pkg-config --libs freetype2`")
elseif option.use_ftconfig == true then
settings.cc.flags:Add("`freetype-config --cflags`")
settings.link.flags:Add("`freetype-config --libs`")
elseif option.use_winlib > 0 then
settings.cc.includes:Add(FreeType.basepath .. "/include")
if option.use_winlib == 32 then
settings.link.libpath:Add(FreeType.basepath .. "/lib32")
settings.link.libpath:Add(FreeType.basepath .. "/lib/x86")
else
settings.link.libpath:Add(FreeType.basepath .. "/lib64")
settings.link.libpath:Add(FreeType.basepath .. "/lib/x64")
end
settings.link.libs:Add("freetype")
end
@ -39,12 +46,14 @@ FreeType = {
local save = function(option, output)
output:option(option, "value")
output:option(option, "use_pkgconfig")
output:option(option, "use_ftconfig")
output:option(option, "use_winlib")
end
local display = function(option)
if option.value == true then
if option.use_pkgconfig == true then return "using pkg-config" end
if option.use_ftconfig == true then return "using freetype-config" end
if option.use_winlib == 32 then return "using supplied win32 libraries" end
if option.use_winlib == 64 then return "using supplied win64 libraries" end

View file

@ -1 +1 @@
1.2.15
2.0.5

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<application>
<id type="desktop">teeworlds.desktop</id>
<license>Zlib and CC-BY-SA-3.0</license>
<metadata_license>CC0-1.0</metadata_license>
<summary>Online multiplayer shooter game</summary>
<description>
<p>
Teeworlds is a free online multiplayer game. Battle with up to 16 players
in a variety of game modes, including Team Deathmatch and Capture The Flag.
You can even design your own maps!
</p>
</description>
<url type="homepage">https://www.teeworlds.com/</url>
<screenshots>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_desert.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_grass.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_winter.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_jungle.png</screenshot>
</screenshots>
</application>

9
other/teeworlds.desktop Normal file
View file

@ -0,0 +1,9 @@
[Desktop Entry]
Name=Teeworlds
GenericName=Online multi-player 2D platform shooter
Type=Application
Terminal=false
Exec=teeworlds
Icon=teeworlds
Comment=Teeworlds: Jumping the Gun
Categories=Game;ArcadeGame;

View file

@ -1,4 +1,4 @@
Teeworlds
Teeworlds [![CircleCI](https://circleci.com/gh/teeworlds/teeworlds.svg?style=svg)](https://circleci.com/gh/teeworlds/teeworlds)
=========
A retro multiplayer shooter
@ -17,4 +17,8 @@ text including copyright information.
Please visit https://www.teeworlds.com/ for up-to-date information about
the game, including new versions, custom maps and much more.
Instructions to build the game can be found at
https://teeworlds.com/?page=docs&wiki=compiling_everything. In
particular, you will need SDL2 and FreeType installed.
Originally written by Magnus Auvinen.

View file

@ -52,7 +52,7 @@ def parse_source():
return l10n
def load_languagefile(filename):
return json.load(open(filename))
return json.load(open(filename), strict=False) # accept \t tabs
def write_languagefile(outputfilename, l10n_src, old_l10n_data):
outputfilename += '.po'
@ -110,7 +110,10 @@ if __name__ == '__main__':
'Content-Transfer-Encoding': '8bit',
}
for (msg, ctxt), occurrences in l10n_src.items():
po.append(polib.POEntry(msgid=msg, msgstr="", occurrences=occurrences, msgctxt=ctxt))
commenttxt = ctxt
if(commenttxt):
commenttxt = 'Context: '+commenttxt
po.append(polib.POEntry(msgid=msg, msgstr="", occurrences=occurrences, msgctxt=ctxt, comment=commenttxt))
po.save('data/languages/base.pot')
for filename in os.listdir("data/languages"):

View file

@ -1,4 +1,5 @@
import shutil, optparse, os, re, sys, zipfile
from distutils.dir_util import copy_tree
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])) + "/..")
import twlib
@ -88,6 +89,12 @@ def clean():
package = "%s-%s-%s" %(name, version, platform)
package_dir = package
source_package_dir = "build/"
if platform == 'win32' or platform == 'linux_x86':
source_package_dir += "x86/release/"
else:
source_package_dir += "x86_64/release/"
print("cleaning target")
shutil.rmtree(package_dir, True)
os.mkdir(package_dir)
@ -118,18 +125,17 @@ shutil.copy("license.txt", package_dir)
shutil.copy("storage.cfg", package_dir)
if include_data and not use_bundle:
os.mkdir(os.path.join(package_dir, "data"))
copydir("data", package_dir)
copyfiles(languages_dir, package_dir+"/data/languages")
copyfiles(maps_dir, package_dir+"/data/maps")
copy_tree(source_package_dir+"data", package_dir+"/data")
copy_tree(languages_dir, package_dir+"/data/languages")
copy_tree(maps_dir, package_dir+"/data/maps")
if platform[:3] == "win":
shutil.copy("other/config_directory.bat", package_dir)
shutil.copy("SDL.dll", package_dir)
shutil.copy("freetype.dll", package_dir)
shutil.copy(source_package_dir+"SDL2.dll", package_dir)
shutil.copy(source_package_dir+"freetype.dll", package_dir)
if include_exe and not use_bundle:
shutil.copy(name+exe_ext, package_dir)
shutil.copy(name+"_srv"+exe_ext, package_dir)
shutil.copy(source_package_dir+name+exe_ext, package_dir)
shutil.copy(source_package_dir+name+"_srv"+exe_ext, package_dir)
if include_src:
for p in ["src", "scripts", "datasrc", "other", "objs"]:
@ -140,7 +146,7 @@ if include_src:
if use_bundle:
bins = [name, name+'_srv', 'serverlaunch']
platforms = ('x86', 'x86_64', 'ppc')
platforms = ('x86_64')
for bin in bins:
to_lipo = []
for p in platforms:
@ -155,19 +161,24 @@ if use_bundle:
clientbundle_bin_dir = os.path.join(clientbundle_content_dir, "MacOS")
clientbundle_resource_dir = os.path.join(clientbundle_content_dir, "Resources")
clientbundle_framework_dir = os.path.join(clientbundle_content_dir, "Frameworks")
binary_path = clientbundle_bin_dir + "/" + name+exe_ext
freetypelib_path = clientbundle_framework_dir + "/libfreetype.6.dylib"
os.mkdir(os.path.join(package_dir, "Teeworlds.app"))
os.mkdir(clientbundle_content_dir)
os.mkdir(clientbundle_bin_dir)
os.mkdir(clientbundle_resource_dir)
os.mkdir(clientbundle_framework_dir)
os.mkdir(os.path.join(clientbundle_resource_dir, "data"))
copydir("data", clientbundle_resource_dir)
os.chdir(languages_dir)
copydir("data", "../"+clientbundle_resource_dir)
os.chdir("..")
copy_tree(source_package_dir+"data", clientbundle_resource_dir+"/data")
copy_tree(languages_dir, clientbundle_resource_dir+"/data/languages")
copy_tree(maps_dir, clientbundle_resource_dir+"/data/maps")
shutil.copy("other/icons/Teeworlds.icns", clientbundle_resource_dir)
shutil.copy(name+exe_ext, clientbundle_bin_dir)
os.system("cp -R /Library/Frameworks/SDL.framework " + clientbundle_framework_dir)
shutil.copy(source_package_dir+name+exe_ext, clientbundle_bin_dir)
os.system("install_name_tool -change /usr/local/opt/freetype/lib/libfreetype.6.dylib @executable_path/../Frameworks/libfreetype.6.dylib " + binary_path)
os.system("install_name_tool -change /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib @executable_path/../Frameworks/libSDL2-2.0.0.dylib " + binary_path)
os.system("cp /usr/local/opt/freetype/lib/libfreetype.6.dylib " + clientbundle_framework_dir)
os.system("cp /usr/local/opt/libpng/lib/libpng16.16.dylib " + clientbundle_framework_dir)
os.system("cp /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib " + clientbundle_framework_dir)
os.system("install_name_tool -change /usr/local/opt/libpng/lib/libpng16.16.dylib @executable_path/../Frameworks/libpng16.16.dylib " + freetypelib_path)
file(os.path.join(clientbundle_content_dir, "Info.plist"), "w").write("""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -187,6 +198,10 @@ if use_bundle:
<string>????</string>
<key>CFBundleVersion</key>
<string>%s</string>
<key>CFBundleIdentifier</key>
<string>com.TeeworldsClient.app</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
""" % (version))
@ -203,10 +218,10 @@ if use_bundle:
os.mkdir(os.path.join(serverbundle_resource_dir, "data"))
os.mkdir(os.path.join(serverbundle_resource_dir, "data/maps"))
os.mkdir(os.path.join(serverbundle_resource_dir, "data/mapres"))
copydir("data/maps", serverbundle_resource_dir)
copy_tree(maps_dir, serverbundle_resource_dir+"/data/maps")
shutil.copy("other/icons/Teeworlds_srv.icns", serverbundle_resource_dir)
shutil.copy(name+"_srv"+exe_ext, serverbundle_bin_dir)
shutil.copy("serverlaunch"+exe_ext, serverbundle_bin_dir + "/"+name+"_server")
shutil.copy(source_package_dir+name+"_srv"+exe_ext, serverbundle_bin_dir)
shutil.copy(source_package_dir+"serverlaunch"+exe_ext, serverbundle_bin_dir + "/"+name+"_server")
file(os.path.join(serverbundle_content_dir, "Info.plist"), "w").write("""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

View file

@ -1,162 +1,180 @@
#!/bin/env python3
# coding: utf-8
from socket import *
import struct
import sys
import threading
import time
import random
NUM_MASTERSERVERS = 4
MASTERSERVER_PORT = 8300
MASTERSERVER_PORT = 8283
TIMEOUT = 2
SERVERTYPE_NORMAL = 0
SERVERTYPE_LEGACY = 1
# src/mastersrv/mastersrv.h
PACKET_GETLIST = b"\xff\xff\xff\xffreq2"
PACKET_LIST = b"\xff\xff\xff\xfflis2"
PACKET_GETLIST = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreqt"
PACKET_GETLIST2 = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreq2"
PACKET_GETINFO = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgief"
PACKET_GETINFO2 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie2" + "\x00"
PACKET_GETINFO3 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie3" + "\x00"
PACKET_GETINFO = b"\xff\xff\xff\xffgie3"
PACKET_INFO = b"\xff\xff\xff\xffinf3"
# see CNetBase::SendControlMsgWithToken
def pack_control_msg_with_token(token_srv,token_cl):
NET_PACKETFLAG_CONTROL = 1
NET_CTRLMSG_TOKEN = 5
NET_TOKENREQUEST_DATASIZE = 512
b = [0]*(4 + 3 + NET_TOKENREQUEST_DATASIZE)
# Header
b[0] = (NET_PACKETFLAG_CONTROL<<2)&0xfc
b[3] = (token_srv >> 24) & 0xff
b[4] = (token_srv >> 16) & 0xff
b[5] = (token_srv >> 8) & 0xff
b[6] = (token_srv) & 0xff
# Data
b[7] = NET_CTRLMSG_TOKEN
b[8] = (token_cl >> 24) & 0xff
b[9] = (token_cl >> 16) & 0xff
b[10] = (token_cl >> 8) & 0xff
b[11] = (token_cl) & 0xff
return bytes(b)
def unpack_control_msg_with_token(msg):
b = list(msg)
token_cl = (b[3] << 24) + (b[4] << 16) + (b[5] << 8) + (b[6])
token_srv = (b[8] << 24) + (b[9] << 16) + (b[10] << 8) + (b[11])
return token_cl,token_srv
# CNetBase::SendPacketConnless
def header_connless(token_srv, token_cl):
NET_PACKETFLAG_CONNLESS = 8
NET_PACKETVERSION = 1
b = [0]*9
# Header
b[0] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03)
b[1] = (token_srv >> 24) & 0xff
b[2] = (token_srv >> 16) & 0xff
b[3] = (token_srv >> 8) & 0xff
b[4] = (token_srv) & 0xff
# ResponseToken
b[5] = (token_cl >> 24) & 0xff
b[6] = (token_cl >> 16) & 0xff
b[7] = (token_cl >> 8) & 0xff
b[8] = (token_cl) & 0xff
return bytes(b)
# CVariableInt::Unpack from src/engine/shared/compression.cpp
def unpack_int(b):
l = list(b[:5])
i = 0
Sign = (l[i]>>6)&1;
res = l[i] & 0x3F;
for _ in (0,):
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7+7);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7+7+7);
i += 1;
res ^= -Sign
return res, b[i:]
class Server_Info(threading.Thread):
def __init__(self, address, type):
def __init__(self, address):
self.address = address
self.type = type
self.finished = False
threading.Thread.__init__(self, target = self.run)
def run(self):
self.info = None
if self.type == SERVERTYPE_NORMAL:
self.info = get_server_info3(self.address)
elif self.type == SERVERTYPE_LEGACY:
self.info = get_server_info(self.address)
if self.info:
self.info = get_server_info2(self.address)
self.finished = True
def get_server_info(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO, address)
sock.settimeout(TIMEOUT)
token = random.randrange(0x100000000)
# Token request
sock.sendto(pack_control_msg_with_token(-1,token),address)
data, addr = sock.recvfrom(1024)
token_cl, token_srv = unpack_control_msg_with_token(data)
assert token_cl == token, "Server %s send wrong token: %d (%d expected)" % (address, token_cl, token)
# Get info request
sock.sendto(header_connless(token_srv, token_cl) + PACKET_GETINFO + b'\x00', address)
data, addr = sock.recvfrom(4096)
head = header_connless(token_cl, token_srv) + PACKET_INFO + b'\x00'
assert data[:len(head)] == head, "Server %s info header mismatch: %r != %r (expected)" % (address, data[:len(head)], head)
sock.close()
data = data[14:] # skip header
slots = data.split("\x00")
data = data[len(head):] # skip header
slots = data.split(b"\x00", maxsplit=5)
server_info = {}
server_info["version"] = slots[0]
server_info["name"] = slots[1]
server_info["map"] = slots[2]
server_info["gametype"] = slots[3]
server_info["flags"] = int(slots[4])
server_info["progression"] = int(slots[5])
server_info["num_players"] = int(slots[6])
server_info["max_players"] = int(slots[7])
server_info["address"] = address
server_info["version"] = slots[0].decode()
server_info["name"] = slots[1].decode()
server_info["hostname"] = slots[2].decode()
server_info["map"] = slots[3].decode()
server_info["gametype"] = slots[4].decode()
data = slots[5]
# these integers should fit in one byte each
server_info["flags"], server_info["skill"] = tuple(data[:2])
data = data[2:]
server_info["num_players"], data = unpack_int(data)
server_info["max_players"], data = unpack_int(data)
server_info["num_clients"], data = unpack_int(data)
server_info["max_clients"], data = unpack_int(data)
server_info["players"] = []
for i in xrange(0, server_info["num_players"]):
for i in range(server_info["num_clients"]):
player = {}
player["name"] = slots[8+i*2]
player["score"] = int(slots[8+i*2+1])
slots = data.split(b"\x00", maxsplit=2)
player["name"] = slots[0].decode()
player["clan"] = slots[1].decode()
data = slots[2]
player["country"], data = unpack_int(data)
player["score"], data = unpack_int(data)
player["player"], data = unpack_int(data)
server_info["players"].append(player)
return server_info
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
print('> Server %s did not answer' % (address,))
except:
# print('> Server %s did something wrong here' % (address,))
# import traceback
# traceback.print_exc()
pass
finally:
sock.close()
return None
def get_server_info2(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO2, address)
data, addr = sock.recvfrom(1024)
sock.close()
data = data[14:] # skip header
slots = data.split("\x00")
server_info = {}
server_info["token"] = slots[0]
server_info["version"] = slots[1]
server_info["name"] = slots[2]
server_info["map"] = slots[3]
server_info["gametype"] = slots[4]
server_info["flags"] = int(slots[5])
server_info["progression"] = int(slots[6])
server_info["num_players"] = int(slots[7])
server_info["max_players"] = int(slots[8])
server_info["players"] = []
for i in xrange(0, server_info["num_players"]):
player = {}
player["name"] = slots[9+i*2]
player["score"] = int(slots[9+i*2+1])
server_info["players"].append(player)
return server_info
except:
sock.close()
return None
def get_server_info3(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO3, address)
data, addr = sock.recvfrom(1400)
sock.close()
data = data[14:] # skip header
slots = data.split("\x00")
server_info = {}
server_info["token"] = slots[0]
server_info["version"] = slots[1]
server_info["name"] = slots[2]
server_info["map"] = slots[3]
server_info["gametype"] = slots[4]
server_info["flags"] = int(slots[5])
server_info["num_players"] = int(slots[6])
server_info["max_players"] = int(slots[7])
server_info["num_clients"] = int(slots[8])
server_info["max_clients"] = int(slots[9])
server_info["players"] = []
for i in xrange(0, server_info["num_clients"]):
player = {}
player["name"] = slots[10+i*5]
player["clan"] = slots[10+i*5+1]
player["country"] = int(slots[10+i*5+2])
player["score"] = int(slots[10+i*5+3])
if int(slots[10+i*5+4]):
player["player"] = True
else:
player["player"] = False
server_info["players"].append(player)
return server_info
except:
sock.close()
return None
class Master_Server_Info(threading.Thread):
def __init__(self, address):
@ -165,64 +183,62 @@ class Master_Server_Info(threading.Thread):
threading.Thread.__init__(self, target = self.run)
def run(self):
self.servers = get_list(self.address) + get_list2(self.address)
self.servers = get_list(self.address)
self.finished = True
def get_list(address):
servers = []
answer = False
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETLIST, address)
token = random.randrange(0x100000000)
# Token request
sock.sendto(pack_control_msg_with_token(-1,token),address)
data, addr = sock.recvfrom(1024)
token_cl, token_srv = unpack_control_msg_with_token(data)
assert token_cl == token, "Master %s send wrong token: %d (%d expected)" % (address, token_cl, token)
answer = True
# Get list request
sock.sendto(header_connless(token_srv, token_cl) + PACKET_GETLIST, addr)
head = header_connless(token_cl, token_srv) + PACKET_LIST
while 1:
data, addr = sock.recvfrom(1024)
# Header should keep consistent
assert data[:len(head)] == head, "Master %s list header mismatch: %r != %r (expected)" % (address, data[:len(head)], head)
data = data[14:]
num_servers = len(data) / 6
data = data[len(head):]
num_servers = len(data) // 18
for n in range(0, num_servers):
ip = ".".join(map(str, map(ord, data[n*6:n*6+4])))
port = ord(data[n*6+5]) * 256 + ord(data[n*6+4])
servers += [[(ip, port), SERVERTYPE_LEGACY]]
except:
sock.close()
return servers
def get_list2(address):
servers = []
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETLIST2, address)
while 1:
data, addr = sock.recvfrom(1400)
data = data[14:]
num_servers = len(data) / 18
for n in range(0, num_servers):
if data[n*18:n*18+12] == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
ip = ".".join(map(str, map(ord, data[n*18+12:n*18+16])))
# IPv4
if data[n*18:n*18+12] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
ip = ".".join(map(str, data[n*18+12:n*18+16]))
# IPv6
else:
ip = ":".join(map(str, map(ord, data[n*18:n*18+16])))
port = (ord(data[n*18+16])<<8) + ord(data[n*18+17])
servers += [[(ip, port), SERVERTYPE_NORMAL]]
ip = ":".join(map(str, data[n*18:n*18+16]))
port = ((data[n*18+16])<<8) + data[n*18+17]
servers += [(ip, port)]
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
if not answer:
print('> Master %s did not answer' % (address,))
except:
# import traceback
# traceback.print_exc()
sock.close()
return servers
if __name__ == '__main__':
master_servers = []
for i in range(1, NUM_MASTERSERVERS+1):
@ -231,40 +247,62 @@ for i in range(1, NUM_MASTERSERVERS+1):
m.start()
time.sleep(0.001) # avoid issues
servers = []
servers = set()
while len(master_servers) != 0:
if master_servers[0].finished == True:
if master_servers[0].servers:
servers += master_servers[0].servers
servers.update(master_servers[0].servers)
del master_servers[0]
time.sleep(0.001) # be nice
servers_info = []
print str(len(servers)) + " servers"
print(str(len(servers)) + " servers")
for server in servers:
s = Server_Info(server[0], server[1])
s = Server_Info(server)
servers_info.append(s)
s.start()
time.sleep(0.001) # avoid issues
num_players = 0
num_clients = 0
num_botplayers = 0
num_botspectators = 0
while len(servers_info) != 0:
if servers_info[0].finished == True:
if servers_info[0].info:
num_players += servers_info[0].info["num_players"]
if servers_info[0].type == SERVERTYPE_NORMAL:
num_clients += servers_info[0].info["num_clients"]
server_info = servers_info[0].info
# check num/max validity
if server_info["num_players"] > server_info["max_players"] \
or server_info["num_clients"] > server_info["max_clients"] \
or server_info["max_players"] > server_info["max_clients"] \
or server_info["num_players"] < 0 \
or server_info["num_clients"] < 0 \
or server_info["max_clients"] < 0 \
or server_info["max_players"] < 0 \
or server_info["max_clients"] > 64:
server_info["bad"] = 'invalid num/max'
print('> Server %s has %s' % (server_info["address"], server_info["bad"]))
# check actual purity
elif server_info["gametype"] in ('DM', 'TDM', 'CTF', 'LMS', 'LTS') \
and server_info["max_players"] > 16:
server_info["bad"] = 'too many players for vanilla'
print('> Server %s has %s' % (server_info["address"], server_info["bad"]))
else:
num_clients += servers_info[0].info["num_players"]
num_players += server_info["num_players"]
num_clients += server_info["num_clients"]
for p in servers_info[0].info["players"]:
if p["player"] == 2:
num_botplayers += 1
if p["player"] == 3:
num_botspectators += 1
del servers_info[0]
time.sleep(0.001) # be nice
print str(num_players) + " players and " + str(num_clients-num_players) + " spectators"
print('%d players (%d bots) and %d spectators (%d bots)' % (num_players, num_botplayers, num_clients - num_players, num_botspectators))

View file

@ -56,4 +56,97 @@ inline vec4 HexToRgba(int hex)
return c;
}
/*
Function: HsvToRgb
Converts Hsv to Rgb
*/
inline vec3 HsvToRgb(vec3 hsv)
{
int h = int(hsv.x * 6.0f);
float f = hsv.x * 6.0f - h;
float p = hsv.z * (1.0f - hsv.y);
float q = hsv.z * (1.0f - hsv.y * f);
float t = hsv.z * (1.0f - hsv.y * (1.0f - f));
vec3 rgb = vec3(0.0f, 0.0f, 0.0f);
switch(h % 6)
{
case 0:
rgb.r = hsv.z;
rgb.g = t;
rgb.b = p;
break;
case 1:
rgb.r = q;
rgb.g = hsv.z;
rgb.b = p;
break;
case 2:
rgb.r = p;
rgb.g = hsv.z;
rgb.b = t;
break;
case 3:
rgb.r = p;
rgb.g = q;
rgb.b = hsv.z;
break;
case 4:
rgb.r = t;
rgb.g = p;
rgb.b = hsv.z;
break;
case 5:
rgb.r = hsv.z;
rgb.g = p;
rgb.b = q;
break;
}
return rgb;
}
/*
Function: RgbToHsv
Converts Rgb to Hsv
*/
inline vec3 RgbToHsv(vec3 rgb)
{
float h_min = min(min(rgb.r, rgb.g), rgb.b);
float h_max = max(max(rgb.r, rgb.g), rgb.b);
// hue
float hue = 0.0f;
if(h_max == h_min)
hue = 0.0f;
else if(h_max == rgb.r)
hue = (rgb.g-rgb.b) / (h_max-h_min);
else if(h_max == rgb.g)
hue = 2.0f + (rgb.b-rgb.r) / (h_max-h_min);
else
hue = 4.0f + (rgb.r-rgb.g) / (h_max-h_min);
hue /= 6.0f;
if(hue < 0.0f)
hue += 1.0f;
// saturation
float s = 0.0f;
if(h_max != 0.0f)
s = (h_max - h_min)/h_max;
// lightness
float l = h_max;
return vec3(hue, s, l);
}
#endif

View file

@ -140,6 +140,14 @@
#endif
#endif
#if defined(__arm__)
#define CONF_ARCH_ARM 1
#define CONF_ARCH_STRING "arm"
#if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG)
#define CONF_ARCH_ENDIAN_LITTLE 1
#endif
#endif
#ifndef CONF_FAMILY_STRING
#define CONF_FAMILY_STRING "unknown"

View file

@ -47,6 +47,7 @@ inline T bezier(const T p0, const T p1, const T p2, const T p3, TB amount)
return mix(c20, c21, amount); // c30
}
inline int random_int() { return (((rand() & 0xffff) << 16) | (rand() & 0xffff)) & 0x7FFFFFFF; };
inline float frandom() { return rand()/(float)(RAND_MAX); }
// float to fixed

View file

@ -39,6 +39,7 @@
#include <fcntl.h>
#include <direct.h>
#include <errno.h>
#include <wincrypt.h>
#else
#error NOT IMPLEMENTED
#endif
@ -59,7 +60,6 @@ static DBG_LOGGER loggers[16];
static int num_loggers = 0;
static NETSTATS network_stats = {0};
static MEMSTATS memory_stats = {0};
static NETSOCKET invalid_socket = {NETTYPE_INVALID, -1, -1};
@ -105,6 +105,94 @@ void dbg_msg(const char *sys, const char *fmt, ...)
loggers[i](str);
}
#if defined(CONF_FAMILY_WINDOWS)
static void logger_win_console(const char *line)
{
#define _MAX_LENGTH 1024
#define _MAX_LENGTH_ERROR (_MAX_LENGTH+32)
static const int UNICODE_REPLACEMENT_CHAR = 0xfffd;
static const char *STR_TOO_LONG = "(str too long)";
static const char *INVALID_UTF8 = "(invalid utf8)";
wchar_t wline[_MAX_LENGTH_ERROR];
size_t len = 0;
const char *read = line;
const char *error = STR_TOO_LONG;
while(len < _MAX_LENGTH)
{
// Read a character. This also advances the read pointer
int glyph = str_utf8_decode(&read);
if(glyph < 0)
{
// If there was an error decoding the UTF-8 sequence,
// emit a replacement character. Since the
// str_utf8_decode function will not work after such
// an error, end the string here.
glyph = UNICODE_REPLACEMENT_CHAR;
error = INVALID_UTF8;
wline[len] = glyph;
break;
}
else if(glyph == 0)
{
// A character code of 0 signals the end of the string.
error = 0;
break;
}
else if(glyph > 0xffff)
{
// Since the windows console does not really support
// UTF-16, don't mind doing actual UTF-16 encoding,
// but rather emit a replacement character.
glyph = UNICODE_REPLACEMENT_CHAR;
}
else if(glyph == 0x2022)
{
// The 'bullet' character might get converted to a 'beep',
// so it will be replaced by the 'bullet operator'.
glyph = 0x2219;
}
// Again, since the windows console does not really support
// UTF-16, but rather something along the lines of UCS-2,
// simply put the character into the output.
wline[len++] = glyph;
}
if(error)
{
read = error;
while(1)
{
// Errors are simple ascii, no need for UTF-8
// decoding
char character = *read;
if(character == 0)
break;
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for error");
wline[len++] = character;
read++;
}
}
// Terminate the line
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\r");
wline[len++] = '\r';
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\n");
wline[len++] = '\n';
// Ignore any error that might occur
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wline, len, 0, 0);
#undef _MAX_LENGTH
#undef _MAX_LENGTH_ERROR
}
#endif
static void logger_stdout(const char *line)
{
printf("%s\n", line);
@ -128,7 +216,18 @@ static void logger_file(const char *line)
io_flush(logfile);
}
void dbg_logger_stdout() { dbg_logger(logger_stdout); }
void dbg_logger_stdout()
{
#if defined(CONF_FAMILY_WINDOWS)
if(GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR)
{
dbg_logger(logger_win_console);
return;
}
#endif
dbg_logger(logger_stdout);
}
void dbg_logger_debugger() { dbg_logger(logger_debugger); }
void dbg_logger_file(const char *filename)
{
@ -160,79 +259,13 @@ static const int MEM_GUARD_VAL = 0xbaadc0de;
void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment)
{
/* TODO: fix alignment */
/* TODO: add debugging */
MEMTAIL *tail;
MEMHEADER *header = (struct MEMHEADER *)malloc(size+sizeof(MEMHEADER)+sizeof(MEMTAIL));
dbg_assert(header != 0, "mem_alloc failure");
if(!header)
return NULL;
tail = (struct MEMTAIL *)(((char*)(header+1))+size);
header->size = size;
header->filename = filename;
header->line = line;
memory_stats.allocated += header->size;
memory_stats.total_allocations++;
memory_stats.active_allocations++;
tail->guard = MEM_GUARD_VAL;
header->prev = (MEMHEADER *)0;
header->next = first;
if(first)
first->prev = header;
first = header;
/*dbg_msg("mem", "++ %p", header+1); */
return header+1;
return malloc(size);
}
void mem_free(void *p)
{
if(p)
{
MEMHEADER *header = (MEMHEADER *)p - 1;
MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size);
if(tail->guard != MEM_GUARD_VAL)
dbg_msg("mem", "!! %p", p);
/* dbg_msg("mem", "-- %p", p); */
memory_stats.allocated -= header->size;
memory_stats.active_allocations--;
if(header->prev)
header->prev->next = header->next;
else
first = header->next;
if(header->next)
header->next->prev = header->prev;
free(header);
free(p);
}
}
void mem_debug_dump(IOHANDLE file)
{
char buf[1024];
MEMHEADER *header = first;
if(!file)
file = io_open("memory.txt", IOFLAG_WRITE);
if(file)
{
while(header)
{
str_format(buf, sizeof(buf), "%s(%d): %d", header->filename, header->line, header->size);
io_write(file, buf, strlen(buf));
io_write_newline(file);
header = header->next;
}
io_close(file);
}
}
void mem_copy(void *dest, const void *source, unsigned size)
{
@ -369,14 +402,44 @@ int io_flush(IOHANDLE io)
return 0;
}
struct THREAD_RUN
{
void (*threadfunc)(void *);
void *u;
};
#if defined(CONF_FAMILY_UNIX)
static void *thread_run(void *user)
#elif defined(CONF_FAMILY_WINDOWS)
static unsigned long __stdcall thread_run(void *user)
#else
#error not implemented
#endif
{
struct THREAD_RUN *data = user;
void (*threadfunc)(void *) = data->threadfunc;
void *u = data->u;
free(data);
threadfunc(u);
return 0;
}
void *thread_init(void (*threadfunc)(void *), void *u)
{
struct THREAD_RUN *data = malloc(sizeof(*data));
data->threadfunc = threadfunc;
data->u = u;
#if defined(CONF_FAMILY_UNIX)
{
pthread_t id;
pthread_create(&id, NULL, (void *(*)(void*))threadfunc, u);
if(pthread_create(&id, NULL, thread_run, data) != 0)
{
return 0;
}
return (void*)id;
}
#elif defined(CONF_FAMILY_WINDOWS)
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, u, 0, NULL);
return CreateThread(NULL, 0, thread_run, data, 0, NULL);
#else
#error not implemented
#endif
@ -853,7 +916,7 @@ static int priv_net_close_all_sockets(NETSOCKET sock)
return 0;
}
static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen)
static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen, int use_random_port)
{
int sock, e;
@ -883,27 +946,46 @@ static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, i
#endif
/* bind the socket */
while(1)
{
/* pick random port */
if(use_random_port)
{
int port = htons(rand()%16384+49152); /* 49152 to 65535 */
if(domain == AF_INET)
((struct sockaddr_in *)(addr))->sin_port = port;
else
((struct sockaddr_in6 *)(addr))->sin6_port = port;
}
e = bind(sock, addr, sockaddrlen);
if(e != 0)
if(e == 0)
break;
else
{
#if defined(CONF_FAMILY_WINDOWS)
char buf[128];
int error = WSAGetLastError();
if(error == WSAEADDRINUSE && use_random_port)
continue;
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0)
buf[0] = 0;
dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, error, buf);
#else
if(errno == EADDRINUSE && use_random_port)
continue;
dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno));
#endif
priv_net_close_socket(sock);
return -1;
}
}
/* return the newly created socket */
return sock;
}
NETSOCKET net_udp_create(NETADDR bindaddr)
NETSOCKET net_udp_create(NETADDR bindaddr, int use_random_port)
{
NETSOCKET sock = invalid_socket;
NETADDR tmpbindaddr = bindaddr;
@ -918,7 +1000,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
/* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV4;
netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr));
socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr), use_random_port);
if(socket >= 0)
{
sock.type |= NETTYPE_IPV4;
@ -940,7 +1022,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
/* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV6;
netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr));
socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr), use_random_port);
if(socket >= 0)
{
sock.type |= NETTYPE_IPV6;
@ -1077,7 +1159,7 @@ NETSOCKET net_tcp_create(NETADDR bindaddr)
/* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV4;
netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), 0);
if(socket >= 0)
{
sock.type |= NETTYPE_IPV4;
@ -1093,7 +1175,7 @@ NETSOCKET net_tcp_create(NETADDR bindaddr)
/* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV6;
netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), 0);
if(socket >= 0)
{
sock.type |= NETTYPE_IPV6;
@ -1357,19 +1439,46 @@ int fs_storage_path(const char *appname, char *path, int max)
return 0;
#else
char *home = getenv("HOME");
#if !defined(CONF_PLATFORM_MACOSX)
int i;
#endif
if(!home)
return -1;
#if defined(CONF_PLATFORM_MACOSX)
snprintf(path, max, "%s/Library/Application Support/%s", home, appname);
#else
return 0;
#endif
int i;
char *xdgdatahome = getenv("XDG_DATA_HOME");
char xdgpath[max];
/* old folder location */
snprintf(path, max, "%s/.%s", home, appname);
for(i = strlen(home)+2; path[i]; i++)
path[i] = tolower(path[i]);
#endif
if(!xdgdatahome)
{
/* use default location */
snprintf(xdgpath, max, "%s/.local/share/%s", home, appname);
for(i = strlen(home)+14; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
else
{
snprintf(xdgpath, max, "%s/%s", xdgdatahome, appname);
for(i = strlen(xdgdatahome)+1; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
/* check for old location / backward compatibility */
if(fs_is_dir(path))
{
/* use old folder path */
/* for backward compatibility */
return 0;
}
snprintf(path, max, "%s", xdgpath);
return 0;
#endif
@ -1549,6 +1658,18 @@ int time_houroftheday()
return time_info->tm_hour;
}
int time_isxmasday()
{
time_t time_data;
struct tm *time_info;
time(&time_data);
time_info = localtime(&time_data);
if(time_info->tm_mon == 11 && time_info->tm_mday >= 24 && time_info->tm_mday <= 26)
return 1;
return 0;
}
void str_append(char *dst, const char *src, int dst_size)
{
int s = strlen(dst);
@ -1847,58 +1968,11 @@ int mem_comp(const void *a, const void *b, int size)
return memcmp(a,b,size);
}
const MEMSTATS *mem_stats()
{
return &memory_stats;
}
void net_stats(NETSTATS *stats_inout)
{
*stats_inout = network_stats;
}
void gui_messagebox(const char *title, const char *message)
{
#if defined(CONF_PLATFORM_MACOSX)
DialogRef theItem;
DialogItemIndex itemIndex;
/* FIXME: really needed? can we rely on glfw? */
/* HACK - get events without a bundle */
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
TransformProcessType(&psn,kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
/* END HACK */
CreateStandardAlert(kAlertStopAlert,
CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
NULL,
&theItem);
RunStandardAlert(theItem, NULL, &itemIndex);
#elif defined(CONF_FAMILY_UNIX)
static char cmd[1024];
int err;
/* use xmessage which is available on nearly every X11 system */
snprintf(cmd, sizeof(cmd), "xmessage -center -title '%s' '%s'",
title,
message);
err = system(cmd);
dbg_msg("gui/msgbox", "result = %i", err);
#elif defined(CONF_FAMILY_WINDOWS)
MessageBox(NULL,
message,
title,
MB_ICONEXCLAMATION | MB_OK);
#else
/* this is not critical */
#warning not implemented
#endif
}
int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
char str_uppercase(char c)
@ -2030,24 +2104,24 @@ int str_utf8_decode(const char **ptr)
}
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
{
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch = (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
if(ch < 0x80 || ch > 0x7FF) ch = -1;
}
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
{
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch = (*buf++ & 0x1F) << 12; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
if(ch < 0x800 || ch > 0xFFFF) ch = -1;
}
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
{
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch = (*buf++ & 0x0F) << 18; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 12; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
if(ch < 0x10000 || ch > 0x10FFFF) ch = -1;
}
else
{
@ -2093,6 +2167,69 @@ unsigned str_quickhash(const char *str)
return hash;
}
struct SECURE_RANDOM_DATA
{
int initialized;
#if defined(CONF_FAMILY_WINDOWS)
HCRYPTPROV provider;
#else
IOHANDLE urandom;
#endif
};
static struct SECURE_RANDOM_DATA secure_random_data = { 0 };
int secure_random_init()
{
if(secure_random_data.initialized)
{
return 0;
}
#if defined(CONF_FAMILY_WINDOWS)
if(CryptAcquireContext(&secure_random_data.provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
secure_random_data.initialized = 1;
return 0;
}
else
{
return 1;
}
#else
secure_random_data.urandom = io_open("/dev/urandom", IOFLAG_READ);
if(secure_random_data.urandom)
{
secure_random_data.initialized = 1;
return 0;
}
else
{
return 1;
}
#endif
}
void secure_random_fill(void *bytes, unsigned length)
{
if(!secure_random_data.initialized)
{
dbg_msg("secure", "called secure_random_fill before secure_random_init");
dbg_break();
}
#if defined(CONF_FAMILY_WINDOWS)
if(!CryptGenRandom(secure_random_data.provider, length, bytes))
{
dbg_msg("secure", "CryptGenRandom failed, last_error=%d", GetLastError());
dbg_break();
}
#else
if(length != io_read(secure_random_data.urandom, bytes, length))
{
dbg_msg("secure", "io_read returned with a short read");
dbg_break();
}
#endif
}
#if defined(__cplusplus)
}

View file

@ -170,14 +170,6 @@ void mem_zero(void *block, unsigned size);
*/
int mem_comp(const void *a, const void *b, int size);
/*
Function: mem_check
Validates the heap
Will trigger a assert if memory has failed.
*/
int mem_check_imp();
#define mem_check() dbg_assert_imp(__FILE__, __LINE__, mem_check_imp(), "Memory check failed")
/* Group: File IO */
enum {
IOFLAG_READ = 1,
@ -475,6 +467,16 @@ int time_timestamp();
*/
int time_houroftheday();
/*
Function: time_isxmasday
Checks if it's xmas
Returns:
1 - if it's a xmas day
0 - if not
*/
int time_isxmasday();
/* Group: Network General */
typedef struct
{
@ -576,12 +578,13 @@ int net_addr_from_str(NETADDR *addr, const char *string);
Parameters:
bindaddr - Address to bind the socket to.
use_random_port - use a random port
Returns:
On success it returns an handle to the socket. On failure it
returns NETSOCKET_INVALID.
*/
NETSOCKET net_udp_create(NETADDR bindaddr);
NETSOCKET net_udp_create(NETADDR bindaddr, int use_random_port);
/*
Function: net_udp_send
@ -1202,8 +1205,6 @@ int net_would_block();
int net_socket_read_wait(NETSOCKET sock, int time);
void mem_debug_dump(IOHANDLE file);
void swap_endian(void *data, unsigned elem_size, unsigned num);
@ -1214,15 +1215,6 @@ void dbg_logger_stdout();
void dbg_logger_debugger();
void dbg_logger_file(const char *filename);
typedef struct
{
int allocated;
int active_allocations;
int total_allocations;
} MEMSTATS;
const MEMSTATS *mem_stats();
typedef struct
{
int sent_packets;
@ -1240,16 +1232,6 @@ int str_isspace(char c);
char str_uppercase(char c);
unsigned str_quickhash(const char *str);
/*
Function: gui_messagebox
Display plain OS-dependent message box
Parameters:
title - title of the message box
message - text to display
*/
void gui_messagebox(const char *title, const char *message);
char *str_utf8_skip_whitespaces(char *str);
/*
@ -1330,6 +1312,27 @@ int str_utf8_encode(char *ptr, int chr);
*/
int str_utf8_check(const char *str);
/*
Function: secure_random_init
Initializes the secure random module.
You *MUST* check the return value of this function.
Returns:
0 - Initialization succeeded.
1 - Initialization failed.
*/
int secure_random_init();
/*
Function: secure_random_fill
Fills the buffer with the specified amount of random bytes.
Parameters:
bytes - Pointer to the start of the buffer.
length - Length of the buffer.
*/
void secure_random_fill(void *bytes, unsigned length);
#ifdef __cplusplus
}
#endif

View file

@ -35,7 +35,9 @@
#elif defined(_MSC_VER)
#include <intrin.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
inline unsigned atomic_inc(volatile unsigned *pValue)

View file

@ -17,7 +17,7 @@ public:
union { T y,v; };
vector2_base() {}
vector2_base(float nx, float ny)
vector2_base(T nx, T ny)
{
x = nx;
y = ny;
@ -119,7 +119,7 @@ public:
union { T z,b,v,l; };
vector3_base() {}
vector3_base(float nx, float ny, float nz)
vector3_base(T nx, T ny, T nz)
{
x = nx;
y = ny;
@ -198,7 +198,7 @@ public:
union { T w,a; };
vector4_base() {}
vector4_base(float nx, float ny, float nz, float nw)
vector4_base(T nx, T ny, T nz, T nw)
{
x = nx;
y = ny;

View file

@ -88,10 +88,17 @@ public:
virtual void AutoScreenshot_Start() = 0;
virtual void ServerBrowserUpdate() = 0;
// gfx
virtual void SwitchWindowScreen(int Index) = 0;
virtual void ToggleFullscreen() = 0;
virtual void ToggleWindowBordered() = 0;
virtual void ToggleWindowVSync() = 0;
// networking
virtual void EnterGame() = 0;
//
virtual const char *MapDownloadName() const = 0;
virtual int MapDownloadAmount() const = 0;
virtual int MapDownloadTotalsize() const = 0;
@ -160,6 +167,7 @@ public:
virtual void OnEnterGame() = 0;
virtual void OnShutdown() = 0;
virtual void OnRender() = 0;
virtual void OnUpdate() = 0;
virtual void OnStateChange(int NewState, int OldState) = 0;
virtual void OnConnected() = 0;
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker) = 0;
@ -171,6 +179,7 @@ public:
virtual const char *GetItemName(int Type) const = 0;
virtual const char *Version() const = 0;
virtual const char *NetVersion() const = 0;
virtual int ClientVersion() const = 0;
};

View file

@ -12,9 +12,13 @@
#include "graphics_threaded.h"
#include "backend_sdl.h"
#if defined(CONF_FAMILY_WINDOWS)
PFNGLTEXIMAGE3DPROC glTexImage3D;
PFNGLTEXIMAGE3DPROC glTexImage3DInternal;
GLAPI void APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
{
glTexImage3DInternal(target, level, internalFormat, width, height, depth, border, format, type, pixels);
}
#endif
// ------------ CGraphicsBackend_Threaded
@ -171,7 +175,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
else if(State.m_Dimension == 3 && (m_aTextures[State.m_Texture].m_State&CTexture::STATE_TEX3D))
{
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D);
glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D[State.m_TextureArrayIndex]);
}
else
dbg_msg("render", "invalid texture %d %d %d\n", State.m_Texture, State.m_Dimension, m_aTextures[State.m_Texture].m_State);
@ -244,6 +248,13 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
{
m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_Max3DTexSize);
dbg_msg("render", "opengl max texture sizes: %d, %d(3D)", m_MaxTexSize, m_Max3DTexSize);
if(m_Max3DTexSize < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION)
dbg_msg("render", "*** warning *** max 3D texture size is too low - using the fallback system");
m_TextureArraySize = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
*pCommand->m_pTextureArraySize = m_TextureArraySize;
}
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
@ -262,7 +273,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer:
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX2D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex2D);
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX3D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D);
glDeleteTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D);
*m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize;
m_aTextures[pCommand->m_Slot].m_State = CTexture::STATE_EMPTY;
m_aTextures[pCommand->m_Slot].m_MemSize = 0;
@ -278,16 +289,13 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
// resample if needed
if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB)
{
int MaxTexSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexSize);
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D)
int MaxTexSize = m_MaxTexSize;
if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{
int Max3DTexSize;
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Max3DTexSize);
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE2D)
MaxTexSize = min(MaxTexSize, Max3DTexSize*16);
MaxTexSize = min(MaxTexSize, m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION);
else
MaxTexSize = Max3DTexSize*16;
MaxTexSize = m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION;
}
if(Width > MaxTexSize || Height > MaxTexSize)
{
@ -302,7 +310,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
mem_free(pTexData);
pTexData = pTmpData;
}
else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
else if(Width > IGraphics::NUMTILES_DIMENSION && Height > IGraphics::NUMTILES_DIMENSION && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
{
Width>>=1;
Height>>=1;
@ -357,6 +365,9 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if(pCommand->m_Flags&CCommandBuffer::TEXTFLAG_LINEARMIPMAPS)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData);
}
@ -374,43 +385,46 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
}
// 3D texture
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D)
if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{
Width /= 16;
Height /= 16;
Depth = 256;
Width /= IGraphics::NUMTILES_DIMENSION;
Height /= IGraphics::NUMTILES_DIMENSION;
Depth = min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
// copy and reorder texture data
int MemSize = Width*Height*Depth*pCommand->m_PixelSize;
int MemSize = Width*Height*IGraphics::NUMTILES_DIMENSION*IGraphics::NUMTILES_DIMENSION*pCommand->m_PixelSize;
char *pTmpData = (char *)mem_alloc(MemSize, sizeof(void*));
const int TileSize = (Height * Width) * pCommand->m_PixelSize;
const int TileRowSize = Width * pCommand->m_PixelSize;
const int ImagePitch = Width*16 * pCommand->m_PixelSize;
const int ImagePitch = Width * IGraphics::NUMTILES_DIMENSION * pCommand->m_PixelSize;
mem_zero(pTmpData, MemSize);
for(int i = 0; i < 256; i++)
for(int i = 0; i < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION; i++)
{
const int px = (i%16) * Width;
const int py = (i/16) * Height;
const char *pTileData = (const char *)pTexData + (py * Width*16 + px) * pCommand->m_PixelSize;
const int px = (i%IGraphics::NUMTILES_DIMENSION) * Width;
const int py = (i/IGraphics::NUMTILES_DIMENSION) * Height;
const char *pTileData = (const char *)pTexData + (py * Width * IGraphics::NUMTILES_DIMENSION + px) * pCommand->m_PixelSize;
for(int y = 0; y < Height; y++)
mem_copy(pTmpData + i*TileSize + y*TileRowSize, pTileData + y * ImagePitch, TileRowSize);
}
mem_free(pTexData);
pTexData = pTmpData;
//
glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D);
glGenTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D);
m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D;
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D);
for(int i = 0; i < m_TextureArraySize; ++i)
{
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D[i]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
pTexData = pTmpData+i*(Width*Height*Depth*pCommand->m_PixelSize);
glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
}
pTexData = pTmpData;
}
*m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize;
@ -453,8 +467,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom
GLint aViewport[4] = {0,0,0,0};
glGetIntegerv(GL_VIEWPORT, aViewport);
int w = aViewport[2];
int h = aViewport[3];
int w = pCommand->m_W == -1 ? aViewport[2] : pCommand->m_W;
int h = pCommand->m_H == -1 ? aViewport[3] : pCommand->m_H;
int x = pCommand->m_X;
int y = aViewport[3] - pCommand->m_Y - 1 - (h - 1);
// we allocate one more row to use when we are flipping the texture
unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
@ -464,15 +480,15 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom
GLint Alignment;
glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData);
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData);
glPixelStorei(GL_PACK_ALIGNMENT, Alignment);
// flip the pixel because opengl works from bottom left corner
for(int y = 0; y < h/2; y++)
for(int ty = 0; ty < h/2; ty++)
{
mem_copy(pTempRow, pPixelData+y*w*3, w*3);
mem_copy(pPixelData+y*w*3, pPixelData+(h-y-1)*w*3, w*3);
mem_copy(pPixelData+(h-y-1)*w*3, pTempRow,w*3);
mem_copy(pTempRow, pPixelData+ty*w*3, w*3);
mem_copy(pPixelData+ty*w*3, pPixelData+(h-ty-1)*w*3, w*3);
mem_copy(pPixelData+(h-ty-1)*w*3, pTempRow,w*3);
}
// fill in the information
@ -539,6 +555,11 @@ void CCommandProcessorFragment_SDL::Cmd_Swap(const CCommandBuffer::SCommand_Swap
glFinish();
}
void CCommandProcessorFragment_SDL::Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand)
{
*pCommand->m_pRetOk = SDL_GL_SetSwapInterval(pCommand->m_VSync) == 0;
}
void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand)
{
SDL_DisplayMode mode;
@ -584,6 +605,7 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
switch(pBaseCommand->m_Cmd)
{
case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast<const CCommandBuffer::SCommand_Swap *>(pBaseCommand)); break;
case CCommandBuffer::CMD_VSYNC: Cmd_VSync(static_cast<const CCommandBuffer::SCommand_VSync *>(pBaseCommand)); break;
case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast<const CCommandBuffer::SCommand_VideoModes *>(pBaseCommand)); break;
case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break;
case CMD_SHUTDOWN: Cmd_Shutdown(static_cast<const SCommand_Shutdown *>(pBaseCommand)); break;
@ -619,7 +641,7 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
// ------------ CGraphicsBackend_SDL_OpenGL
int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight)
int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight)
{
if(!SDL_WasInit(SDL_INIT_VIDEO))
{
@ -628,34 +650,43 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
dbg_msg("gfx", "unable to init SDL video: %s", SDL_GetError());
return -1;
}
#ifdef CONF_FAMILY_WINDOWS
if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention
putenv("SDL_VIDEO_WINDOW_POS=center"); // ignore_convention
#endif
}
SDL_Rect ScreenBounds;
if(SDL_GetDisplayBounds(Screen, &ScreenBounds) < 0)
// set screen
SDL_Rect ScreenPos;
m_NumScreens = SDL_GetNumVideoDisplays();
if(m_NumScreens > 0)
{
dbg_msg("gfx", "unable to get current screen bounds: %s", SDL_GetError());
clamp(*Screen, 0, m_NumScreens-1);
if(SDL_GetDisplayBounds(*Screen, &ScreenPos) != 0)
{
dbg_msg("gfx", "unable to retrieve screen information: %s", SDL_GetError());
return -1;
}
// use current resolution as default
if(*pWidth == 0 || *pHeight == 0)
}
else
{
*pWidth = ScreenBounds.w;
*pHeight = ScreenBounds.h;
dbg_msg("gfx", "unable to retrieve number of screens: %s", SDL_GetError());
return -1;
}
// store desktop resolution for settings reset button
*pDesktopWidth = ScreenBounds.w;
*pDesktopHeight = ScreenBounds.h;
SDL_DisplayMode DisplayMode;
if(SDL_GetDesktopDisplayMode(*Screen, &DisplayMode))
{
dbg_msg("gfx", "unable to get desktop resolution: %s", SDL_GetError());
return -1;
}
*pDesktopWidth = DisplayMode.w;
*pDesktopHeight = DisplayMode.h;
dbg_assert(!(Flags&IGraphicsBackend::INITFLAG_BORDERLESS)
|| !(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN),
"only one of borderless and fullscreen may be activated at the same time");
// use desktop resolution as default resolution
if (*pWidth == 0 || *pWidth == 0)
{
*pWidth = *pDesktopWidth;
*pHeight = *pDesktopHeight;
}
// set flags
int SdlFlags = SDL_WINDOW_OPENGL;
@ -664,10 +695,12 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
if(Flags&IGraphicsBackend::INITFLAG_BORDERLESS)
SdlFlags |= SDL_WINDOW_BORDERLESS;
if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN)
#if defined(CONF_FAMILY_WINDOWS) || defined(CONF_PLATFORM_MACOSX)
SdlFlags |= SDL_WINDOW_FULLSCREEN;
#if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (game freezes when losing focus in fullscreen)
SdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; // always use "fake" fullscreen
*pWidth = *pDesktopWidth;
*pHeight = *pDesktopHeight;
#else
SdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
SdlFlags |= SDL_WINDOW_FULLSCREEN;
#endif
// set gl attributes
@ -683,14 +716,17 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
}
m_pWindow = SDL_CreateWindow(
pName,
SDL_WINDOWPOS_UNDEFINED_DISPLAY(0),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(0),
*pWidth,
*pHeight,
SdlFlags);
// calculate centered position in windowed mode
int OffsetX = 0;
int OffsetY = 0;
if(!(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) && *pDesktopWidth > *pWidth && *pDesktopHeight > *pHeight)
{
OffsetX = (*pDesktopWidth - *pWidth) / 2;
OffsetY = (*pDesktopHeight - *pHeight) / 2;
}
// create window
m_pWindow = SDL_CreateWindow(pName, ScreenPos.x+OffsetX, ScreenPos.y+OffsetY, *pWidth, *pHeight, SdlFlags);
if(m_pWindow == NULL)
{
dbg_msg("gfx", "unable to create window: %s", SDL_GetError());
@ -699,8 +735,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
SDL_GetWindowSize(m_pWindow, pWidth, pHeight);
// create gl context
m_GLContext = SDL_GL_CreateContext(m_pWindow);
if(m_GLContext == NULL)
{
dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError());
@ -708,8 +744,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
}
#if defined(CONF_FAMILY_WINDOWS)
glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
if(glTexImage3D == 0)
glTexImage3DInternal = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
if(glTexImage3DInternal == 0)
{
dbg_msg("gfx", "glTexImage3D not supported");
return -1;
@ -726,13 +762,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
// issue init commands for OpenGL and SDL
CCommandBuffer CmdBuffer(1024, 512);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdBuffer.AddCommand(CmdOpenGL);
CCommandProcessorFragment_SDL::SCommand_Init CmdSDL;
CmdSDL.m_pWindow = m_pWindow;
CmdSDL.m_GLContext = m_GLContext;
CmdBuffer.AddCommand(CmdSDL);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdOpenGL.m_pTextureArraySize = &m_TextureArraySize;
CmdBuffer.AddCommand(CmdOpenGL);
RunBuffer(&CmdBuffer);
WaitForIdle();
@ -772,7 +809,41 @@ void CGraphicsBackend_SDL_OpenGL::Minimize()
void CGraphicsBackend_SDL_OpenGL::Maximize()
{
// TODO: SDL
SDL_MaximizeWindow(m_pWindow);
}
bool CGraphicsBackend_SDL_OpenGL::Fullscreen(bool State)
{
#if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (game freezes when losing focus in fullscreen)
return SDL_SetWindowFullscreen(m_pWindow, State ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) == 0;
#else
return SDL_SetWindowFullscreen(m_pWindow, State ? SDL_WINDOW_FULLSCREEN : 0) == 0;
#endif
}
void CGraphicsBackend_SDL_OpenGL::SetWindowBordered(bool State)
{
SDL_SetWindowBordered(m_pWindow, SDL_bool(State));
}
bool CGraphicsBackend_SDL_OpenGL::SetWindowScreen(int Index)
{
if(Index >= 0 && Index < m_NumScreens)
{
SDL_Rect ScreenPos;
if(SDL_GetDisplayBounds(Index, &ScreenPos) == 0)
{
SDL_SetWindowPosition(m_pWindow, ScreenPos.x, ScreenPos.y);
return true;
}
}
return false;
}
int CGraphicsBackend_SDL_OpenGL::GetWindowScreen()
{
return SDL_GetWindowDisplayIndex(m_pWindow);
}
int CGraphicsBackend_SDL_OpenGL::WindowActive()

View file

@ -91,15 +91,21 @@ class CCommandProcessorFragment_OpenGL
STATE_EMPTY = 0,
STATE_TEX2D = 1,
STATE_TEX3D = 2,
MIN_GL_MAX_3D_TEXTURE_SIZE = 64, // GL_MAX_3D_TEXTURE_SIZE must be at least 64 according to the standard
MAX_ARRAYSIZE_TEX3D = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / MIN_GL_MAX_3D_TEXTURE_SIZE, // = 4
};
GLuint m_Tex2D;
GLuint m_Tex3D;
GLuint m_Tex3D[MAX_ARRAYSIZE_TEX3D];
int m_State;
int m_Format;
int m_MemSize;
};
CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES];
volatile int *m_pTextureMemoryUsage;
int m_MaxTexSize;
int m_Max3DTexSize;
int m_TextureArraySize;
public:
enum
@ -111,6 +117,7 @@ public:
{
SCommand_Init() : SCommand(CMD_INIT) {}
volatile int *m_pTextureMemoryUsage;
int *m_pTextureArraySize;
};
private:
@ -163,6 +170,7 @@ private:
void Cmd_Init(const SCommand_Init *pCommand);
void Cmd_Shutdown(const SCommand_Shutdown *pCommand);
void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand);
void Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand);
void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand);
public:
CCommandProcessorFragment_SDL();
@ -187,14 +195,23 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
SDL_GLContext m_GLContext;
ICommandProcessor *m_pProcessor;
volatile int m_TextureMemoryUsage;
int m_NumScreens;
int m_TextureArraySize;
public:
virtual int Init(const char *pName, int Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight);
virtual int Init(const char *pName, int *Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight);
virtual int Shutdown();
virtual int MemoryUsage() const;
virtual int GetTextureArraySize() const { return m_TextureArraySize; }
virtual int GetNumScreens() const { return m_NumScreens; }
virtual void Minimize();
virtual void Maximize();
virtual bool Fullscreen(bool State); // on=true/off=false
virtual void SetWindowBordered(bool State); // on=true/off=false
virtual bool SetWindowScreen(int Index);
virtual int GetWindowScreen();
virtual int WindowActive();
virtual int WindowOpen();
};

View file

@ -2,6 +2,7 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <new>
#include <immintrin.h> //_mm_pause
#include <stdlib.h> // qsort
#include <stdarg.h>
@ -56,15 +57,15 @@
void CGraph::Init(float Min, float Max)
{
m_Min = Min;
m_Max = Max;
m_MinRange = m_Min = Min;
m_MaxRange = m_Max = Max;
m_Index = 0;
}
void CGraph::ScaleMax()
{
int i = 0;
m_Max = 0;
m_Max = m_MaxRange;
for(i = 0; i < MAX_VALUES; i++)
{
if(m_aValues[i] > m_Max)
@ -75,7 +76,7 @@ void CGraph::ScaleMax()
void CGraph::ScaleMin()
{
int i = 0;
m_Min = m_Max;
m_Min = m_MinRange;
for(i = 0; i < MAX_VALUES; i++)
{
if(m_aValues[i] < m_Min)
@ -239,8 +240,7 @@ void CSmoothTime::Update(CGraph *pGraph, int64 Target, int TimeLeft, int AdjustD
UpdateInt(Target);
}
CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta)
CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta), m_pConLinkIdentifier("teeworlds:")
{
m_pEditor = 0;
m_pInput = 0;
@ -255,6 +255,8 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD
m_RenderFrameTimeHigh = 0.0f;
m_RenderFrames = 0;
m_LastRenderTime = time_get();
m_LastCpuTime = time_get();
m_LastAvgCpuFrameTime = 0;
m_GameTickSpeed = SERVER_TICK_SPEED;
@ -290,8 +292,6 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD
m_MapdownloadAmount = -1;
m_MapdownloadTotalsize = -1;
m_CurrentServerInfoRequestTime = -1;
m_CurrentInput = 0;
m_State = IClient::STATE_OFFLINE;
@ -338,6 +338,7 @@ void CClient::SendInfo()
CMsgPacker Msg(NETMSG_INFO, true);
Msg.AddString(GameClient()->NetVersion(), 128);
Msg.AddString(g_Config.m_Password, 128);
Msg.AddInt(GameClient()->ClientVersion());
SendMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
}
@ -376,20 +377,6 @@ bool CClient::ConnectionProblems() const
return m_NetClient.GotProblems() != 0;
}
void CClient::DirectInput(int *pInput, int Size)
{
CMsgPacker Msg(NETMSG_INPUT, true);
Msg.AddInt(m_AckGameTick);
Msg.AddInt(m_PredTick);
Msg.AddInt(Size);
for(int i = 0; i < Size/4; i++)
Msg.AddInt(pInput[i]);
SendMsg(&Msg, 0);
}
void CClient::SendInput()
{
int64 Now = time_get();
@ -417,6 +404,12 @@ void CClient::SendInput()
for(int i = 0; i < Size/4; i++)
Msg.AddInt(m_aInputs[m_CurrentInput].m_aData[i]);
int PingCorrection = 0;
int64 TagTime;
if(m_SnapshotStorage.Get(m_AckGameTick, &TagTime, 0, 0) >= 0)
PingCorrection = (int)(((Now-TagTime)*1000)/time_freq());
Msg.AddInt(PingCorrection);
m_CurrentInput++;
m_CurrentInput%=200;
@ -506,7 +499,7 @@ void CClient::Connect(const char *pAddress)
str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
ServerInfoRequest();
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
if(net_addr_from_str(&m_ServerAddress, m_aServerAddressStr) != 0 && net_host_lookup(m_aServerAddressStr, &m_ServerAddress, m_NetClient.NetType()) != 0)
{
@ -577,12 +570,6 @@ void CClient::GetServerInfo(CServerInfo *pServerInfo) const
mem_copy(pServerInfo, &m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
}
void CClient::ServerInfoRequest()
{
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
m_CurrentServerInfoRequestTime = 0;
}
int CClient::LoadData()
{
m_DebugFont = Graphics()->LoadTexture("ui/debug_font.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, IGraphics::TEXLOAD_NORESAMPLE);
@ -685,10 +672,8 @@ void CClient::DebugRender()
total = 42
*/
FrameTimeAvg = FrameTimeAvg*0.9f + m_RenderFrameTime*0.1f;
str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d mem %dk %d gfxmem: %dk fps: %3d",
str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d gfxmem: %dk fps: %3d",
m_CurGameTick, m_PredTick,
mem_stats()->allocated/1024,
mem_stats()->total_allocations,
Graphics()->MemoryUsage()/1024,
(int)(1.0f/FrameTimeAvg + 0.5f));
Graphics()->QuadsText(2, 2, 16, aBuffer);
@ -743,7 +728,11 @@ void CClient::DebugRender()
m_FpsGraph.ScaleMax();
m_FpsGraph.ScaleMin();
m_FpsGraph.Render(Graphics(), m_DebugFont, x, sp*5, w, h, "FPS");
m_InputtimeMarginGraph.ScaleMin();
m_InputtimeMarginGraph.ScaleMax();
m_InputtimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp, w, h, "Prediction Margin");
m_GametimeMarginGraph.ScaleMin();
m_GametimeMarginGraph.ScaleMax();
m_GametimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp+h+sp, w, h, "Gametime Margin");
}
}
@ -837,9 +826,9 @@ int CClient::PlayerScoreComp(const void *a, const void *b)
{
CServerInfo::CClient *p0 = (CServerInfo::CClient *)a;
CServerInfo::CClient *p1 = (CServerInfo::CClient *)b;
if(p0->m_Player && !p1->m_Player)
if(!(p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && (p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
return -1;
if(!p0->m_Player && p1->m_Player)
if((p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && !(p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
return 1;
if(p0->m_Score == p1->m_Score)
return 0;
@ -848,6 +837,68 @@ int CClient::PlayerScoreComp(const void *a, const void *b)
return -1;
}
int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pToken)
{
if(pToken)
*pToken = pUnpacker->GetInt();
str_copy(pInfo->m_aVersion, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aVersion));
str_copy(pInfo->m_aName, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aName));
str_clean_whitespaces(pInfo->m_aName);
str_copy(pInfo->m_aHostname, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aHostname));
if(pInfo->m_aHostname[0] == 0)
str_copy(pInfo->m_aHostname, pInfo->m_aAddress, sizeof(pInfo->m_aHostname));
str_copy(pInfo->m_aMap, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aMap));
str_copy(pInfo->m_aGameType, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aGameType));
pInfo->m_Flags = (pUnpacker->GetInt()&SERVERINFO_FLAG_PASSWORD) ? IServerBrowser::FLAG_PASSWORD : 0;
pInfo->m_ServerLevel = clamp<int>(pUnpacker->GetInt(), SERVERINFO_LEVEL_MIN, SERVERINFO_LEVEL_MAX);
pInfo->m_NumPlayers = pUnpacker->GetInt();
pInfo->m_MaxPlayers = pUnpacker->GetInt();
pInfo->m_NumClients = pUnpacker->GetInt();
pInfo->m_MaxClients = pUnpacker->GetInt();
pInfo->m_NumBotPlayers = 0;
pInfo->m_NumBotSpectators = 0;
// don't add invalid info to the server browser list
if(pInfo->m_NumClients < 0 || pInfo->m_NumClients > pInfo->m_MaxClients || pInfo->m_MaxClients < 0 || pInfo->m_MaxClients > MAX_CLIENTS ||
pInfo->m_NumPlayers < 0 || pInfo->m_NumPlayers > pInfo->m_NumClients || pInfo->m_MaxPlayers < 0 || pInfo->m_MaxPlayers > pInfo->m_MaxClients)
return -1;
// drop standard gametype with more than MAX_PLAYERS
if(pInfo->m_MaxPlayers > MAX_PLAYERS && (str_comp(pInfo->m_aGameType, "DM") == 0 || str_comp(pInfo->m_aGameType, "TDM") == 0 || str_comp(pInfo->m_aGameType, "CTF") == 0 ||
str_comp(pInfo->m_aGameType, "LTS") == 0 || str_comp(pInfo->m_aGameType, "LMS") == 0))
return -1;
// use short version
if(!pToken)
return 0;
int NumPlayers = 0;
int NumClients = 0;
for(int i = 0; i < pInfo->m_NumClients; i++)
{
str_copy(pInfo->m_aClients[i].m_aName, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aName));
str_copy(pInfo->m_aClients[i].m_aClan, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aClan));
pInfo->m_aClients[i].m_Country = pUnpacker->GetInt();
pInfo->m_aClients[i].m_Score = pUnpacker->GetInt();
pInfo->m_aClients[i].m_PlayerType = pUnpacker->GetInt()&CServerInfo::CClient::PLAYERFLAG_MASK;
if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_BOT)
{
if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)
pInfo->m_NumBotSpectators++;
else
pInfo->m_NumBotPlayers++;
}
NumClients++;
if(!(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
NumPlayers++;
}
pInfo->m_NumPlayers = NumPlayers;
pInfo->m_NumClients = NumClients;
return 0;
}
void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
{
// version server
@ -884,7 +935,7 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
Packet.m_pData = VERSIONSRV_GETMAPLIST;
Packet.m_DataSize = sizeof(VERSIONSRV_GETMAPLIST);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient.Send(&Packet);
m_ContactClient.Send(&Packet);
}
// map version list
@ -951,56 +1002,14 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
// server info
if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_INFO) && mem_comp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
{
// we got ze info
CUnpacker Up;
CServerInfo Info = {0};
Up.Reset((unsigned char*)pPacket->m_pData+sizeof(SERVERBROWSE_INFO), pPacket->m_DataSize-sizeof(SERVERBROWSE_INFO));
int Token = Up.GetInt();
str_copy(Info.m_aVersion, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aVersion));
str_copy(Info.m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aName));
str_copy(Info.m_aHostname, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aHostname));
str_copy(Info.m_aMap, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aMap));
str_copy(Info.m_aGameType, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aGameType));
Info.m_Flags = (Up.GetInt()&SERVERINFO_FLAG_PASSWORD) ? IServerBrowser::FLAG_PASSWORD : 0;
Info.m_ServerLevel = clamp<int>(Up.GetInt(), SERVERINFO_LEVEL_MIN, SERVERINFO_LEVEL_MAX);
Info.m_NumPlayers = Up.GetInt();
Info.m_MaxPlayers = Up.GetInt();
Info.m_NumClients = Up.GetInt();
Info.m_MaxClients = Up.GetInt();
// don't add invalid info to the server browser list
if(Info.m_NumClients < 0 || Info.m_NumClients > MAX_CLIENTS || Info.m_MaxClients < 0 || Info.m_MaxClients > MAX_CLIENTS ||
Info.m_NumPlayers < 0 || Info.m_NumPlayers > Info.m_NumClients || Info.m_MaxPlayers < 0 || Info.m_MaxPlayers > Info.m_MaxClients)
return;
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true);
if(Info.m_aHostname[0] == 0)
str_copy(Info.m_aHostname, Info.m_aAddress, sizeof(Info.m_aHostname));
for(int i = 0; i < Info.m_NumClients; i++)
int Token;
if(!UnpackServerInfo(&Up, &Info, &Token) && !Up.Error())
{
str_copy(Info.m_aClients[i].m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aName));
str_copy(Info.m_aClients[i].m_aClan, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aClan));
Info.m_aClients[i].m_Country = Up.GetInt();
Info.m_aClients[i].m_Score = Up.GetInt();
Info.m_aClients[i].m_Player = Up.GetInt() != 0 ? true : false;
}
str_clean_whitespaces(Info.m_aName);
if(!Up.Error())
{
// sort players
qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp);
if(net_addr_comp(&m_ServerAddress, &pPacket->m_Address) == 0)
{
mem_copy(&m_CurrentServerInfo, &Info, sizeof(m_CurrentServerInfo));
m_CurrentServerInfo.m_NetAddr = m_ServerAddress;
m_CurrentServerInfoRequestTime = -1;
}
else
m_ServerBrowser.Set(pPacket->m_Address, CServerBrowser::SET_TOKEN, Token, &Info);
}
}
@ -1022,7 +1031,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(Sys)
{
// system message
if(Msg == NETMSG_MAP_CHANGE)
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_CHANGE)
{
const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES);
int MapCrc = Unpacker.GetInt();
@ -1088,7 +1097,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
}
}
}
else if(Msg == NETMSG_MAP_DATA)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_DATA)
{
if(!m_MapdownloadFile)
return;
@ -1133,7 +1142,18 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package");
}
}
else if(Msg == NETMSG_CON_READY)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_SERVERINFO)
{
CServerInfo Info = {0};
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true);
if(!UnpackServerInfo(&Unpacker, &Info, 0) && !Unpacker.Error())
{
qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp);
mem_copy(&m_CurrentServerInfo, &Info, sizeof(m_CurrentServerInfo));
m_CurrentServerInfo.m_NetAddr = m_ServerAddress;
}
}
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_CON_READY)
{
GameClient()->OnConnected();
}
@ -1142,7 +1162,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
CMsgPacker Msg(NETMSG_PING_REPLY, true);
SendMsg(&Msg, 0);
}
else if(Msg == NETMSG_RCON_CMD_ADD)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_ADD)
{
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC);
@ -1150,25 +1170,25 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(Unpacker.Error() == 0)
m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp);
}
else if(Msg == NETMSG_RCON_CMD_REM)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_REM)
{
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(Unpacker.Error() == 0)
m_pConsole->DeregisterTemp(pName);
}
else if(Msg == NETMSG_RCON_AUTH_ON)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_ON)
{
m_RconAuthed = 1;
m_UseTempRconCommands = 1;
}
else if(Msg == NETMSG_RCON_AUTH_OFF)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_OFF)
{
m_RconAuthed = 0;
if(m_UseTempRconCommands)
m_pConsole->DeregisterTempAll();
m_UseTempRconCommands = 0;
}
else if(Msg == NETMSG_RCON_LINE)
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_LINE)
{
const char *pLine = Unpacker.GetString();
if(Unpacker.Error() == 0)
@ -1229,7 +1249,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
pData = (const char *)Unpacker.GetRaw(PartSize);
if(Unpacker.Error())
if(Unpacker.Error() || NumParts < 1 || NumParts > CSnapshot::MAX_PARTS || Part < 0 || Part >= NumParts || PartSize < 0 || PartSize > MAX_SNAPSHOT_PACKSIZE)
return;
if(GameTick >= m_CurrentRecvTick)
@ -1293,7 +1313,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(CompleteSize)
{
int IntSize = CVariableInt::Decompress(m_aSnapshotIncommingData, CompleteSize, aTmpBuffer2);
int IntSize = CVariableInt::Decompress(m_aSnapshotIncommingData, CompleteSize, aTmpBuffer2, sizeof(aTmpBuffer2));
if(IntSize < 0) // failure during decompression, bail
return;
@ -1373,7 +1393,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_GameTime.Init((GameTick-1)*time_freq()/50);
m_aSnapshots[SNAP_PREV] = m_SnapshotStorage.m_pFirst;
m_aSnapshots[SNAP_CURRENT] = m_SnapshotStorage.m_pLast;
m_LocalStartTime = time_get();
SetState(IClient::STATE_ONLINE);
DemoRecorder_HandleAutoStart();
}
@ -1394,6 +1413,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
}
}
else
{
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0)
{
// game message
GameClient()->OnMessage(Msg, &Unpacker);
@ -1402,6 +1423,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize);
}
}
}
void CClient::PumpNetwork()
{
@ -1429,15 +1451,21 @@ void CClient::PumpNetwork()
}
}
// process packets
// process non-connless packets
CNetChunk Packet;
while(m_NetClient.Recv(&Packet))
{
if(Packet.m_ClientID == -1)
ProcessConnlessPacket(&Packet);
else
if(!(Packet.m_Flags&NETSENDFLAG_CONNLESS))
ProcessServerPacket(&Packet);
}
// process connless packets data
m_ContactClient.Update();
while(m_ContactClient.Recv(&Packet))
{
if(Packet.m_Flags&NETSENDFLAG_CONNLESS)
ProcessConnlessPacket(&Packet);
}
}
void CClient::OnDemoPlayerSnapshot(void *pData, int Size)
@ -1601,15 +1629,6 @@ void CClient::Update()
if(m_PredTick > m_CurGameTick && m_PredTick < m_CurGameTick+50)
GameClient()->OnPredict();
}
// fetch server info if we don't have it
if(State() >= IClient::STATE_LOADING &&
m_CurrentServerInfoRequestTime >= 0 &&
time_get() > m_CurrentServerInfoRequestTime)
{
m_ServerBrowser.Request(m_ServerAddress);
m_CurrentServerInfoRequestTime = time_get()+time_freq()*2;
}
}
// STRESS TEST: join the server again
@ -1646,18 +1665,24 @@ void CClient::Update()
// update the server browser
m_ServerBrowser.Update(m_ResortServerBrowser);
m_ResortServerBrowser = false;
// update gameclient
if(!m_EditorActive)
GameClient()->OnUpdate();
}
void CClient::VersionUpdate()
{
if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT)
{
Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_NetClient.NetType());
Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_ContactClient.NetType());
m_VersionInfo.m_State = CVersionInfo::STATE_START;
}
else if(m_VersionInfo.m_State == CVersionInfo::STATE_START)
{
if(m_VersionInfo.m_VersionServeraddr.m_Job.Status() == CJob::STATE_DONE)
{
if(m_VersionInfo.m_VersionServeraddr.m_Job.Result() == 0)
{
CNetChunk Packet;
@ -1671,9 +1696,12 @@ void CClient::VersionUpdate()
Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient.Send(&Packet);
m_ContactClient.Send(&Packet);
m_VersionInfo.m_State = CVersionInfo::STATE_READY;
}
else
m_VersionInfo.m_State = CVersionInfo::STATE_ERROR;
}
}
}
@ -1699,10 +1727,90 @@ void CClient::InitInterfaces()
m_pStorage = Kernel()->RequestInterface<IStorage>();
//
m_ServerBrowser.SetBaseInfo(&m_NetClient, m_pGameClient->NetVersion());
m_ServerBrowser.Init(&m_ContactClient, m_pGameClient->NetVersion());
m_Friends.Init();
}
bool CClient::LimitFps()
{
if(g_Config.m_GfxVsync || !g_Config.m_GfxLimitFps) return false;
/**
If desired frame time is not reached:
Skip rendering the frame
Do another game loop
If we don't have the time to do another game loop:
Wait until desired frametime
Returns true if frame should be skipped
**/
#ifdef CONF_DEBUG
static double DbgTimeWaited = 0.0;
static int64 DbgFramesSkippedCount = 0;
static int64 DbgLastSkippedDbgMsg = time_get();
#endif
int64 Now = time_get();
const double LastCpuFrameTime = (Now - m_LastCpuTime) / (double)time_freq();
m_LastAvgCpuFrameTime = (m_LastAvgCpuFrameTime + LastCpuFrameTime * 4.0) / 5.0;
m_LastCpuTime = Now;
bool SkipFrame = true;
double RenderDeltaTime = (Now - m_LastRenderTime) / (double)time_freq();
const double DesiredTime = 1.0/g_Config.m_GfxMaxFps;
// we can't skip another frame, so wait instead
if(SkipFrame && RenderDeltaTime < DesiredTime &&
m_LastAvgCpuFrameTime * 1.20 > (DesiredTime - RenderDeltaTime))
{
#ifdef CONF_DEBUG
DbgTimeWaited += DesiredTime - RenderDeltaTime;
#endif
const double Freq = (double)time_freq();
const int64 LastT = m_LastRenderTime;
double d = DesiredTime - RenderDeltaTime;
while(d > 0.00001)
{
Now = time_get();
RenderDeltaTime = (Now - LastT) / Freq;
d = DesiredTime - RenderDeltaTime;
_mm_pause();
}
SkipFrame = false;
m_LastCpuTime = Now;
}
// RenderDeltaTime exceeds DesiredTime, render
if(SkipFrame && RenderDeltaTime > DesiredTime)
{
SkipFrame = false;
}
#ifdef CONF_DEBUG
DbgFramesSkippedCount += SkipFrame? 1:0;
Now = time_get();
if(g_Config.m_GfxLimitFps &&
g_Config.m_Debug &&
(Now - DbgLastSkippedDbgMsg) / (double)time_freq() > 5.0)
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "LimitFps: FramesSkippedCount=%d TimeWaited=%.3f (per sec)",
DbgFramesSkippedCount/5,
DbgTimeWaited/5.0);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", aBuf);
DbgFramesSkippedCount = 0;
DbgTimeWaited = 0;
DbgLastSkippedDbgMsg = Now;
}
#endif
return SkipFrame;
}
void CClient::Run()
{
m_LocalStartTime = time_get();
@ -1753,9 +1861,15 @@ void CClient::Run()
mem_zero(&BindAddr, sizeof(BindAddr));
BindAddr.type = NETTYPE_ALL;
}
if(!m_NetClient.Open(BindAddr, 0))
if(!m_NetClient.Open(BindAddr, BindAddr.port ? 0 : NETCREATE_FLAG_RANDOMPORT))
{
dbg_msg("client", "couldn't open socket");
dbg_msg("client", "couldn't open socket(net)");
return;
}
BindAddr.port = 0;
if(!m_ContactClient.Open(BindAddr, 0))
{
dbg_msg("client", "couldn't open socket(contact)");
return;
}
}
@ -1767,7 +1881,7 @@ void CClient::Run()
Input()->Init();
// start refreshing addresses while we load
MasterServer()->RefreshAddresses(m_NetClient.NetType());
MasterServer()->RefreshAddresses(m_ContactClient.NetType());
// init the editor
m_pEditor->Init();
@ -1783,21 +1897,12 @@ void CClient::Run()
str_format(aBuf, sizeof(aBuf), "version %s", GameClient()->NetVersion());
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
// connect to the server if wanted
/*
if(config.cl_connect[0] != 0)
Connect(config.cl_connect);
config.cl_connect[0] = 0;
*/
//
m_FpsGraph.Init(0.0f, 200.0f);
m_FpsGraph.Init(0.0f, 120.0f);
// never start with the editor
g_Config.m_ClEditor = 0;
Input()->MouseModeRelative();
// process pending commands
m_pConsole->StoreCommands(false);
@ -1828,7 +1933,7 @@ void CClient::Run()
Input()->MouseModeAbsolute();
m_WindowMustRefocus = 1;
}
else if (g_Config.m_DbgFocus && Input()->KeyPressed(KEY_ESCAPE))
else if (g_Config.m_DbgFocus && Input()->KeyPress(KEY_ESCAPE, true))
{
Input()->MouseModeAbsolute();
m_WindowMustRefocus = 1;
@ -1843,37 +1948,37 @@ void CClient::Run()
m_WindowMustRefocus++;
}
if(m_WindowMustRefocus >= 3 || Input()->KeyPressed(KEY_MOUSE_1))
if(m_WindowMustRefocus >= 3 || Input()->KeyPress(KEY_MOUSE_1, true))
{
Input()->MouseModeRelative();
m_WindowMustRefocus = 0;
// update screen in case it got moved
int ActScreen = Graphics()->GetWindowScreen();
if(ActScreen >= 0 && ActScreen != g_Config.m_GfxScreen)
g_Config.m_GfxScreen = ActScreen;
}
}
// panic quit button
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyPressed(KEY_Q))
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_Q, true))
{
Quit();
break;
}
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_D))
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_D, true))
g_Config.m_Debug ^= 1;
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_G))
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_G, true))
g_Config.m_DbgGraphs ^= 1;
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_E))
if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_E, true))
{
g_Config.m_ClEditor = g_Config.m_ClEditor^1;
Input()->MouseModeRelative();
}
/*
if(!gfx_window_open())
break;
*/
// render
{
if(g_Config.m_ClEditor)
@ -1889,13 +1994,16 @@ void CClient::Run()
Update();
if(!g_Config.m_GfxAsyncRender || m_pGraphics->IsIdle())
const bool SkipFrame = LimitFps();
if(!SkipFrame && (!g_Config.m_GfxAsyncRender || m_pGraphics->IsIdle()))
{
m_RenderFrames++;
// update frametime
int64 Now = time_get();
m_RenderFrameTime = (Now - m_LastRenderTime) / (float)time_freq();
if(m_RenderFrameTime < m_RenderFrameTimeLow)
m_RenderFrameTimeLow = m_RenderFrameTime;
if(m_RenderFrameTime > m_RenderFrameTimeHigh)
@ -1972,6 +2080,8 @@ void CClient::Run()
m_pGraphics->Shutdown();
m_pSound->Shutdown();
m_ServerBrowser.SaveServerlist();
// shutdown SDL
{
SDL_Quit();
@ -2193,6 +2303,89 @@ void CClient::ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUse
((CClient *)pUserData)->ServerBrowserUpdate();
}
void CClient::SwitchWindowScreen(int Index)
{
// Todo SDL: remove this when fixed (changing screen when in fullscreen is bugged)
if(g_Config.m_GfxFullscreen)
{
ToggleFullscreen();
if(Graphics()->SetWindowScreen(Index))
g_Config.m_GfxScreen = Index;
ToggleFullscreen();
}
else
{
if(Graphics()->SetWindowScreen(Index))
g_Config.m_GfxScreen = Index;
}
}
void CClient::ConchainWindowScreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxScreen != pResult->GetInteger(0))
pSelf->SwitchWindowScreen(pResult->GetInteger(0));
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleFullscreen()
{
if(Graphics()->Fullscreen(g_Config.m_GfxFullscreen^1))
g_Config.m_GfxFullscreen ^= 1;
}
void CClient::ConchainFullscreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxFullscreen != pResult->GetInteger(0))
pSelf->ToggleFullscreen();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleWindowBordered()
{
g_Config.m_GfxBorderless ^= 1;
Graphics()->SetWindowBordered(!g_Config.m_GfxBorderless);
}
void CClient::ConchainWindowBordered(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(!g_Config.m_GfxFullscreen && (g_Config.m_GfxBorderless != pResult->GetInteger(0)))
pSelf->ToggleWindowBordered();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleWindowVSync()
{
if(Graphics()->SetVSync(g_Config.m_GfxVsync^1))
g_Config.m_GfxVsync ^= 1;
}
void CClient::ConchainWindowVSync(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxVsync != pResult->GetInteger(0))
pSelf->ToggleWindowVSync();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::RegisterCommands()
{
m_pConsole = Kernel()->RequestInterface<IConsole>();
@ -2213,8 +2406,11 @@ void CClient::RegisterCommands()
// used for server browser update
m_pConsole->Chain("br_filter_string", ConchainServerBrowserUpdate, this);
m_pConsole->Chain("br_filter_gametype", ConchainServerBrowserUpdate, this);
m_pConsole->Chain("br_filter_serveraddress", ConchainServerBrowserUpdate, this);
m_pConsole->Chain("gfx_screen", ConchainWindowScreen, this);
m_pConsole->Chain("gfx_fullscreen", ConchainFullscreen, this);
m_pConsole->Chain("gfx_borderless", ConchainWindowBordered, this);
m_pConsole->Chain("gfx_vsync", ConchainWindowVSync, this);
}
static CClient *CreateClient()
@ -2224,6 +2420,11 @@ static CClient *CreateClient()
return new(pClient) CClient;
}
void CClient::HandleTeeworldsConnectLink(const char *pConLink)
{
str_copy(m_aCmdConnect, pConLink, sizeof(m_aCmdConnect));
}
/*
Server Time
Client Mirror Time
@ -2235,7 +2436,6 @@ static CClient *CreateClient()
Prediction Latency
Upstream latency
*/
#if defined(CONF_PLATFORM_MACOSX)
extern "C" int SDL_main(int argc, char **argv_) // ignore_convention
{
@ -2245,14 +2445,27 @@ int main(int argc, const char **argv) // ignore_convention
{
#endif
#if defined(CONF_FAMILY_WINDOWS)
#ifdef CONF_RELEASE
bool HideConsole = true;
#else
bool HideConsole = false;
#endif
for(int i = 1; i < argc; i++) // ignore_convention
{
if(str_comp("-c", argv[i]) == 0 || str_comp("--console", argv[i]) == 0) // ignore_convention
{
HideConsole = false;
break;
}
if(str_comp("-s", argv[i]) == 0 || str_comp("--silent", argv[i]) == 0) // ignore_convention
{
FreeConsole();
HideConsole = true;
break;
}
}
if(HideConsole)
FreeConsole();
#endif
bool UseDefaultConfig = false;
@ -2335,9 +2548,26 @@ int main(int argc, const char **argv) // ignore_convention
// parse the command line arguments
if(argc > 1) // ignore_convention
{
switch(argc) // ignore_convention
{
case 2:
{
// handle Teeworlds connect link
const int Length = str_length(pClient->m_pConLinkIdentifier);
if(str_comp_num(pClient->m_pConLinkIdentifier, argv[1], Length) == 0) // ignore_convention
{
pClient->HandleTeeworldsConnectLink(argv[1] + Length); // ignore_convention
break;
}
}
default:
pConsole->ParseArguments(argc - 1, &argv[1]); // ignore_convention
}
}
}
// restore empty config strings to their defaults
pConfig->RestoreStrings();

View file

@ -13,6 +13,7 @@ public:
};
float m_Min, m_Max;
float m_MinRange, m_MaxRange;
float m_aValues[MAX_VALUES];
float m_aColors[MAX_VALUES][3];
int m_Index;
@ -70,6 +71,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
};
class CNetClient m_NetClient;
class CNetClient m_ContactClient;
class CDemoPlayer m_DemoPlayer;
class CDemoRecorder m_DemoRecorder;
class CServerBrowser m_ServerBrowser;
@ -84,6 +86,8 @@ class CClient : public IClient, public CDemoPlayer::IListner
IGraphics::CTextureHandle m_DebugFont;
int64 m_LastRenderTime;
int64 m_LastCpuTime;
float m_LastAvgCpuFrameTime;
float m_RenderFrameTimeLow;
float m_RenderFrameTimeHigh;
int m_RenderFrames;
@ -161,7 +165,6 @@ class CClient : public IClient, public CDemoPlayer::IListner
//
class CServerInfo m_CurrentServerInfo;
int64 m_CurrentServerInfoRequestTime; // >= 0 should request, == -1 got info
// version info
struct CVersionInfo
@ -171,6 +174,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
STATE_INIT=0,
STATE_START,
STATE_READY,
STATE_ERROR,
};
int m_State;
@ -208,7 +212,6 @@ public:
virtual IGraphics::CTextureHandle GetDebugFont() const { return m_DebugFont; }
void DirectInput(int *pInput, int Size);
void SendInput();
// TODO: OPT: do this alot smarter!
@ -230,7 +233,6 @@ public:
virtual void GetServerInfo(CServerInfo *pServerInfo) const;
void ServerInfoRequest();
int LoadData();
@ -255,9 +257,11 @@ public:
static int PlayerScoreComp(const void *a, const void *b);
int UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pToken);
void ProcessConnlessPacket(CNetChunk *pPacket);
void ProcessServerPacket(CNetChunk *pPacket);
virtual const char *MapDownloadName() const { return m_aMapdownloadName; }
virtual int MapDownloadAmount() const { return m_MapdownloadAmount; }
virtual int MapDownloadTotalsize() const { return m_MapdownloadTotalsize; }
@ -271,6 +275,7 @@ public:
void RegisterInterfaces();
void InitInterfaces();
bool LimitFps();
void Run();
@ -289,6 +294,10 @@ public:
static void Con_StopRecord(IConsole::IResult *pResult, void *pUserData);
static void Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData);
static void ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainFullscreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowBordered(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowScreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowVSync(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
void RegisterCommands();
@ -303,5 +312,15 @@ public:
void AutoScreenshot_Cleanup();
void ServerBrowserUpdate();
// gfx
void SwitchWindowScreen(int Index);
void ToggleFullscreen();
void ToggleWindowBordered();
void ToggleWindowVSync();
// Teeworlds connect link
const char * const m_pConLinkIdentifier;
void HandleTeeworldsConnectLink(const char *pConLink);
};
#endif

View file

@ -264,20 +264,22 @@ void CGraphics_Threaded::LinesDraw(const CLineItem *pArray, int Num)
AddVertices(2*Num);
}
int CGraphics_Threaded::UnloadTexture(CTextureHandle Index)
int CGraphics_Threaded::UnloadTexture(CTextureHandle *Index)
{
if(Index.Id() == m_InvalidTexture.Id())
if(Index->Id() == m_InvalidTexture.Id())
return 0;
if(!Index.IsValid())
if(!Index->IsValid())
return 0;
CCommandBuffer::SCommand_Texture_Destroy Cmd;
Cmd.m_Slot = Index.Id();
Cmd.m_Slot = Index->Id();
m_pCommandBuffer->AddCommand(Cmd);
m_aTextureIndices[Index.Id()] = m_FirstFreeTexture;
m_FirstFreeTexture = Index.Id();
m_aTextureIndices[Index->Id()] = m_FirstFreeTexture;
m_FirstFreeTexture = Index->Id();
Index->Invalidate();
return 0;
}
@ -358,6 +360,8 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
}
if(Flags&IGraphics::TEXLOAD_MULTI_DIMENSION)
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_TEXTURE3D;
if(Flags&IGraphics::TEXLOAD_LINEARMIPMAPS)
Cmd.m_Flags |= CCommandBuffer::TEXTFLAG_LINEARMIPMAPS;
// copy texture data
@ -424,7 +428,7 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto
return 0;
}
if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA)) // ignore_convention
if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA) || Png.width > (2<<12) || Png.height > (2<<12)) // ignore_convention
{
dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename);
png_close_file(&Png); // ignore_convention
@ -463,6 +467,8 @@ void CGraphics_Threaded::ScreenshotDirect(const char *pFilename)
CCommandBuffer::SCommand_Screenshot Cmd;
Cmd.m_pImage = &Image;
Cmd.m_X = 0; Cmd.m_Y = 0;
Cmd.m_W = -1; Cmd.m_H = -1;
m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result
@ -516,6 +522,7 @@ void CGraphics_Threaded::QuadsBegin()
QuadsSetSubset(0,0,1,1,-1);
QuadsSetRotation(0);
SetColor(1,1,1,1);
m_TextureArrayIndex = m_pBackend->GetTextureArraySize() > 1 ? -1 : 0;
}
void CGraphics_Threaded::QuadsEnd()
@ -566,17 +573,36 @@ void CGraphics_Threaded::SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft,
SetColorVertex(Array, 4);
}
void CGraphics_Threaded::TilesetFallbackSystem(int TextureIndex)
{
int NewTextureArrayIndex = TextureIndex / (256 / m_pBackend->GetTextureArraySize());
if(m_TextureArrayIndex == -1)
m_TextureArrayIndex = NewTextureArrayIndex;
else if(m_TextureArrayIndex != NewTextureArrayIndex)
{
// have to switch the texture index
FlushVertices();
m_TextureArrayIndex = NewTextureArrayIndex;
}
}
void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex)
{
dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin");
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = TlU; m_aTexture[1].u = BrU;
m_aTexture[0].v = TlV; m_aTexture[1].v = TlV;
m_aTexture[3].u = TlU; m_aTexture[2].u = BrU;
m_aTexture[3].v = BrV; m_aTexture[2].v = BrV;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
}
@ -584,12 +610,18 @@ void CGraphics_Threaded::QuadsSetSubsetFree(
float x0, float y0, float x1, float y1,
float x2, float y2, float x3, float y3, int TextureIndex)
{
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = x0; m_aTexture[0].v = y0;
m_aTexture[1].u = x1; m_aTexture[1].v = y1;
m_aTexture[2].u = x2; m_aTexture[2].v = y2;
m_aTexture[3].u = x3; m_aTexture[3].v = y3;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
}
@ -707,18 +739,12 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, const char *pTe
int CGraphics_Threaded::IssueInit()
{
int Flags = 0;
if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen)
{
dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless");
g_Config.m_GfxBorderless = 0;
}
if(g_Config.m_GfxBorderless) Flags |= IGraphicsBackend::INITFLAG_BORDERLESS;
else if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN;
if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN;
if(g_Config.m_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC;
if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE;
return m_pBackend->Init("Teeworlds", g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight);
return m_pBackend->Init("Teeworlds", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight);
}
int CGraphics_Threaded::InitWindow()
@ -839,6 +865,11 @@ void CGraphics_Threaded::Shutdown()
delete m_apCommandBuffers[i];
}
int CGraphics_Threaded::GetNumScreens() const
{
return m_pBackend->GetNumScreens();
}
void CGraphics_Threaded::Minimize()
{
m_pBackend->Minimize();
@ -846,10 +877,29 @@ void CGraphics_Threaded::Minimize()
void CGraphics_Threaded::Maximize()
{
// TODO: SDL
m_pBackend->Maximize();
}
bool CGraphics_Threaded::Fullscreen(bool State)
{
return m_pBackend->Fullscreen(State);
}
void CGraphics_Threaded::SetWindowBordered(bool State)
{
m_pBackend->SetWindowBordered(State);
}
bool CGraphics_Threaded::SetWindowScreen(int Index)
{
return m_pBackend->SetWindowScreen(Index);
}
int CGraphics_Threaded::GetWindowScreen()
{
return m_pBackend->GetWindowScreen();
}
int CGraphics_Threaded::WindowActive()
{
return m_pBackend->WindowActive();
@ -861,6 +911,28 @@ int CGraphics_Threaded::WindowOpen()
}
void CGraphics_Threaded::ReadBackbuffer(unsigned char **ppPixels, int x, int y, int w, int h)
{
if(!ppPixels)
return;
// add swap command
CImageInfo Image;
mem_zero(&Image, sizeof(Image));
CCommandBuffer::SCommand_Screenshot Cmd;
Cmd.m_pImage = &Image;
Cmd.m_X = x; Cmd.m_Y = y;
Cmd.m_W = w; Cmd.m_H = h;
m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result
KickCommandBuffer();
WaitForIdle();
*ppPixels = (unsigned char *)Image.m_pData; // take ownership!
}
void CGraphics_Threaded::TakeScreenshot(const char *pFilename)
{
// TODO: screenshot support
@ -889,6 +961,21 @@ void CGraphics_Threaded::Swap()
KickCommandBuffer();
}
bool CGraphics_Threaded::SetVSync(bool State)
{
// add vsnc command
bool RetOk = 0;
CCommandBuffer::SCommand_VSync Cmd;
Cmd.m_VSync = State ? 1 : 0;
Cmd.m_pRetOk = &RetOk;
m_pCommandBuffer->AddCommand(Cmd);
// kick the command buffer
KickCommandBuffer();
WaitForIdle();
return RetOk;
}
// syncronization
void CGraphics_Threaded::InsertSignal(semaphore *pSemaphore)
{
@ -923,10 +1010,11 @@ int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes, int Scre
mem_zero(&Image, sizeof(Image));
int NumModes = 0;
CCommandBuffer::SCommand_VideoModes Cmd(Screen);
CCommandBuffer::SCommand_VideoModes Cmd;
Cmd.m_pModes = pModes;
Cmd.m_MaxModes = MaxModes;
Cmd.m_pNumModes = &NumModes;
Cmd.m_Screen = Screen;
m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result and return it

View file

@ -82,6 +82,7 @@ public:
CMD_SWAP,
// misc
CMD_VSYNC,
CMD_SCREENSHOT,
CMD_VIDEOMODES,
@ -99,6 +100,7 @@ public:
TEXFLAG_QUALITY = 4,
TEXFLAG_TEXTURE3D = 8,
TEXFLAG_TEXTURE2D = 16,
TEXTFLAG_LINEARMIPMAPS = 32,
};
enum
@ -141,6 +143,7 @@ public:
int m_WrapModeU;
int m_WrapModeV;
int m_Texture;
int m_TextureArrayIndex;
int m_Dimension;
SPoint m_ScreenTL;
SPoint m_ScreenBR;
@ -183,13 +186,13 @@ public:
struct SCommand_Screenshot : public SCommand
{
SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {}
int m_X, m_Y, m_W, m_H; // specify rectangle size, -1 if fullscreen (width/height)
CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well
};
struct SCommand_VideoModes : public SCommand
{
SCommand_VideoModes(int screen) : SCommand(CMD_VIDEOMODES),
m_Screen(screen) {}
SCommand_VideoModes() : SCommand(CMD_VIDEOMODES) {}
CVideoMode *m_pModes; // processor will fill this in
int m_MaxModes; // maximum of modes the processor can write to the m_pModes
@ -204,6 +207,14 @@ public:
int m_Finish;
};
struct SCommand_VSync : public SCommand
{
SCommand_VSync() : SCommand(CMD_VSYNC) {}
int m_VSync;
bool *m_pRetOk;
};
struct SCommand_Texture_Create : public SCommand
{
SCommand_Texture_Create() : SCommand(CMD_TEXTURE_CREATE) {}
@ -302,13 +313,20 @@ public:
virtual ~IGraphicsBackend() {}
virtual int Init(const char *pName, int Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight) = 0;
virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight) = 0;
virtual int Shutdown() = 0;
virtual int MemoryUsage() const = 0;
virtual int GetTextureArraySize() const = 0;
virtual int GetNumScreens() const = 0;
virtual void Minimize() = 0;
virtual void Maximize() = 0;
virtual bool Fullscreen(bool State) = 0;
virtual void SetWindowBordered(bool State) = 0;
virtual bool SetWindowScreen(int Index) = 0;
virtual int GetWindowScreen() = 0;
virtual int WindowActive() = 0;
virtual int WindowOpen() = 0;
@ -356,6 +374,7 @@ class CGraphics_Threaded : public IEngineGraphics
CTextureHandle m_InvalidTexture;
int m_TextureArrayIndex;
int m_aTextureIndices[MAX_TEXTURES];
int m_FirstFreeTexture;
int m_TextureMemoryUsage;
@ -391,7 +410,7 @@ public:
virtual void LinesEnd();
virtual void LinesDraw(const CLineItem *pArray, int Num);
virtual int UnloadTexture(IGraphics::CTextureHandle Index);
virtual int UnloadTexture(IGraphics::CTextureHandle *Index);
virtual IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags);
virtual int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData);
@ -413,6 +432,7 @@ public:
virtual void SetColor(float r, float g, float b, float a);
virtual void SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, vec4 BottomRight);
void TilesetFallbackSystem(int TextureIndex);
virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex = -1);
virtual void QuadsSetSubsetFree(
float x0, float y0, float x1, float y1,
@ -423,8 +443,13 @@ public:
virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num);
virtual void QuadsText(float x, float y, float Size, const char *pText);
virtual int GetNumScreens() const;
virtual void Minimize();
virtual void Maximize();
virtual bool Fullscreen(bool State);
virtual void SetWindowBordered(bool State);
virtual bool SetWindowScreen(int Index);
virtual int GetWindowScreen();
virtual int WindowActive();
virtual int WindowOpen();
@ -432,8 +457,10 @@ public:
virtual int Init();
virtual void Shutdown();
virtual void ReadBackbuffer(unsigned char **ppPixels, int x, int y, int w, int h);
virtual void TakeScreenshot(const char *pFilename);
virtual void Swap();
virtual bool SetVSync(bool State);
virtual int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen);

View file

@ -4,26 +4,30 @@
#include <base/system.h>
#include <engine/shared/config.h>
#include <engine/console.h>
#include <engine/graphics.h>
#include <engine/input.h>
#include <engine/keys.h>
#include "input.h"
//print >>f, "int inp_key_code(const char *key_name) { int i; if (!strcmp(key_name, \"-?-\")) return -1; else for (i = 0; i < 512; i++) if (!strcmp(key_strings[i], key_name)) return i; return -1; }"
// this header is protected so you don't include it from anywere
#define KEYS_INCLUDE
#include "keynames.h"
#undef KEYS_INCLUDE
void CInput::AddEvent(int Unicode, int Key, int Flags)
void CInput::AddEvent(char *pText, int Key, int Flags)
{
if(m_NumEvents != INPUT_BUFFER_SIZE)
{
m_aInputEvents[m_NumEvents].m_Unicode = Unicode;
m_aInputEvents[m_NumEvents].m_Key = Key;
m_aInputEvents[m_NumEvents].m_Flags = Flags;
if(!pText)
m_aInputEvents[m_NumEvents].m_aText[0] = 0;
else
str_copy(m_aInputEvents[m_NumEvents].m_aText, pText, sizeof(m_aInputEvents[m_NumEvents].m_aText));
m_aInputEvents[m_NumEvents].m_InputCount = m_InputCounter;
m_NumEvents++;
}
}
@ -33,9 +37,8 @@ CInput::CInput()
mem_zero(m_aInputCount, sizeof(m_aInputCount));
mem_zero(m_aInputState, sizeof(m_aInputState));
m_InputCurrent = 0;
m_InputCounter = 1;
m_InputGrabbed = 0;
m_InputDispatched = false;
m_LastRelease = 0;
m_ReleaseDelta = -1;
@ -46,36 +49,49 @@ CInput::CInput()
void CInput::Init()
{
m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
m_pConsole = Kernel()->RequestInterface<IConsole>();
// FIXME: unicode handling: use SDL_StartTextInput/SDL_StopTextInput on inputs
// FIXME: key repeat: not a global setting anymore; need to do manually
SDL_SetRelativeMouseMode(SDL_TRUE);
MouseModeRelative();
}
void CInput::MouseRelative(float *x, float *y)
{
if(!m_InputGrabbed)
return;
int nx = 0, ny = 0;
float Sens = g_Config.m_InpMousesens/100.0f;
if(m_InputGrabbed)
{
SDL_GetRelativeMouseState(&nx,&ny);
}
*x = nx*Sens;
*y = ny*Sens;
}
void CInput::MouseModeAbsolute()
{
if(m_InputGrabbed)
{
m_InputGrabbed = 0;
SDL_ShowCursor(SDL_ENABLE);
SDL_SetRelativeMouseMode(SDL_FALSE);
}
}
void CInput::MouseModeRelative()
{
if(!m_InputGrabbed)
{
m_InputGrabbed = 1;
SDL_ShowCursor(SDL_DISABLE);
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, g_Config.m_InpGrab ? "0" : "1", SDL_HINT_OVERRIDE) == SDL_FALSE)
{
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "input", "unable to switch relative mouse mode");
}
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_GetRelativeMouseState(NULL, NULL);
}
}
int CInput::MouseDoubleClick()
@ -89,47 +105,42 @@ int CInput::MouseDoubleClick()
return 0;
}
void CInput::ClearKeyStates()
void CInput::Clear()
{
mem_zero(m_aInputState, sizeof(m_aInputState));
mem_zero(m_aInputCount, sizeof(m_aInputCount));
m_NumEvents = 0;
}
int CInput::KeyState(int Key)
bool CInput::KeyState(int Key) const
{
return m_aInputState[m_InputCurrent][Key];
return m_aInputState[Key>=KEY_MOUSE_1 ? Key : SDL_GetScancodeFromKey(KeyToKeycode(Key))];
}
int CInput::Update()
{
if(m_InputDispatched)
{
// clear and begin count on the other one
m_InputCurrent^=1;
mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent]));
mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent]));
m_InputDispatched = false;
}
// keep the counter between 1..0xFFFF, 0 means not pressed
m_InputCounter = (m_InputCounter%0xFFFF)+1;
{
int i;
const Uint8 *pState = SDL_GetKeyboardState(&i);
if(i >= KEY_LAST)
i = KEY_LAST-1;
mem_copy(m_aInputState[m_InputCurrent], pState, i);
mem_copy(m_aInputState, pState, i);
}
// these states must always be updated manually because they are not in the GetKeyState from SDL
int i = SDL_GetMouseState(NULL, NULL);
if(i&SDL_BUTTON(1)) m_aInputState[m_InputCurrent][KEY_MOUSE_1] = 1; // 1 is left
if(i&SDL_BUTTON(3)) m_aInputState[m_InputCurrent][KEY_MOUSE_2] = 1; // 3 is right
if(i&SDL_BUTTON(2)) m_aInputState[m_InputCurrent][KEY_MOUSE_3] = 1; // 2 is middle
if(i&SDL_BUTTON(4)) m_aInputState[m_InputCurrent][KEY_MOUSE_4] = 1;
if(i&SDL_BUTTON(5)) m_aInputState[m_InputCurrent][KEY_MOUSE_5] = 1;
if(i&SDL_BUTTON(6)) m_aInputState[m_InputCurrent][KEY_MOUSE_6] = 1;
if(i&SDL_BUTTON(7)) m_aInputState[m_InputCurrent][KEY_MOUSE_7] = 1;
if(i&SDL_BUTTON(8)) m_aInputState[m_InputCurrent][KEY_MOUSE_8] = 1;
if(i&SDL_BUTTON(9)) m_aInputState[m_InputCurrent][KEY_MOUSE_9] = 1;
if(i&SDL_BUTTON(1)) m_aInputState[KEY_MOUSE_1] = 1; // 1 is left
if(i&SDL_BUTTON(3)) m_aInputState[KEY_MOUSE_2] = 1; // 3 is right
if(i&SDL_BUTTON(2)) m_aInputState[KEY_MOUSE_3] = 1; // 2 is middle
if(i&SDL_BUTTON(4)) m_aInputState[KEY_MOUSE_4] = 1;
if(i&SDL_BUTTON(5)) m_aInputState[KEY_MOUSE_5] = 1;
if(i&SDL_BUTTON(6)) m_aInputState[KEY_MOUSE_6] = 1;
if(i&SDL_BUTTON(7)) m_aInputState[KEY_MOUSE_7] = 1;
if(i&SDL_BUTTON(8)) m_aInputState[KEY_MOUSE_8] = 1;
if(i&SDL_BUTTON(9)) m_aInputState[KEY_MOUSE_9] = 1;
{
SDL_Event Event;
@ -137,26 +148,23 @@ int CInput::Update()
while(SDL_PollEvent(&Event))
{
int Key = -1;
int Scancode = 0;
int Action = IInput::FLAG_PRESS;
switch (Event.type)
{
case SDL_TEXTINPUT:
{
int TextLength, i;
TextLength = strlen(Event.text.text);
for(i = 0; i < TextLength; i++)
{
AddEvent(Event.text.text[i], 0, 0);
}
}
AddEvent(Event.text.text, 0, IInput::FLAG_TEXT);
break;
// handle keys
case SDL_KEYDOWN:
Key = SDL_GetScancodeFromName(SDL_GetKeyName(Event.key.keysym.sym));
Key = KeycodeToKey(Event.key.keysym.sym);
Scancode = Event.key.keysym.scancode;
break;
case SDL_KEYUP:
Action = IInput::FLAG_RELEASE;
Key = SDL_GetScancodeFromName(SDL_GetKeyName(Event.key.keysym.sym));
Key = KeycodeToKey(Event.key.keysym.sym);
Scancode = Event.key.keysym.scancode;
break;
// handle mouse buttons
@ -174,19 +182,31 @@ int CInput::Update()
if(Event.button.button == SDL_BUTTON_LEFT) Key = KEY_MOUSE_1; // ignore_convention
if(Event.button.button == SDL_BUTTON_RIGHT) Key = KEY_MOUSE_2; // ignore_convention
if(Event.button.button == SDL_BUTTON_MIDDLE) Key = KEY_MOUSE_3; // ignore_convention
if(Event.button.button == 4) Key = KEY_MOUSE_4; // ignore_convention
if(Event.button.button == 5) Key = KEY_MOUSE_5; // ignore_convention
if(Event.button.button == 6) Key = KEY_MOUSE_6; // ignore_convention
if(Event.button.button == 7) Key = KEY_MOUSE_7; // ignore_convention
if(Event.button.button == 8) Key = KEY_MOUSE_8; // ignore_convention
if(Event.button.button == 9) Key = KEY_MOUSE_9; // ignore_convention
Scancode = Key;
break;
case SDL_MOUSEWHEEL:
if(Event.wheel.y > 0) Key = KEY_MOUSE_WHEEL_UP; // ignore_convention
if(Event.wheel.y < 0) Key = KEY_MOUSE_WHEEL_DOWN; // ignore_convention
AddEvent(0, Key, Action);
Action = IInput::FLAG_RELEASE;
Action |= IInput::FLAG_RELEASE;
break;
#if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (mouse state is faulty on start)
case SDL_WINDOWEVENT:
if(Event.window.event == SDL_WINDOWEVENT_MAXIMIZED)
{
MouseModeAbsolute();
MouseModeRelative();
}
break;
#endif
// other messages
case SDL_QUIT:
return 1;
@ -195,9 +215,11 @@ int CInput::Update()
//
if(Key != -1)
{
m_aInputCount[m_InputCurrent][Key].m_Presses++;
if(Action == IInput::FLAG_PRESS)
m_aInputState[m_InputCurrent][Key] = 1;
if(Action&IInput::FLAG_PRESS)
{
m_aInputState[Scancode] = 1;
m_aInputCount[Key] = m_InputCounter;
}
AddEvent(0, Key, Action);
}

View file

@ -6,13 +6,24 @@
class CInput : public IEngineInput
{
IEngineGraphics *m_pGraphics;
IConsole *m_pConsole;
int m_InputGrabbed;
int64 m_LastRelease;
int64 m_ReleaseDelta;
void AddEvent(int Unicode, int Key, int Flags);
void AddEvent(char *pText, int Key, int Flags);
void Clear();
bool IsEventValid(CEvent *pEvent) const { return pEvent->m_InputCount == m_InputCounter; };
//quick access to input
unsigned short m_aInputCount[g_MaxKeys]; // tw-KEY
unsigned char m_aInputState[g_MaxKeys]; // SDL_SCANCODE
int m_InputCounter;
void ClearKeyStates();
bool KeyState(int Key) const;
IEngineGraphics *Graphics() { return m_pGraphics; }
@ -21,16 +32,14 @@ public:
virtual void Init();
bool KeyIsPressed(int Key) const { return KeyState(Key); }
bool KeyPress(int Key, bool CheckCounter) const { return CheckCounter ? (m_aInputCount[Key] == m_InputCounter) : m_aInputCount[Key]; }
virtual void MouseRelative(float *x, float *y);
virtual void MouseModeAbsolute();
virtual void MouseModeRelative();
virtual int MouseDoubleClick();
void ClearKeyStates();
int KeyState(int Key);
int ButtonPressed(int Button) { return m_aInputState[m_InputCurrent][Button]; }
virtual int Update();
};

View file

@ -4,14 +4,105 @@
#error do not include this header!
#endif
#include <string.h>
const char g_aaKeyStrings[512][20] =
{
"unknown",
"&1",
"&2",
"&3",
"&4",
"&5",
"&6",
"&7",
"backspace",
"tab",
"&10",
"&11",
"&12",
"return",
"&14",
"&15",
"&16",
"&17",
"&18",
"&19",
"&20",
"&21",
"&22",
"&23",
"&24",
"&25",
"&26",
"escape",
"&28",
"&29",
"&30",
"&31",
"space",
"exclaim",
"quotedbl",
"hash",
"dollar",
"percent",
"ampersand",
"quote",
"leftparen",
"rightparen",
"asterix",
"plus",
"comma",
"minus",
"period",
"slash",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"colon",
"semicolon",
"less",
"equals",
"greater",
"question",
"at",
"&65",
"&66",
"&67",
"&68",
"&69",
"&70",
"&71",
"&72",
"&73",
"&74",
"&75",
"&76",
"&77",
"&78",
"&79",
"&80",
"&81",
"&82",
"&83",
"&84",
"&85",
"&86",
"&87",
"&88",
"&89",
"&90",
"leftbracket",
"backslash",
"rightbracket",
"caret",
"underscore",
"backquote",
"a",
"b",
"c",
@ -38,33 +129,68 @@ const char g_aaKeyStrings[512][20] =
"x",
"y",
"z",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"return",
"escape",
"backspace",
"tab",
"space",
"minus",
"equals",
"leftbracket",
"rightbracket",
"backslash",
"nonushash",
"semicolon",
"apostrophe",
"grave",
"comma",
"period",
"slash",
"&123",
"&124",
"&125",
"&126",
"delete",
"&128",
"&129",
"&130",
"&131",
"&132",
"&133",
"&134",
"&135",
"&136",
"&137",
"&138",
"&139",
"&140",
"&141",
"&142",
"&143",
"&144",
"&145",
"&146",
"&147",
"&148",
"&149",
"&150",
"&151",
"&152",
"&153",
"&154",
"&155",
"&156",
"&157",
"&158",
"&159",
"&160",
"&161",
"&162",
"&163",
"&164",
"&165",
"&166",
"&167",
"&168",
"&169",
"&170",
"&171",
"&172",
"&173",
"&174",
"&175",
"&176",
"&177",
"&178",
"&179",
"&180",
"&181",
"&182",
"&183",
"&184",
"capslock",
"f1",
"f2",
@ -84,7 +210,7 @@ const char g_aaKeyStrings[512][20] =
"insert",
"home",
"pageup",
"delete",
"&204",
"end",
"pagedown",
"right",
@ -108,7 +234,7 @@ const char g_aaKeyStrings[512][20] =
"kp_9",
"kp_0",
"kp_period",
"nonusbackslash",
"&228",
"application",
"power",
"kp_equals",
@ -138,29 +264,29 @@ const char g_aaKeyStrings[512][20] =
"mute",
"volumeup",
"volumedown",
"&130",
"&131",
"&132",
"&258",
"&259",
"&260",
"kp_comma",
"kp_equalsas400",
"international1",
"international2",
"international3",
"international4",
"international5",
"international6",
"international7",
"international8",
"international9",
"lang1",
"lang2",
"lang3",
"lang4",
"lang5",
"lang6",
"lang7",
"lang8",
"lang9",
"&263",
"&264",
"&265",
"&266",
"&267",
"&268",
"&269",
"&270",
"&271",
"&272",
"&273",
"&274",
"&275",
"&276",
"&277",
"&278",
"&279",
"&280",
"alterase",
"sysreq",
"cancel",
@ -173,17 +299,17 @@ const char g_aaKeyStrings[512][20] =
"clearagain",
"crsel",
"exsel",
"&165",
"&166",
"&167",
"&168",
"&169",
"&170",
"&171",
"&172",
"&173",
"&174",
"&175",
"&293",
"&294",
"&295",
"&296",
"&297",
"&298",
"&299",
"&300",
"&301",
"&302",
"&303",
"kp_00",
"kp_000",
"thousandsseparator",
@ -230,8 +356,8 @@ const char g_aaKeyStrings[512][20] =
"kp_octal",
"kp_decimal",
"kp_hexadecimal",
"&222",
"&223",
"&350",
"&351",
"lctrl",
"lshift",
"lalt",
@ -240,134 +366,6 @@ const char g_aaKeyStrings[512][20] =
"rshift",
"ralt",
"rgui",
"&232",
"&233",
"&234",
"&235",
"&236",
"&237",
"&238",
"&239",
"&240",
"&241",
"&242",
"&243",
"&244",
"&245",
"&246",
"&247",
"&248",
"&249",
"&250",
"&251",
"&252",
"&253",
"&254",
"&255",
"&256",
"mode",
"audionext",
"audioprev",
"audiostop",
"audioplay",
"audiomute",
"mediaselect",
"www",
"mail",
"calculator",
"computer",
"ac_search",
"ac_home",
"ac_back",
"ac_forward",
"ac_stop",
"ac_refresh",
"ac_bookmarks",
"brightnessdown",
"brightnessup",
"displayswitch",
"kbdillumtoggle",
"kbdillumdown",
"kbdillumup",
"eject",
"sleep",
"app1",
"app2",
"mouse1",
"mouse2",
"mouse3",
"mouse4",
"mouse5",
"mouse6",
"mouse7",
"mouse8",
"mousewheelup",
"mousewheeldown",
"&295",
"&296",
"&297",
"&298",
"&299",
"&300",
"&301",
"&302",
"&303",
"&304",
"&305",
"&306",
"&307",
"&308",
"&309",
"&310",
"&311",
"&312",
"&313",
"&314",
"&315",
"&316",
"&317",
"&318",
"&319",
"&320",
"&321",
"&322",
"&323",
"&324",
"&325",
"&326",
"&327",
"&328",
"&329",
"&330",
"&331",
"&332",
"&333",
"&334",
"&335",
"&336",
"&337",
"&338",
"&339",
"&340",
"&341",
"&342",
"&343",
"&344",
"&345",
"&346",
"&347",
"&348",
"&349",
"&350",
"&351",
"&352",
"&353",
"&354",
"&355",
"&356",
"&357",
"&358",
"&359",
"&360",
"&361",
"&362",
@ -393,43 +391,43 @@ const char g_aaKeyStrings[512][20] =
"&382",
"&383",
"&384",
"&385",
"&386",
"&387",
"&388",
"&389",
"&390",
"&391",
"&392",
"&393",
"&394",
"&395",
"&396",
"&397",
"&398",
"&399",
"&400",
"&401",
"&402",
"&403",
"&404",
"&405",
"&406",
"&407",
"&408",
"&409",
"&410",
"&411",
"&412",
"&413",
"&414",
"&415",
"&416",
"&417",
"&418",
"&419",
"&420",
"&421",
"mode",
"audionext",
"audioprev",
"audiostop",
"audioplay",
"audiomute",
"mediaselect",
"www",
"mail",
"calculator",
"computer",
"ac_search",
"ac_home",
"ac_back",
"ac_forward",
"ac_stop",
"ac_refresh",
"ac_bookmarks",
"brightnessdown",
"brightnessup",
"displayswitch",
"kbdillumtoggle",
"kbdillumdown",
"kpdillumup",
"eject",
"sleep",
"mouse1",
"mouse2",
"mouse3",
"mouse4",
"mouse5",
"mouse6",
"mouse7",
"mouse8",
"mouse9",
"mousewheelup",
"mousewheeldown",
"&422",
"&423",
"&424",

File diff suppressed because it is too large Load diff

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