Merge branch 'master' into pr_cmake

This commit is contained in:
oy 2019-01-02 19:31:36 +01:00 committed by GitHub
commit 02e716f509
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 223 additions and 62 deletions

2
.gitignore vendored
View file

@ -16,6 +16,8 @@ scripts/work/
/SDL.dll /SDL.dll
/freetype.dll /freetype.dll
/autoexec.cfg /autoexec.cfg
other/freetype
other/sdl
_test.exe _test.exe
Info.plist Info.plist

15
bam.lua
View file

@ -268,6 +268,12 @@ function GenerateWindowsSettings(settings, conf, target_arch, compiler)
-- Content -- Content
BuildContent(settings) BuildContent(settings)
-- dependencies
AddJob("other/sdl/include/SDL.h", "Downloading SDL2 headers and DLL...", dl .. " sdl SDL2.dll") -- TODO: split up dll and headers!
AddJob("other/freetype/include/ft2build.h", "Downloading freetype headers and DLL...", dl .. " freetype freetype.dll")
AddDependency(cur_builddir .. "/objs/engine/client/backend_sdl" .. settings.cc.extension, "other/sdl/include/SDL.h")
AddDependency(cur_builddir .. "/objs/engine/client/text" .. settings.cc.extension, "other/freetype/include/ft2build.h")
end end
function SharedCommonFiles() function SharedCommonFiles()
@ -433,7 +439,7 @@ function GenerateSettings(conf, arch, builddir, compiler)
return settings return settings
end end
-- String formatting wth named parameters, by RiciLake http://lua-users.org/wiki/StringInterpolation -- String formatting with named parameters, by RiciLake http://lua-users.org/wiki/StringInterpolation
function interp(s, tab) function interp(s, tab)
return (s:gsub('%%%((%a%w*)%)([-0-9%.]*[cdeEfgGiouxXsq])', return (s:gsub('%%%((%a%w*)%)([-0-9%.]*[cdeEfgGiouxXsq])',
function(k, fmt) function(k, fmt)
@ -495,12 +501,19 @@ end
for a, cur_arch in ipairs(archs) do for a, cur_arch in ipairs(archs) do
for c, cur_conf in ipairs(confs) do for c, cur_conf in ipairs(confs) do
cur_builddir = interp(builddir, {platform=family, arch=cur_arch, target=cur_target, conf=cur_conf, compiler=compiler}) cur_builddir = interp(builddir, {platform=family, arch=cur_arch, target=cur_target, conf=cur_conf, compiler=compiler})
if family == "windows" then
dl = Python("scripts/download.py")
dl = dl .. " --arch " .. cur_arch .. " --conf " .. cur_conf
AddJob(cur_builddir .. "/SDL2.dll", "Downloading SDL.dll for " .. cur_arch .. "/" .. cur_conf, dl .. " SDL2.dll") -- TODO: Make me working!
AddJob(cur_builddir .. "/freetype.dll", "Downloading freetype.dll for " .. cur_arch .. "/" .. cur_conf, dl .. " freetype.dll")
end
local settings = GenerateSettings(cur_conf, cur_arch, cur_builddir, compiler) local settings = GenerateSettings(cur_conf, cur_arch, cur_builddir, compiler)
for t, cur_target in pairs(targets) do for t, cur_target in pairs(targets) do
table.insert(subtargets[cur_target], PathJoin(cur_builddir, cur_target .. settings.link.extension)) table.insert(subtargets[cur_target], PathJoin(cur_builddir, cur_target .. settings.link.extension))
end end
end end
end end
for cur_name, cur_target in pairs(targets) do for cur_name, cur_target in pairs(targets) do
-- Supertarget for all configurations and architectures of that target -- Supertarget for all configurations and architectures of that target
PseudoTarget(cur_name, subtargets[cur_target]) PseudoTarget(cur_name, subtargets[cur_target])

61
scripts/download.py Normal file
View file

@ -0,0 +1,61 @@
import shutil, os, re, sys, zipfile
from distutils.dir_util import copy_tree
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])) + "/..")
import twlib
def unzip(filename, where):
try:
z = zipfile.ZipFile(filename, "r")
except:
return False
for name in z.namelist():
z.extract(name, where)
z.close()
return z.namelist()[0]
def downloadAll(arch, conf, targets):
url = "https://github.com/teeworlds/teeworlds-libs/archive/master.zip"
if arch == "x86_64":
_arch = "x64"
else:
_arch = arch
builddir = "build/" + arch + "/" + conf + "/"
# download and unzip
src_package_libs = twlib.fetch_file(url)
if not src_package_libs:
print("couldn't download libs")
sys.exit(-1)
libs_dir = unzip(src_package_libs, ".")
if not libs_dir:
print("couldn't unzip libs")
sys.exit(-1)
libs_dir = "teeworlds-libs-master"
if "SDL2.dll" in targets:
shutil.copy(libs_dir + "/sdl/windows/lib/" + _arch + "/SDL2.dll", builddir)
if "freetype.dll" in targets:
shutil.copy(libs_dir + "/freetype/windows/lib/" + _arch + "/freetype.dll", builddir)
if "sdl" in targets:
copy_tree(libs_dir + "/sdl/windows/", "other/sdl/")
if "freetype" in targets:
copy_tree(libs_dir + "/freetype/windows/", "other/freetype/")
# cleanup
try:
shutil.rmtree(libs_dir)
os.remove(src_package_libs)
except: pass
def main():
import argparse
p = argparse.ArgumentParser(description="Download freetype and SDL library and header files for Windows.")
p.add_argument("--arch", default="x86", choices=["x86", "x86_64"], help="Architecture for the downloaded libraries (Default: x86)")
p.add_argument("--conf", default="debug", choices=["debug", "release"], help="Build type (Default: debug)")
p.add_argument("targets", metavar="TARGET", nargs='+', choices=["SDL2.dll", "freetype.dll", "sdl", "freetype"], help='Target to download. Valid choices are "SDL.dll", "freetype.dll", "sdl" and "freetype"')
args = p.parse_args()
downloadAll(args.arch, args.conf, args.targets)
if __name__ == '__main__':
main()

View file

@ -1798,6 +1798,22 @@ void str_sanitize(char *str_in)
} }
} }
/* removes all forbidden windows/unix characters in filenames*/
char* str_sanitize_filename(char* aName)
{
char *str = (char *)aName;
while(*str)
{
// replace forbidden characters with a whispace
if(*str == '/' || *str == '<' || *str == '>' || *str == ':' || *str == '"'
|| *str == '/' || *str == '\\' || *str == '|' || *str == '?' || *str == '*')
*str = ' ';
str++;
}
str_clean_whitespaces(aName);
return aName;
}
/* removes leading and trailing spaces and limits the use of multiple spaces */ /* removes leading and trailing spaces and limits the use of multiple spaces */
void str_clean_whitespaces(char *str_in) void str_clean_whitespaces(char *str_in)
{ {

View file

@ -841,6 +841,19 @@ void str_sanitize_cc(char *str);
*/ */
void str_sanitize(char *str); void str_sanitize(char *str);
/*
Function: str_sanitize_filename
Replaces all forbidden Windows/Unix characters with whitespace
or nothing if leading or trailing.
Parameters:
str - String to sanitize.
Remarks:
- The strings are treated as zero-terminated strings.
*/
char* str_sanitize_filename(char* aName);
/* /*
Function: str_check_pathname Function: str_check_pathname
Check if the string contains '..' (parent directory) paths. Check if the string contains '..' (parent directory) paths.

View file

@ -12,11 +12,10 @@
#include "graphics_threaded.h" #include "graphics_threaded.h"
#include "backend_sdl.h" #include "backend_sdl.h"
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
PFNGLTEXIMAGE3DPROC glTexImage3DInternal; PFNGLTEXIMAGE3DPROC glTexImage3DInternal;
void GLAPIENTRY glTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) 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); glTexImage3DInternal(target, level, internalFormat, width, height, depth, border, format, type, pixels);
} }
@ -160,7 +159,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
} }
else else
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
// texture // texture
int SrcBlendMode = GL_ONE; int SrcBlendMode = GL_ONE;
@ -335,7 +334,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
} }
} }
m_aTextures[pCommand->m_Slot].m_Format = pCommand->m_Format; m_aTextures[pCommand->m_Slot].m_Format = pCommand->m_Format;
// //
int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format);
int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat);
@ -384,7 +383,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
m_aTextures[pCommand->m_Slot].m_MemSize += TexWidth*TexHeight*pCommand->m_PixelSize; m_aTextures[pCommand->m_Slot].m_MemSize += TexWidth*TexHeight*pCommand->m_PixelSize;
} }
} }
// 3D texture // 3D texture
if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE) if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{ {
@ -410,12 +409,12 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
} }
mem_free(pTexData); mem_free(pTexData);
// //
glGenTextures(m_TextureArraySize, 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; m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D;
for(int i = 0; i < m_TextureArraySize; ++i) for(int i = 0; i < m_TextureArraySize; ++i)
{ {
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D[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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -425,7 +424,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
} }
pTexData = pTmpData; pTexData = pTmpData;
} }
*m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize;
@ -441,7 +440,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_
void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand)
{ {
SetState(pCommand->m_State); SetState(pCommand->m_State);
glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices);
glTexCoordPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*3); glTexCoordPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*3);
glColorPointer(4, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*6); glColorPointer(4, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*6);
@ -472,7 +471,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom
int h = pCommand->m_H == -1 ? aViewport[3] : pCommand->m_H; int h = pCommand->m_H == -1 ? aViewport[3] : pCommand->m_H;
int x = pCommand->m_X; int x = pCommand->m_X;
int y = aViewport[3] - pCommand->m_Y - 1 - (h - 1); int y = aViewport[3] - pCommand->m_Y - 1 - (h - 1);
// we allocate one more row to use when we are flipping the texture // 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); unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
unsigned char *pTempRow = pPixelData+w*h*3; unsigned char *pTempRow = pPixelData+w*h*3;
@ -626,16 +625,16 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex); const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex);
if(pBaseCommand == 0x0) if(pBaseCommand == 0x0)
break; break;
if(m_OpenGL.RunCommand(pBaseCommand)) if(m_OpenGL.RunCommand(pBaseCommand))
continue; continue;
if(m_SDL.RunCommand(pBaseCommand)) if(m_SDL.RunCommand(pBaseCommand))
continue; continue;
if(m_General.RunCommand(pBaseCommand)) if(m_General.RunCommand(pBaseCommand))
continue; continue;
dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd); dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd);
} }
} }
@ -703,7 +702,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
#else #else
SdlFlags |= SDL_WINDOW_FULLSCREEN; SdlFlags |= SDL_WINDOW_FULLSCREEN;
#endif #endif
// set gl attributes // set gl attributes
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if(FsaaSamples) if(FsaaSamples)
@ -786,7 +785,7 @@ int CGraphicsBackend_SDL_OpenGL::Shutdown()
CmdBuffer.AddCommand(Cmd); CmdBuffer.AddCommand(Cmd);
RunBuffer(&CmdBuffer); RunBuffer(&CmdBuffer);
WaitForIdle(); WaitForIdle();
// stop and delete the processor // stop and delete the processor
StopProcessor(); StopProcessor();
delete m_pProcessor; delete m_pProcessor;

View file

@ -125,21 +125,23 @@ static void Mix(short *pFinalOut, unsigned Frames)
float Dist = sqrtf((float)dx*dx+dy*dy); float Dist = sqrtf((float)dx*dx+dy*dy);
if(Dist >= 0.0f && Dist < m_MaxDistance) if(Dist >= 0.0f && Dist < m_MaxDistance)
{ {
// constant panning (-3dB center)
float a = 0.5f;
if(dx < 0)
a -= (Dist/m_MaxDistance)/2.0f;
else
a += (Dist/m_MaxDistance)/2.0f;
float Lgain = sinf((1-a)*pi/2.0f);
float Rgain = sinf(a*pi/2.0f);
// linear falloff // linear falloff
float Falloff = 1.0f - Dist/m_MaxDistance; float Falloff = 1.0f - Dist/m_MaxDistance;
Lvol = Lvol*Lgain*Falloff; // amplitude after falloff
Rvol = Rvol*Rgain*Falloff; float FalloffAmp = v->m_pChannel->m_Vol * Falloff;
// distribute volume to the channels depending on x difference
float Lpan = 0.5f - dx/m_MaxDistance/2.0f;
float Rpan = 1.0f - Lpan;
// apply square root to preserve sound power after panning
float LampFactor = sqrt(Lpan);
float RampFactor = sqrt(Rpan);
// volume of the channels
Lvol = FalloffAmp*LampFactor;
Rvol = FalloffAmp*RampFactor;
} }
else else
{ {

View file

@ -760,15 +760,16 @@ void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int Cli
void CServer::UpdateClientRconCommands() void CServer::UpdateClientRconCommands()
{ {
int ClientID = Tick() % MAX_CLIENTS; for(int ClientID = Tick() % MAX_RCONCMD_RATIO; ClientID < MaxClients(); ClientID += MAX_RCONCMD_RATIO)
if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed)
{ {
int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD; if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed)
for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i)
{ {
SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID); int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD;
m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER); for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i)
{
SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID);
m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER);
}
} }
} }
} }

View file

@ -76,6 +76,7 @@ public:
AUTHED_ADMIN, AUTHED_ADMIN,
MAX_RCONCMD_SEND=16, MAX_RCONCMD_SEND=16,
MAX_RCONCMD_RATIO=8,
}; };
class CClient class CClient

View file

@ -139,6 +139,11 @@ void CChat::ConShowChat(IConsole::IResult *pResult, void *pUserData)
((CChat *)pUserData)->m_Show = pResult->GetInteger(0) != 0; ((CChat *)pUserData)->m_Show = pResult->GetInteger(0) != 0;
} }
void CChat::OnInit()
{
m_Input.Init(Input());
}
void CChat::OnConsoleInit() void CChat::OnConsoleInit()
{ {
Console()->Register("say", "r", CFGFLAG_CLIENT, ConSay, this, "Say in chat"); Console()->Register("say", "r", CFGFLAG_CLIENT, ConSay, this, "Say in chat");

View file

@ -81,6 +81,7 @@ public:
void Say(int Team, const char *pLine); void Say(int Team, const char *pLine);
virtual void OnInit();
virtual void OnReset(); virtual void OnReset();
virtual void OnConsoleInit(); virtual void OnConsoleInit();
virtual void OnStateChange(int NewState, int OldState); virtual void OnStateChange(int NewState, int OldState);

View file

@ -57,6 +57,7 @@ CGameConsole::CInstance::CInstance(int Type)
void CGameConsole::CInstance::Init(CGameConsole *pGameConsole) void CGameConsole::CInstance::Init(CGameConsole *pGameConsole)
{ {
m_pGameConsole = pGameConsole; m_pGameConsole = pGameConsole;
m_Input.Init(m_pGameConsole->Input());
}; };
void CGameConsole::CInstance::ClearBacklog() void CGameConsole::CInstance::ClearBacklog()

View file

@ -448,11 +448,10 @@ int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrS
s_DoScroll = true; s_DoScroll = true;
s_ScrollStart = UI()->MouseX(); s_ScrollStart = UI()->MouseX();
int MxRel = (int)(UI()->MouseX() - pRect->x); int MxRel = (int)(UI()->MouseX() - pRect->x);
float Offset = pRect->w/2.0f-TextRender()->TextWidth(0, FontSize, pStr, -1)/2.0f;
for(int i = 1; i <= Len; i++) for(int i = 1; i <= Len; i++)
{ {
if(Offset + TextRender()->TextWidth(0, FontSize, pStr, i) - *pOffset > MxRel) if(TextRender()->TextWidth(0, FontSize, pStr, i) - *pOffset > MxRel)
{ {
s_AtIndex = i - 1; s_AtIndex = i - 1;
break; break;
@ -487,7 +486,7 @@ int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrS
{ {
Len = str_length(pStr); Len = str_length(pStr);
int NumChars = Len; int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars); ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars, Input());
} }
} }
} }
@ -562,15 +561,14 @@ int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrS
UI()->ClipEnable(pRect); UI()->ClipEnable(pRect);
Textbox.x -= *pOffset; Textbox.x -= *pOffset;
UI()->DoLabel(&Textbox, pDisplayStr, FontSize, CUI::ALIGN_CENTER); UI()->DoLabel(&Textbox, pDisplayStr, FontSize, CUI::ALIGN_LEFT);
// render the cursor // render the cursor
if(UI()->LastActiveItem() == pID && !JustGotActive) if(UI()->LastActiveItem() == pID && !JustGotActive)
{ {
float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1); float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex);
Textbox = *pRect; Textbox = *pRect;
Textbox.x += Textbox.w/2.0f-w/2.0f; Textbox.VSplitLeft(2.0f, 0, &Textbox);
w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex);
Textbox.x += (w-*pOffset-TextRender()->TextWidth(0, FontSize, "|", -1)/2); Textbox.x += (w-*pOffset-TextRender()->TextWidth(0, FontSize, "|", -1)/2);
if((2*time_get()/time_freq()) % 2) // make it blink if((2*time_get()/time_freq()) % 2) // make it blink

View file

@ -531,7 +531,7 @@ private:
void HandleCallvote(int Page, bool Force); void HandleCallvote(int Page, bool Force);
void RenderServerControl(CUIRect MainView); void RenderServerControl(CUIRect MainView);
void RenderServerControlKick(CUIRect MainView, bool FilterSpectators); void RenderServerControlKick(CUIRect MainView, bool FilterSpectators);
void RenderServerControlServer(CUIRect MainView); bool RenderServerControlServer(CUIRect MainView);
// found in menus_browser.cpp // found in menus_browser.cpp
// int m_ScrollOffset; // int m_ScrollOffset;

View file

@ -2132,11 +2132,15 @@ void CMenus::RenderServerbrowserBottomBox(CUIRect MainView)
} }
void CMenus::DoGameIcon(const char *pName, const CUIRect *pRect, int Type) void CMenus::DoGameIcon(const char *pName, const CUIRect *pRect, int Type)
{ {
char aNameBuf[128];
str_copy(aNameBuf, pName, sizeof(aNameBuf));
str_sanitize_filename(aNameBuf);
// get texture // get texture
IGraphics::CTextureHandle Tex = m_GameIconDefault; IGraphics::CTextureHandle Tex = m_GameIconDefault;
for(int i = 0; i < m_lGameIcons.size(); ++i) for(int i = 0; i < m_lGameIcons.size(); ++i)
{ {
if(!str_comp_nocase(pName, m_lGameIcons[i].m_Name)) if(!str_comp_nocase(aNameBuf, m_lGameIcons[i].m_Name))
{ {
Tex = m_lGameIcons[i].m_IconTexture; Tex = m_lGameIcons[i].m_IconTexture;
break; break;

View file

@ -469,8 +469,9 @@ void CMenus::RenderServerInfo(CUIRect MainView)
TextRender()->Text(0, Motd.x, Motd.y, ButtonHeight*ms_FontmodHeight*0.8f, m_pClient->m_pMotd->GetMotd(), (int)Motd.w); TextRender()->Text(0, Motd.x, Motd.y, ButtonHeight*ms_FontmodHeight*0.8f, m_pClient->m_pMotd->GetMotd(), (int)Motd.w);
} }
void CMenus::RenderServerControlServer(CUIRect MainView) bool CMenus::RenderServerControlServer(CUIRect MainView)
{ {
bool doCallVote = false;
static int s_VoteList = 0; static int s_VoteList = 0;
static CListBoxState s_ListBoxState; static CListBoxState s_ListBoxState;
CUIRect List = MainView; CUIRect List = MainView;
@ -482,14 +483,15 @@ void CMenus::RenderServerControlServer(CUIRect MainView)
CListboxItem Item = UiDoListboxNextItem(&s_ListBoxState, pOption); CListboxItem Item = UiDoListboxNextItem(&s_ListBoxState, pOption);
if(Item.m_Visible) if(Item.m_Visible)
{ {
Item.m_Rect.VMargin(5.0f, &Item.m_Rect); Item.m_Rect.VMargin(5.0f, &Item.m_Rect);
Item.m_Rect.y += 2.0f; Item.m_Rect.y += 2.0f;
UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, Item.m_Rect.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT); UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, Item.m_Rect.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
} }
} }
m_CallvoteSelectedOption = UiDoListboxEnd(&s_ListBoxState, 0); m_CallvoteSelectedOption = UiDoListboxEnd(&s_ListBoxState, &doCallVote);
return doCallVote;
} }
void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators) void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
@ -676,9 +678,10 @@ void CMenus::RenderServerControl(CUIRect MainView)
MainView.HSplitBottom(90.0f+2*20.0f, &MainView, &Extended); MainView.HSplitBottom(90.0f+2*20.0f, &MainView, &Extended);
RenderTools()->DrawUIRect(&Extended, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f); RenderTools()->DrawUIRect(&Extended, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
bool doCallVote = false;
// render page // render page
if(s_ControlPage == 0) if(s_ControlPage == 0)
RenderServerControlServer(MainView); doCallVote = RenderServerControlServer(MainView); // double click triggers vote
else if(s_ControlPage == 1) else if(s_ControlPage == 1)
RenderServerControlKick(MainView, false); RenderServerControlKick(MainView, false);
else if(s_ControlPage == 2) else if(s_ControlPage == 2)
@ -720,7 +723,7 @@ void CMenus::RenderServerControl(CUIRect MainView)
{ {
// call vote // call vote
static CButtonContainer s_CallVoteButton; static CButtonContainer s_CallVoteButton;
if(DoButton_Menu(&s_CallVoteButton, Localize("Call vote"), 0, &Button)) if(DoButton_Menu(&s_CallVoteButton, Localize("Call vote"), 0, &Button) || doCallVote)
HandleCallvote(s_ControlPage, false); HandleCallvote(s_ControlPage, false);
} }
else else

View file

@ -1,11 +1,13 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <engine/keys.h> #include <engine/keys.h>
#include <engine/input.h>
#include "lineinput.h" #include "lineinput.h"
CLineInput::CLineInput() CLineInput::CLineInput()
{ {
Clear(); Clear();
m_pInput = 0;
} }
void CLineInput::Clear() void CLineInput::Clear()
@ -16,6 +18,11 @@ void CLineInput::Clear()
m_NumChars = 0; m_NumChars = 0;
} }
void CLineInput::Init(IInput *pInput)
{
m_pInput = pInput;
}
void CLineInput::Set(const char *pString) void CLineInput::Set(const char *pString)
{ {
str_copy(m_Str, pString, sizeof(m_Str)); str_copy(m_Str, pString, sizeof(m_Str));
@ -30,7 +37,15 @@ void CLineInput::Set(const char *pString)
} }
} }
bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr) bool CLineInput::CtrlStop(char c)
{
// jump to spaces and special ASCII characters
return ((32 <= c && c <= 47) || // !"#$%&'()*+,-./
(58 <= c && c <= 64) || // :;<=>?@
(91 <= c && c <= 96)); // [\]^_`
}
bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr, IInput *pInput)
{ {
int NumChars = *pNumCharsPtr; int NumChars = *pNumCharsPtr;
int CursorPos = *pCursorPosPtr; int CursorPos = *pCursorPosPtr;
@ -74,31 +89,54 @@ bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, in
if(Event.m_Flags&IInput::FLAG_PRESS) if(Event.m_Flags&IInput::FLAG_PRESS)
{ {
int Key = Event.m_Key; int Key = Event.m_Key;
bool Ctrl = false;
#ifdef CONF_PLATFORM_MACOSX
if(pInput && (pInput->KeyIsPressed(KEY_LALT) || pInput->KeyIsPressed(KEY_RALT)))
#else
if(pInput && (pInput->KeyIsPressed(KEY_LCTRL) || pInput->KeyIsPressed(KEY_RCTRL)))
#endif
Ctrl = true;
if(Key == KEY_BACKSPACE && CursorPos > 0) if(Key == KEY_BACKSPACE && CursorPos > 0)
{ {
int NewCursorPos = str_utf8_rewind(pStr, CursorPos); int NewCursorPos = CursorPos;
do
{
NewCursorPos = str_utf8_rewind(pStr, NewCursorPos);
NumChars -= 1;
} while(Ctrl && NewCursorPos > 0 && !CtrlStop(pStr[NewCursorPos - 1]));
int CharSize = CursorPos-NewCursorPos; int CharSize = CursorPos-NewCursorPos;
mem_move(pStr+NewCursorPos, pStr+CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term mem_move(pStr+NewCursorPos, pStr+CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term
CursorPos = NewCursorPos; CursorPos = NewCursorPos;
Len -= CharSize; Len -= CharSize;
if(CharSize > 0)
--NumChars;
Changes = true; Changes = true;
} }
else if(Key == KEY_DELETE && CursorPos < Len) else if(Key == KEY_DELETE && CursorPos < Len)
{ {
int p = str_utf8_forward(pStr, CursorPos); int EndCursorPos = CursorPos;
int CharSize = p-CursorPos; do
{
EndCursorPos = str_utf8_forward(pStr, EndCursorPos);
NumChars -= 1;
} while(Ctrl && EndCursorPos < Len && !CtrlStop(pStr[EndCursorPos - 1]));
int CharSize = EndCursorPos - CursorPos;
mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term
Len -= CharSize; Len -= CharSize;
if(CharSize > 0)
--NumChars;
Changes = true; Changes = true;
} }
else if(Key == KEY_LEFT && CursorPos > 0) else if(Key == KEY_LEFT && CursorPos > 0)
CursorPos = str_utf8_rewind(pStr, CursorPos); {
do
{
CursorPos = str_utf8_rewind(pStr, CursorPos);
} while(Ctrl && CursorPos > 0 && !CtrlStop(pStr[CursorPos - 1]));
}
else if(Key == KEY_RIGHT && CursorPos < Len) else if(Key == KEY_RIGHT && CursorPos < Len)
CursorPos = str_utf8_forward(pStr, CursorPos); {
do
{
CursorPos = str_utf8_forward(pStr, CursorPos);
} while(Ctrl && CursorPos < Len && !CtrlStop(pStr[CursorPos - 1]));
}
else if(Key == KEY_HOME) else if(Key == KEY_HOME)
CursorPos = 0; CursorPos = 0;
else if(Key == KEY_END) else if(Key == KEY_END)
@ -114,5 +152,5 @@ bool CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, in
bool CLineInput::ProcessInput(IInput::CEvent e) bool CLineInput::ProcessInput(IInput::CEvent e)
{ {
return Manipulate(e, m_Str, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars); return Manipulate(e, m_Str, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars, m_pInput);
} }

View file

@ -17,8 +17,10 @@ class CLineInput
int m_Len; int m_Len;
int m_CursorPos; int m_CursorPos;
int m_NumChars; int m_NumChars;
IInput *m_pInput;
public: public:
static bool Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr); static bool CtrlStop(char c);
static bool Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr, IInput *pInput);
class CCallback class CCallback
{ {
@ -28,6 +30,7 @@ public:
}; };
CLineInput(); CLineInput();
void Init(IInput *pInput);
void Clear(); void Clear();
bool ProcessInput(IInput::CEvent e); bool ProcessInput(IInput::CEvent e);
void Set(const char *pString); void Set(const char *pString);

View file

@ -340,7 +340,7 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str
{ {
Len = str_length(pStr); Len = str_length(pStr);
int NumChars = Len; int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars); ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars, Input());
} }
} }