From 2aee50d5b1753b2a007fad35629cd2a16e77ba33 Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 3 Aug 2011 23:13:35 +0200 Subject: fixed a nasty noise problem. Closes #812 --- src/engine/client/sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index c2ca91f7..aae52e32 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -126,7 +126,7 @@ static void Mix(short *pFinalOut, unsigned Frames) int dy = v->m_Y - m_CenterY; int Dist = (int)sqrtf((float)dx*dx+dy*dy); // float here. nasty int p = IntAbs(dx); - if(Dist < Range) + if(Dist >= 0 && Dist < Range) { // panning if(dx > 0) -- cgit 1.4.1 From c6fd4a2cc57f8d9dec7164aff98f5a73abc9698d Mon Sep 17 00:00:00 2001 From: Shereef Marzouk Date: Thu, 11 Aug 2011 10:59:14 +0200 Subject: General whitespace and tab cleanup --- src/base/system.c | 8 +- src/engine/client/sound.cpp | 60 ++++++------ src/engine/docs/client_time.txt | 2 +- src/engine/docs/prediction.txt | 2 +- src/engine/docs/server_op.txt | 4 +- src/engine/docs/snapshots.txt | 2 +- src/engine/server/server.cpp | 2 +- src/engine/serverbrowser.h | 2 +- src/engine/shared/console.cpp | 8 +- src/engine/shared/demo.cpp | 2 +- src/engine/shared/masterserver.cpp | 2 +- src/engine/shared/network_console.cpp | 6 +- src/engine/shared/network_console_conn.cpp | 2 +- src/engine/sound.h | 4 +- src/game/client/components/chat.cpp | 2 +- src/game/client/components/hud.cpp | 2 +- src/game/client/components/menus.cpp | 2 +- src/game/client/components/menus_browser.cpp | 4 +- src/game/client/components/menus_ingame.cpp | 2 +- src/game/client/components/menus_settings.cpp | 4 +- src/game/client/components/sounds.cpp | 6 +- src/game/editor/auto_map.cpp | 50 +++++----- src/game/editor/auto_map.h | 8 +- src/game/editor/editor.cpp | 130 +++++++++++++------------- src/game/editor/editor.h | 2 +- src/game/editor/layer_tiles.cpp | 4 +- src/game/editor/popups.cpp | 4 +- src/tools/dilate.cpp | 2 +- 28 files changed, 164 insertions(+), 164 deletions(-) (limited to 'src/engine/client') diff --git a/src/base/system.c b/src/base/system.c index 466e3ca6..e451cb9a 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -1119,7 +1119,7 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) sockaddr_len = sizeof(addr); s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len); - + if (s != -1) { sockaddr_to_netaddr((const struct sockaddr *)&addr, a); @@ -1135,7 +1135,7 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) sockaddr_len = sizeof(addr); s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len); - + if (s != -1) { sockaddr_to_netaddr((const struct sockaddr *)&addr, a); @@ -1186,7 +1186,7 @@ int net_tcp_send(NETSOCKET sock, const void *data, int size) bytes = send((int)sock.ipv4sock, (const char*)data, size, 0); if(sock.ipv6sock >= 0) bytes = send((int)sock.ipv6sock, (const char*)data, size, 0); - + return bytes; } @@ -1198,7 +1198,7 @@ int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0); if(sock.ipv6sock >= 0) bytes = recv((int)sock.ipv6sock, (char*)data, maxsize, 0); - + return bytes; } diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index aae52e32..45404d18 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -19,7 +19,7 @@ enum NUM_SAMPLES = 512, NUM_VOICES = 64, NUM_CHANNELS = 16, - + MAX_FRAMES = 1024 }; @@ -89,9 +89,9 @@ static void Mix(short *pFinalOut, unsigned Frames) // aquire lock while we are mixing lock_wait(m_SoundLock); - + MasterVol = m_SoundVolume; - + for(unsigned i = 0; i < NUM_VOICES; i++) { if(m_aVoices[i].m_pSample) @@ -103,7 +103,7 @@ static void Mix(short *pFinalOut, unsigned Frames) int Step = v->m_pSample->m_Channels; // setup input sources short *pInL = &v->m_pSample->m_pData[v->m_Tick*Step]; short *pInR = &v->m_pSample->m_pData[v->m_Tick*Step+1]; - + unsigned End = v->m_pSample->m_NumFrames-v->m_Tick; int Rvol = v->m_pChannel->m_Vol; @@ -112,7 +112,7 @@ static void Mix(short *pFinalOut, unsigned Frames) // make sure that we don't go outside the sound data if(Frames < End) End = Frames; - + // check if we have a mono sound if(v->m_pSample->m_Channels == 1) pInR = pInL; @@ -133,7 +133,7 @@ static void Mix(short *pFinalOut, unsigned Frames) Lvol = ((Range-p)*Lvol)/Range; else Rvol = ((Range-p)*Rvol)/Range; - + // falloff Lvol = (Lvol*(Range-Dist))/Range; Rvol = (Rvol*(Range-Dist))/Range; @@ -154,7 +154,7 @@ static void Mix(short *pFinalOut, unsigned Frames) pInR += Step; v->m_Tick++; } - + // free voice if not used any more if(v->m_Tick == v->m_pSample->m_NumFrames) { @@ -165,8 +165,8 @@ static void Mix(short *pFinalOut, unsigned Frames) } } } - - + + // release the lock lock_release(m_SoundLock); @@ -201,14 +201,14 @@ int CSound::Init() m_SoundEnabled = 0; m_pGraphics = Kernel()->RequestInterface(); m_pStorage = Kernel()->RequestInterface(); - + SDL_AudioSpec Format; - + m_SoundLock = lock_create(); - + if(!g_Config.m_SndEnable) return 0; - + m_MixingRate = g_Config.m_SndRate; // Set 16-bit stereo audio at 22Khz @@ -229,7 +229,7 @@ int CSound::Init() dbg_msg("client/sound", "sound init successful"); SDL_PauseAudio(0); - + m_SoundEnabled = 1; Update(); // update the volume return 0; @@ -239,17 +239,17 @@ int CSound::Update() { // update volume int WantedVolume = g_Config.m_SndVolume; - + if(!m_pGraphics->WindowActive() && g_Config.m_SndNonactiveMute) WantedVolume = 0; - + if(WantedVolume != m_SoundVolume) { lock_wait(m_SoundLock); m_SoundVolume = WantedVolume; lock_release(m_SoundLock); } - + return 0; } @@ -277,7 +277,7 @@ void CSound::RateConvert(int SampleID) CSample *pSample = &m_aSamples[SampleID]; int NumFrames = 0; short *pNewData = 0; - + // make sure that we need to convert this sound if(!pSample->m_pData || pSample->m_Rate == m_MixingRate) return; @@ -285,7 +285,7 @@ void CSound::RateConvert(int SampleID) // allocate new data NumFrames = (int)((pSample->m_NumFrames/(float)pSample->m_Rate)*m_MixingRate); pNewData = (short *)mem_alloc(NumFrames*pSample->m_Channels*sizeof(short), 1); - + for(int i = 0; i < NumFrames; i++) { // resample TODO: this should be done better, like linear atleast @@ -293,7 +293,7 @@ void CSound::RateConvert(int SampleID) int f = (int)(a*pSample->m_NumFrames); if(f >= pSample->m_NumFrames) f = pSample->m_NumFrames-1; - + // set new data if(pSample->m_Channels == 1) pNewData[i] = pSample->m_pData[f]; @@ -303,7 +303,7 @@ void CSound::RateConvert(int SampleID) pNewData[i*2+1] = pSample->m_pData[f*2+1]; } } - + // free old data and apply new mem_free(pSample->m_pData); pSample->m_pData = pNewData; @@ -321,15 +321,15 @@ int CSound::LoadWV(const char *pFilename) int SampleID = -1; char aError[100]; WavpackContext *pContext; - + // don't waste memory on sound when we are stress testing if(g_Config.m_DbgStress) return -1; - + // no need to load sound when we are running with no sound if(!m_SoundEnabled) return 1; - + if(!m_pStorage) return -1; @@ -372,7 +372,7 @@ int CSound::LoadWV(const char *pFilename) dbg_msg("sound/wv", "file is %d Hz, not 44100 Hz. filename='%s'", snd->rate, filename); return -1; }*/ - + if(BitsPerSample != 16) { dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", BitsPerSample, pFilename); @@ -382,7 +382,7 @@ int CSound::LoadWV(const char *pFilename) pData = (int *)mem_alloc(4*m_aSamples*m_aChannels, 1); WavpackUnpackSamples(pContext, pData, m_aSamples); // TODO: check return value pSrc = pData; - + pSample->m_pData = (short *)mem_alloc(2*m_aSamples*m_aChannels, 1); pDst = pSample->m_pData; @@ -428,9 +428,9 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y) { int VoiceID = -1; int i; - + lock_wait(m_SoundLock); - + // search for voice for(i = 0; i < NUM_VOICES; i++) { @@ -442,7 +442,7 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y) break; } } - + // voice found, use it if(VoiceID != -1) { @@ -457,7 +457,7 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y) m_aVoices[VoiceID].m_X = (int)x; m_aVoices[VoiceID].m_Y = (int)y; } - + lock_release(m_SoundLock); return VoiceID; } diff --git a/src/engine/docs/client_time.txt b/src/engine/docs/client_time.txt index bc76f91c..0d4dd53e 100644 --- a/src/engine/docs/client_time.txt +++ b/src/engine/docs/client_time.txt @@ -6,6 +6,6 @@ predtick, predintratick prevtick tick predtick 4 8 14 |---------------------|---------------------| - 0 <- intratick -> 1 + 0 <- intratick -> 1 0 <- ticktime(in s)-> X 0 <- predintratick?-> 1 diff --git a/src/engine/docs/prediction.txt b/src/engine/docs/prediction.txt index d5771d1a..e740b1e8 100644 --- a/src/engine/docs/prediction.txt +++ b/src/engine/docs/prediction.txt @@ -8,7 +8,7 @@ Predicted input sent to the server can be retrived by calling > { > int tick; > prediction_reset(); -> +> > for(tick = client_tick()+1; tick <= client_predtick(); tick++) > { > MY_INPUT *input = (MY_INPUT *)client_get_input(); diff --git a/src/engine/docs/server_op.txt b/src/engine/docs/server_op.txt index 59181e62..c0a054c4 100644 --- a/src/engine/docs/server_op.txt +++ b/src/engine/docs/server_op.txt @@ -25,13 +25,13 @@ while running send snapshot end for end - + process new network messages end while unload map (end) - + Section: Reinit diff --git a/src/engine/docs/snapshots.txt b/src/engine/docs/snapshots.txt index 647b049a..adb84863 100644 --- a/src/engine/docs/snapshots.txt +++ b/src/engine/docs/snapshots.txt @@ -48,7 +48,7 @@ After a snapshot have been created, compression is applyed to reduce the bandwid Topic: Interval -The interval for how often a client recives a snapshot changes during the course of the connection. There are three different snapshot rates. +The interval for how often a client recives a snapshot changes during the course of the connection. There are three different snapshot rates. - *Init*. 5 snapshots per second. Used when a client is connecting and used until the client has acknowlaged a snapshot. This mechanism is used because the first snapshot because no delta compression can be done. diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 6f6d9e1c..93e96db9 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -672,7 +672,7 @@ void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int Cli void CServer::UpdateClientRconCommands() { int ClientID = Tick() % MAX_CLIENTS; - + 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; diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index 1a49eaf0..79919b09 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -24,7 +24,7 @@ public: int m_Country; int m_Score; bool m_Player; - + int m_FriendState; }; diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index e4cb1991..de5116c1 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -665,7 +665,7 @@ void CConsole::Register(const char *pName, const char *pParams, pCommand->m_pName = pName; pCommand->m_pHelp = pHelp; pCommand->m_pParams = pParams; - + pCommand->m_Flags = Flags; pCommand->m_Temp = false; @@ -699,7 +699,7 @@ void CConsole::RegisterTemp(const char *pName, const char *pParams, int Flags, c } pCommand->m_pfnCallback = 0; - pCommand->m_pUserData = 0; + pCommand->m_pUserData = 0; pCommand->m_Flags = Flags; pCommand->m_Temp = true; @@ -729,7 +729,7 @@ void CConsole::DeregisterTemp(const char *pName) break; } } - + // add to recycle list if(pRemoved) { @@ -742,7 +742,7 @@ void CConsole::DeregisterTempAll() { // set non temp as first one for(; m_pFirstCommand && m_pFirstCommand->m_Temp; m_pFirstCommand = m_pFirstCommand->m_pNext); - + // remove temp entries from command list for(CCommand *pCommand = m_pFirstCommand; pCommand && pCommand->m_pNext; pCommand = pCommand->m_pNext) { diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 51dd51d9..2bd7c28a 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -775,7 +775,7 @@ void CDemoPlayer::GetDemoName(char *pBuffer, int BufferSize) const else if(*pFileName == '.') pEnd = pFileName; } - + int Length = pEnd > pExtractedName ? min(BufferSize, (int)(pEnd-pExtractedName+1)) : BufferSize; str_copy(pBuffer, pExtractedName, Length); } diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp index 1271eeaf..eb63bab5 100644 --- a/src/engine/shared/masterserver.cpp +++ b/src/engine/shared/masterserver.cpp @@ -157,7 +157,7 @@ public: Added = true; break; } - + if(!Added) { for(int i = 0; i < MAX_MASTERSERVERS; ++i) diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 13ed3751..cfa081a2 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -56,7 +56,7 @@ int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) { char aError[256] = { 0 }; int FreeSlot = -1; - + // look for free slot or multiple client for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) { @@ -115,7 +115,7 @@ int CNetConsole::Update() } else str_format(aBuf, sizeof(aBuf), "You have been banned for life"); - + net_tcp_send(Socket, aBuf, str_length(aBuf)); net_tcp_close(Socket); } @@ -170,7 +170,7 @@ bool CNetConsole::AddBan(NETADDR Addr, int Seconds) { if(m_NumBans == MAX_BANS) return false; - + Addr.port = 0; int Index = FindBan(Addr); if(Index == -1) diff --git a/src/engine/shared/network_console_conn.cpp b/src/engine/shared/network_console_conn.cpp index 75b581fa..9bc163af 100644 --- a/src/engine/shared/network_console_conn.cpp +++ b/src/engine/shared/network_console_conn.cpp @@ -181,6 +181,6 @@ int CConsoleNetConnection::Send(const char *pLine) pData += Send; Length -= Send; } - + return 0; } diff --git a/src/engine/sound.h b/src/engine/sound.h index f55a978d..fa5bfc85 100644 --- a/src/engine/sound.h +++ b/src/engine/sound.h @@ -19,10 +19,10 @@ public: virtual bool IsSoundEnabled() = 0; virtual int LoadWV(const char *pFilename) = 0; - + virtual void SetChannel(int ChannelID, float Volume, float Panning) = 0; virtual void SetListenerPos(float x, float y) = 0; - + virtual int PlayAt(int ChannelID, int SampleID, int Flags, float x, float y) = 0; virtual int Play(int ChannelID, int SampleID, int Flags) = 0; virtual void Stop(int SampleID) = 0; diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index aba38bf6..a3bf5252 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -283,7 +283,7 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine) m_aLines[m_CurrentLine].m_ClientID = ClientID; m_aLines[m_CurrentLine].m_Team = Team; m_aLines[m_CurrentLine].m_NameColor = -2; - + // check for highlighted name const char *pHL = str_find_nocase(pLine, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aName); if(pHL) diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 11343912..17365116 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -108,7 +108,7 @@ void CHud::RenderScoreHud() if(GameFlags&GAMEFLAG_FLAGS) { - int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 && + int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 && (Client()->GameTick()-m_pClient->m_FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20; if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/BlinkTimer)&1))) { diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 8f330f78..8813c667 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1108,7 +1108,7 @@ int CMenus::Render() Box.HSplitBottom(24.f, &Box, &Part); Box.HSplitBottom(20.f, &Box, 0); Box.VMargin(20.0f, &Box); - + static int ActSelection = -2; if(ActSelection == -2) ActSelection = g_Config.m_BrFilterCountryIndex; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 8501c67d..825fe3da 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -516,7 +516,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPureMap, Localize("Standard map"), g_Config.m_BrFilterPureMap, &Button)) g_Config.m_BrFilterPureMap ^= 1; - + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterGametypeStrict, Localize("Strict gametype filter"), g_Config.m_BrFilterGametypeStrict, &Button)) g_Config.m_BrFilterGametypeStrict ^= 1; @@ -563,7 +563,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) Button.HMargin(3.0f, &Button); if(DoButton_CheckBox(&g_Config.m_BrFilterCountry, Localize("Player country:"), g_Config.m_BrFilterCountry, &Button)) g_Config.m_BrFilterCountry ^= 1; - + float OldWidth = Rect.w; Rect.w = Rect.h*2; Rect.x += (OldWidth-Rect.w)/2.0f; diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index a809aef0..1afcefe5 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -391,7 +391,7 @@ void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators) { if(!m_pClient->m_Snap.m_paInfoByTeam[i]) continue; - + int Index = m_pClient->m_Snap.m_paInfoByTeam[i]->m_ClientID; if(Index == m_pClient->m_Snap.m_LocalClientID || FilterSpectators && m_pClient->m_Snap.m_paInfoByTeam[i]->m_Team == TEAM_SPECTATORS) continue; diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 51fdbd29..7692ac27 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -543,7 +543,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) WeaponSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &WeaponSettings); UiDoGetButtons(5, 12, WeaponSettings); } - + // defaults { ResetButton.HSplitTop(10.0f, 0, &ResetButton); @@ -554,7 +554,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) if(DoButton_Menu((void*)&s_DefaultButton, Localize("Reset to defaults"), 0, &ResetButton)) m_pClient->m_pBinds->SetDefaults(); } - + // voting settings { VotingSettings.VSplitLeft(10.0f, 0, &VotingSettings); diff --git a/src/game/client/components/sounds.cpp b/src/game/client/components/sounds.cpp index c4ade00e..65fb56fb 100644 --- a/src/game/client/components/sounds.cpp +++ b/src/game/client/components/sounds.cpp @@ -144,7 +144,7 @@ void CSounds::Play(int Chn, int SetId, float Vol, vec2 Pos) if(!pSet->m_NumSounds) return; - + int Flags = 0; if(Chn == CHN_MUSIC) Flags = ISound::FLAG_LOOP; @@ -170,9 +170,9 @@ void CSounds::Stop(int SetId) { if(m_WaitForSoundJob || SetId < 0 || SetId >= g_pData->m_NumSounds) return; - + CDataSoundset *pSet = &g_pData->m_aSounds[SetId]; - + for(int i = 0; i < pSet->m_NumSounds; i++) Sound()->Stop(pSet->m_aSounds[i].m_Id); } diff --git a/src/game/editor/auto_map.cpp b/src/game/editor/auto_map.cpp index 528e459b..3abcf0f4 100644 --- a/src/game/editor/auto_map.cpp +++ b/src/game/editor/auto_map.cpp @@ -20,15 +20,15 @@ void CAutoMapper::Load(const char* pTileName) IOHANDLE RulesFile = m_pEditor->Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_ALL); if(!RulesFile) return; - + CLineReader LineReader; LineReader.Init(RulesFile); - + CConfiguration *pCurrentConf = 0; CIndexRule *pCurrentIndex = 0; - + char aBuf[256]; - + // read each line while(char *pLine = LineReader.Get()) { @@ -40,11 +40,11 @@ void CAutoMapper::Load(const char* pTileName) { // new configuration, get the name pLine++; - + CConfiguration NewConf; int ID = m_lConfigs.add(NewConf); pCurrentConf = &m_lConfigs[ID]; - + str_copy(pCurrentConf->m_aName, pLine, str_length(pLine)); } else @@ -54,15 +54,15 @@ void CAutoMapper::Load(const char* pTileName) // new index int ID = 0; char aFlip[128] = ""; - + sscanf(pLine, "Index %d %127s", &ID, aFlip); - + CIndexRule NewIndexRule; NewIndexRule.m_ID = ID; NewIndexRule.m_Flag = 0; NewIndexRule.m_RandomValue = 0; NewIndexRule.m_BaseTile = false; - + if(str_length(aFlip) > 0) { if(!str_comp(aFlip, "XFLIP")) @@ -70,7 +70,7 @@ void CAutoMapper::Load(const char* pTileName) else if(!str_comp(aFlip, "YFLIP")) NewIndexRule.m_Flag = TILEFLAG_HFLIP; } - + // add the index rule object and make it current int ArrayID = pCurrentConf->m_aIndexRules.add(NewIndexRule); pCurrentIndex = &pCurrentConf->m_aIndexRules[ArrayID]; @@ -85,9 +85,9 @@ void CAutoMapper::Load(const char* pTileName) char aValue[128]; int Value = CPosRule::EMPTY; bool IndexValue = false; - + sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue); - + if(!str_comp(aValue, "FULL")) Value = CPosRule::FULL; else if(!str_comp_num(aValue, "INDEX", 5)) @@ -106,12 +106,12 @@ void CAutoMapper::Load(const char* pTileName) } } } - + io_close(RulesFile); - + str_format(aBuf, sizeof(aBuf),"loaded %s", aPath); m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf); - + m_FileLoaded = true; } @@ -127,14 +127,14 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) { if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size()) return; - + CConfiguration *pConf = &m_lConfigs[ConfigID]; - + if(!pConf->m_aIndexRules.size()) return; - + int BaseTile = 1; - + // find base tile if there is one for(int i = 0; i < pConf->m_aIndexRules.size(); ++i) { @@ -144,7 +144,7 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) break; } } - + // auto map ! int MaxIndex = pLayer->m_Width*pLayer->m_Height; for(int y = 0; y < pLayer->m_Height; y++) @@ -159,7 +159,7 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) if(y == 0 || y == pLayer->m_Height-1 || x == 0 || x == pLayer->m_Width-1) continue; - + for(int i = 0; i < pConf->m_aIndexRules.size(); ++i) { if(pConf->m_aIndexRules[i].m_BaseTile) @@ -170,7 +170,7 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) { CPosRule *pRule = &pConf->m_aIndexRules[i].m_aRules[j]; int CheckIndex = (y+pRule->m_Y)*pLayer->m_Width+(x+pRule->m_X); - + if(CheckIndex < 0 || CheckIndex >= MaxIndex) RespectRules = false; else @@ -184,15 +184,15 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) { if(pLayer->m_pTiles[CheckIndex].m_Index > 0 && pRule->m_Value == CPosRule::EMPTY) RespectRules = false; - + if(pLayer->m_pTiles[CheckIndex].m_Index == 0 && pRule->m_Value == CPosRule::FULL) RespectRules = false; } } } - + if(RespectRules && - (pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue) == 1)) + (pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue) == 1)) { pTile->m_Index = pConf->m_aIndexRules[i].m_ID; pTile->m_Flags = pConf->m_aIndexRules[i].m_Flag; diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h index ee570378..c5537d4f 100644 --- a/src/game/editor/auto_map.h +++ b/src/game/editor/auto_map.h @@ -11,7 +11,7 @@ class CAutoMapper int m_Y; int m_Value; bool m_IndexValue; - + enum { EMPTY=0, @@ -33,16 +33,16 @@ class CAutoMapper array m_aIndexRules; char m_aName[128]; }; - + public: CAutoMapper(class CEditor *pEditor); - + void Load(const char* pTileName); void Proceed(class CLayerTiles *pLayer, int ConfigID); int ConfigNamesNum() { return m_lConfigs.size(); } const char* GetConfigName(int Index); - + const bool IsLoaded() { return m_FileLoaded; } private: array m_lConfigs; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 84308ab6..b7c1d0cb 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -164,7 +164,7 @@ void CEditorImage::AnalyseTileFlags() int tw = m_Width/16; // tilesizes int th = m_Height/16; if ( tw == th ) - { + { unsigned char *pPixelData = (unsigned char *)m_pData; int TileID = 0; @@ -381,8 +381,8 @@ float CEditor::UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Curre Handle.y += (pRect->h-Handle.h)*Current; // logic - float Ret = Current; - int Inside = UI()->MouseInside(&Handle); + float Ret = Current; + int Inside = UI()->MouseInside(&Handle); if(UI()->ActiveItem() == pID) { @@ -423,7 +423,7 @@ float CEditor::UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Curre Slider.Margin(5.0f, &Slider); RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f)*ButtonColorMul(pID), CUI::CORNER_ALL, 2.5f); - return Ret; + return Ret; } vec4 CEditor::GetButtonColor(const void *pID, int Checked) @@ -490,7 +490,7 @@ int CEditor::DoButton_File(const void *pID, const char *pText, int Checked, cons int CEditor::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) { CUIRect r = *pRect; - RenderTools()->DrawUIRect(&r, vec4(0.5f, 0.5f, 0.5f, 1.0f), CUI::CORNER_T, 3.0f); + RenderTools()->DrawUIRect(&r, vec4(0.5f, 0.5f, 0.5f, 1.0f), CUI::CORNER_T, 3.0f); r = *pRect; r.VMargin(5.0f, &r); @@ -515,18 +515,18 @@ int CEditor::DoButton_MenuItem(const void *pID, const char *pText, int Checked, int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) { RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_T, 5.0f); - CUIRect NewRect = *pRect; - NewRect.y += NewRect.h/2.0f-7.0f; - UI()->DoLabel(&NewRect, pText, 10, 0, -1); + CUIRect NewRect = *pRect; + NewRect.y += NewRect.h/2.0f-7.0f; + UI()->DoLabel(&NewRect, pText, 10, 0, -1); return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); } int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize) { RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), Corners, 3.0f); - CUIRect NewRect = *pRect; - NewRect.HMargin(NewRect.h/2.0f-FontSize/2.0f-1.0f, &NewRect); - UI()->DoLabel(&NewRect, pText, FontSize, 0, -1); + CUIRect NewRect = *pRect; + NewRect.HMargin(NewRect.h/2.0f-FontSize/2.0f-1.0f, &NewRect); + UI()->DoLabel(&NewRect, pText, FontSize, 0, -1); return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); } @@ -550,7 +550,7 @@ void CEditor::RenderGrid(CLayerGroup *pGroup) return; float aGroupPoints[4]; - pGroup->Mapping(aGroupPoints); + pGroup->Mapping(aGroupPoints); float w = UI()->Screen()->w; float h = UI()->Screen()->h; @@ -562,7 +562,7 @@ void CEditor::RenderGrid(CLayerGroup *pGroup) int XGridOffset = XOffset % m_GridFactor; int YGridOffset = YOffset % m_GridFactor; - Graphics()->TextureSet(-1); + Graphics()->TextureSet(-1); Graphics()->LinesBegin(); for(int i = 0; i < (int)w; i++) @@ -601,9 +601,9 @@ void CEditor::RenderBackground(CUIRect View, int Texture, float Size, float Brig int CEditor::UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip) { - // logic - static float s_Value; - int Inside = UI()->MouseInside(pRect); + // logic + static float s_Value; + int Inside = UI()->MouseInside(pRect); if(UI()->ActiveItem() == pID) { @@ -652,9 +652,9 @@ int CEditor::UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, in char aBuf[128]; str_format(aBuf, sizeof(aBuf),"%s %d", pLabel, Current); RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, 0), CUI::CORNER_ALL, 5.0f); - pRect->y += pRect->h/2.0f-7.0f; - UI()->DoLabel(pRect, aBuf, 10, 0, -1); - + pRect->y += pRect->h/2.0f-7.0f; + UI()->DoLabel(pRect, aBuf, 10, 0, -1); + return Current; } @@ -713,7 +713,7 @@ void CEditor::CallbackAppendMap(const char *pFileName, int StorageType, void *pU pEditor->m_aFileName[0] = 0; else pEditor->SortImages(); - + pEditor->m_Dialog = DIALOG_NONE; } void CEditor::CallbackSaveMap(const char *pFileName, int StorageType, void *pUser) @@ -734,7 +734,7 @@ void CEditor::CallbackSaveMap(const char *pFileName, int StorageType, void *pUse pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder; pEditor->m_Map.m_Modified = false; } - + pEditor->m_Dialog = DIALOG_NONE; } @@ -742,11 +742,11 @@ void CEditor::DoToolbar(CUIRect ToolBar) { CUIRect TB_Top, TB_Bottom; CUIRect Button; - + ToolBar.HSplitTop(ToolBar.h/2.0f, &TB_Top, &TB_Bottom); - - TB_Top.HSplitBottom(2.5f, &TB_Top, 0); - TB_Bottom.HSplitTop(2.5f, 0, &TB_Bottom); + + TB_Top.HSplitBottom(2.5f, &TB_Top, 0); + TB_Bottom.HSplitTop(2.5f, 0, &TB_Bottom); // ctrl+o to open if(Input()->KeyDown('o') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) @@ -763,7 +763,7 @@ void CEditor::DoToolbar(CUIRect ToolBar) // ctrl+s to save if(Input()->KeyDown('s') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) { - if(m_aFileName[0] && m_ValidSaveFilename) + if(m_aFileName[0] && m_ValidSaveFilename) { str_copy(m_aFileSaveName, m_aFileName, sizeof(m_aFileSaveName)); m_PopupEventType = POPEVENT_SAVE; @@ -947,13 +947,13 @@ void CEditor::DoToolbar(CUIRect ToolBar) } } } - + // tile manipulation { TB_Bottom.VSplitLeft(40.0f, &Button, &TB_Bottom); static int s_BorderBut = 0; CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); - + if(DoButton_Editor(&s_BorderBut, "Border", pT?0:-1, &Button, 0, "Adds border tiles")) { if(pT) @@ -1102,14 +1102,14 @@ void CEditor::DoQuad(CQuad *q, int Index) y = (int)((wy+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); else y = (int)((wy-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); - + int OldX = q->m_aPoints[4].x; int OldY = q->m_aPoints[4].y; q->m_aPoints[4].x = f2fx(x); q->m_aPoints[4].y = f2fx(y); int DiffX = q->m_aPoints[4].x - OldX; int DiffY = q->m_aPoints[4].y - OldY; - + for(int v = 0; v < 4; v++) { q->m_aPoints[v].x += DiffX; @@ -1198,7 +1198,7 @@ void CEditor::DoQuad(CQuad *q, int Index) { if(m_SelectedQuad != Index) m_SelectedPoints = 0; - m_SelectedQuad = Index; + m_SelectedQuad = Index; s_Operation = OP_CONTEXT_MENU; UI()->SetActiveItem(pID); } @@ -1295,12 +1295,12 @@ void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V) for(int m = 0; m < 4; m++) if(m_SelectedPoints&(1<m_aTexcoords[m].x += f2fx(dx*0.001f); pQuad->m_aTexcoords[(m+2)%4].x += f2fx(dx*0.001f); - + pQuad->m_aTexcoords[m].y += f2fx(dy*0.001f); pQuad->m_aTexcoords[m^1].y += f2fx(dy*0.001f); } @@ -1590,8 +1590,8 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar) { if(!UI()->MouseButton(0)) { - for(int k = 0; k < NumEditLayers; k++) - pEditLayers[k]->FillSelection(m_Brush.IsEmpty(), m_Brush.m_lLayers[0], r); + for(int k = 0; k < NumEditLayers; k++) + pEditLayers[k]->FillSelection(m_Brush.IsEmpty(), m_Brush.m_lLayers[0], r); } else { @@ -1623,10 +1623,10 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar) } } - + CLayerTiles *pLayer = (CLayerTiles*)GetSelectedLayerType(0, LAYERTYPE_TILES); if((Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) && pLayer) - s_Operation = OP_BRUSH_PAINT; + s_Operation = OP_BRUSH_PAINT; } if(!m_Brush.IsEmpty()) @@ -1736,7 +1736,7 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar) { CLayerGroup *g = m_Map.m_pGameGroup; g->MapScreen(); - + Graphics()->TextureSet(-1); Graphics()->LinesBegin(); @@ -1935,7 +1935,7 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int * if(pProps[i].m_Value < 0) str_copy(aBuf, "None", sizeof(aBuf)); else - str_format(aBuf, sizeof(aBuf),"%s", m_Map.m_lImages[pProps[i].m_Value]->m_aName); + str_format(aBuf, sizeof(aBuf),"%s", m_Map.m_lImages[pProps[i].m_Value]->m_aName); if(DoButton_Editor(&pIDs[i], aBuf, 0, &Shifter, 0, 0)) PopupSelectImageInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY()); @@ -2174,8 +2174,8 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser) pEditor->SortImages(); for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) { - if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, pImg->m_aName)) - pEditor->m_SelectedImage = i; + if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, pImg->m_aName)) + pEditor->m_SelectedImage = i; } pEditor->m_Dialog = DIALOG_NONE; } @@ -2192,8 +2192,8 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) ExtractName(pFileName, aBuf, sizeof(aBuf)); for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) { - if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) - return; + if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) + return; } CEditorImage *pImg = new CEditorImage(pEditor); @@ -2319,7 +2319,7 @@ void CEditor::SortImages() gs_pSortedIndex = 0; } } - + void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) { @@ -2750,7 +2750,7 @@ void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle str_copy(m_aFileDialogFileName, pDefaultName, sizeof(m_aFileDialogFileName)); if(pBasePath) str_copy(m_aFileDialogCurrentFolder, pBasePath, sizeof(m_aFileDialogCurrentFolder)); - + FilelistPopulate(m_FileDialogStorageType); m_Dialog = DIALOG_FILE; @@ -2770,10 +2770,10 @@ void CEditor::RenderModebar(CUIRect View) const char *pButName = m_Mode == MODE_LAYERS ? "Layers" : "Images"; if(DoButton_Tab(&s_Button, pButName, 0, &Button, 0, "Switch between images and layers managment.")) { - if(m_Mode == MODE_LAYERS) - m_Mode = MODE_IMAGES; - else - m_Mode = MODE_LAYERS; + if(m_Mode == MODE_LAYERS) + m_Mode = MODE_IMAGES; + else + m_Mode = MODE_LAYERS; } } @@ -3127,7 +3127,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) UI()->SetActiveItem(0); } else - { + { if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) { if(i != 0) @@ -3482,12 +3482,12 @@ void CEditor::Reset(bool CreateDefault) m_SelectedPoints = 0; m_SelectedEnvelope = 0; m_SelectedImage = 0; - + m_WorldOffsetX = 0; m_WorldOffsetY = 0; m_EditorOffsetX = 0.0f; m_EditorOffsetY = 0.0f; - + m_WorldZoom = 1.0f; m_ZoomLevel = 200; @@ -3633,19 +3633,19 @@ void CEditor::Init() void CEditor::DoMapBorder() { - CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); - - for(int i = 0; i < pT->m_Width*2; ++i) - pT->m_pTiles[i].m_Index = 1; - - for(int i = 0; i < pT->m_Width*pT->m_Height; ++i) - { - if(i%pT->m_Width < 2 || i%pT->m_Width > pT->m_Width-3) - pT->m_pTiles[i].m_Index = 1; - } - - for(int i = (pT->m_Width*(pT->m_Height-2)); i < pT->m_Width*pT->m_Height; ++i) - pT->m_pTiles[i].m_Index = 1; + CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); + + for(int i = 0; i < pT->m_Width*2; ++i) + pT->m_pTiles[i].m_Index = 1; + + for(int i = 0; i < pT->m_Width*pT->m_Height; ++i) + { + if(i%pT->m_Width < 2 || i%pT->m_Width > pT->m_Width-3) + pT->m_pTiles[i].m_Index = 1; + } + + for(int i = (pT->m_Width*(pT->m_Height-2)); i < pT->m_Width*pT->m_Height; ++i) + pT->m_pTiles[i].m_Index = 1; } void CEditor::UpdateAndRender() diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 1a904953..db99a78c 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -713,7 +713,7 @@ public: void PopupSelectGametileOpInvoke(float x, float y); int PopupSelectGameTileOpResult(); - + void PopupSelectConfigAutoMapInvoke(float x, float y); int PopupSelectConfigAutoMapResult(); diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp index eb78a23d..7532c1bd 100644 --- a/src/game/editor/layer_tiles.cpp +++ b/src/game/editor/layer_tiles.cpp @@ -363,7 +363,7 @@ void CLayerTiles::ShowInfo() int CLayerTiles::RenderProperties(CUIRect *pToolBox) { CUIRect Button; - + bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty(); if(m_pEditor->m_Map.m_pGameLayer != this) { @@ -373,7 +373,7 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox) pToolBox->HSplitBottom(12.0f, pToolBox, &Button); if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Auto map", 0, &Button, 0, "")) m_pEditor->PopupSelectConfigAutoMapInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY()); - + int Result = m_pEditor->PopupSelectConfigAutoMapResult(); if(Result > -1) { diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 0d8036e3..a97146aa 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -811,7 +811,7 @@ int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View) CUIRect Button; static int s_AutoMapperConfigButtons[256]; CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper; - + for(int i = 0; i < pAutoMapper->ConfigNamesNum(); ++i) { View.HSplitTop(2.0f, 0, &View); @@ -837,7 +837,7 @@ int CEditor::PopupSelectConfigAutoMapResult() { if(s_AutoMapConfigSelected < 0) return -1; - + int Result = s_AutoMapConfigSelected; s_AutoMapConfigSelected = -1; return Result; diff --git a/src/tools/dilate.cpp b/src/tools/dilate.cpp index eb770a90..55094a5b 100644 --- a/src/tools/dilate.cpp +++ b/src/tools/dilate.cpp @@ -96,7 +96,7 @@ int main(int argc, const char **argv) dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]); return -1; } - + for(int i = 1; i < argc; i++) DilateFile(argv[i]); return 0; -- cgit 1.4.1 From 1452b6811cb2d4a547d941d8c8aaaf56b50e9ec6 Mon Sep 17 00:00:00 2001 From: eeeee Date: Thu, 3 Nov 2011 07:17:04 +0400 Subject: Replaced sorting implementation with stable one to prevent annoying flickering on server browser update. --- src/engine/client/serverbrowser.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index ddfc7597..0ffc03e8 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -283,16 +283,16 @@ void CServerBrowser::Sort() // sort if(g_Config.m_BrSort == IServerBrowser::SORT_NAME) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareName)); + std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareName)); else if(g_Config.m_BrSort == IServerBrowser::SORT_PING) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortComparePing)); + std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortComparePing)); else if(g_Config.m_BrSort == IServerBrowser::SORT_MAP) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareMap)); + std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareMap)); else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, + std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, g_Config.m_BrFilterSpectators ? &CServerBrowser::SortCompareNumPlayers : &CServerBrowser::SortCompareNumClients)); else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype)); + std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype)); // invert the list if requested if(g_Config.m_BrSortOrder) -- cgit 1.4.1 From 8238853b8cb3b25b5b10f70f4787ae38682eb1c4 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 29 Nov 2011 22:18:40 +0100 Subject: added a todo note --- src/engine/client/serverbrowser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 0ffc03e8..d60c15b8 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -1,6 +1,6 @@ /* (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. */ -#include // sort +#include // sort TODO: remove this #include #include -- cgit 1.4.1 From 48d367db204adb2eb0bef9764b12773891d6975f Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 29 Nov 2011 22:34:47 +0100 Subject: added faster way of inverting the sorted serverlist by KillaBilla. Closes #885 --- src/engine/client/serverbrowser.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index d60c15b8..87964003 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -26,7 +26,7 @@ class SortWrap CServerBrowser *m_pThis; public: SortWrap(CServerBrowser *t, SortFunc f) : m_pfnSort(f), m_pThis(t) {} - bool operator()(int a, int b) { return (m_pThis->*m_pfnSort)(a, b); } + bool operator()(int a, int b) { return (g_Config.m_BrSortOrder ? (m_pThis->*m_pfnSort)(b, a) : (m_pThis->*m_pfnSort)(a, b)); } }; CServerBrowser::CServerBrowser() @@ -294,17 +294,6 @@ void CServerBrowser::Sort() else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE) std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype)); - // invert the list if requested - if(g_Config.m_BrSortOrder) - { - for(i = 0; i < m_NumSortedServers/2; i++) - { - int Temp = m_pSortedServerlist[i]; - m_pSortedServerlist[i] = m_pSortedServerlist[m_NumSortedServers-i-1]; - m_pSortedServerlist[m_NumSortedServers-i-1] = Temp; - } - } - // set indexes for(i = 0; i < m_NumSortedServers; i++) m_ppServerlist[m_pSortedServerlist[i]]->m_Info.m_SortedIndex = i; -- cgit 1.4.1 From 05f77f64affc2445c7e386088e97c6411664cab3 Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 30 Nov 2011 01:41:00 +0100 Subject: added caching for the play command. Closes #891 --- src/engine/client/client.cpp | 2 +- src/game/client/components/menus.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index bec7d4d6..9f43b9ce 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2154,7 +2154,7 @@ void CClient::RegisterCommands() m_pConsole->Register("screenshot", "", CFGFLAG_CLIENT, Con_Screenshot, this, "Take a screenshot"); m_pConsole->Register("rcon", "r", CFGFLAG_CLIENT, Con_Rcon, this, "Send specified command to rcon"); m_pConsole->Register("rcon_auth", "s", CFGFLAG_CLIENT, Con_RconAuth, this, "Authenticate to rcon"); - m_pConsole->Register("play", "r", CFGFLAG_CLIENT, Con_Play, this, "Play the file specified"); + m_pConsole->Register("play", "r", CFGFLAG_CLIENT|CFGFLAG_STORE, Con_Play, this, "Play the file specified"); m_pConsole->Register("record", "?s", CFGFLAG_CLIENT, Con_Record, this, "Record to the file"); m_pConsole->Register("stoprecord", "", CFGFLAG_CLIENT, Con_StopRecord, this, "Stop recording"); m_pConsole->Register("add_favorite", "s", CFGFLAG_CLIENT, Con_AddFavorite, this, "Add a server as a favorite"); diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 8813c667..a39139c8 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -35,11 +35,10 @@ vec4 CMenus::ms_GuiColor; vec4 CMenus::ms_ColorTabbarInactiveOutgame; vec4 CMenus::ms_ColorTabbarActiveOutgame; vec4 CMenus::ms_ColorTabbarInactive; -vec4 CMenus::ms_ColorTabbarActive; +vec4 CMenus::ms_ColorTabbarActive = vec4(0,0,0,0.5f); vec4 CMenus::ms_ColorTabbarInactiveIngame; vec4 CMenus::ms_ColorTabbarActiveIngame; - float CMenus::ms_ButtonHeight = 25.0f; float CMenus::ms_ListheaderHeight = 17.0f; float CMenus::ms_FontmodHeight = 0.8f; -- cgit 1.4.1 From 0fdc9c1b8e3e08623c3359a2d3bd863b95f9e0a6 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 4 Dec 2011 14:17:05 +0100 Subject: cleaned up few things --- src/engine/client/graphics.cpp | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index d1f0b8a8..a6b1a47a 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -5,19 +5,7 @@ #include #include "SDL.h" - -#ifdef CONF_FAMILY_WINDOWS - #define WIN32_LEAN_AND_MEAN - #include -#endif - -#ifdef CONF_PLATFORM_MACOSX - #include - #include -#else - #include - #include -#endif +#include "SDL_opengl.h" #include #include @@ -32,13 +20,6 @@ #include "graphics.h" -// compressed textures -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 - -#define TEXTURE_MAX_ANISOTROPY_EXT 0x84FE - static CVideoMode g_aFakeModes[] = { {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, @@ -743,19 +724,14 @@ bool CGraphics_OpenGL::Init() int CGraphics_SDL::TryInit() { - const SDL_VideoInfo *pInfo; - int Flags = SDL_OPENGL; - m_ScreenWidth = g_Config.m_GfxScreenWidth; m_ScreenHeight = g_Config.m_GfxScreenHeight; - pInfo = SDL_GetVideoInfo(); + const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // set flags - Flags = SDL_OPENGL; - Flags |= SDL_GL_DOUBLEBUFFER; - Flags |= SDL_HWPALETTE; + int Flags = SDL_OPENGL; if(g_Config.m_DbgResizable) Flags |= SDL_RESIZABLE; -- cgit 1.4.1 From 6e20c32859ee4518f398a12b65586463ddeecaab Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 10 Dec 2011 18:23:29 +0100 Subject: removed some resource loading spam. Closes #894 --- src/engine/client/graphics.cpp | 2 ++ src/game/client/components/countryflags.cpp | 8 ++++++-- src/game/client/components/skins.cpp | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index a6b1a47a..617162ae 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -381,6 +381,8 @@ int CGraphics_OpenGL::LoadTexture(const char *pFilename, int StorageType, int St ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, StoreFormat, Flags); mem_free(Img.m_pData); + if(ID != m_InvalidTexture && g_Config.m_Debug) + dbg_msg("graphics/texture", "loaded %s", pFilename); return ID; } diff --git a/src/game/client/components/countryflags.cpp b/src/game/client/components/countryflags.cpp index 6daf3c2e..c2af9a59 100644 --- a/src/game/client/components/countryflags.cpp +++ b/src/game/client/components/countryflags.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "countryflags.h" @@ -72,8 +73,11 @@ void CCountryFlags::LoadCountryflagsIndexfile() str_copy(CountryFlag.m_aCountryCodeString, aOrigin, sizeof(CountryFlag.m_aCountryCodeString)); CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); mem_free(Info.m_pData); - str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin); - Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); + if(g_Config.m_Debug) + { + str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin); + Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); + } m_aCountryFlags.add(CountryFlag); } io_close(File); diff --git a/src/game/client/components/skins.cpp b/src/game/client/components/skins.cpp index dd38e9ea..babf49bb 100644 --- a/src/game/client/components/skins.cpp +++ b/src/game/client/components/skins.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "skins.h" @@ -103,8 +104,11 @@ int CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser) // set skin data str_copy(Skin.m_aName, pName, min((int)sizeof(Skin.m_aName),l-3)); - str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName); - pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); + if(g_Config.m_Debug) + { + str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); + } pSelf->m_aSkins.add(Skin); return 0; -- cgit 1.4.1 From af9775f4003c0a3bcb3efd12faccff95e60ef333 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 29 Dec 2011 13:03:06 +0100 Subject: fixed texture increasing in the text renderer --- src/engine/client/text.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index 4a3a2eb3..88e97d4a 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -285,7 +285,8 @@ class CTextRender : public IEngineTextRender Oldest = i; } - if(time_get()-pSizeData->m_aCharacters[Oldest].m_TouchTime < time_freq()) + if(time_get()-pSizeData->m_aCharacters[Oldest].m_TouchTime < time_freq() && + (pSizeData->m_NumXChars < MAX_CHARACTERS || pSizeData->m_NumYChars < MAX_CHARACTERS)) { IncreaseTextureSize(pSizeData); return GetSlot(pSizeData); -- cgit 1.4.1 From 988b1c22cf3bb4a949bcad48d6be87257a84960f Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 29 Dec 2011 13:06:53 +0100 Subject: fixed that the server browser list gets sorted twice on a new entry --- src/engine/client/serverbrowser.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 87964003..98a22d75 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -370,7 +370,6 @@ void CServerBrowser::SetInfo(CServerEntry *pEntry, const CServerInfo &Info) }*/ pEntry->m_GotInfo = 1; - Sort(); } CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr) -- cgit 1.4.1 From b44ee3d9755ff35a6df1358dcfe85ce681bbe081 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 29 Dec 2011 23:36:53 +0100 Subject: reworked ban system --- src/base/system.c | 22 +- src/base/system.h | 17 +- src/engine/client/client.cpp | 2 +- src/engine/client/serverbrowser.cpp | 11 +- src/engine/server/server.cpp | 331 ++++++----------- src/engine/server/server.h | 33 +- src/engine/shared/config.cpp | 7 +- src/engine/shared/console.cpp | 11 +- src/engine/shared/econ.cpp | 17 +- src/engine/shared/econ.h | 3 +- src/engine/shared/masterserver.cpp | 6 +- src/engine/shared/netban.cpp | 615 +++++++++++++++++++++++++++++++ src/engine/shared/netban.h | 184 +++++++++ src/engine/shared/network.h | 73 +--- src/engine/shared/network_console.cpp | 97 +---- src/engine/shared/network_server.cpp | 256 +------------ src/game/client/components/console.cpp | 8 +- src/game/client/components/maplayers.cpp | 7 +- src/mastersrv/mastersrv.cpp | 88 ++--- src/tools/crapnet.cpp | 4 +- src/tools/fake_server.cpp | 2 +- 21 files changed, 1060 insertions(+), 734 deletions(-) create mode 100644 src/engine/shared/netban.cpp create mode 100644 src/engine/shared/netban.h (limited to 'src/engine/client') diff --git a/src/base/system.c b/src/base/system.c index 7b60dab5..bf06a36e 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -125,7 +125,7 @@ static IOHANDLE logfile = 0; static void logger_file(const char *line) { io_write(logfile, line, strlen(line)); - io_write(logfile, "\n", 1); + io_write_newline(logfile); io_flush(logfile); } @@ -222,8 +222,9 @@ void mem_debug_dump(IOHANDLE file) { while(header) { - str_format(buf, sizeof(buf), "%s(%d): %d\n", header->filename, header->line, header->size); + 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; } @@ -346,6 +347,15 @@ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size) return fwrite(buffer, 1, size, (FILE*)io); } +unsigned io_write_newline(IOHANDLE io) +{ +#if defined(CONF_FAMILY_WINDOWS) + return fwrite("\r\n", 1, 2, (FILE*)io); +#else + return fwrite("\n", 1, 1, (FILE*)io); +#endif +} + int io_close(IOHANDLE io) { fclose((FILE*)io); @@ -585,18 +595,18 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b) return mem_comp(a, b, sizeof(NETADDR)); } -void net_addr_str(const NETADDR *addr, char *string, int max_length) +void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port) { if(addr->type == NETTYPE_IPV4) { - if(addr->port != 0) + if(add_port != 0) str_format(string, max_length, "%d.%d.%d.%d:%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3], addr->port); else str_format(string, max_length, "%d.%d.%d.%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]); } else if(addr->type == NETTYPE_IPV6) { - if(addr->port != 0) + if(add_port != 0) str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d", (addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7], (addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15], @@ -1500,7 +1510,7 @@ int net_socket_read_wait(NETSOCKET sock, int time) return 0; } -unsigned time_timestamp() +int time_timestamp() { return time(0); } diff --git a/src/base/system.h b/src/base/system.h index 749668de..5060fcb0 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -239,6 +239,18 @@ unsigned io_skip(IOHANDLE io, int size); */ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size); +/* + Function: io_write_newline + Writes newline to file. + + Parameters: + io - Handle to the file. + + Returns: + Number of bytes written. +*/ +unsigned io_write_newline(IOHANDLE io); + /* Function: io_seek Seeks to a specified offset in the file. @@ -425,7 +437,7 @@ int64 time_freq(); Returns: The time as a UNIX timestamp */ -unsigned time_timestamp(); +int time_timestamp(); /* Group: Network General */ typedef struct @@ -499,12 +511,13 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b); addr - Address to turn into a string. string - Buffer to fill with the string. max_length - Maximum size of the string. + add_port - add port to string or not Remarks: - The string will always be zero terminated */ -void net_addr_str(const NETADDR *addr, char *string, int max_length); +void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port); /* Function: net_addr_from_str diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 9f43b9ce..c3bd770c 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -964,7 +964,7 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket) 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)); + net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true); for(int i = 0; i < Info.m_NumClients; i++) { diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 98a22d75..4dda9da9 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -387,7 +387,7 @@ CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr) pEntry->m_Info.m_NetAddr = Addr; pEntry->m_Info.m_Latency = 999; - net_addr_str(&Addr, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress)); + net_addr_str(&Addr, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), true); str_copy(pEntry->m_Info.m_aName, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aName)); // check if it's a favorite @@ -527,7 +527,7 @@ void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) cons if(g_Config.m_Debug) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf),"requesting server info from %s", aAddrStr); m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); @@ -668,7 +668,7 @@ void CServerBrowser::AddFavorite(const NETADDR &Addr) if(g_Config.m_Debug) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "added fav, %s", aAddrStr); m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); @@ -722,12 +722,11 @@ void CServerBrowser::ConfigSaveCallback(IConfig *pConfig, void *pUserData) { CServerBrowser *pSelf = (CServerBrowser *)pUserData; - int i; char aAddrStr[128]; char aBuffer[256]; - for(i = 0; i < pSelf->m_NumFavoriteServers; i++) + for(int i = 0; i < pSelf->m_NumFavoriteServers; i++) { - net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr)); + net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr), true); str_format(aBuffer, sizeof(aBuffer), "add_favorite %s", aAddrStr); pConfig->WriteLine(aBuffer); } diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 09891ba7..9587b94c 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -77,17 +78,6 @@ static void StrUTF8Rtrim(char *pStr) } -static int StrAllnum(const char *pStr) -{ - while(*pStr) - { - if(!(*pStr >= '0' && *pStr <= '9')) - return 0; - pStr++; - } - return 1; -} - CSnapIDPool::CSnapIDPool() { Reset(); @@ -176,6 +166,101 @@ void CSnapIDPool::FreeID(int ID) } } + +void CServerBan::Init(IConsole *pConsole, IStorage *pStorage, CServer* pServer) +{ + CNetBan::Init(pConsole, pStorage); + + m_pServer = pServer; + + // overwrites base command, todo: improve this + Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBanExt, this, "Ban player with ip/client id for x minutes for any reason"); +} + +template +int CServerBan::BanExt(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason) +{ + // validate address + if(Server()->m_RconClientID >= 0 && Server()->m_RconClientID < MAX_CLIENTS && + Server()->m_aClients[Server()->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY) + { + if(NetMatch(pData, Server()->m_NetServer.ClientAddr(Server()->m_RconClientID))) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (you can't ban yourself)"); + return -1; + } + + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(i == Server()->m_RconClientID || Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY) + continue; + + if(Server()->m_aClients[i].m_Authed >= Server()->m_RconAuthLevel && NetMatch(pData, Server()->m_NetServer.ClientAddr(i))) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (command denied)"); + return -1; + } + } + } + + int Result = Ban(pBanPool, pData, Seconds, pReason); + if(Result != 0) + return Result; + + // drop banned clients + T::CDataType Data = *pData; + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY) + continue; + + if(NetMatch(&Data, Server()->m_NetServer.ClientAddr(i))) + { + CNetHash NetHash(&Data); + char aBuf[256]; + MakeBanInfo(pBanPool->Find(&Data, &NetHash), aBuf, sizeof(aBuf), MSGTYPE_PLAYER); + Server()->m_NetServer.Drop(i, aBuf); + } + } + + return Result; +} + +int CServerBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason) +{ + return BanExt(&m_BanAddrPool, pAddr, Seconds, pReason); +} + +int CServerBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason) +{ + if(pRange->IsValid()) + return BanExt(&m_BanRangePool, pRange, Seconds, pReason); + + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)"); + return -1; +} + +void CServerBan::ConBanExt(IConsole::IResult *pResult, void *pUser) +{ + CServerBan *pThis = static_cast(pUser); + + const char *pStr = pResult->GetString(0); + int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : 30; + const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given"; + + if(StrAllnum(pStr)) + { + int ClientID = str_toint(pStr); + if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->Server()->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY) + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid client id)"); + else + pThis->BanAddr(pThis->Server()->m_NetServer.ClientAddr(ClientID), Minutes*60, pReason); + } + else + ConBan(pResult, pUser); +} + + void CServer::CClient::Reset() { // reset input @@ -368,11 +453,7 @@ int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo) void CServer::GetClientAddr(int ClientID, char *pAddrStr, int Size) { if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME) - { - NETADDR Addr = m_NetServer.ClientAddr(ClientID); - Addr.port = 0; - net_addr_str(&Addr, pAddrStr, Size); - } + net_addr_str(m_NetServer.ClientAddr(ClientID), pAddrStr, Size, false); } @@ -618,9 +699,8 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) { CServer *pThis = (CServer *)pUser; - NETADDR Addr = pThis->m_NetServer.ClientAddr(ClientID); char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pThis->m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); @@ -714,7 +794,6 @@ void CServer::UpdateClientRconCommands() void CServer::ProcessClientPacket(CNetChunk *pPacket) { int ClientID = pPacket->m_ClientID; - NETADDR Addr; CUnpacker Unpacker; Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize); @@ -793,9 +872,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING) { - Addr = m_NetServer.ClientAddr(ClientID); char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "player is ready. ClientID=%x addr=%s", ClientID, aAddrStr); @@ -809,9 +887,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { if(m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID)) { - Addr = m_NetServer.ClientAddr(ClientID); char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "player has entered the game. ClientID=%x addr=%s", ClientID, aAddrStr); @@ -945,10 +1022,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(!g_Config.m_SvRconBantime) m_NetServer.Drop(ClientID, "Too many remote console authentication tries"); else - { - NETADDR Addr = m_NetServer.ClientAddr(ClientID); - BanAdd(Addr, g_Config.m_SvRconBantime*60, "Too many remote console authentication tries"); - } + m_ServerBan.BanAddr(m_NetServer.ClientAddr(ClientID), g_Config.m_SvRconBantime*60, "Too many remote console authentication tries"); } } else @@ -992,7 +1066,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } } -void CServer::SendServerInfo(NETADDR *pAddr, int Token) +void CServer::SendServerInfo(const NETADDR *pAddr, int Token) { CNetChunk Packet; CPacker p; @@ -1061,38 +1135,10 @@ void CServer::UpdateServerInfo() for(int i = 0; i < MAX_CLIENTS; ++i) { if(m_aClients[i].m_State != CClient::STATE_EMPTY) - { - NETADDR Addr = m_NetServer.ClientAddr(i); - SendServerInfo(&Addr, -1); - } + SendServerInfo(m_NetServer.ClientAddr(i), -1); } } -int CServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason) -{ - Addr.port = 0; - char aAddrStr[128]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - char aBuf[256]; - if(Seconds) - str_format(aBuf, sizeof(aBuf), "banned %s for %d minutes", aAddrStr, Seconds/60); - else - str_format(aBuf, sizeof(aBuf), "banned %s for life", aAddrStr); - Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - - return m_NetServer.BanAdd(Addr, Seconds, pReason); -} - -int CServer::BanRemove(NETADDR Addr) -{ - return m_NetServer.BanRemove(Addr); -} - -int CServer::BanRemoveAll() -{ - return m_NetServer.BanRemoveAll(); -} - void CServer::PumpNetwork() { @@ -1119,6 +1165,7 @@ void CServer::PumpNetwork() ProcessClientPacket(&Packet); } + m_ServerBan.Update(); m_Econ.Update(); } @@ -1217,7 +1264,7 @@ int CServer::Run() BindAddr.port = g_Config.m_SvPort; } - if(!m_NetServer.Open(BindAddr, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0)) + if(!m_NetServer.Open(BindAddr, &m_ServerBan, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0)) { dbg_msg("server", "couldn't open socket. port might already be in use"); return -1; @@ -1225,7 +1272,8 @@ int CServer::Run() m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); - m_Econ.Init(Console()); + m_ServerBan.Init(Console(), Storage(), this); + m_Econ.Init(Console(), &m_ServerBan); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName); @@ -1388,170 +1436,23 @@ void CServer::ConKick(IConsole::IResult *pResult, void *pUser) ((CServer *)pUser)->Kick(pResult->GetInteger(0), "Kicked by console"); } -void CServer::ConBan(IConsole::IResult *pResult, void *pUser) -{ - NETADDR Addr; - CServer *pServer = (CServer *)pUser; - const char *pStr = pResult->GetString(0); - int Minutes = 30; - const char *pReason = "No reason given"; - - if(pResult->NumArguments() > 1) - Minutes = max(0, pResult->GetInteger(1)); - - if(pResult->NumArguments() > 2) - pReason = pResult->GetString(2); - - if(net_addr_from_str(&Addr, pStr) == 0) - { - if(pServer->m_RconClientID >= 0 && pServer->m_RconClientID < MAX_CLIENTS && pServer->m_aClients[pServer->m_RconClientID].m_State != CClient::STATE_EMPTY) - { - NETADDR AddrCheck = pServer->m_NetServer.ClientAddr(pServer->m_RconClientID); - Addr.port = AddrCheck.port = 0; - if(net_addr_comp(&Addr, &AddrCheck) == 0) - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); - return; - } - - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(i == pServer->m_RconClientID) - continue; - - AddrCheck = pServer->m_NetServer.ClientAddr(i); - AddrCheck.port = 0; - if(net_addr_comp(&Addr, &AddrCheck) == 0 && pServer->m_aClients[i].m_Authed > pServer->m_RconAuthLevel) - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); - return; - } - } - } - pServer->BanAdd(Addr, Minutes*60, pReason); - } - else if(StrAllnum(pStr)) - { - int ClientID = str_toint(pStr); - - if(ClientID < 0 || ClientID >= MAX_CLIENTS || pServer->m_aClients[ClientID].m_State == CClient::STATE_EMPTY) - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid client id"); - return; - } - else if(pServer->m_RconClientID == ClientID) - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); - return; - } - else if(pServer->m_aClients[ClientID].m_Authed > pServer->m_RconAuthLevel) - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); - return; - } - - Addr = pServer->m_NetServer.ClientAddr(ClientID); - pServer->BanAdd(Addr, Minutes*60, pReason); - } - else - { - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid network address to ban"); - return; - } -} - -void CServer::ConUnban(IConsole::IResult *pResult, void *pUser) -{ - NETADDR Addr; - CServer *pServer = (CServer *)pUser; - const char *pStr = pResult->GetString(0); - - if(net_addr_from_str(&Addr, pStr) == 0 && !pServer->BanRemove(Addr)) - { - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "unbanned %s", aAddrStr); - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - } - else if(StrAllnum(pStr)) - { - int BanIndex = str_toint(pStr); - CNetServer::CBanInfo Info; - if(BanIndex < 0 || !pServer->m_NetServer.BanGet(BanIndex, &Info)) - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid ban index"); - else if(!pServer->BanRemove(Info.m_Addr)) - { - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Info.m_Addr, aAddrStr, sizeof(aAddrStr)); - - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "unbanned %s", aAddrStr); - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - } - } - else - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid network address"); -} - -void CServer::ConUnbanAll(IConsole::IResult *pResult, void *pUser) -{ - CServer *pServer = (CServer *)pUser; - if(!pServer->BanRemoveAll()) - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "unbanned all"); -} - -void CServer::ConBans(IConsole::IResult *pResult, void *pUser) -{ - unsigned Now = time_timestamp(); - char aBuf[1024]; - char aAddrStr[NETADDR_MAXSTRSIZE]; - CServer* pServer = (CServer *)pUser; - - int Num = pServer->m_NetServer.BanNum(); - for(int i = 0; i < Num; i++) - { - CNetServer::CBanInfo Info; - pServer->m_NetServer.BanGet(i, &Info); - NETADDR Addr = Info.m_Addr; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - - if(Info.m_Expires == -1) - { - str_format(aBuf, sizeof(aBuf), "#%i %s for life", i, aAddrStr); - } - else - { - unsigned t = Info.m_Expires - Now; - str_format(aBuf, sizeof(aBuf), "#%i %s for %d minutes and %d seconds", i, aAddrStr, t/60, t%60); - } - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); - } - str_format(aBuf, sizeof(aBuf), "%d ban(s)", Num); - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); -} - void CServer::ConStatus(IConsole::IResult *pResult, void *pUser) { - int i; - NETADDR Addr; char aBuf[1024]; char aAddrStr[NETADDR_MAXSTRSIZE]; - CServer* pServer = (CServer *)pUser; + CServer* pThis = static_cast(pUser); - for(i = 0; i < MAX_CLIENTS; i++) + for(int i = 0; i < MAX_CLIENTS; i++) { - if(pServer->m_aClients[i].m_State != CClient::STATE_EMPTY) + if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY) { - Addr = pServer->m_NetServer.ClientAddr(i); - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - if(pServer->m_aClients[i].m_State == CClient::STATE_INGAME) + net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true); + if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME) str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d", i, aAddrStr, - pServer->m_aClients[i].m_aName, pServer->m_aClients[i].m_Score); + pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score); else str_format(aBuf, sizeof(aBuf), "id=%d addr=%s connecting", i, aAddrStr); - pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); } } } @@ -1664,10 +1565,6 @@ void CServer::RegisterCommands() m_pConsole = Kernel()->RequestInterface(); Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason"); - Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, "Ban player with ip/id for x minutes for any reason"); - Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, "Unban ip"); - Console()->Register("unban_all", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnbanAll, this, "Clear all bans"); - Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, "Show banlist"); Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players"); Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down"); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 4c450a48..2ff06a05 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -5,6 +5,7 @@ #include + class CSnapIDPool { enum @@ -39,6 +40,25 @@ public: void FreeID(int ID); }; + +class CServerBan : public CNetBan +{ + class CServer *m_pServer; + + template int BanExt(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason); + +public: + class CServer *Server() const { return m_pServer; } + + void Init(class IConsole *pConsole, class IStorage *pStorage, class CServer* pServer); + + int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); + int BanRange(const CNetRange *pRange, int Seconds, const char *pReason); + + static void ConBanExt(class IConsole::IResult *pResult, void *pUser); +}; + + class CServer : public IServer { class IGameServer *m_pGameServer; @@ -114,6 +134,7 @@ public: CSnapIDPool m_IDPool; CNetServer m_NetServer; CEcon m_Econ; + CServerBan m_ServerBan; IEngineMap *m_pMap; @@ -184,13 +205,9 @@ public: void ProcessClientPacket(CNetChunk *pPacket); - void SendServerInfo(NETADDR *pAddr, int Token); + void SendServerInfo(const NETADDR *pAddr, int Token); void UpdateServerInfo(); - int BanAdd(NETADDR Addr, int Seconds, const char *pReason); - int BanRemove(NETADDR Addr); - int BanRemoveAll(); - void PumpNetwork(); char *GetMapName(); @@ -200,11 +217,7 @@ public: int Run(); static void ConKick(IConsole::IResult *pResult, void *pUser); - static void ConBan(IConsole::IResult *pResult, void *pUser); - static void ConUnban(IConsole::IResult *pResult, void *pUser); - static void ConUnbanAll(IConsole::IResult *pResult, void *pUser); - static void ConBans(IConsole::IResult *pResult, void *pUser); - static void ConStatus(IConsole::IResult *pResult, void *pUser); + static void ConStatus(IConsole::IResult *pResult, void *pUser); static void ConShutdown(IConsole::IResult *pResult, void *pUser); static void ConRecord(IConsole::IResult *pResult, void *pUser); static void ConStopRecord(IConsole::IResult *pResult, void *pUser); diff --git a/src/engine/shared/config.cpp b/src/engine/shared/config.cpp index b9aa1320..d0cb7a6b 100644 --- a/src/engine/shared/config.cpp +++ b/src/engine/shared/config.cpp @@ -111,13 +111,8 @@ public: { if(!m_ConfigFile) return; -#if defined(CONF_FAMILY_WINDOWS) - static const char Newline[] = "\r\n"; -#else - static const char Newline[] = "\n"; -#endif io_write(m_ConfigFile, pLine, str_length(pLine)); - io_write(m_ConfigFile, Newline, sizeof(Newline)-1); + io_write_newline(m_ConfigFile); } }; diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index de5116c1..1b98a158 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -658,7 +658,13 @@ void CConsole::AddCommandSorted(CCommand *pCommand) void CConsole::Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) { - CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand; + CCommand *pCommand = FindCommand(pName, Flags); + bool DoAdd = false; + if(pCommand == 0) + { + pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand; + DoAdd = true; + } pCommand->m_pfnCallback = pfnFunc; pCommand->m_pUserData = pUser; @@ -669,7 +675,8 @@ void CConsole::Register(const char *pName, const char *pParams, pCommand->m_Flags = Flags; pCommand->m_Temp = false; - AddCommandSorted(pCommand); + if(DoAdd) + AddCommandSorted(pCommand); } void CConsole::RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index 617cdbd6..3eaf7aac 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -2,14 +2,15 @@ #include #include "econ.h" +#include "netban.h" + int CEcon::NewClientCallback(int ClientID, void *pUser) { CEcon *pThis = (CEcon *)pUser; - NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID); char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pThis->m_NetConsole.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[128]; str_format(aBuf, sizeof(aBuf), "client accepted. cid=%d addr=%s'", ClientID, aAddrStr); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf); @@ -26,9 +27,8 @@ int CEcon::DelClientCallback(int ClientID, const char *pReason, void *pUser) { CEcon *pThis = (CEcon *)pUser; - NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID); char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pThis->m_NetConsole.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf); @@ -52,7 +52,7 @@ void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUse } } -void CEcon::Init(IConsole *pConsole) +void CEcon::Init(IConsole *pConsole, CNetBan *pNetBan) { m_pConsole = pConsole; @@ -74,7 +74,7 @@ void CEcon::Init(IConsole *pConsole) BindAddr.port = g_Config.m_EcPort; } - if(m_NetConsole.Open(BindAddr, 0)) + if(m_NetConsole.Open(BindAddr, pNetBan, 0)) { m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this); m_Ready = true; @@ -123,10 +123,7 @@ void CEcon::Update() if(!g_Config.m_EcBantime) m_NetConsole.Drop(ClientID, "Too many authentication tries"); else - { - NETADDR Addr = m_NetConsole.ClientAddr(ClientID); - m_NetConsole.AddBan(Addr, g_Config.m_EcBantime*60); - } + m_NetConsole.NetBan()->BanAddr(m_NetConsole.ClientAddr(ClientID), g_Config.m_EcBantime*60, "Too many authentication tries"); } } } diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h index daec34c4..ed7d929b 100644 --- a/src/engine/shared/econ.h +++ b/src/engine/shared/econ.h @@ -3,6 +3,7 @@ #include "network.h" + class CEcon { enum @@ -41,7 +42,7 @@ class CEcon public: IConsole *Console() { return m_pConsole; } - void Init(IConsole *pConsole); + void Init(IConsole *pConsole, class CNetBan *pNetBan); void Update(); void Send(int ClientID, const char *pLine); void Shutdown(); diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp index eb63bab5..95482639 100644 --- a/src/engine/shared/masterserver.cpp +++ b/src/engine/shared/masterserver.cpp @@ -192,13 +192,13 @@ public: { char aAddrStr[NETADDR_MAXSTRSIZE]; if(m_aMasterServers[i].m_Addr.type != NETTYPE_INVALID) - net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr), true); else aAddrStr[0] = 0; char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "%s %s\n", m_aMasterServers[i].m_aHostname, aAddrStr); - + str_format(aBuf, sizeof(aBuf), "%s %s", m_aMasterServers[i].m_aHostname, aAddrStr); io_write(File, aBuf, str_length(aBuf)); + io_write_newline(File); } io_close(File); diff --git a/src/engine/shared/netban.cpp b/src/engine/shared/netban.cpp new file mode 100644 index 00000000..eebe7c84 --- /dev/null +++ b/src/engine/shared/netban.cpp @@ -0,0 +1,615 @@ +#include + +#include +#include +#include + +#include "netban.h" + + +bool CNetBan::StrAllnum(const char *pStr) +{ + while(*pStr) + { + if(!(*pStr >= '0' && *pStr <= '9')) + return false; + pStr++; + } + return true; +} + + +CNetBan::CNetHash::CNetHash(const NETADDR *pAddr) +{ + if(pAddr->type==NETTYPE_IPV4) + m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3])&0xFF; + else + m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3]+pAddr->ip[4]+pAddr->ip[5]+pAddr->ip[6]+pAddr->ip[7]+ + pAddr->ip[8]+pAddr->ip[9]+pAddr->ip[10]+pAddr->ip[11]+pAddr->ip[12]+pAddr->ip[13]+pAddr->ip[14]+pAddr->ip[15])&0xFF; + m_HashIndex = 0; +} + +CNetBan::CNetHash::CNetHash(const CNetRange *pRange) +{ + m_Hash = 0; + m_HashIndex = 0; + for(int i = 0; pRange->m_LB.ip[i] == pRange->m_UB.ip[i]; ++i) + { + m_Hash += pRange->m_LB.ip[i]; + ++m_HashIndex; + } + m_Hash &= 0xFF; +} + +int CNetBan::CNetHash::MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17]) +{ + int Length = pAddr->type==NETTYPE_IPV4 ? 4 : 16; + aHash[0].m_Hash = 0; + aHash[0].m_HashIndex = 0; + for(int i = 1, Sum = 0; i <= Length; ++i) + { + Sum += pAddr->ip[i-1]; + aHash[i].m_Hash = Sum&0xFF; + aHash[i].m_HashIndex = i%Length; + } + return Length; +} + + +template +typename CNetBan::CBan *CNetBan::CBanPool::Add(const T *pData, const CBanInfo *pInfo, const CNetHash *pNetHash) +{ + if(!m_pFirstFree) + return 0; + + // create new ban + CBan *pBan = m_pFirstFree; + pBan->m_Data = *pData; + pBan->m_Info = *pInfo; + pBan->m_NetHash = *pNetHash; + if(pBan->m_pNext) + pBan->m_pNext->m_pPrev = pBan->m_pPrev; + if(pBan->m_pPrev) + pBan->m_pPrev->m_pNext = pBan->m_pNext; + else + m_pFirstFree = pBan->m_pNext; + + // add it to the hash list + if(m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]) + m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]->m_pHashPrev = pBan; + pBan->m_pHashPrev = 0; + pBan->m_pHashNext = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; + m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash] = pBan; + + // insert it into the used list + if(m_pFirstUsed) + { + for(CBan *p = m_pFirstUsed; ; p = p->m_pNext) + { + if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires)) + { + // insert before + pBan->m_pNext = p; + pBan->m_pPrev = p->m_pPrev; + if(p->m_pPrev) + p->m_pPrev->m_pNext = pBan; + else + m_pFirstUsed = pBan; + p->m_pPrev = pBan; + break; + } + + if(!p->m_pNext) + { + // last entry + p->m_pNext = pBan; + pBan->m_pPrev = p; + pBan->m_pNext = 0; + break; + } + } + } + else + { + m_pFirstUsed = pBan; + pBan->m_pNext = pBan->m_pPrev = 0; + } + + // update ban count + ++m_CountUsed; + + return pBan; +} + +template +int CNetBan::CBanPool::Remove(CBan *pBan) +{ + if(pBan == 0) + return -1; + + // remove from hash list + if(pBan->m_pHashNext) + pBan->m_pHashNext->m_pHashPrev = pBan->m_pHashPrev; + if(pBan->m_pHashPrev) + pBan->m_pHashPrev->m_pHashNext = pBan->m_pHashNext; + else + m_paaHashList[pBan->m_NetHash.m_HashIndex][pBan->m_NetHash.m_Hash] = pBan->m_pHashNext; + pBan->m_pHashNext = pBan->m_pHashPrev = 0; + + // remove from used list + if(pBan->m_pNext) + pBan->m_pNext->m_pPrev = pBan->m_pPrev; + if(pBan->m_pPrev) + pBan->m_pPrev->m_pNext = pBan->m_pNext; + else + m_pFirstUsed = pBan->m_pNext; + + // add to recycle list + if(m_pFirstFree) + m_pFirstFree->m_pPrev = pBan; + pBan->m_pPrev = 0; + pBan->m_pNext = m_pFirstFree; + m_pFirstFree = pBan; + + // update ban count + --m_CountUsed; + + return 0; +} + +template +void CNetBan::CBanPool::Update(CBan *pBan, const CBanInfo *pInfo) +{ + pBan->m_Info = *pInfo; + + // remove from used list + if(pBan->m_pNext) + pBan->m_pNext->m_pPrev = pBan->m_pPrev; + if(pBan->m_pPrev) + pBan->m_pPrev->m_pNext = pBan->m_pNext; + else + m_pFirstUsed = pBan->m_pNext; + + // insert it into the used list + if(m_pFirstUsed) + { + for(CBan *p = m_pFirstUsed; ; p = p->m_pNext) + { + if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires)) + { + // insert before + pBan->m_pNext = p; + pBan->m_pPrev = p->m_pPrev; + if(p->m_pPrev) + p->m_pPrev->m_pNext = pBan; + else + m_pFirstUsed = pBan; + p->m_pPrev = pBan; + break; + } + + if(!p->m_pNext) + { + // last entry + p->m_pNext = pBan; + pBan->m_pPrev = p; + pBan->m_pNext = 0; + break; + } + } + } + else + { + m_pFirstUsed = pBan; + pBan->m_pNext = pBan->m_pPrev = 0; + } +} + +template +void CNetBan::CBanPool::Reset() +{ + mem_zero(m_paaHashList, sizeof(m_paaHashList)); + mem_zero(m_aBans, sizeof(m_aBans)); + m_pFirstUsed = 0; + m_CountUsed = 0; + + for(int i = 1; i < MAX_BANS-1; ++i) + { + m_aBans[i].m_pNext = &m_aBans[i+1]; + m_aBans[i].m_pPrev = &m_aBans[i-1]; + } + + m_aBans[0].m_pNext = &m_aBans[1]; + m_aBans[MAX_BANS-1].m_pPrev = &m_aBans[MAX_BANS-2]; + m_pFirstFree = &m_aBans[0]; +} + +template +typename CNetBan::CBan *CNetBan::CBanPool::Find(const T *pData, const CNetHash *pNetHash) const +{ + for(CBan *pBan = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; pBan; pBan = pBan->m_pHashNext) + { + if(NetComp(&pBan->m_Data, pData) == 0) + return pBan; + } + + return 0; +} + +template +typename CNetBan::CBan *CNetBan::CBanPool::Get(int Index) const +{ + if(Index < 0 || Index >= Num()) + return 0; + + for(CNetBan::CBan *pBan = m_pFirstUsed; pBan; pBan = pBan->m_pNext, --Index) + { + if(Index == 0) + return pBan; + } + + return 0; +} + + +template +void CNetBan::MakeBanInfo(const CBan *pBan, char *pBuf, unsigned BuffSize, int Type) const +{ + if(pBan == 0) + { + if(BuffSize > 0) + pBuf[0] = 0; + return; + } + + // build type based part + char aBuf[256]; + if(Type == MSGTYPE_PLAYER) + str_copy(aBuf, "You have been banned", sizeof(aBuf)); + else + { + char aTemp[256]; + switch(Type) + { + case MSGTYPE_LIST: + str_format(aBuf, sizeof(aBuf), "%s banned", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; + case MSGTYPE_BANADD: + str_format(aBuf, sizeof(aBuf), "banned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; + case MSGTYPE_BANREM: + str_format(aBuf, sizeof(aBuf), "unbanned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; + default: + aBuf[0] = 0; + } + } + + // add info part + if(pBan->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER) + { + int Mins = ((pBan->m_Info.m_Expires-time_timestamp()) + 59) / 60; + if(Mins <= 1) + str_format(pBuf, BuffSize, "%s for 1 minute (%s)", aBuf, pBan->m_Info.m_aReason); + else + str_format(pBuf, BuffSize, "%s for %d minutes (%s)", aBuf, Mins, pBan->m_Info.m_aReason); + } + else + str_format(pBuf, BuffSize, "%s for life (%s)", aBuf, pBan->m_Info.m_aReason); +} + +template +int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason) +{ + // do not ban localhost + if(NetMatch(pData, &m_LocalhostIPV4) || NetMatch(pData, &m_LocalhostIPV6)) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (localhost)"); + return -1; + } + + int Stamp = Seconds > 0 ? time_timestamp()+Seconds : CBanInfo::EXPIRES_NEVER; + + // set up info + CBanInfo Info = {0}; + Info.m_Expires = Stamp; + str_copy(Info.m_aReason, pReason, sizeof(Info.m_aReason)); + + // check if it already exists + CNetHash NetHash(pData); + CBan *pBan = pBanPool->Find(pData, &NetHash); + if(pBan) + { + // adjust the ban + pBanPool->Update(pBan, &Info); + char aBuf[128]; + MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + return 1; + } + + // add ban and print result + pBan = pBanPool->Add(pData, &Info, &NetHash); + if(pBan) + { + char aBuf[128]; + MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANADD); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + return 0; + } + else + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (full banlist)"); + return -1; +} + +template +int CNetBan::Unban(T *pBanPool, const typename T::CDataType *pData) +{ + CNetHash NetHash(pData); + CBan *pBan = pBanPool->Find(pData, &NetHash); + if(pBan) + { + char aBuf[256]; + MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANREM); + pBanPool->Remove(pBan); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + return 0; + } + else + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban failed (invalid entry)"); + return -1; +} + +void CNetBan::Init(IConsole *pConsole, IStorage *pStorage) +{ + m_pConsole = pConsole; + m_pStorage = pStorage; + m_BanAddrPool.Reset(); + m_BanRangePool.Reset(); + + net_host_lookup("localhost", &m_LocalhostIPV4, NETTYPE_IPV4); + net_host_lookup("localhost", &m_LocalhostIPV6, NETTYPE_IPV6); + + Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBan, this, "Ban ip for x minutes for any reason"); + Console()->Register("ban_range", "ss?ir", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBanRange, this, "Ban ip range for x minutes for any reason"); + Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnban, this, "Unban ip/banlist entry"); + Console()->Register("unban_range", "ss", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnbanRange, this, "Unban ip range"); + Console()->Register("unban_all", "", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnbanAll, this, "Unban all entries"); + Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBans, this, "Show banlist"); + Console()->Register("bans_save", "s", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBansSave, this, "Save banlist in a file"); +} + +void CNetBan::Update() +{ + int Now = time_timestamp(); + + // remove expired bans + char aBuf[256], aNetStr[256]; + while(m_BanAddrPool.First() && m_BanAddrPool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanAddrPool.First()->m_Info.m_Expires < Now) + { + str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanAddrPool.First()->m_Data, aNetStr, sizeof(aNetStr))); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + m_BanAddrPool.Remove(m_BanAddrPool.First()); + } + while(m_BanRangePool.First() && m_BanRangePool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanRangePool.First()->m_Info.m_Expires < Now) + { + str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanRangePool.First()->m_Data, aNetStr, sizeof(aNetStr))); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + m_BanRangePool.Remove(m_BanRangePool.First()); + } +} + +int CNetBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason) +{ + return Ban(&m_BanAddrPool, pAddr, Seconds, pReason); +} + +int CNetBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason) +{ + if(pRange->IsValid()) + return Ban(&m_BanRangePool, pRange, Seconds, pReason); + + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)"); + return -1; +} + +int CNetBan::UnbanByAddr(const NETADDR *pAddr) +{ + return Unban(&m_BanAddrPool, pAddr); +} + +int CNetBan::UnbanByRange(const CNetRange *pRange) +{ + if(pRange->IsValid()) + return Unban(&m_BanRangePool, pRange); + + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)"); + return -1; +} + +int CNetBan::UnbanByIndex(int Index) +{ + int Result; + char aBuf[256]; + CBanAddr *pBan = m_BanAddrPool.Get(Index); + if(pBan) + { + NetToString(&pBan->m_Data, aBuf, sizeof(aBuf)); + Result = m_BanAddrPool.Remove(pBan); + } + else + { + CBanRange *pBan = m_BanRangePool.Get(Index-m_BanAddrPool.Num()); + if(pBan) + { + NetToString(&pBan->m_Data, aBuf, sizeof(aBuf)); + Result = m_BanRangePool.Remove(pBan); + } + else + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban failed (invalid index)"); + return -1; + } + } + + char aMsg[256]; + str_format(aMsg, sizeof(aMsg), "unbanned index %i (%s)", Index, aBuf); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg); + return Result; +} + +bool CNetBan::IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const +{ + CNetHash aHash[17]; + int Length = CNetHash::MakeHashArray(pAddr, aHash); + + // check ban adresses + CBanAddr *pBan = m_BanAddrPool.Find(pAddr, &aHash[Length]); + if(pBan) + { + MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER); + return true; + } + + // check ban ranges + for(int i = Length-1; i >= 0; --i) + { + for(CBanRange *pBan = m_BanRangePool.First(&aHash[i]); pBan; pBan = pBan->m_pHashNext) + { + if(NetMatch(&pBan->m_Data, pAddr, i, Length)) + { + MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER); + return true; + } + } + } + + return false; +} + +void CNetBan::ConBan(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + const char *pStr = pResult->GetString(0); + int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : 30; + const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given"; + + NETADDR Addr; + if(net_addr_from_str(&Addr, pStr) == 0) + pThis->BanAddr(&Addr, Minutes*60, pReason); + else + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid network address)"); +} + +void CNetBan::ConBanRange(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + const char *pStr1 = pResult->GetString(0); + const char *pStr2 = pResult->GetString(1); + int Minutes = pResult->NumArguments()>2 ? clamp(pResult->GetInteger(2), 0, 44640) : 30; + const char *pReason = pResult->NumArguments()>3 ? pResult->GetString(3) : "No reason given"; + + CNetRange Range; + if(net_addr_from_str(&Range.m_LB, pStr1) == 0 && net_addr_from_str(&Range.m_UB, pStr2) == 0) + pThis->BanRange(&Range, Minutes*60, pReason); + else + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid range)"); +} + +void CNetBan::ConUnban(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + const char *pStr = pResult->GetString(0); + if(StrAllnum(pStr)) + pThis->UnbanByIndex(str_toint(pStr)); + else + { + NETADDR Addr; + if(net_addr_from_str(&Addr, pStr) == 0) + pThis->UnbanByAddr(&Addr); + else + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban error (invalid network address)"); + } +} + +void CNetBan::ConUnbanRange(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + const char *pStr1 = pResult->GetString(0); + const char *pStr2 = pResult->GetString(1); + + CNetRange Range; + if(net_addr_from_str(&Range.m_LB, pStr1) == 0 && net_addr_from_str(&Range.m_UB, pStr2) == 0) + pThis->UnbanByRange(&Range); + else + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban error (invalid range)"); +} + +void CNetBan::ConUnbanAll(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + pThis->UnbanAll(); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unbanned all entries"); +} + +void CNetBan::ConBans(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + int Count = 0; + char aBuf[256], aMsg[256]; + for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext) + { + pThis->MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST); + str_format(aMsg, sizeof(aMsg), "#%i %s", Count++, aBuf); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg); + } + for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext) + { + pThis->MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST); + str_format(aMsg, sizeof(aMsg), "#%i %s", Count++, aBuf); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg); + } + str_format(aMsg, sizeof(aMsg), "%d %s", Count, Count==1?"ban":"bans"); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg); +} + +void CNetBan::ConBansSave(IConsole::IResult *pResult, void *pUser) +{ + CNetBan *pThis = static_cast(pUser); + + char aBuf[256]; + IOHANDLE File = pThis->Storage()->OpenFile(pResult->GetString(0), IOFLAG_WRITE, IStorage::TYPE_SAVE); + if(!File) + { + str_format(aBuf, sizeof(aBuf), "failed to save banlist to '%s'", pResult->GetString(0)); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); + return; + } + + int Now = time_timestamp(); + char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE]; + for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext) + { + int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1; + net_addr_str(&pBan->m_Data, aAddrStr1, sizeof(aAddrStr1), false); + str_format(aBuf, sizeof(aBuf), "ban_ip %s %i %s", aAddrStr1, Min, pBan->m_Info.m_aReason); + io_write(File, aBuf, str_length(aBuf)); + io_write_newline(File); + } + for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext) + { + int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1; + net_addr_str(&pBan->m_Data.m_LB, aAddrStr1, sizeof(aAddrStr1), false); + net_addr_str(&pBan->m_Data.m_UB, aAddrStr2, sizeof(aAddrStr2), false); + str_format(aBuf, sizeof(aBuf), "ban_range %s %i %s", aAddrStr1, aAddrStr2, Min, pBan->m_Info.m_aReason); + io_write(File, aBuf, str_length(aBuf)); + io_write_newline(File); + } + + io_close(File); + str_format(aBuf, sizeof(aBuf), "saved banlist to '%s'", pResult->GetString(0)); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf); +} diff --git a/src/engine/shared/netban.h b/src/engine/shared/netban.h new file mode 100644 index 00000000..a93cc797 --- /dev/null +++ b/src/engine/shared/netban.h @@ -0,0 +1,184 @@ +#ifndef ENGINE_SHARED_NETBAN_H +#define ENGINE_SHARED_NETBAN_H + +#include + + +inline int NetComp(const NETADDR *pAddr1, const NETADDR *pAddr2) +{ + return mem_comp(pAddr1, pAddr2, pAddr1->type==NETTYPE_IPV4 ? 8 : 20); +} + +class CNetRange +{ +public: + NETADDR m_LB; + NETADDR m_UB; + + bool IsValid() const { return m_LB.type == m_UB.type && NetComp(&m_LB, &m_UB) < 0; } +}; + +inline int NetComp(const CNetRange *pRange1, const CNetRange *pRange2) +{ + return NetComp(&pRange1->m_LB, &pRange2->m_LB) || NetComp(&pRange1->m_UB, &pRange2->m_UB); +} + + +class CNetBan +{ +protected: + bool NetMatch(const NETADDR *pAddr1, const NETADDR *pAddr2) const + { + return NetComp(pAddr1, pAddr2) == 0; + } + + bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr, int Start, int Length) const + { + return pRange->m_LB.type == pAddr->type && + mem_comp(&pRange->m_LB.ip[Start], &pAddr->ip[Start], Length-Start) <= 0 && mem_comp(&pRange->m_UB.ip[Start], &pAddr->ip[Start], Length-Start) >= 0; + } + + bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr) const + { + return NetMatch(pRange, pAddr, 0, pRange->m_LB.type==NETTYPE_IPV4 ? 4 : 16); + } + + const char *NetToString(const NETADDR *pData, char *pBuffer, unsigned BufferSize) const + { + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(pData, aAddrStr, sizeof(aAddrStr), false); + str_format(pBuffer, BufferSize, "'%s'", aAddrStr); + return pBuffer; + } + + const char *NetToString(const CNetRange *pData, char *pBuffer, unsigned BufferSize) const + { + char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE]; + net_addr_str(&pData->m_LB, aAddrStr1, sizeof(aAddrStr1), false); + net_addr_str(&pData->m_UB, aAddrStr2, sizeof(aAddrStr2), false); + str_format(pBuffer, BufferSize, "'%s' - '%s'", aAddrStr1, aAddrStr2); + return pBuffer; + } + + // todo: move? + static bool StrAllnum(const char *pStr); + + class CNetHash + { + public: + int m_Hash; + int m_HashIndex; // matching parts for ranges, 0 for addr + + CNetHash() {} + CNetHash(const NETADDR *pAddr); + CNetHash(const CNetRange *pRange); + + static int MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17]); + }; + + struct CBanInfo + { + enum + { + EXPIRES_NEVER=-1, + REASON_LENGTH=64, + }; + int m_Expires; + char m_aReason[REASON_LENGTH]; + }; + + template struct CBan + { + T m_Data; + CBanInfo m_Info; + CNetHash m_NetHash; + + // hash list + CBan *m_pHashNext; + CBan *m_pHashPrev; + + // used or free list + CBan *m_pNext; + CBan *m_pPrev; + }; + + template class CBanPool + { + public: + typedef T CDataType; + + CBan *Add(const CDataType *pData, const CBanInfo *pInfo, const CNetHash *pNetHash); + int Remove(CBan *pBan); + void Update(CBan *pBan, const CBanInfo *pInfo); + void Reset(); + + int Num() const { return m_CountUsed; } + bool IsFull() const { return m_CountUsed == MAX_BANS; } + + CBan *First() const { return m_pFirstUsed; } + CBan *First(const CNetHash *pNetHash) const { return m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; } + CBan *Find(const CDataType *pData, const CNetHash *pNetHash) const; + CBan *Get(int Index) const; + + private: + enum + { + MAX_BANS=1024, + }; + + CBan *m_paaHashList[HashCount][256]; + CBan m_aBans[MAX_BANS]; + CBan *m_pFirstFree; + CBan *m_pFirstUsed; + int m_CountUsed; + }; + + typedef CBanPool CBanAddrPool; + typedef CBanPool CBanRangePool; + typedef CBan CBanAddr; + typedef CBan CBanRange; + + template void MakeBanInfo(const CBan *pBan, char *pBuf, unsigned BuffSize, int Type) const; + template int Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason); + template int Unban(T *pBanPool, const typename T::CDataType *pData); + + class IConsole *m_pConsole; + class IStorage *m_pStorage; + CBanAddrPool m_BanAddrPool; + CBanRangePool m_BanRangePool; + NETADDR m_LocalhostIPV4, m_LocalhostIPV6; + +public: + enum + { + MSGTYPE_PLAYER=0, + MSGTYPE_LIST, + MSGTYPE_BANADD, + MSGTYPE_BANREM, + }; + + class IConsole *Console() const { return m_pConsole; } + class IStorage *Storage() const { return m_pStorage; } + + virtual ~CNetBan() {} + virtual void Init(class IConsole *pConsole, class IStorage *pStorage); + void Update(); + + virtual int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); + virtual int BanRange(const CNetRange *pRange, int Seconds, const char *pReason); + int UnbanByAddr(const NETADDR *pAddr); + int UnbanByRange(const CNetRange *pRange); + int UnbanByIndex(int Index); + void UnbanAll() { m_BanAddrPool.Reset(); m_BanRangePool.Reset(); } + bool IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const; + + static void ConBan(class IConsole::IResult *pResult, void *pUser); + static void ConBanRange(class IConsole::IResult *pResult, void *pUser); + static void ConUnban(class IConsole::IResult *pResult, void *pUser); + static void ConUnbanRange(class IConsole::IResult *pResult, void *pUser); + static void ConUnbanAll(class IConsole::IResult *pResult, void *pUser); + static void ConBans(class IConsole::IResult *pResult, void *pUser); + static void ConBansSave(class IConsole::IResult *pResult, void *pUser); +}; + +#endif diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index ca460d67..dd43389e 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -73,8 +73,6 @@ enum NET_CTRLMSG_ACCEPT=3, NET_CTRLMSG_CLOSE=4, - NET_SERVER_MAXBANS=1024, - NET_CONN_BUFFERSIZE=1024*32, NET_ENUM_TERMINATOR @@ -182,7 +180,7 @@ public: const char *ErrorString(); void SignalResend(); int State() const { return m_State; } - NETADDR PeerAddress() const { return m_PeerAddr; } + const NETADDR *PeerAddress() const { return &m_PeerAddr; } void ResetErrorString() { m_ErrorString[0] = 0; } const char *ErrorString() const { return m_ErrorString; } @@ -214,7 +212,7 @@ public: void Disconnect(const char *pReason); int State() const { return m_State; } - NETADDR PeerAddress() const { return m_PeerAddr; } + const NETADDR *PeerAddress() const { return &m_PeerAddr; } const char *ErrorString() const { return m_aErrorString; } void Reset(); @@ -244,59 +242,29 @@ public: // server side class CNetServer { -public: - struct CBanInfo - { - NETADDR m_Addr; - int m_Expires; - char m_Reason[128]; - }; - -private: struct CSlot { public: CNetConnection m_Connection; }; - struct CBan - { - public: - CBanInfo m_Info; - - // hash list - CBan *m_pHashNext; - CBan *m_pHashPrev; - - // used or free list - CBan *m_pNext; - CBan *m_pPrev; - }; - - NETSOCKET m_Socket; + class CNetBan *m_pNetBan; CSlot m_aSlots[NET_MAX_CLIENTS]; int m_MaxClients; int m_MaxClientsPerIP; - CBan *m_aBans[256]; - CBan m_BanPool[NET_SERVER_MAXBANS]; - CBan *m_BanPool_FirstFree; - CBan *m_BanPool_FirstUsed; - NETFUNC_NEWCLIENT m_pfnNewClient; NETFUNC_DELCLIENT m_pfnDelClient; void *m_UserPtr; CNetRecvUnpacker m_RecvUnpacker; - void BanRemoveByObject(CBan *pBan); - public: int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); // - bool Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int Flags); + bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags); int Close(); // @@ -307,16 +275,10 @@ public: // int Drop(int ClientID, const char *pReason); - // banning - int BanAdd(NETADDR Addr, int Seconds, const char *pReason); - int BanRemove(NETADDR Addr); - int BanRemoveAll(); - int BanNum(); // caution, slow - int BanGet(int Index, CBanInfo *pInfo); // caution, slow - // status requests - NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } + const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } NETSOCKET Socket() const { return m_Socket; } + class CNetBan *NetBan() const { return m_pNetBan; } int NetType() const { return m_Socket.type; } int MaxClients() const { return m_MaxClients; } @@ -326,27 +288,13 @@ public: class CNetConsole { - enum - { - MAX_BANS=128, - }; - - int FindBan(NETADDR Addr); - void UpdateBans(); - - struct CBanEntry - { - NETADDR m_Addr; - int m_Expires; - } m_aBans[MAX_BANS]; - int m_NumBans; - struct CSlot { CConsoleNetConnection m_Connection; }; NETSOCKET m_Socket; + class CNetBan *m_pNetBan; CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS]; NETFUNC_NEWCLIENT m_pfnNewClient; @@ -359,7 +307,7 @@ public: void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); // - bool Open(NETADDR BindAddr, int Flags); + bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int Flags); int Close(); // @@ -371,10 +319,9 @@ public: int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); int Drop(int ClientID, const char *pReason); - bool AddBan(NETADDR Addr, int Seconds); - // status requests - NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } + const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } + class CNetBan *NetBan() const { return m_pNetBan; } }; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index cfa081a2..ded83f68 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -1,15 +1,21 @@ /* (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. */ #include + +#include + +#include "netban.h" #include "network.h" -bool CNetConsole::Open(NETADDR BindAddr, int Flags) + +bool CNetConsole::Open(NETADDR BindAddr, CNetBan *pNetBan, int Flags) { // zero out the whole structure mem_zero(this, sizeof(*this)); m_Socket.type = NETTYPE_INVALID; m_Socket.ipv4sock = -1; m_Socket.ipv6sock = -1; + m_pNetBan = pNetBan; // open socket m_Socket = net_tcp_create(BindAddr); @@ -64,8 +70,7 @@ int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) FreeSlot = i; if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); - if(net_addr_comp(pAddr, &PeerAddr) == 0) + if(net_addr_comp(pAddr, m_aSlots[i].m_Connection.PeerAddress()) == 0) { str_copy(aError, "only one client per IP allowed", sizeof(aError)); break; @@ -99,26 +104,16 @@ int CNetConsole::Update() if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0) { - int Index = FindBan(Addr); - if(Index == -1) - AcceptClient(Socket, &Addr); - else + // check if we just should drop the packet + char aBuf[128]; + if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) { - char aBuf[128]; - if(m_aBans[Index].m_Expires > -1) - { - int Mins = (m_aBans[Index].m_Expires-time_timestamp()+ 59) / 60; - if(Mins <= 1) - str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute"); - else - str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins); - } - else - str_format(aBuf, sizeof(aBuf), "You have been banned for life"); - + // banned, reply with a message and drop net_tcp_send(Socket, aBuf, str_length(aBuf)); net_tcp_close(Socket); } + else + AcceptClient(Socket, &Addr); } for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) @@ -129,8 +124,6 @@ int CNetConsole::Update() Drop(i, m_aSlots[i].m_Connection.ErrorString()); } - UpdateBans(); - return 0; } @@ -155,65 +148,3 @@ int CNetConsole::Send(int ClientID, const char *pLine) else return -1; } - -int CNetConsole::FindBan(NETADDR Addr) -{ - Addr.port = 0; - for(int i = 0; i < m_NumBans; i++) - if(net_addr_comp(&m_aBans[i].m_Addr, &Addr) == 0) - return i; - - return -1; -} - -bool CNetConsole::AddBan(NETADDR Addr, int Seconds) -{ - if(m_NumBans == MAX_BANS) - return false; - - Addr.port = 0; - int Index = FindBan(Addr); - if(Index == -1) - { - Index = m_NumBans++; - m_aBans[Index].m_Addr = Addr; - } - m_aBans[Index].m_Expires = Seconds>0 ? time_timestamp()+Seconds : -1; - - for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) - { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); - PeerAddr.port = 0; - if(net_addr_comp(&Addr, &PeerAddr) == 0) - { - char aBuf[128]; - if(Seconds>0) - { - int Mins = (Seconds + 59) / 60; - if(Mins <= 1) - str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute"); - else - str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins); - } - else - str_format(aBuf, sizeof(aBuf), "You have been banned for life"); - Drop(i, aBuf); - } - } - } - return true; -} - -void CNetConsole::UpdateBans() -{ - int Now = time_timestamp(); - for(int i = 0; i < m_NumBans; ++i) - if(m_aBans[i].m_Expires > 0 && m_aBans[i].m_Expires < Now) - { - m_aBans[i] = m_aBans[m_NumBans-1]; - --m_NumBans; - break; - } -} diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index b4986bf0..1264a4a5 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -1,32 +1,14 @@ /* (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. */ #include -#include "network.h" -#define MACRO_LIST_LINK_FIRST(Object, First, Prev, Next) \ - { if(First) First->Prev = Object; \ - Object->Prev = (struct CBan *)0; \ - Object->Next = First; \ - First = Object; } - -#define MACRO_LIST_LINK_AFTER(Object, After, Prev, Next) \ - { Object->Prev = After; \ - Object->Next = After->Next; \ - After->Next = Object; \ - if(Object->Next) \ - Object->Next->Prev = Object; \ - } +#include -#define MACRO_LIST_UNLINK(Object, First, Prev, Next) \ - { if(Object->Next) Object->Next->Prev = Object->Prev; \ - if(Object->Prev) Object->Prev->Next = Object->Next; \ - else First = Object->Next; \ - Object->Next = 0; Object->Prev = 0; } +#include "netban.h" +#include "network.h" -#define MACRO_LIST_FIND(Start, Next, Expression) \ - { while(Start && !(Expression)) Start = Start->Next; } -bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int Flags) +bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags) { // zero out the whole structure mem_zero(this, sizeof(*this)); @@ -36,6 +18,8 @@ bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int if(!m_Socket.type) return false; + m_pNetBan = pNetBan; + // clamp clients m_MaxClients = MaxClients; if(m_MaxClients > NET_MAX_CLIENTS) @@ -48,8 +32,6 @@ bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int for(int i = 0; i < NET_MAX_CLIENTS; i++) m_aSlots[i].m_Connection.Init(m_Socket); - BanRemoveAll(); - return true; } @@ -85,181 +67,8 @@ int CNetServer::Drop(int ClientID, const char *pReason) return 0; } -int CNetServer::BanGet(int Index, CBanInfo *pInfo) -{ - CBan *pBan; - for(pBan = m_BanPool_FirstUsed; pBan && Index; pBan = pBan->m_pNext, Index--) - {} - - if(!pBan) - return 0; - *pInfo = pBan->m_Info; - return 1; -} - -int CNetServer::BanNum() -{ - int Count = 0; - CBan *pBan; - for(pBan = m_BanPool_FirstUsed; pBan; pBan = pBan->m_pNext) - Count++; - return Count; -} - -void CNetServer::BanRemoveByObject(CBan *pBan) -{ - int IpHash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3]+ - pBan->m_Info.m_Addr.ip[4]+pBan->m_Info.m_Addr.ip[5]+pBan->m_Info.m_Addr.ip[6]+pBan->m_Info.m_Addr.ip[7]+ - pBan->m_Info.m_Addr.ip[8]+pBan->m_Info.m_Addr.ip[9]+pBan->m_Info.m_Addr.ip[10]+pBan->m_Info.m_Addr.ip[11]+ - pBan->m_Info.m_Addr.ip[12]+pBan->m_Info.m_Addr.ip[13]+pBan->m_Info.m_Addr.ip[14]+pBan->m_Info.m_Addr.ip[15])&0xff; - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&pBan->m_Info.m_Addr, aAddrStr, sizeof(aAddrStr)); - dbg_msg("netserver", "removing ban on %s", aAddrStr); - MACRO_LIST_UNLINK(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); - MACRO_LIST_UNLINK(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext); - MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext); -} - -int CNetServer::BanRemove(NETADDR Addr) -{ - int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+ - Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff; - CBan *pBan = m_aBans[IpHash]; - - MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0); - - if(pBan) - { - BanRemoveByObject(pBan); - return 0; - } - - return -1; -} - -int CNetServer::BanRemoveAll() -{ - // clear bans memory - mem_zero(m_aBans, sizeof(m_aBans)); - mem_zero(m_BanPool, sizeof(m_BanPool)); - m_BanPool_FirstFree = 0; - m_BanPool_FirstUsed = 0; - - // setup all pointers for bans - for(int i = 1; i < NET_SERVER_MAXBANS-1; i++) - { - m_BanPool[i].m_pNext = &m_BanPool[i+1]; - m_BanPool[i].m_pPrev = &m_BanPool[i-1]; - } - - m_BanPool[0].m_pNext = &m_BanPool[1]; - m_BanPool[NET_SERVER_MAXBANS-1].m_pPrev = &m_BanPool[NET_SERVER_MAXBANS-2]; - m_BanPool_FirstFree = &m_BanPool[0]; - - return 0; -} - -int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason) -{ - int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+ - Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff; - int Stamp = -1; - CBan *pBan; - - // remove the port - Addr.port = 0; - - if(Seconds) - Stamp = time_timestamp() + Seconds; - - // search to see if it already exists - pBan = m_aBans[IpHash]; - MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0); - if(pBan) - { - // adjust the ban - pBan->m_Info.m_Expires = Stamp; - return 0; - } - - if(!m_BanPool_FirstFree) - return -1; - - // fetch and clear the new ban - pBan = m_BanPool_FirstFree; - MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext); - - // setup the ban info - pBan->m_Info.m_Expires = Stamp; - pBan->m_Info.m_Addr = Addr; - str_copy(pBan->m_Info.m_Reason, pReason, sizeof(pBan->m_Info.m_Reason)); - - // add it to the ban hash - MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext); - - // insert it into the used list - { - if(m_BanPool_FirstUsed) - { - CBan *pInsertAfter = m_BanPool_FirstUsed; - MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires); - - if(pInsertAfter) - pInsertAfter = pInsertAfter->m_pPrev; - else - { - // add to last - pInsertAfter = m_BanPool_FirstUsed; - while(pInsertAfter->m_pNext) - pInsertAfter = pInsertAfter->m_pNext; - } - - if(pInsertAfter) - { - MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext); - } - else - { - MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); - } - } - else - { - MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); - } - } - - // drop banned clients - { - char Buf[128]; - NETADDR BanAddr; - - if(Stamp > -1) - { - int Mins = (Seconds + 59) / 60; - if(Mins <= 1) - str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason); - else - str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason); - } - else - str_format(Buf, sizeof(Buf), "You have been banned for life (%s)", pReason); - - for(int i = 0; i < MaxClients(); i++) - { - BanAddr = m_aSlots[i].m_Connection.PeerAddress(); - BanAddr.port = 0; - - if(net_addr_comp(&Addr, &BanAddr) == 0) - Drop(i, Buf); - } - } - return 0; -} - int CNetServer::Update() { - int Now = time_timestamp(); for(int i = 0; i < MaxClients(); i++) { m_aSlots[i].m_Connection.Update(); @@ -267,13 +76,6 @@ int CNetServer::Update() Drop(i, m_aSlots[i].m_Connection.ErrorString()); } - // remove expired bans - while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now) - { - CBan *pBan = m_BanPool_FirstUsed; - BanRemoveByObject(pBan); - } - return 0; } @@ -282,8 +84,6 @@ int CNetServer::Update() */ int CNetServer::Recv(CNetChunk *pChunk) { - unsigned Now = time_timestamp(); - while(1) { NETADDR Addr; @@ -301,36 +101,12 @@ int CNetServer::Recv(CNetChunk *pChunk) if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0) { - CBan *pBan = 0; - NETADDR BanAddr = Addr; - int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3]+BanAddr.ip[4]+BanAddr.ip[5]+BanAddr.ip[6]+BanAddr.ip[7]+ - BanAddr.ip[8]+BanAddr.ip[9]+BanAddr.ip[10]+BanAddr.ip[11]+BanAddr.ip[12]+BanAddr.ip[13]+BanAddr.ip[14]+BanAddr.ip[15])&0xff; - int Found = 0; - BanAddr.port = 0; - - // search a ban - for(pBan = m_aBans[IpHash]; pBan; pBan = pBan->m_pHashNext) - { - if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0) - break; - } - // check if we just should drop the packet - if(pBan) + char aBuf[128]; + if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) { // banned, reply with a message - char BanStr[128]; - if(pBan->m_Info.m_Expires > -1) - { - int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60; - if(Mins <= 1) - str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason); - else - str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason); - } - else - str_format(BanStr, sizeof(BanStr), "Banned for life (%s)", pBan->m_Info.m_Reason); - CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1); + CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1); continue; } @@ -348,16 +124,15 @@ int CNetServer::Recv(CNetChunk *pChunk) // TODO: check size here if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT) { - Found = 0; + bool Found = false; // check if we already got this client for(int i = 0; i < MaxClients(); i++) { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE && - net_addr_comp(&PeerAddr, &Addr) == 0) + net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) { - Found = 1; // silent ignore.. we got this client already + Found = true; // silent ignore.. we got this client already break; } } @@ -374,7 +149,7 @@ int CNetServer::Recv(CNetChunk *pChunk) if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) continue; - OtherAddr = m_aSlots[i].m_Connection.PeerAddress(); + OtherAddr = *m_aSlots[i].m_Connection.PeerAddress(); OtherAddr.port = 0; if(!net_addr_comp(&ThisAddr, &OtherAddr)) { @@ -392,7 +167,7 @@ int CNetServer::Recv(CNetChunk *pChunk) { if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) { - Found = 1; + Found = true; m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr); if(m_pfnNewClient) m_pfnNewClient(i, m_UserPtr); @@ -412,8 +187,7 @@ int CNetServer::Recv(CNetChunk *pChunk) // normal packet, find matching slot for(int i = 0; i < MaxClients(); i++) { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); - if(net_addr_comp(&PeerAddr, &Addr) == 0) + if(net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) { if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr)) { diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index f2e9e65d..d16d56cd 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -612,16 +612,10 @@ void CGameConsole::Dump(int Type) IOHANDLE io = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(io) { - #if defined(CONF_FAMILY_WINDOWS) - static const char Newline[] = "\r\n"; - #else - static const char Newline[] = "\n"; - #endif - for(CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.First(); pEntry; pEntry = pConsole->m_Backlog.Next(pEntry)) { io_write(io, pEntry->m_aText, str_length(pEntry->m_aText)); - io_write(io, Newline, sizeof(Newline)-1); + io_write_newline(io); } io_close(io); } diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp index a1e629a6..f0460d26 100644 --- a/src/game/client/components/maplayers.cpp +++ b/src/game/client/components/maplayers.cpp @@ -188,16 +188,11 @@ void CMapLayers::OnRender() IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(File) { - #if defined(CONF_FAMILY_WINDOWS) - static const char Newline[] = "\r\n"; - #else - static const char Newline[] = "\n"; - #endif for(int y = 0; y < pTMap->m_Height; y++) { for(int x = 0; x < pTMap->m_Width; x++) io_write(File, &(pTiles[y*pTMap->m_Width + x].m_Index), sizeof(pTiles[y*pTMap->m_Width + x].m_Index)); - io_write(File, Newline, sizeof(Newline)-1); + io_write_newline(File); } io_close(File); } diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index 70e4aecf..632a524c 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -1,20 +1,23 @@ /* (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. */ #include -#include -#include + #include -#include #include +#include + +#include +#include +#include #include "mastersrv.h" + enum { MTU = 1400, MAX_SERVERS_PER_PACKET=75, MAX_PACKETS=16, MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS, - MAX_BANS=128, EXPIRE_TIME = 90 }; @@ -77,14 +80,7 @@ static CCountPacketData m_CountData; static CCountPacketData m_CountDataLegacy; -struct CBanEntry -{ - NETADDR m_Address; - int64 m_Expire; -}; - -static CBanEntry m_aBans[MAX_BANS]; -static int m_NumBans = 0; +CNetBan m_NetBan; static CNetClient m_NetChecker; // NAT/FW checker static CNetClient m_NetOp; // main @@ -217,9 +213,9 @@ void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt, ServerType Type) } char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true); char aAltAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr)); + net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr), true); dbg_msg("mastersrv", "checking: %s (%s)", aAddrStr, aAltAddrStr); m_aCheckServers[m_NumCheckServers].m_Address = *pInfo; m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAlt; @@ -237,7 +233,7 @@ void AddServer(NETADDR *pInfo, ServerType Type) if(net_addr_comp(&m_aServers[i].m_Address, pInfo) == 0) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true); dbg_msg("mastersrv", "updated: %s", aAddrStr); m_aServers[i].m_Expire = time_get()+time_freq()*EXPIRE_TIME; return; @@ -252,7 +248,7 @@ void AddServer(NETADDR *pInfo, ServerType Type) } char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr)); + net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true); dbg_msg("mastersrv", "added: %s", aAddrStr); m_aServers[m_NumServers].m_Address = *pInfo; m_aServers[m_NumServers].m_Expire = time_get()+time_freq()*EXPIRE_TIME; @@ -271,9 +267,9 @@ void UpdateServers() if(m_aCheckServers[i].m_TryCount == 10) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr), true); char aAltAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr)); + net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr), true); dbg_msg("mastersrv", "check failed: %s (%s)", aAddrStr, aAltAddrStr); // FAIL!! @@ -305,7 +301,7 @@ void PurgeServers() { // remove server char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr), true); dbg_msg("mastersrv", "expired: %s", aAddrStr); m_aServers[i] = m_aServers[m_NumServers-1]; m_NumServers--; @@ -315,53 +311,9 @@ void PurgeServers() } } -bool CheckBan(NETADDR Addr) -{ - for(int i = 0; i < m_NumBans; i++) - { - if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0) - { - return true; - } - } - Addr.port = 0; - for(int i = 0; i < m_NumBans; i++) - { - if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0) - { - return true; - } - } - return false; -} - -void ConAddBan(IConsole::IResult *pResult, void *pUser) -{ - if(m_NumBans == MAX_BANS) - { - dbg_msg("mastersrv", "error: banlist is full"); - return; - } - - if(net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0)) != 0) - { - dbg_msg("mastersrv", "error: invalid address"); - return; - } - - if(CheckBan(m_aBans[m_NumBans].m_Address)) - { - dbg_msg("mastersrv", "duplicate ban: %s", pResult->GetString(0)); - return; - } - - dbg_msg("mastersrv", "ban added: %s", pResult->GetString(0)); - m_NumBans++; -} - void ReloadBans() { - m_NumBans = 0; + m_NetBan.UnbanAll(); m_pConsole->ExecuteFile("master.cfg"); } @@ -398,7 +350,7 @@ int main(int argc, const char **argv) // ignore_convention IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); m_pConsole = CreateConsole(CFGFLAG_MASTER); - m_pConsole->Register("ban", "s", CFGFLAG_MASTER, ConAddBan, 0, "Ban IP from mastersrv"); + m_NetBan.Init(m_pConsole, pStorage); bool RegisterFail = !pKernel->RegisterInterface(pStorage); RegisterFail |= !pKernel->RegisterInterface(m_pConsole); @@ -418,7 +370,8 @@ int main(int argc, const char **argv) // ignore_convention while(m_NetOp.Recv(&Packet)) { // check if the server is banned - if(CheckBan(Packet.m_Address)) continue; + if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0)) + continue; if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT)+2 && mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0) @@ -519,7 +472,8 @@ int main(int argc, const char **argv) // ignore_convention while(m_NetChecker.Recv(&Packet)) { // check if the server is banned - if(CheckBan(Packet.m_Address)) continue; + if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0)) + continue; if(Packet.m_DataSize == sizeof(SERVERBROWSE_FWRESPONSE) && mem_comp(Packet.m_pData, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0) diff --git a/src/tools/crapnet.cpp b/src/tools/crapnet.cpp index 98b6c0a7..fbd20445 100644 --- a/src/tools/crapnet.cpp +++ b/src/tools/crapnet.cpp @@ -129,7 +129,7 @@ void Run(int Port, NETADDR Dest) if(m_ConfigLog) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&From, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&From, aAddrStr, sizeof(aAddrStr), true); dbg_msg("crapnet", "<< %08d %s (%d)", p->m_ID, aAddrStr, p->m_DataSize); } } @@ -193,7 +193,7 @@ void Run(int Port, NETADDR Dest) if(m_ConfigLog) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&p->m_SendTo, aAddrStr, sizeof(aAddrStr)); + net_addr_str(&p->m_SendTo, aAddrStr, sizeof(aAddrStr), true); dbg_msg("crapnet", ">> %08d %s (%d) %s", p->m_ID, aAddrStr, p->m_DataSize, aFlags); } diff --git a/src/tools/fake_server.cpp b/src/tools/fake_server.cpp index 68c47659..9e76b3e7 100644 --- a/src/tools/fake_server.cpp +++ b/src/tools/fake_server.cpp @@ -113,7 +113,7 @@ static int Run() int64 NextHeartBeat = 0; NETADDR BindAddr = {NETTYPE_IPV4, {0},0}; - if(!pNet->Open(BindAddr, 0, 0, 0)) + if(!pNet->Open(BindAddr, 0, 0, 0, 0)) return 0; while(1) -- cgit 1.4.1 From 8ffe5826156d07b1feb7fc58bf59a1431e01160f Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Fri, 30 Dec 2011 16:02:22 +0100 Subject: ugly incomplete hack to put the rendering into another thread so we don't have to wait for the flip --- src/base/tl/threading.h | 78 ++++++++++++++++++++++++++++ src/engine/client/client.cpp | 98 +++++++++++++++++++++++++++++++++--- src/engine/client/client.h | 6 +++ src/game/client/components/menus.cpp | 3 ++ 4 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 src/base/tl/threading.h (limited to 'src/engine/client') diff --git a/src/base/tl/threading.h b/src/base/tl/threading.h new file mode 100644 index 00000000..66751ec4 --- /dev/null +++ b/src/base/tl/threading.h @@ -0,0 +1,78 @@ + +#pragma once + +#include "../system.h" + +inline unsigned atomic_inc(volatile unsigned *pValue) +{ + return __sync_fetch_and_add(pValue, 1); +} + +inline unsigned atomic_dec(volatile unsigned *pValue) +{ + return __sync_fetch_and_add(pValue, -1); +} + +inline unsigned atomic_compswap(volatile unsigned *pValue, unsigned comperand, unsigned value) +{ + return __sync_val_compare_and_swap(pValue, comperand, value); +} + +inline void sync_barrier() +{ + __sync_synchronize(); +} + +#include +typedef sem_t SEMAPHORE; +inline void semaphore_init(SEMAPHORE *sem) { sem_init(sem, 0, 0); } +inline void semaphore_wait(SEMAPHORE *sem) { sem_wait(sem); } +inline void semaphore_signal(SEMAPHORE *sem) { sem_post(sem); } +inline void semaphore_destroy(SEMAPHORE *sem) { sem_destroy(sem); } + +class semaphore +{ + SEMAPHORE sem; +public: + semaphore() { semaphore_init(&sem); } + ~semaphore() { semaphore_destroy(&sem); } + void wait() { semaphore_wait(&sem); } + void signal() { semaphore_signal(&sem); } +}; + +class lock +{ + friend class scope_lock; + + LOCK var; + + void take() { lock_wait(var); } + void release() { lock_release(var); } + +public: + lock() + { + var = lock_create(); + } + + ~lock() + { + lock_destroy(var); + } +}; + +class scope_lock +{ + lock *var; +public: + scope_lock(lock *l) + { + var = l; + var->take(); + } + + ~scope_lock() + { + var->release(); + } +}; diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 9f43b9ce..4107cd85 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -1688,17 +1689,27 @@ void CClient::InitInterfaces() m_Friends.Init(); } -void CClient::Run() -{ - int64 ReportTime = time_get(); - int64 ReportInterval = time_freq()*1; - m_LocalStartTime = time_get(); - m_SnapshotParts = 0; +enum +{ + GFXSTATE_ERROR = -1, + GFXSTATE_INIT = 0, + GFXSTATE_IDLE, + GFXSTATE_RENDERING, + GFXSTATE_SWAPPING, +}; +void CClient::GraphicsThread() +{ // init graphics if(m_pGraphics->Init() != 0) + { + m_GfxState = GFXSTATE_ERROR; + m_GfxStateSemaphore.signal(); + m_GfxState = GFXSTATE_ERROR; return; + } + // open socket { @@ -1708,6 +1719,7 @@ void CClient::Run() if(!m_NetClient.Open(BindAddr, 0)) { dbg_msg("client", "couldn't start network"); + m_GfxState = GFXSTATE_ERROR; return; } } @@ -1722,16 +1734,66 @@ void CClient::Run() MasterServer()->RefreshAddresses(m_NetClient.NetType()); // init the editor - m_pEditor->Init(); + //m_pEditor->Init(); // init sound, allowed to fail m_SoundInitFailed = Sound()->Init() != 0; // load data if(!LoadData()) + { + m_GfxState = GFXSTATE_ERROR; return; + } GameClient()->OnInit(); + + + while(1) + { + // do idle + sync_barrier(); + m_GfxState = GFXSTATE_IDLE; + m_GfxStateSemaphore.signal(); + m_GfxRenderSemaphore.wait(); + + // do render + m_GfxState = GFXSTATE_RENDERING; + m_GfxStateSemaphore.signal(); + Render(); + sync_barrier(); + + // do swap + m_GfxState = GFXSTATE_SWAPPING; + m_GfxStateSemaphore.signal(); + m_pGraphics->Swap(); + } + + // do shutdown +} + +void CClient::Run() +{ + int64 ReportTime = time_get(); + int64 ReportInterval = time_freq()*1; + + m_LocalStartTime = time_get(); + m_SnapshotParts = 0; + + m_GfxState = GFXSTATE_INIT; + thread_create(GraphicsThreadProxy, this); + + // wait for gfx to init + while(1) + { + m_GfxStateSemaphore.wait(); + if(m_GfxState == GFXSTATE_ERROR) + return; + if(m_GfxState != GFXSTATE_INIT) + break; + } + + char aBuf[256]; str_format(aBuf, sizeof(aBuf), "version %s", GameClient()->NetVersion()); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); @@ -1847,7 +1909,27 @@ void CClient::Run() m_EditorActive = false; Update(); + + + if(m_GfxState == GFXSTATE_IDLE) + { + // issue new rendering + m_GfxRenderSemaphore.signal(); + + // wait for gfx to finish rendering + while(m_GfxState != GFXSTATE_SWAPPING) + m_GfxStateSemaphore.wait(); + } + + /* + if(m_pGraphics->AsyncSwapIsDone()) + { + m_pGraphics->BeginScene(); + Render(); + m_pGraphics->EndScene(); + }*/ + /* if(g_Config.m_DbgStress) { if((m_Frames%10) == 0) @@ -1860,7 +1942,7 @@ void CClient::Run() { Render(); m_pGraphics->Swap(); - } + }*/ } AutoScreenshot_Cleanup(); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 1504a4e4..83553eb4 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -172,6 +172,12 @@ class CClient : public IClient, public CDemoPlayer::IListner class CHostLookup m_VersionServeraddr; } m_VersionInfo; + semaphore m_GfxRenderSemaphore; + semaphore m_GfxStateSemaphore; + volatile int m_GfxState; + static void GraphicsThreadProxy(void *pThis) { ((CClient*)pThis)->GraphicsThread(); } + void GraphicsThread(); + public: IEngine *Engine() { return m_pEngine; } IEngineGraphics *Graphics() { return m_pGraphics; } diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index a39139c8..fc1ca2db 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -627,6 +627,9 @@ int CMenus::RenderMenubar(CUIRect r) void CMenus::RenderLoading() { + // TODO: not supported right now due to separate render thread + return; + static int64 LastLoadRender = 0; float Percent = m_LoadCurrent++/(float)m_LoadTotal; -- cgit 1.4.1 From de3e94d9019ac9004e622a6e87535f51017fec46 Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 30 Dec 2011 19:21:00 +0100 Subject: clean up temp commands on logout in the client --- src/engine/client/client.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index c3bd770c..90cb172d 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -546,6 +546,7 @@ void CClient::DisconnectWithReason(const char *pReason) // m_RconAuthed = 0; + m_UseTempRconCommands = 0; m_pConsole->DeregisterTempAll(); m_NetClient.Disconnect(pReason); SetState(IClient::STATE_OFFLINE); @@ -1153,9 +1154,12 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) int Result = Unpacker.GetInt(); if(Unpacker.Error() == 0) m_RconAuthed = Result; + int Old = m_UseTempRconCommands; m_UseTempRconCommands = Unpacker.GetInt(); if(Unpacker.Error() != 0) m_UseTempRconCommands = 0; + if(Old != 0 && m_UseTempRconCommands == 0) + m_pConsole->DeregisterTempAll(); } else if(Msg == NETMSG_RCON_LINE) { -- cgit 1.4.1 From 8e568857959291f442ba8f11abac059b6bd6a9e9 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 01:06:04 +0100 Subject: initial commit of the threaded graphics. can start game and render the gui. no textures at the moment. still waits for the swap for now --- src/engine/client/client.cpp | 93 +-- src/engine/client/graphics.cpp | 2 +- src/engine/client/graphics.h | 342 +++++++++ src/engine/client/graphics_threaded.cpp | 1225 +++++++++++++++++++++++++++++++ src/game/client/components/menus.cpp | 1 - 5 files changed, 1576 insertions(+), 87 deletions(-) create mode 100644 src/engine/client/graphics_threaded.cpp (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 4107cd85..bb888c60 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1689,28 +1689,21 @@ void CClient::InitInterfaces() m_Friends.Init(); } - -enum +void CClient::Run() { - GFXSTATE_ERROR = -1, - GFXSTATE_INIT = 0, - GFXSTATE_IDLE, - GFXSTATE_RENDERING, - GFXSTATE_SWAPPING, -}; + int64 ReportTime = time_get(); + int64 ReportInterval = time_freq()*1; + + m_LocalStartTime = time_get(); + m_SnapshotParts = 0; -void CClient::GraphicsThread() -{ // init graphics if(m_pGraphics->Init() != 0) { - m_GfxState = GFXSTATE_ERROR; - m_GfxStateSemaphore.signal(); - m_GfxState = GFXSTATE_ERROR; + dbg_msg("client", "couldn't init graphics"); return; } - // open socket { NETADDR BindAddr; @@ -1719,7 +1712,6 @@ void CClient::GraphicsThread() if(!m_NetClient.Open(BindAddr, 0)) { dbg_msg("client", "couldn't start network"); - m_GfxState = GFXSTATE_ERROR; return; } } @@ -1741,59 +1733,10 @@ void CClient::GraphicsThread() // load data if(!LoadData()) - { - m_GfxState = GFXSTATE_ERROR; return; - } GameClient()->OnInit(); - - while(1) - { - // do idle - sync_barrier(); - m_GfxState = GFXSTATE_IDLE; - m_GfxStateSemaphore.signal(); - m_GfxRenderSemaphore.wait(); - - // do render - m_GfxState = GFXSTATE_RENDERING; - m_GfxStateSemaphore.signal(); - Render(); - sync_barrier(); - - // do swap - m_GfxState = GFXSTATE_SWAPPING; - m_GfxStateSemaphore.signal(); - m_pGraphics->Swap(); - } - - // do shutdown -} - -void CClient::Run() -{ - int64 ReportTime = time_get(); - int64 ReportInterval = time_freq()*1; - - m_LocalStartTime = time_get(); - m_SnapshotParts = 0; - - m_GfxState = GFXSTATE_INIT; - thread_create(GraphicsThreadProxy, this); - - // wait for gfx to init - while(1) - { - m_GfxStateSemaphore.wait(); - if(m_GfxState == GFXSTATE_ERROR) - return; - if(m_GfxState != GFXSTATE_INIT) - break; - } - - char aBuf[256]; str_format(aBuf, sizeof(aBuf), "version %s", GameClient()->NetVersion()); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); @@ -1910,26 +1853,6 @@ void CClient::Run() Update(); - - if(m_GfxState == GFXSTATE_IDLE) - { - // issue new rendering - m_GfxRenderSemaphore.signal(); - - // wait for gfx to finish rendering - while(m_GfxState != GFXSTATE_SWAPPING) - m_GfxStateSemaphore.wait(); - - } - - /* - if(m_pGraphics->AsyncSwapIsDone()) - { - m_pGraphics->BeginScene(); - Render(); - m_pGraphics->EndScene(); - }*/ - /* if(g_Config.m_DbgStress) { if((m_Frames%10) == 0) @@ -1942,7 +1865,7 @@ void CClient::Run() { Render(); m_pGraphics->Swap(); - }*/ + } } AutoScreenshot_Cleanup(); diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 617162ae..2d034f3f 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -950,4 +950,4 @@ int CGraphics_SDL::GetVideoModes(CVideoMode *pModes, int MaxModes) return NumModes; } -extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } +//extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index 95e9769a..84142d9d 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -3,6 +3,348 @@ #ifndef ENGINE_CLIENT_GRAPHICS_H #define ENGINE_CLIENT_GRAPHICS_H +#include + +class CCommandBuffer +{ + class CBuffer + { + unsigned char *m_pData; + unsigned m_Size; + unsigned m_Used; + public: + CBuffer(unsigned BufferSize) + { + m_Size = BufferSize; + m_pData = new unsigned char[m_Size]; + m_Used = 0; + } + + ~CBuffer() + { + delete [] m_pData; + m_pData = 0x0; + m_Used = 0; + m_Size = 0; + } + + void Reset() + { + m_Used = 0; + } + + void *Alloc(unsigned Requested) + { + if(Requested + m_Used > m_Size) + return 0; + void *pPtr = &m_pData[m_Used]; + m_Used += Requested; + return pPtr; + } + + unsigned char *DataPtr() { return m_pData; } + unsigned DataSize() { return m_Size; } + unsigned DataUsed() { return m_Used; } + }; + + CBuffer m_CmdBuffer; + CBuffer m_DataBuffer; +public: + enum + { + // + CMD_NOP = 0, + + // + CMD_INIT, + CMD_SHUTDOWN, + + // + CMD_RUNBUFFER, + + // syncronization + CMD_SIGNAL, + + // texture commands + CMD_TEXTURE_CREATE, + CMD_TEXTURE_DESTROY, + + // rendering + CMD_CLEAR, + CMD_RENDER, + + // swap + CMD_SWAP, + }; + + enum + { + // + PRIMTYPE_INVALID = 0, + PRIMTYPE_LINES, + PRIMTYPE_QUADS, + }; + + enum + { + BLEND_NONE = 0, + BLEND_ALPHA, + BLEND_ADDITIVE, + }; + + struct SPoint { float x, y, z; }; + struct STexCoord { float u, v; }; + struct SColor { float r, g, b, a; }; + + struct SVertex + { + SPoint m_Pos; + STexCoord m_Tex; + SColor m_Color; + } ; + + struct SCommand + { + public: + SCommand(unsigned Cmd) : m_Cmd(Cmd), m_Size(0) {} + unsigned m_Cmd; + unsigned m_Size; + }; + + struct SState + { + int m_BlendMode; + int m_Texture; + SPoint m_ScreenTL; + SPoint m_ScreenBR; + + // clip + bool m_ClipEnable; + int m_ClipX; + int m_ClipY; + int m_ClipW; + int m_ClipH; + }; + + struct SCommand_Clear : public SCommand + { + SCommand_Clear() : SCommand(CMD_CLEAR) {} + SColor m_Color; + }; + + + struct SCommand_Init : public SCommand + { + SCommand_Init() : SCommand(CMD_INIT) {} + volatile int *m_pResult; + }; + + struct SCommand_RunBuffer : public SCommand + { + SCommand_RunBuffer() : SCommand(CMD_RUNBUFFER) {} + CCommandBuffer *m_pOtherBuffer; + }; + + struct SCommand_Render : public SCommand + { + SCommand_Render() : SCommand(CMD_RENDER) {} + SState m_State; + unsigned m_PrimType; + unsigned m_PrimCount; + SVertex *m_pVertices; + }; + + struct SCommand_Swap : public SCommand + { + SCommand_Swap() : SCommand(CMD_SWAP) {} + }; + + // + CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) + : m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize) + { + } + + void *AllocData(unsigned WantedSize) + { + return m_DataBuffer.Alloc(WantedSize); + } + + template + void AddCommand(const T &Command) + { + SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command)); + if(!pCmd) + return; + + mem_copy(pCmd, &Command, sizeof(Command)); + pCmd->m_Size = sizeof(Command); + } + + SCommand *GetCommand(unsigned *pIndex) + { + if(*pIndex >= m_CmdBuffer.DataUsed()) + return NULL; + + SCommand *pCommand = (SCommand *)&m_CmdBuffer.DataPtr()[*pIndex]; + *pIndex += pCommand->m_Size; + return pCommand; + } + + void Reset() + { + m_CmdBuffer.Reset(); + m_DataBuffer.Reset(); + } +}; + +class ICommandProcessor +{ +public: + virtual ~ICommandProcessor() {} + virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; +}; + + +class CCommandProcessorHandler +{ + ICommandProcessor *m_pProcessor; + CCommandBuffer * volatile m_pBuffer; + volatile bool m_Shutdown; + semaphore m_Activity; + semaphore m_BufferDone; + void *m_pThread; + + static void ThreadFunc(void *pUser); + +public: + CCommandProcessorHandler(); + void Start(ICommandProcessor *pProcessor); + void RunBuffer(CCommandBuffer *pBuffer); + bool IsIdle() const { return m_pBuffer == 0; } + void WaitForIdle(); +}; + +class CGraphics_Threaded : public IEngineGraphics +{ + CCommandBuffer::SState m_State; + CCommandProcessorHandler m_Handler; + + CCommandBuffer *m_apCommandBuffers[2]; + CCommandBuffer *m_pCommandBuffer; + unsigned m_CurrentCommandBuffer; + + // + class IStorage *m_pStorage; + class IConsole *m_pConsole; + + enum + { + MAX_VERTICES = 32*1024, + MAX_TEXTURES = 1024*4, + + DRAWING_QUADS=1, + DRAWING_LINES=2 + }; + + CCommandBuffer::SVertex m_aVertices[MAX_VERTICES]; + int m_NumVertices; + + CCommandBuffer::SColor m_aColor[4]; + CCommandBuffer::STexCoord m_aTexture[4]; + + bool m_RenderEnable; + + float m_Rotation; + int m_Drawing; + bool m_DoScreenshot; + char m_aScreenshotName[128]; + + int m_InvalidTexture; + + struct CTexture + { + GLuint m_Tex; + int m_MemSize; + int m_Flags; + int m_Next; + }; + + CTexture m_aTextures[MAX_TEXTURES]; + int m_FirstFreeTexture; + int m_TextureMemoryUsage; + + void Flush(); + void AddVertices(int Count); + void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints); + + static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); + static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); +public: + CGraphics_Threaded(); + + virtual void ClipEnable(int x, int y, int w, int h); + virtual void ClipDisable(); + + virtual void BlendNone(); + virtual void BlendNormal(); + virtual void BlendAdditive(); + + virtual int MemoryUsage() const; + + virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY); + virtual void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY); + + virtual void LinesBegin(); + virtual void LinesEnd(); + virtual void LinesDraw(const CLineItem *pArray, int Num); + + virtual int UnloadTexture(int Index); + virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); + + // simple uncompressed RGBA loaders + virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); + virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType); + + void ScreenshotDirect(const char *pFilename); + + virtual void TextureSet(int TextureID); + + virtual void Clear(float r, float g, float b); + + virtual void QuadsBegin(); + virtual void QuadsEnd(); + virtual void QuadsSetRotation(float Angle); + + virtual void SetColorVertex(const CColorVertex *pArray, int Num); + virtual void SetColor(float r, float g, float b, float a); + + virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV); + virtual void QuadsSetSubsetFree( + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3); + + virtual void QuadsDraw(CQuadItem *pArray, int Num); + virtual void QuadsDrawTL(const CQuadItem *pArray, int Num); + virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); + virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); + + virtual void Minimize(); + virtual void Maximize(); + + virtual int WindowActive(); + virtual int WindowOpen(); + + virtual bool Init(); + virtual void Shutdown(); + + virtual void TakeScreenshot(const char *pFilename); + virtual void Swap(); + + virtual int GetVideoModes(CVideoMode *pModes, int MaxModes); + +}; + class CGraphics_OpenGL : public IEngineGraphics { protected: diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp new file mode 100644 index 00000000..c227dbd5 --- /dev/null +++ b/src/engine/client/graphics_threaded.cpp @@ -0,0 +1,1225 @@ +/* (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. */ + +#include +#include + +#include "SDL.h" +#include "SDL_opengl.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include // cosf, sinf + +#include "graphics.h" + + +static CVideoMode g_aFakeModes[] = { + {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, + {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8}, + {1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8}, + {1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8}, + {1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8}, + {1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8}, + {1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8}, + {1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8}, + {1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8}, + {2048,1536,8,8,8}, + + {320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5}, + {720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5}, + {1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5}, + {1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5}, + {1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5}, + {1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5}, + {1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5}, + {1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5}, + {1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5}, + {2048,1536,5,6,5} +}; + + +class CCommandProcessorFragment_OpenGL +{ +public: + void SetState(const CCommandBuffer::SState &State) + { + // blend + switch(State.m_BlendMode) + { + case CCommandBuffer::BLEND_NONE: + glDisable(GL_BLEND); + break; + case CCommandBuffer::BLEND_ALPHA: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case CCommandBuffer::BLEND_ADDITIVE: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + default: + dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); + }; + + // clip + /*if(State.m_ClipEnable) + { + glScissor(State.m_ClipX, State.m_ClipY+State.m_ClipH, State.m_ClipW, State.m_ClipH); + glEnable(GL_SCISSOR_TEST); + } + else*/ + glDisable(GL_SCISSOR_TEST); + + // texture + glDisable(GL_TEXTURE_2D); + + // screen mapping + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); + + } + + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + { + + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_TEXTURE_CREATE: + break; + case CCommandBuffer::CMD_TEXTURE_DESTROY: + break; + case CCommandBuffer::CMD_CLEAR: + { + const CCommandBuffer::SCommand_Clear *pCommand = (CCommandBuffer::SCommand_Clear *)pBaseCommand; + glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } break; + case CCommandBuffer::CMD_RENDER: + { + const CCommandBuffer::SCommand_Render *pCommand = (CCommandBuffer::SCommand_Render *)pBaseCommand; + SetState(pCommand->m_State); + + glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); + glTexCoordPointer(2, 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)*5); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + switch(pCommand->m_PrimType) + { + case CCommandBuffer::PRIMTYPE_QUADS: + glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4); + break; + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd); + }; + } break; + default: + return false; + break; + } + + return true; + } +}; + +class CCommandProcessorFragment_SDL +{ + // SDL stuff + SDL_Surface *m_pScreenSurface; + + int m_ScreenWidth; + int m_ScreenHeight; + + int TryInit() + { + m_ScreenWidth = g_Config.m_GfxScreenWidth; + m_ScreenHeight = g_Config.m_GfxScreenHeight; + + const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); + + // set flags + int Flags = SDL_OPENGL; + if(g_Config.m_DbgResizable) + Flags |= SDL_RESIZABLE; + + if(pInfo->hw_available) // ignore_convention + Flags |= SDL_HWSURFACE; + else + Flags |= SDL_SWSURFACE; + + if(pInfo->blit_hw) // ignore_convention + Flags |= SDL_HWACCEL; + + if(g_Config.m_GfxFullscreen) + Flags |= SDL_FULLSCREEN; + + // set gl attributes + if(g_Config.m_GfxFsaaSamples) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, g_Config.m_GfxFsaaSamples); + } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, g_Config.m_GfxVsync); + + // set caption + SDL_WM_SetCaption("Teeworlds", "Teeworlds"); + + // create window + m_pScreenSurface = SDL_SetVideoMode(m_ScreenWidth, m_ScreenHeight, 0, Flags); + if(m_pScreenSurface == NULL) + { + dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); + return -1; + } + + return 0; + } + + + int InitWindow() + { + if(TryInit() == 0) + return 0; + + // try disabling fsaa + while(g_Config.m_GfxFsaaSamples) + { + g_Config.m_GfxFsaaSamples--; + + if(g_Config.m_GfxFsaaSamples) + dbg_msg("gfx", "lowering FSAA to %d and trying again", g_Config.m_GfxFsaaSamples); + else + dbg_msg("gfx", "disabling FSAA and trying again"); + + if(TryInit() == 0) + return 0; + } + + // try lowering the resolution + if(g_Config.m_GfxScreenWidth != 640 || g_Config.m_GfxScreenHeight != 480) + { + dbg_msg("gfx", "setting resolution to 640x480 and trying again"); + g_Config.m_GfxScreenWidth = 640; + g_Config.m_GfxScreenHeight = 480; + + if(TryInit() == 0) + return 0; + } + + dbg_msg("gfx", "out of ideas. failed to init graphics"); + + return -1; + } + + int Init() + { + { + int Systems = SDL_INIT_VIDEO; + + if(g_Config.m_SndEnable) + Systems |= SDL_INIT_AUDIO; + + if(g_Config.m_ClEventthread) + Systems |= SDL_INIT_EVENTTHREAD; + + if(SDL_Init(Systems) < 0) + { + dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); + return -1; + } + } + + atexit(SDL_Quit); // ignore_convention + + #ifdef CONF_FAMILY_WINDOWS + if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention + putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention + #endif + + if(InitWindow() != 0) + return -1; + + SDL_ShowCursor(0); + + // set some default settings + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glAlphaFunc(GL_GREATER, 0); + glEnable(GL_ALPHA_TEST); + glDepthMask(0); + + return 0; + } + + +public: + CCommandProcessorFragment_SDL() + { + m_pScreenSurface = 0x0; + } + + bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) + { + + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_NOP: + break; + case CCommandBuffer::CMD_INIT: + { + const CCommandBuffer::SCommand_Init *pCommand = (CCommandBuffer::SCommand_Init *)pBaseCommand; + *pCommand->m_pResult = Init(); + } break; + case CCommandBuffer::CMD_SHUTDOWN: + break; + case CCommandBuffer::CMD_SWAP: + { + SDL_GL_SwapBuffers(); + } break; + default: + return false; + break; + } + + return true; + } +}; + + +class CCommandProcessor_SDL_OpenGL : public ICommandProcessor +{ + CCommandProcessorFragment_OpenGL m_OpenGL; + CCommandProcessorFragment_SDL m_SDL; + public: + virtual void RunBuffer(CCommandBuffer *pBuffer) + { + unsigned CmdIndex = 0; + while(1) + { + CCommandBuffer::SCommand * const pBaseCommand = pBuffer->GetCommand(&CmdIndex); + if(pBaseCommand == 0x0) + break; + + if(m_OpenGL.RunCommand(pBaseCommand)) + continue; + + if(m_SDL.RunCommand(pBaseCommand)) + continue; + + dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd); + } + } +}; + +void CCommandProcessorHandler::ThreadFunc(void *pUser) +{ + CCommandProcessorHandler *pThis = (CCommandProcessorHandler *)pUser; + + while(!pThis->m_Shutdown) + { + pThis->m_Activity.wait(); + if(pThis->m_pBuffer) + { + pThis->m_pProcessor->RunBuffer(pThis->m_pBuffer); + sync_barrier(); + pThis->m_pBuffer = 0x0; + pThis->m_BufferDone.signal(); + } + } +} + +CCommandProcessorHandler::CCommandProcessorHandler() +{ + m_pBuffer = 0x0; + m_pProcessor = 0x0; + m_pThread = 0x0; +} + +void CCommandProcessorHandler::Start(ICommandProcessor *pProcessor) +{ + m_Shutdown = false; + m_pProcessor = pProcessor; + m_pThread = thread_create(ThreadFunc, this); + m_BufferDone.signal(); +} + +void CCommandProcessorHandler::RunBuffer(CCommandBuffer *pBuffer) +{ + WaitForIdle(); + m_pBuffer = pBuffer; + m_Activity.signal(); +} + +void CCommandProcessorHandler::WaitForIdle() +{ + while(m_pBuffer != 0x0) + m_BufferDone.wait(); +} + + +/* +void RenderThread() +{ + .wait() + if(m_pCommandBuffer) + RunBuffer(m_pCommandBuffer); + // reset buffer? + m_pCommandBuffer = 0; +}*/ + +void CGraphics_Threaded::Flush() +{ + if(m_NumVertices == 0) + return; + + int NumVerts = m_NumVertices; + m_NumVertices = 0; + + CCommandBuffer::SCommand_Render Cmd; + Cmd.m_State = m_State; + + if(m_Drawing == DRAWING_QUADS) + { + Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_QUADS; + Cmd.m_PrimCount = NumVerts/4; + } + else if(m_Drawing == DRAWING_LINES) + { + Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_LINES; + Cmd.m_PrimCount = NumVerts/2; + } + else + return; + + Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts); + if(Cmd.m_pVertices == 0x0) + return; + + mem_copy(Cmd.m_pVertices, m_aVertices, sizeof(CCommandBuffer::SVertex)*NumVerts); + m_pCommandBuffer->AddCommand(Cmd); +} + +void CGraphics_Threaded::AddVertices(int Count) +{ + m_NumVertices += Count; + if((m_NumVertices + Count) >= MAX_VERTICES) + Flush(); +} + +void CGraphics_Threaded::Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints) +{ + float c = cosf(m_Rotation); + float s = sinf(m_Rotation); + float x, y; + int i; + + for(i = 0; i < 4; i++) + { + x = pPoints[i].m_Pos.x - rCenter.x; + y = pPoints[i].m_Pos.y - rCenter.y; + pPoints[i].m_Pos.x = x * c - y * s + rCenter.x; + pPoints[i].m_Pos.y = x * s + y * c + rCenter.y; + } +} + +unsigned char CGraphics_Threaded::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp) +{ + int Value = 0; + for(int x = 0; x < ScaleW; x++) + for(int y = 0; y < ScaleH; y++) + Value += pData[((v+y)*w+(u+x))*Bpp+Offset]; + return Value/(ScaleW*ScaleH); +} + +unsigned char *CGraphics_Threaded::Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) +{ + unsigned char *pTmpData; + int ScaleW = Width/NewWidth; + int ScaleH = Height/NewHeight; + + int Bpp = 3; + if(Format == CImageInfo::FORMAT_RGBA) + Bpp = 4; + + pTmpData = (unsigned char *)mem_alloc(NewWidth*NewHeight*Bpp, 1); + + int c = 0; + for(int y = 0; y < NewHeight; y++) + for(int x = 0; x < NewWidth; x++, c++) + { + pTmpData[c*Bpp] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 0, ScaleW, ScaleH, Bpp); + pTmpData[c*Bpp+1] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 1, ScaleW, ScaleH, Bpp); + pTmpData[c*Bpp+2] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 2, ScaleW, ScaleH, Bpp); + if(Bpp == 4) + pTmpData[c*Bpp+3] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 3, ScaleW, ScaleH, Bpp); + } + + return pTmpData; +} + +CGraphics_Threaded::CGraphics_Threaded() +{ + m_State.m_ScreenTL.x = 0; + m_State.m_ScreenTL.y = 0; + m_State.m_ScreenBR.x = 0; + m_State.m_ScreenBR.y = 0; + m_State.m_ClipEnable = false; + m_State.m_ClipX = 0; + m_State.m_ClipY = 0; + m_State.m_ClipW = 0; + m_State.m_ClipH = 0; + m_State.m_Texture = -1; + m_State.m_BlendMode = CCommandBuffer::BLEND_NONE; + + + + m_NumVertices = 0; + + m_ScreenWidth = -1; + m_ScreenHeight = -1; + + m_Rotation = 0; + m_Drawing = 0; + m_InvalidTexture = 0; + + m_TextureMemoryUsage = 0; + + m_RenderEnable = true; + m_DoScreenshot = false; +} + +void CGraphics_Threaded::ClipEnable(int x, int y, int w, int h) +{ + if(x < 0) + w += x; + if(y < 0) + h += y; + + x = clamp(x, 0, ScreenWidth()); + y = clamp(y, 0, ScreenHeight()); + w = clamp(w, 0, ScreenWidth()-x); + h = clamp(h, 0, ScreenHeight()-y); + + m_State.m_ClipEnable = true; + m_State.m_ClipX = x; + m_State.m_ClipY = ScreenHeight()-(y+h); + m_State.m_ClipW = w; + m_State.m_ClipH = h; +} + +void CGraphics_Threaded::ClipDisable() +{ + m_State.m_ClipEnable = false; +} + +void CGraphics_Threaded::BlendNone() +{ + m_State.m_BlendMode = CCommandBuffer::BLEND_NONE; +} + +void CGraphics_Threaded::BlendNormal() +{ + m_State.m_BlendMode = CCommandBuffer::BLEND_ALPHA; +} + +void CGraphics_Threaded::BlendAdditive() +{ + m_State.m_BlendMode = CCommandBuffer::BLEND_ADDITIVE; +} + +int CGraphics_Threaded::MemoryUsage() const +{ + return m_TextureMemoryUsage; +} + +void CGraphics_Threaded::MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) +{ + m_State.m_ScreenTL.x = TopLeftX; + m_State.m_ScreenTL.y = TopLeftY; + m_State.m_ScreenBR.x = BottomRightX; + m_State.m_ScreenBR.y = BottomRightY; +} + +void CGraphics_Threaded::GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) +{ + *pTopLeftX = m_State.m_ScreenTL.x; + *pTopLeftY = m_State.m_ScreenTL.y; + *pBottomRightX = m_State.m_ScreenBR.x; + *pBottomRightY = m_State.m_ScreenBR.y; +} + +void CGraphics_Threaded::LinesBegin() +{ + dbg_assert(m_Drawing == 0, "called Graphics()->LinesBegin twice"); + m_Drawing = DRAWING_LINES; + SetColor(1,1,1,1); +} + +void CGraphics_Threaded::LinesEnd() +{ + dbg_assert(m_Drawing == DRAWING_LINES, "called Graphics()->LinesEnd without begin"); + Flush(); + m_Drawing = 0; +} + +void CGraphics_Threaded::LinesDraw(const CLineItem *pArray, int Num) +{ + dbg_assert(m_Drawing == DRAWING_LINES, "called Graphics()->LinesDraw without begin"); + + for(int i = 0; i < Num; ++i) + { + m_aVertices[m_NumVertices + 2*i].m_Pos.x = pArray[i].m_X0; + m_aVertices[m_NumVertices + 2*i].m_Pos.y = pArray[i].m_Y0; + m_aVertices[m_NumVertices + 2*i].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices + 2*i].m_Color = m_aColor[0]; + + m_aVertices[m_NumVertices + 2*i + 1].m_Pos.x = pArray[i].m_X1; + m_aVertices[m_NumVertices + 2*i + 1].m_Pos.y = pArray[i].m_Y1; + m_aVertices[m_NumVertices + 2*i + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 2*i + 1].m_Color = m_aColor[1]; + } + + AddVertices(2*Num); +} + +int CGraphics_Threaded::UnloadTexture(int Index) +{ + return 0; + if(Index == m_InvalidTexture) + return 0; + + if(Index < 0) + return 0; + + glDeleteTextures(1, &m_aTextures[Index].m_Tex); + m_aTextures[Index].m_Next = m_FirstFreeTexture; + m_TextureMemoryUsage -= m_aTextures[Index].m_MemSize; + m_FirstFreeTexture = Index; + return 0; +} + + +int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) +{ + return 0; + + int Mipmap = 1; + unsigned char *pTexData = (unsigned char *)pData; + unsigned char *pTmpData = 0; + int Oglformat = 0; + int StoreOglformat = 0; + int Tex = 0; + + // don't waste memory on texture if we are stress testing + if(g_Config.m_DbgStress) + return m_InvalidTexture; + + // grab texture + Tex = m_FirstFreeTexture; + m_FirstFreeTexture = m_aTextures[Tex].m_Next; + m_aTextures[Tex].m_Next = -1; + + // resample if needed + if(!(Flags&TEXLOAD_NORESAMPLE) && (Format == CImageInfo::FORMAT_RGBA || Format == CImageInfo::FORMAT_RGB)) + { + if(Width > GL_MAX_TEXTURE_SIZE || Height > GL_MAX_TEXTURE_SIZE) + { + int NewWidth = min(Width, GL_MAX_TEXTURE_SIZE); + int NewHeight = min(Height, GL_MAX_TEXTURE_SIZE); + pTmpData = Rescale(Width, Height, NewWidth, NewHeight, Format, pTexData); + pTexData = pTmpData; + Width = NewWidth; + Height = NewHeight; + } + else if(Width > 16 && Height > 16 && g_Config.m_GfxTextureQuality == 0) + { + pTmpData = Rescale(Width, Height, Width/2, Height/2, Format, pTexData); + pTexData = pTmpData; + Width /= 2; + Height /= 2; + } + } + + Oglformat = GL_RGBA; + if(Format == CImageInfo::FORMAT_RGB) + Oglformat = GL_RGB; + else if(Format == CImageInfo::FORMAT_ALPHA) + Oglformat = GL_ALPHA; + + // upload texture + if(g_Config.m_GfxTextureCompression) + { + StoreOglformat = GL_COMPRESSED_RGBA_ARB; + if(StoreFormat == CImageInfo::FORMAT_RGB) + StoreOglformat = GL_COMPRESSED_RGB_ARB; + else if(StoreFormat == CImageInfo::FORMAT_ALPHA) + StoreOglformat = GL_COMPRESSED_ALPHA_ARB; + } + else + { + StoreOglformat = GL_RGBA; + if(StoreFormat == CImageInfo::FORMAT_RGB) + StoreOglformat = GL_RGB; + else if(StoreFormat == CImageInfo::FORMAT_ALPHA) + StoreOglformat = GL_ALPHA; + } + + glGenTextures(1, &m_aTextures[Tex].m_Tex); + glBindTexture(GL_TEXTURE_2D, m_aTextures[Tex].m_Tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); + + // calculate memory usage + { + int PixelSize = 4; + if(StoreFormat == CImageInfo::FORMAT_RGB) + PixelSize = 3; + else if(StoreFormat == CImageInfo::FORMAT_ALPHA) + PixelSize = 1; + + m_aTextures[Tex].m_MemSize = Width*Height*PixelSize; + if(Mipmap) + { + while(Width > 2 && Height > 2) + { + Width>>=1; + Height>>=1; + m_aTextures[Tex].m_MemSize += Width*Height*PixelSize; + } + } + } + + m_TextureMemoryUsage += m_aTextures[Tex].m_MemSize; + mem_free(pTmpData); + return Tex; +} + +// simple uncompressed RGBA loaders +int CGraphics_Threaded::LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) +{ + return 0; + + int l = str_length(pFilename); + int ID; + CImageInfo Img; + + if(l < 3) + return -1; + if(LoadPNG(&Img, pFilename, StorageType)) + { + if (StoreFormat == CImageInfo::FORMAT_AUTO) + StoreFormat = Img.m_Format; + + ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, StoreFormat, Flags); + mem_free(Img.m_pData); + if(ID != m_InvalidTexture && g_Config.m_Debug) + dbg_msg("graphics/texture", "loaded %s", pFilename); + return ID; + } + + return m_InvalidTexture; +} + +int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) +{ + return 0; + + char aCompleteFilename[512]; + unsigned char *pBuffer; + png_t Png; // ignore_convention + + // open file for reading + png_init(0,0); // ignore_convention + + IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType, aCompleteFilename, sizeof(aCompleteFilename)); + if(File) + io_close(File); + else + { + dbg_msg("game/png", "failed to open file. filename='%s'", pFilename); + return 0; + } + + int Error = png_open_file(&Png, aCompleteFilename); // ignore_convention + if(Error != PNG_NO_ERROR) + { + dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename); + if(Error != PNG_FILE_ERROR) + png_close_file(&Png); // ignore_convention + return 0; + } + + if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA)) // ignore_convention + { + dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename); + png_close_file(&Png); // ignore_convention + return 0; + } + + pBuffer = (unsigned char *)mem_alloc(Png.width * Png.height * Png.bpp, 1); // ignore_convention + png_get_data(&Png, pBuffer); // ignore_convention + png_close_file(&Png); // ignore_convention + + pImg->m_Width = Png.width; // ignore_convention + pImg->m_Height = Png.height; // ignore_convention + if(Png.color_type == PNG_TRUECOLOR) // ignore_convention + pImg->m_Format = CImageInfo::FORMAT_RGB; + else if(Png.color_type == PNG_TRUECOLOR_ALPHA) // ignore_convention + pImg->m_Format = CImageInfo::FORMAT_RGBA; + pImg->m_pData = pBuffer; + return 1; +} + +void CGraphics_Threaded::ScreenshotDirect(const char *pFilename) +{ + // fetch image data + int y; + int w = m_ScreenWidth; + int h = m_ScreenHeight; + unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1); + unsigned char *pTempRow = pPixelData+w*h*3; + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); + glPixelStorei(GL_PACK_ALIGNMENT, Alignment); + + // flip the pixel because opengl works from bottom left corner + for(y = 0; y < h/2; y++) + { + 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); + } + + // find filename + { + char aWholePath[1024]; + png_t Png; // ignore_convention + + IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath)); + if(File) + io_close(File); + + // save png + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); + png_open_file_write(&Png, aWholePath); // ignore_convention + png_set_data(&Png, w, h, 8, PNG_TRUECOLOR, (unsigned char *)pPixelData); // ignore_convention + png_close_file(&Png); // ignore_convention + } + + // clean up + mem_free(pPixelData); +} + +void CGraphics_Threaded::TextureSet(int TextureID) +{ + return; + + dbg_assert(m_Drawing == 0, "called Graphics()->TextureSet within begin"); + if(TextureID == -1) + { + glDisable(GL_TEXTURE_2D); + } + else + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_aTextures[TextureID].m_Tex); + } +} + +void CGraphics_Threaded::Clear(float r, float g, float b) +{ + CCommandBuffer::SCommand_Clear Cmd; + Cmd.m_Color.r = r; + Cmd.m_Color.g = g; + Cmd.m_Color.b = b; + Cmd.m_Color.a = 0; + m_pCommandBuffer->AddCommand(Cmd); +} + +void CGraphics_Threaded::QuadsBegin() +{ + dbg_assert(m_Drawing == 0, "called Graphics()->QuadsBegin twice"); + m_Drawing = DRAWING_QUADS; + + QuadsSetSubset(0,0,1,1); + QuadsSetRotation(0); + SetColor(1,1,1,1); +} + +void CGraphics_Threaded::QuadsEnd() +{ + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsEnd without begin"); + Flush(); + m_Drawing = 0; +} + +void CGraphics_Threaded::QuadsSetRotation(float Angle) +{ + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetRotation without begin"); + m_Rotation = Angle; +} + +void CGraphics_Threaded::SetColorVertex(const CColorVertex *pArray, int Num) +{ + dbg_assert(m_Drawing != 0, "called Graphics()->SetColorVertex without begin"); + + for(int i = 0; i < Num; ++i) + { + m_aColor[pArray[i].m_Index].r = pArray[i].m_R; + m_aColor[pArray[i].m_Index].g = pArray[i].m_G; + m_aColor[pArray[i].m_Index].b = pArray[i].m_B; + m_aColor[pArray[i].m_Index].a = pArray[i].m_A; + } +} + +void CGraphics_Threaded::SetColor(float r, float g, float b, float a) +{ + dbg_assert(m_Drawing != 0, "called Graphics()->SetColor without begin"); + CColorVertex Array[4] = { + CColorVertex(0, r, g, b, a), + CColorVertex(1, r, g, b, a), + CColorVertex(2, r, g, b, a), + CColorVertex(3, r, g, b, a)}; + SetColorVertex(Array, 4); +} + +void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV) +{ + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin"); + + 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; +} + +void CGraphics_Threaded::QuadsSetSubsetFree( + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3) +{ + 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; +} + +void CGraphics_Threaded::QuadsDraw(CQuadItem *pArray, int Num) +{ + for(int i = 0; i < Num; ++i) + { + pArray[i].m_X -= pArray[i].m_Width/2; + pArray[i].m_Y -= pArray[i].m_Height/2; + } + + QuadsDrawTL(pArray, Num); +} + +void CGraphics_Threaded::QuadsDrawTL(const CQuadItem *pArray, int Num) +{ + CCommandBuffer::SPoint Center; + Center.z = 0; + + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsDrawTL without begin"); + + for(int i = 0; i < Num; ++i) + { + m_aVertices[m_NumVertices + 4*i].m_Pos.x = pArray[i].m_X; + m_aVertices[m_NumVertices + 4*i].m_Pos.y = pArray[i].m_Y; + m_aVertices[m_NumVertices + 4*i].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices + 4*i].m_Color = m_aColor[0]; + + m_aVertices[m_NumVertices + 4*i + 1].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; + m_aVertices[m_NumVertices + 4*i + 1].m_Pos.y = pArray[i].m_Y; + m_aVertices[m_NumVertices + 4*i + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 4*i + 1].m_Color = m_aColor[1]; + + m_aVertices[m_NumVertices + 4*i + 2].m_Pos.x = pArray[i].m_X + pArray[i].m_Width; + m_aVertices[m_NumVertices + 4*i + 2].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; + m_aVertices[m_NumVertices + 4*i + 2].m_Tex = m_aTexture[2]; + m_aVertices[m_NumVertices + 4*i + 2].m_Color = m_aColor[2]; + + m_aVertices[m_NumVertices + 4*i + 3].m_Pos.x = pArray[i].m_X; + m_aVertices[m_NumVertices + 4*i + 3].m_Pos.y = pArray[i].m_Y + pArray[i].m_Height; + m_aVertices[m_NumVertices + 4*i + 3].m_Tex = m_aTexture[3]; + m_aVertices[m_NumVertices + 4*i + 3].m_Color = m_aColor[3]; + + if(m_Rotation != 0) + { + Center.x = pArray[i].m_X + pArray[i].m_Width/2; + Center.y = pArray[i].m_Y + pArray[i].m_Height/2; + + Rotate4(Center, &m_aVertices[m_NumVertices + 4*i]); + } + } + + AddVertices(4*Num); +} + +void CGraphics_Threaded::QuadsDrawFreeform(const CFreeformItem *pArray, int Num) +{ + dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsDrawFreeform without begin"); + + for(int i = 0; i < Num; ++i) + { + m_aVertices[m_NumVertices + 4*i].m_Pos.x = pArray[i].m_X0; + m_aVertices[m_NumVertices + 4*i].m_Pos.y = pArray[i].m_Y0; + m_aVertices[m_NumVertices + 4*i].m_Tex = m_aTexture[0]; + m_aVertices[m_NumVertices + 4*i].m_Color = m_aColor[0]; + + m_aVertices[m_NumVertices + 4*i + 1].m_Pos.x = pArray[i].m_X1; + m_aVertices[m_NumVertices + 4*i + 1].m_Pos.y = pArray[i].m_Y1; + m_aVertices[m_NumVertices + 4*i + 1].m_Tex = m_aTexture[1]; + m_aVertices[m_NumVertices + 4*i + 1].m_Color = m_aColor[1]; + + m_aVertices[m_NumVertices + 4*i + 2].m_Pos.x = pArray[i].m_X3; + m_aVertices[m_NumVertices + 4*i + 2].m_Pos.y = pArray[i].m_Y3; + m_aVertices[m_NumVertices + 4*i + 2].m_Tex = m_aTexture[3]; + m_aVertices[m_NumVertices + 4*i + 2].m_Color = m_aColor[3]; + + m_aVertices[m_NumVertices + 4*i + 3].m_Pos.x = pArray[i].m_X2; + m_aVertices[m_NumVertices + 4*i + 3].m_Pos.y = pArray[i].m_Y2; + m_aVertices[m_NumVertices + 4*i + 3].m_Tex = m_aTexture[2]; + m_aVertices[m_NumVertices + 4*i + 3].m_Color = m_aColor[2]; + } + + AddVertices(4*Num); +} + +void CGraphics_Threaded::QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText) +{ + float StartX = x; + + QuadsBegin(); + SetColor(r,g,b,a); + + while(*pText) + { + char c = *pText; + pText++; + + if(c == '\n') + { + x = StartX; + y += Size; + } + else + { + QuadsSetSubset( + (c%16)/16.0f, + (c/16)/16.0f, + (c%16)/16.0f+1.0f/16.0f, + (c/16)/16.0f+1.0f/16.0f); + + CQuadItem QuadItem(x, y, Size, Size); + QuadsDrawTL(&QuadItem, 1); + x += Size/2; + } + } + + QuadsEnd(); +} + +bool CGraphics_Threaded::Init() +{ + // fetch pointers + m_pStorage = Kernel()->RequestInterface(); + m_pConsole = Kernel()->RequestInterface(); + + // Set all z to -5.0f + for(int i = 0; i < MAX_VERTICES; i++) + m_aVertices[i].m_Pos.z = -5.0f; + + // init textures + m_FirstFreeTexture = 0; + for(int i = 0; i < MAX_TEXTURES; i++) + m_aTextures[i].m_Next = i+1; + m_aTextures[MAX_TEXTURES-1].m_Next = -1; + + // start the command processor + ICommandProcessor *pProcessor = new CCommandProcessor_SDL_OpenGL; + m_Handler.Start(pProcessor); + + // create command buffers + m_apCommandBuffers[0] = new CCommandBuffer(1024*512, 1024*1024); + m_apCommandBuffers[1] = new CCommandBuffer(1024*512, 1024*1024); + m_pCommandBuffer = m_apCommandBuffers[0]; + + // issue init command + m_pCommandBuffer->Reset(); + volatile int Result; + CCommandBuffer::SCommand_Init Cmd; + Cmd.m_pResult = &Result; + m_pCommandBuffer->AddCommand(Cmd); + m_Handler.RunBuffer(m_pCommandBuffer); + m_Handler.WaitForIdle(); + + + if(Result == 0) + { + // create null texture, will get id=0 + static const unsigned char aNullTextureData[] = { + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + }; + + m_InvalidTexture = LoadTextureRaw(4,4,CImageInfo::FORMAT_RGBA,aNullTextureData,CImageInfo::FORMAT_RGBA,TEXLOAD_NORESAMPLE); + } + + return Result; +} + +void CGraphics_Threaded::Shutdown() +{ + // TODO: SDL, is this correct? + SDL_Quit(); +} + +void CGraphics_Threaded::Minimize() +{ + SDL_WM_IconifyWindow(); +} + +void CGraphics_Threaded::Maximize() +{ + // TODO: SDL +} + +int CGraphics_Threaded::WindowActive() +{ + return SDL_GetAppState()&SDL_APPINPUTFOCUS; +} + +int CGraphics_Threaded::WindowOpen() +{ + return SDL_GetAppState()&SDL_APPACTIVE; + +} + +void CGraphics_Threaded::TakeScreenshot(const char *pFilename) +{ + // TODO: screenshot support + return; + /* + char aDate[20]; + str_timestamp(aDate, sizeof(aDate)); + str_format(m_aScreenshotName, sizeof(m_aScreenshotName), "screenshots/%s_%s.png", pFilename?pFilename:"screenshot", aDate); + m_DoScreenshot = true; + */ +} + +void CGraphics_Threaded::Swap() +{ + if(0) { + CCommandBuffer::SCommand_Clear Cmd; + Cmd.m_Color.r = 1.0f; + Cmd.m_Color.g = 0.0f; + Cmd.m_Color.b = 0.0f; + Cmd.m_Color.a = 0.0f; + m_pCommandBuffer->AddCommand(Cmd); + } + + CCommandBuffer::SCommand_Swap Cmd; + m_pCommandBuffer->AddCommand(Cmd); + + m_Handler.RunBuffer(m_pCommandBuffer); + m_Handler.WaitForIdle(); + m_pCommandBuffer->Reset(); + + // TODO: screenshot support + /* + if(m_DoScreenshot) + { + ScreenshotDirect(m_aScreenshotName); + m_DoScreenshot = false; + }*/ + + //SDL_GL_SwapBuffers(); + + //if(g_Config.m_GfxFinish) + // glFinish(); +} + + +int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) +{ + // TODO: fix support for video modes, using fake modes for now + //int NumModes = sizeof(g_aFakeModes)/sizeof(CVideoMode); + //SDL_Rect **ppModes; + + //if(g_Config.m_GfxDisplayAllModes) + { + int Count = sizeof(g_aFakeModes)/sizeof(CVideoMode); + mem_copy(pModes, g_aFakeModes, sizeof(g_aFakeModes)); + if(MaxModes < Count) + Count = MaxModes; + return Count; + } + + // TODO: fix this code on osx or windows + /* + + ppModes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); + if(ppModes == NULL) + { + // no modes + NumModes = 0; + } + else if(ppModes == (SDL_Rect**)-1) + { + // all modes + } + else + { + NumModes = 0; + for(int i = 0; ppModes[i]; ++i) + { + if(NumModes == MaxModes) + break; + pModes[NumModes].m_Width = ppModes[i]->w; + pModes[NumModes].m_Height = ppModes[i]->h; + pModes[NumModes].m_Red = 8; + pModes[NumModes].m_Green = 8; + pModes[NumModes].m_Blue = 8; + NumModes++; + } + } + + return NumModes;*/ +} + + +extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_Threaded(); } diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index fc1ca2db..0e61ec6e 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -628,7 +628,6 @@ int CMenus::RenderMenubar(CUIRect r) void CMenus::RenderLoading() { // TODO: not supported right now due to separate render thread - return; static int64 LastLoadRender = 0; float Percent = m_LoadCurrent++/(float)m_LoadTotal; -- cgit 1.4.1 From 09b785a290c8394422b1334e5e07714c7e994521 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 01:11:24 +0100 Subject: splitted out the graphics threaded into a separate header --- src/engine/client/graphics.h | 342 ------------------------------- src/engine/client/graphics_threaded.cpp | 2 +- src/engine/client/graphics_threaded.h | 343 ++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+), 343 deletions(-) create mode 100644 src/engine/client/graphics_threaded.h (limited to 'src/engine/client') diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index 84142d9d..95e9769a 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -3,348 +3,6 @@ #ifndef ENGINE_CLIENT_GRAPHICS_H #define ENGINE_CLIENT_GRAPHICS_H -#include - -class CCommandBuffer -{ - class CBuffer - { - unsigned char *m_pData; - unsigned m_Size; - unsigned m_Used; - public: - CBuffer(unsigned BufferSize) - { - m_Size = BufferSize; - m_pData = new unsigned char[m_Size]; - m_Used = 0; - } - - ~CBuffer() - { - delete [] m_pData; - m_pData = 0x0; - m_Used = 0; - m_Size = 0; - } - - void Reset() - { - m_Used = 0; - } - - void *Alloc(unsigned Requested) - { - if(Requested + m_Used > m_Size) - return 0; - void *pPtr = &m_pData[m_Used]; - m_Used += Requested; - return pPtr; - } - - unsigned char *DataPtr() { return m_pData; } - unsigned DataSize() { return m_Size; } - unsigned DataUsed() { return m_Used; } - }; - - CBuffer m_CmdBuffer; - CBuffer m_DataBuffer; -public: - enum - { - // - CMD_NOP = 0, - - // - CMD_INIT, - CMD_SHUTDOWN, - - // - CMD_RUNBUFFER, - - // syncronization - CMD_SIGNAL, - - // texture commands - CMD_TEXTURE_CREATE, - CMD_TEXTURE_DESTROY, - - // rendering - CMD_CLEAR, - CMD_RENDER, - - // swap - CMD_SWAP, - }; - - enum - { - // - PRIMTYPE_INVALID = 0, - PRIMTYPE_LINES, - PRIMTYPE_QUADS, - }; - - enum - { - BLEND_NONE = 0, - BLEND_ALPHA, - BLEND_ADDITIVE, - }; - - struct SPoint { float x, y, z; }; - struct STexCoord { float u, v; }; - struct SColor { float r, g, b, a; }; - - struct SVertex - { - SPoint m_Pos; - STexCoord m_Tex; - SColor m_Color; - } ; - - struct SCommand - { - public: - SCommand(unsigned Cmd) : m_Cmd(Cmd), m_Size(0) {} - unsigned m_Cmd; - unsigned m_Size; - }; - - struct SState - { - int m_BlendMode; - int m_Texture; - SPoint m_ScreenTL; - SPoint m_ScreenBR; - - // clip - bool m_ClipEnable; - int m_ClipX; - int m_ClipY; - int m_ClipW; - int m_ClipH; - }; - - struct SCommand_Clear : public SCommand - { - SCommand_Clear() : SCommand(CMD_CLEAR) {} - SColor m_Color; - }; - - - struct SCommand_Init : public SCommand - { - SCommand_Init() : SCommand(CMD_INIT) {} - volatile int *m_pResult; - }; - - struct SCommand_RunBuffer : public SCommand - { - SCommand_RunBuffer() : SCommand(CMD_RUNBUFFER) {} - CCommandBuffer *m_pOtherBuffer; - }; - - struct SCommand_Render : public SCommand - { - SCommand_Render() : SCommand(CMD_RENDER) {} - SState m_State; - unsigned m_PrimType; - unsigned m_PrimCount; - SVertex *m_pVertices; - }; - - struct SCommand_Swap : public SCommand - { - SCommand_Swap() : SCommand(CMD_SWAP) {} - }; - - // - CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) - : m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize) - { - } - - void *AllocData(unsigned WantedSize) - { - return m_DataBuffer.Alloc(WantedSize); - } - - template - void AddCommand(const T &Command) - { - SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command)); - if(!pCmd) - return; - - mem_copy(pCmd, &Command, sizeof(Command)); - pCmd->m_Size = sizeof(Command); - } - - SCommand *GetCommand(unsigned *pIndex) - { - if(*pIndex >= m_CmdBuffer.DataUsed()) - return NULL; - - SCommand *pCommand = (SCommand *)&m_CmdBuffer.DataPtr()[*pIndex]; - *pIndex += pCommand->m_Size; - return pCommand; - } - - void Reset() - { - m_CmdBuffer.Reset(); - m_DataBuffer.Reset(); - } -}; - -class ICommandProcessor -{ -public: - virtual ~ICommandProcessor() {} - virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; -}; - - -class CCommandProcessorHandler -{ - ICommandProcessor *m_pProcessor; - CCommandBuffer * volatile m_pBuffer; - volatile bool m_Shutdown; - semaphore m_Activity; - semaphore m_BufferDone; - void *m_pThread; - - static void ThreadFunc(void *pUser); - -public: - CCommandProcessorHandler(); - void Start(ICommandProcessor *pProcessor); - void RunBuffer(CCommandBuffer *pBuffer); - bool IsIdle() const { return m_pBuffer == 0; } - void WaitForIdle(); -}; - -class CGraphics_Threaded : public IEngineGraphics -{ - CCommandBuffer::SState m_State; - CCommandProcessorHandler m_Handler; - - CCommandBuffer *m_apCommandBuffers[2]; - CCommandBuffer *m_pCommandBuffer; - unsigned m_CurrentCommandBuffer; - - // - class IStorage *m_pStorage; - class IConsole *m_pConsole; - - enum - { - MAX_VERTICES = 32*1024, - MAX_TEXTURES = 1024*4, - - DRAWING_QUADS=1, - DRAWING_LINES=2 - }; - - CCommandBuffer::SVertex m_aVertices[MAX_VERTICES]; - int m_NumVertices; - - CCommandBuffer::SColor m_aColor[4]; - CCommandBuffer::STexCoord m_aTexture[4]; - - bool m_RenderEnable; - - float m_Rotation; - int m_Drawing; - bool m_DoScreenshot; - char m_aScreenshotName[128]; - - int m_InvalidTexture; - - struct CTexture - { - GLuint m_Tex; - int m_MemSize; - int m_Flags; - int m_Next; - }; - - CTexture m_aTextures[MAX_TEXTURES]; - int m_FirstFreeTexture; - int m_TextureMemoryUsage; - - void Flush(); - void AddVertices(int Count); - void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints); - - static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); - static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); -public: - CGraphics_Threaded(); - - virtual void ClipEnable(int x, int y, int w, int h); - virtual void ClipDisable(); - - virtual void BlendNone(); - virtual void BlendNormal(); - virtual void BlendAdditive(); - - virtual int MemoryUsage() const; - - virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY); - virtual void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY); - - virtual void LinesBegin(); - virtual void LinesEnd(); - virtual void LinesDraw(const CLineItem *pArray, int Num); - - virtual int UnloadTexture(int Index); - virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); - - // simple uncompressed RGBA loaders - virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); - virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType); - - void ScreenshotDirect(const char *pFilename); - - virtual void TextureSet(int TextureID); - - virtual void Clear(float r, float g, float b); - - virtual void QuadsBegin(); - virtual void QuadsEnd(); - virtual void QuadsSetRotation(float Angle); - - virtual void SetColorVertex(const CColorVertex *pArray, int Num); - virtual void SetColor(float r, float g, float b, float a); - - virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV); - virtual void QuadsSetSubsetFree( - float x0, float y0, float x1, float y1, - float x2, float y2, float x3, float y3); - - virtual void QuadsDraw(CQuadItem *pArray, int Num); - virtual void QuadsDrawTL(const CQuadItem *pArray, int Num); - virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); - virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); - - virtual void Minimize(); - virtual void Maximize(); - - virtual int WindowActive(); - virtual int WindowOpen(); - - virtual bool Init(); - virtual void Shutdown(); - - virtual void TakeScreenshot(const char *pFilename); - virtual void Swap(); - - virtual int GetVideoModes(CVideoMode *pModes, int MaxModes); - -}; - class CGraphics_OpenGL : public IEngineGraphics { protected: diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index c227dbd5..66d17301 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -18,7 +18,7 @@ #include // cosf, sinf -#include "graphics.h" +#include "graphics_threaded.h" static CVideoMode g_aFakeModes[] = { diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h new file mode 100644 index 00000000..876e9410 --- /dev/null +++ b/src/engine/client/graphics_threaded.h @@ -0,0 +1,343 @@ +#pragma once + +#include + +class CCommandBuffer +{ + class CBuffer + { + unsigned char *m_pData; + unsigned m_Size; + unsigned m_Used; + public: + CBuffer(unsigned BufferSize) + { + m_Size = BufferSize; + m_pData = new unsigned char[m_Size]; + m_Used = 0; + } + + ~CBuffer() + { + delete [] m_pData; + m_pData = 0x0; + m_Used = 0; + m_Size = 0; + } + + void Reset() + { + m_Used = 0; + } + + void *Alloc(unsigned Requested) + { + if(Requested + m_Used > m_Size) + return 0; + void *pPtr = &m_pData[m_Used]; + m_Used += Requested; + return pPtr; + } + + unsigned char *DataPtr() { return m_pData; } + unsigned DataSize() { return m_Size; } + unsigned DataUsed() { return m_Used; } + }; + + CBuffer m_CmdBuffer; + CBuffer m_DataBuffer; +public: + enum + { + // + CMD_NOP = 0, + + // + CMD_INIT, + CMD_SHUTDOWN, + + // + CMD_RUNBUFFER, + + // syncronization + CMD_SIGNAL, + + // texture commands + CMD_TEXTURE_CREATE, + CMD_TEXTURE_DESTROY, + + // rendering + CMD_CLEAR, + CMD_RENDER, + + // swap + CMD_SWAP, + }; + + enum + { + // + PRIMTYPE_INVALID = 0, + PRIMTYPE_LINES, + PRIMTYPE_QUADS, + }; + + enum + { + BLEND_NONE = 0, + BLEND_ALPHA, + BLEND_ADDITIVE, + }; + + struct SPoint { float x, y, z; }; + struct STexCoord { float u, v; }; + struct SColor { float r, g, b, a; }; + + struct SVertex + { + SPoint m_Pos; + STexCoord m_Tex; + SColor m_Color; + } ; + + struct SCommand + { + public: + SCommand(unsigned Cmd) : m_Cmd(Cmd), m_Size(0) {} + unsigned m_Cmd; + unsigned m_Size; + }; + + struct SState + { + int m_BlendMode; + int m_Texture; + SPoint m_ScreenTL; + SPoint m_ScreenBR; + + // clip + bool m_ClipEnable; + int m_ClipX; + int m_ClipY; + int m_ClipW; + int m_ClipH; + }; + + struct SCommand_Clear : public SCommand + { + SCommand_Clear() : SCommand(CMD_CLEAR) {} + SColor m_Color; + }; + + + struct SCommand_Init : public SCommand + { + SCommand_Init() : SCommand(CMD_INIT) {} + volatile int *m_pResult; + }; + + struct SCommand_RunBuffer : public SCommand + { + SCommand_RunBuffer() : SCommand(CMD_RUNBUFFER) {} + CCommandBuffer *m_pOtherBuffer; + }; + + struct SCommand_Render : public SCommand + { + SCommand_Render() : SCommand(CMD_RENDER) {} + SState m_State; + unsigned m_PrimType; + unsigned m_PrimCount; + SVertex *m_pVertices; + }; + + struct SCommand_Swap : public SCommand + { + SCommand_Swap() : SCommand(CMD_SWAP) {} + }; + + // + CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) + : m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize) + { + } + + void *AllocData(unsigned WantedSize) + { + return m_DataBuffer.Alloc(WantedSize); + } + + template + void AddCommand(const T &Command) + { + SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command)); + if(!pCmd) + return; + + mem_copy(pCmd, &Command, sizeof(Command)); + pCmd->m_Size = sizeof(Command); + } + + SCommand *GetCommand(unsigned *pIndex) + { + if(*pIndex >= m_CmdBuffer.DataUsed()) + return NULL; + + SCommand *pCommand = (SCommand *)&m_CmdBuffer.DataPtr()[*pIndex]; + *pIndex += pCommand->m_Size; + return pCommand; + } + + void Reset() + { + m_CmdBuffer.Reset(); + m_DataBuffer.Reset(); + } +}; + +class ICommandProcessor +{ +public: + virtual ~ICommandProcessor() {} + virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; +}; + + +class CCommandProcessorHandler +{ + ICommandProcessor *m_pProcessor; + CCommandBuffer * volatile m_pBuffer; + volatile bool m_Shutdown; + semaphore m_Activity; + semaphore m_BufferDone; + void *m_pThread; + + static void ThreadFunc(void *pUser); + +public: + CCommandProcessorHandler(); + void Start(ICommandProcessor *pProcessor); + void RunBuffer(CCommandBuffer *pBuffer); + bool IsIdle() const { return m_pBuffer == 0; } + void WaitForIdle(); +}; + +class CGraphics_Threaded : public IEngineGraphics +{ + CCommandBuffer::SState m_State; + CCommandProcessorHandler m_Handler; + + CCommandBuffer *m_apCommandBuffers[2]; + CCommandBuffer *m_pCommandBuffer; + unsigned m_CurrentCommandBuffer; + + // + class IStorage *m_pStorage; + class IConsole *m_pConsole; + + enum + { + MAX_VERTICES = 32*1024, + MAX_TEXTURES = 1024*4, + + DRAWING_QUADS=1, + DRAWING_LINES=2 + }; + + CCommandBuffer::SVertex m_aVertices[MAX_VERTICES]; + int m_NumVertices; + + CCommandBuffer::SColor m_aColor[4]; + CCommandBuffer::STexCoord m_aTexture[4]; + + bool m_RenderEnable; + + float m_Rotation; + int m_Drawing; + bool m_DoScreenshot; + char m_aScreenshotName[128]; + + int m_InvalidTexture; + + struct CTexture + { + GLuint m_Tex; + int m_MemSize; + int m_Flags; + int m_Next; + }; + + CTexture m_aTextures[MAX_TEXTURES]; + int m_FirstFreeTexture; + int m_TextureMemoryUsage; + + void Flush(); + void AddVertices(int Count); + void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints); + + static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); + static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); +public: + CGraphics_Threaded(); + + virtual void ClipEnable(int x, int y, int w, int h); + virtual void ClipDisable(); + + virtual void BlendNone(); + virtual void BlendNormal(); + virtual void BlendAdditive(); + + virtual int MemoryUsage() const; + + virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY); + virtual void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY); + + virtual void LinesBegin(); + virtual void LinesEnd(); + virtual void LinesDraw(const CLineItem *pArray, int Num); + + virtual int UnloadTexture(int Index); + virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); + + // simple uncompressed RGBA loaders + virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); + virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType); + + void ScreenshotDirect(const char *pFilename); + + virtual void TextureSet(int TextureID); + + virtual void Clear(float r, float g, float b); + + virtual void QuadsBegin(); + virtual void QuadsEnd(); + virtual void QuadsSetRotation(float Angle); + + virtual void SetColorVertex(const CColorVertex *pArray, int Num); + virtual void SetColor(float r, float g, float b, float a); + + virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV); + virtual void QuadsSetSubsetFree( + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3); + + virtual void QuadsDraw(CQuadItem *pArray, int Num); + virtual void QuadsDrawTL(const CQuadItem *pArray, int Num); + virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); + virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); + + virtual void Minimize(); + virtual void Maximize(); + + virtual int WindowActive(); + virtual int WindowOpen(); + + virtual bool Init(); + virtual void Shutdown(); + + virtual void TakeScreenshot(const char *pFilename); + virtual void Swap(); + + virtual int GetVideoModes(CVideoMode *pModes, int MaxModes); + +}; \ No newline at end of file -- cgit 1.4.1 From 50e75da3334e77d027d5b10d85d4022c5dca0821 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 01:23:04 +0100 Subject: fixed so that the resolusion is set correctly on init --- src/engine/client/graphics_threaded.cpp | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 66d17301..c98ab8b9 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -141,14 +141,8 @@ class CCommandProcessorFragment_SDL // SDL stuff SDL_Surface *m_pScreenSurface; - int m_ScreenWidth; - int m_ScreenHeight; - int TryInit() { - m_ScreenWidth = g_Config.m_GfxScreenWidth; - m_ScreenHeight = g_Config.m_GfxScreenHeight; - const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); @@ -187,7 +181,7 @@ class CCommandProcessorFragment_SDL SDL_WM_SetCaption("Teeworlds", "Teeworlds"); // create window - m_pScreenSurface = SDL_SetVideoMode(m_ScreenWidth, m_ScreenHeight, 0, Flags); + m_pScreenSurface = SDL_SetVideoMode(g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, 0, Flags); if(m_pScreenSurface == NULL) { dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); @@ -382,17 +376,6 @@ void CCommandProcessorHandler::WaitForIdle() m_BufferDone.wait(); } - -/* -void RenderThread() -{ - .wait() - if(m_pCommandBuffer) - RunBuffer(m_pCommandBuffer); - // reset buffer? - m_pCommandBuffer = 0; -}*/ - void CGraphics_Threaded::Flush() { if(m_NumVertices == 0) @@ -1088,6 +1071,10 @@ bool CGraphics_Threaded::Init() if(Result == 0) { + // fetch final resolusion + m_ScreenWidth = g_Config.m_GfxScreenWidth; + m_ScreenHeight = g_Config.m_GfxScreenHeight; + // create null texture, will get id=0 static const unsigned char aNullTextureData[] = { 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, -- cgit 1.4.1 From 8a91bfa1ddff0c99d65375b8b5c57e710169543a Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 09:40:11 +0100 Subject: fixed texture upload support. removed raw gl calls from the text render --- src/engine/client/graphics.cpp | 13 ++ src/engine/client/graphics.h | 1 + src/engine/client/graphics_threaded.cpp | 266 ++++++++++++++++++-------------- src/engine/client/graphics_threaded.h | 55 ++++++- src/engine/client/text.cpp | 55 +++---- src/engine/graphics.h | 1 + 6 files changed, 244 insertions(+), 147 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 2d034f3f..b78e5387 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -270,6 +270,18 @@ int CGraphics_OpenGL::UnloadTexture(int Index) return 0; } +int CGraphics_OpenGL::LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData) +{ + int Oglformat = GL_RGBA; + if(Format == CImageInfo::FORMAT_RGB) + Oglformat = GL_RGB; + else if(Format == CImageInfo::FORMAT_ALPHA) + Oglformat = GL_ALPHA; + + glBindTexture(GL_TEXTURE_2D, m_aTextures[TextureID].m_Tex); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pData); + return 0; +} int CGraphics_OpenGL::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) { @@ -336,6 +348,7 @@ int CGraphics_OpenGL::LoadTextureRaw(int Width, int Height, int Format, const vo glGenTextures(1, &m_aTextures[Tex].m_Tex); glBindTexture(GL_TEXTURE_2D, m_aTextures[Tex].m_Tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index 95e9769a..d97513f3 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -89,6 +89,7 @@ public: virtual int UnloadTexture(int Index); virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); + virtual int LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData); // simple uncompressed RGBA loaders virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index c98ab8b9..ade77ef4 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -48,7 +48,13 @@ static CVideoMode g_aFakeModes[] = { class CCommandProcessorFragment_OpenGL { + GLuint m_aTextures[CCommandBuffer::MAX_TEXTURES]; public: + CCommandProcessorFragment_OpenGL() + { + mem_zero(m_aTextures, sizeof(m_aTextures)); + } + void SetState(const CCommandBuffer::SState &State) { // blend @@ -70,22 +76,75 @@ public: }; // clip - /*if(State.m_ClipEnable) + if(State.m_ClipEnable) { - glScissor(State.m_ClipX, State.m_ClipY+State.m_ClipH, State.m_ClipW, State.m_ClipH); + glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); glEnable(GL_SCISSOR_TEST); } - else*/ + else glDisable(GL_SCISSOR_TEST); // texture - glDisable(GL_TEXTURE_2D); + if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture]); + } + else + glDisable(GL_TEXTURE_2D); // screen mapping glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); + } + + int TexFormatToOpenGLFormat(int TexFormat) + { + if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) return GL_RGB; + if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) return GL_ALPHA; + if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) return GL_RGBA; + return GL_RGBA; + } + + void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) + { + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, + TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData); + mem_free(pCommand->m_pData); + } + + void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) + { + glDeleteTextures(1, &m_aTextures[pCommand->m_Slot]); + } + + void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) + { + int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); + + // upload texture + int StoreOglformat = Oglformat; + if(g_Config.m_GfxTextureCompression) + { + StoreOglformat = GL_COMPRESSED_RGBA_ARB; + if(pCommand->m_StoreFormat == CCommandBuffer::TEXFORMAT_RGB) + StoreOglformat = GL_COMPRESSED_RGB_ARB; + else if(Oglformat == CCommandBuffer::TEXFORMAT_ALPHA) + StoreOglformat = GL_COMPRESSED_ALPHA_ARB; + } + else + { + StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); + } + glGenTextures(1, &m_aTextures[pCommand->m_Slot]); + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + mem_free(pCommand->m_pData); } bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) @@ -94,9 +153,17 @@ public: switch(pBaseCommand->m_Cmd) { case CCommandBuffer::CMD_TEXTURE_CREATE: - break; + { + Cmd_Texture_Create((const CCommandBuffer::SCommand_Texture_Create *)pBaseCommand); + } break; case CCommandBuffer::CMD_TEXTURE_DESTROY: - break; + { + Cmd_Texture_Destroy((const CCommandBuffer::SCommand_Texture_Destroy *)pBaseCommand); + } break; + case CCommandBuffer::CMD_TEXTURE_UPDATE: + { + Cmd_Texture_Update((const CCommandBuffer::SCommand_Texture_Update *)pBaseCommand); + } break; case CCommandBuffer::CMD_CLEAR: { const CCommandBuffer::SCommand_Clear *pCommand = (CCommandBuffer::SCommand_Clear *)pBaseCommand; @@ -593,122 +660,112 @@ void CGraphics_Threaded::LinesDraw(const CLineItem *pArray, int Num) int CGraphics_Threaded::UnloadTexture(int Index) { - return 0; if(Index == m_InvalidTexture) return 0; if(Index < 0) return 0; - glDeleteTextures(1, &m_aTextures[Index].m_Tex); + CCommandBuffer::SCommand_Texture_Destroy Cmd; + Cmd.m_Slot = Index; + m_pCommandBuffer->AddCommand(Cmd); + m_aTextures[Index].m_Next = m_FirstFreeTexture; m_TextureMemoryUsage -= m_aTextures[Index].m_MemSize; m_FirstFreeTexture = Index; return 0; } +static int ImageFormatToTexFormat(int Format) +{ + if(Format == CImageInfo::FORMAT_RGB) return CCommandBuffer::TEXFORMAT_RGB; + if(Format == CImageInfo::FORMAT_RGBA) return CCommandBuffer::TEXFORMAT_RGBA; + if(Format == CImageInfo::FORMAT_ALPHA) return CCommandBuffer::TEXFORMAT_ALPHA; + return CCommandBuffer::TEXFORMAT_RGBA; +} -int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) + +int CGraphics_Threaded::LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData) { - return 0; + CCommandBuffer::SCommand_Texture_Update Cmd; + Cmd.m_Slot = TextureID; + Cmd.m_X = x; + Cmd.m_Y = y; + Cmd.m_Width = Width; + Cmd.m_Height = Height; + Cmd.m_Format = ImageFormatToTexFormat(Format); + + // calculate memory usage + int PixelSize = 4; + if(Format == CImageInfo::FORMAT_RGB) + PixelSize = 3; + else if(Format == CImageInfo::FORMAT_ALPHA) + PixelSize = 1; + + int MemSize = Width*Height*PixelSize; + + // copy texture data + void *pTmpData = mem_alloc(MemSize, sizeof(void*)); + mem_copy(pTmpData, pData, MemSize); + Cmd.m_pData = pTmpData; - int Mipmap = 1; - unsigned char *pTexData = (unsigned char *)pData; - unsigned char *pTmpData = 0; - int Oglformat = 0; - int StoreOglformat = 0; - int Tex = 0; + // + m_pCommandBuffer->AddCommand(Cmd); + return 0; +} +int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) +{ // don't waste memory on texture if we are stress testing if(g_Config.m_DbgStress) - return m_InvalidTexture; + return m_InvalidTexture; // grab texture - Tex = m_FirstFreeTexture; + int Tex = m_FirstFreeTexture; m_FirstFreeTexture = m_aTextures[Tex].m_Next; m_aTextures[Tex].m_Next = -1; - // resample if needed - if(!(Flags&TEXLOAD_NORESAMPLE) && (Format == CImageInfo::FORMAT_RGBA || Format == CImageInfo::FORMAT_RGB)) - { - if(Width > GL_MAX_TEXTURE_SIZE || Height > GL_MAX_TEXTURE_SIZE) - { - int NewWidth = min(Width, GL_MAX_TEXTURE_SIZE); - int NewHeight = min(Height, GL_MAX_TEXTURE_SIZE); - pTmpData = Rescale(Width, Height, NewWidth, NewHeight, Format, pTexData); - pTexData = pTmpData; - Width = NewWidth; - Height = NewHeight; - } - else if(Width > 16 && Height > 16 && g_Config.m_GfxTextureQuality == 0) - { - pTmpData = Rescale(Width, Height, Width/2, Height/2, Format, pTexData); - pTexData = pTmpData; - Width /= 2; - Height /= 2; - } - } + CCommandBuffer::SCommand_Texture_Create Cmd; + Cmd.m_Slot = Tex; + Cmd.m_Width = Width; + Cmd.m_Height = Height; + Cmd.m_Format = ImageFormatToTexFormat(Format); + Cmd.m_StoreFormat = ImageFormatToTexFormat(StoreFormat); - Oglformat = GL_RGBA; + // calculate memory usage + int PixelSize = 4; if(Format == CImageInfo::FORMAT_RGB) - Oglformat = GL_RGB; + PixelSize = 3; else if(Format == CImageInfo::FORMAT_ALPHA) - Oglformat = GL_ALPHA; + PixelSize = 1; - // upload texture - if(g_Config.m_GfxTextureCompression) - { - StoreOglformat = GL_COMPRESSED_RGBA_ARB; - if(StoreFormat == CImageInfo::FORMAT_RGB) - StoreOglformat = GL_COMPRESSED_RGB_ARB; - else if(StoreFormat == CImageInfo::FORMAT_ALPHA) - StoreOglformat = GL_COMPRESSED_ALPHA_ARB; - } - else - { - StoreOglformat = GL_RGBA; - if(StoreFormat == CImageInfo::FORMAT_RGB) - StoreOglformat = GL_RGB; - else if(StoreFormat == CImageInfo::FORMAT_ALPHA) - StoreOglformat = GL_ALPHA; - } + int MemSize = Width*Height*PixelSize; - glGenTextures(1, &m_aTextures[Tex].m_Tex); - glBindTexture(GL_TEXTURE_2D, m_aTextures[Tex].m_Tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); + // copy texture data + void *pTmpData = mem_alloc(MemSize, sizeof(void*)); + mem_copy(pTmpData, pData, MemSize); + Cmd.m_pData = pTmpData; + // + m_pCommandBuffer->AddCommand(Cmd); + // calculate memory usage + int MemUsage = MemSize; + while(Width > 2 && Height > 2) { - int PixelSize = 4; - if(StoreFormat == CImageInfo::FORMAT_RGB) - PixelSize = 3; - else if(StoreFormat == CImageInfo::FORMAT_ALPHA) - PixelSize = 1; - - m_aTextures[Tex].m_MemSize = Width*Height*PixelSize; - if(Mipmap) - { - while(Width > 2 && Height > 2) - { - Width>>=1; - Height>>=1; - m_aTextures[Tex].m_MemSize += Width*Height*PixelSize; - } - } + Width>>=1; + Height>>=1; + MemUsage += Width*Height*PixelSize; } - m_TextureMemoryUsage += m_aTextures[Tex].m_MemSize; - mem_free(pTmpData); + m_TextureMemoryUsage += MemUsage; + //mem_free(pTmpData); return Tex; } // simple uncompressed RGBA loaders int CGraphics_Threaded::LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) { - return 0; - int l = str_length(pFilename); int ID; CImageInfo Img; @@ -732,8 +789,6 @@ int CGraphics_Threaded::LoadTexture(const char *pFilename, int StorageType, int int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) { - return 0; - char aCompleteFilename[512]; unsigned char *pBuffer; png_t Png; // ignore_convention @@ -782,6 +837,10 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto void CGraphics_Threaded::ScreenshotDirect(const char *pFilename) { + // TODO: screenshot support + return; + + /* // fetch image data int y; int w = m_ScreenWidth; @@ -822,22 +881,13 @@ void CGraphics_Threaded::ScreenshotDirect(const char *pFilename) // clean up mem_free(pPixelData); + */ } void CGraphics_Threaded::TextureSet(int TextureID) { - return; - dbg_assert(m_Drawing == 0, "called Graphics()->TextureSet within begin"); - if(TextureID == -1) - { - glDisable(GL_TEXTURE_2D); - } - else - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_aTextures[TextureID].m_Tex); - } + m_State.m_Texture = TextureID; } void CGraphics_Threaded::Clear(float r, float g, float b) @@ -1130,22 +1180,6 @@ void CGraphics_Threaded::TakeScreenshot(const char *pFilename) void CGraphics_Threaded::Swap() { - if(0) { - CCommandBuffer::SCommand_Clear Cmd; - Cmd.m_Color.r = 1.0f; - Cmd.m_Color.g = 0.0f; - Cmd.m_Color.b = 0.0f; - Cmd.m_Color.a = 0.0f; - m_pCommandBuffer->AddCommand(Cmd); - } - - CCommandBuffer::SCommand_Swap Cmd; - m_pCommandBuffer->AddCommand(Cmd); - - m_Handler.RunBuffer(m_pCommandBuffer); - m_Handler.WaitForIdle(); - m_pCommandBuffer->Reset(); - // TODO: screenshot support /* if(m_DoScreenshot) @@ -1154,10 +1188,12 @@ void CGraphics_Threaded::Swap() m_DoScreenshot = false; }*/ - //SDL_GL_SwapBuffers(); + CCommandBuffer::SCommand_Swap Cmd; + m_pCommandBuffer->AddCommand(Cmd); - //if(g_Config.m_GfxFinish) - // glFinish(); + m_Handler.RunBuffer(m_pCommandBuffer); + m_Handler.WaitForIdle(); + m_pCommandBuffer->Reset(); } diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 876e9410..1ec8c61c 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -47,6 +47,11 @@ class CCommandBuffer CBuffer m_CmdBuffer; CBuffer m_DataBuffer; public: + enum + { + MAX_TEXTURES=1024*4, + }; + enum { // @@ -65,6 +70,7 @@ public: // texture commands CMD_TEXTURE_CREATE, CMD_TEXTURE_DESTROY, + CMD_TEXTURE_UPDATE, // rendering CMD_CLEAR, @@ -74,6 +80,14 @@ public: CMD_SWAP, }; + enum + { + TEXFORMAT_INVALID = 0, + TEXFORMAT_RGB, + TEXFORMAT_RGBA, + TEXFORMAT_ALPHA, + }; + enum { // @@ -155,6 +169,44 @@ public: { SCommand_Swap() : SCommand(CMD_SWAP) {} }; + + struct SCommand_Texture_Create : public SCommand + { + SCommand_Texture_Create() : SCommand(CMD_TEXTURE_CREATE) {} + + // texture information + int m_Slot; + + int m_Width; + int m_Height; + int m_Format; + int m_StoreFormat; + void *m_pData; // will be freed by the command processor + }; + + struct SCommand_Texture_Update : public SCommand + { + SCommand_Texture_Update() : SCommand(CMD_TEXTURE_UPDATE) {} + + // texture information + int m_Slot; + + int m_X; + int m_Y; + int m_Width; + int m_Height; + int m_Format; + void *m_pData; // will be freed by the command processor + }; + + + struct SCommand_Texture_Destroy : public SCommand + { + SCommand_Texture_Destroy() : SCommand(CMD_TEXTURE_DESTROY) {} + + // texture information + int m_Slot; + }; // CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) @@ -261,7 +313,7 @@ class CGraphics_Threaded : public IEngineGraphics struct CTexture { - GLuint m_Tex; + int m_State; int m_MemSize; int m_Flags; int m_Next; @@ -298,6 +350,7 @@ public: virtual int UnloadTexture(int Index); virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); + virtual int LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData); // simple uncompressed RGBA loaders virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index 4a3a2eb3..51eed547 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -9,21 +9,11 @@ #include #endif -#ifdef CONF_PLATFORM_MACOSX - #include - #include -#else - #include - #include -#endif - // ft2 texture #include #include FT_FREETYPE_H // TODO: Refactor: clean this up - - enum { MAX_CHARACTERS = 64, @@ -54,7 +44,7 @@ struct CFontSizeData int m_FontSize; FT_Face *m_pFace; - GLuint m_aTextures[2]; + int m_aTextures[2]; int m_TextureWidth; int m_TextureHeight; @@ -107,7 +97,7 @@ class CTextRender : public IEngineTextRender float m_TextOutlineB; float m_TextOutlineA; - int m_FontTextureFormat; + //int m_FontTextureFormat; CFont *m_pDefaultFont; @@ -158,26 +148,25 @@ class CTextRender : public IEngineTextRender void *pMem = mem_alloc(Width*Height, 1); mem_zero(pMem, Width*Height); - if(pSizeData->m_aTextures[0] == 0) - glGenTextures(2, pSizeData->m_aTextures); - else - FontMemoryUsage -= pSizeData->m_TextureWidth*pSizeData->m_TextureHeight*2; + for(int i = 0; i < 2; i++) + { + if(pSizeData->m_aTextures[i] != 0) + { + Graphics()->UnloadTexture(pSizeData->m_aTextures[i]); + FontMemoryUsage -= pSizeData->m_TextureWidth*pSizeData->m_TextureHeight; + pSizeData->m_aTextures[i] = 0; + } + + pSizeData->m_aTextures[i] = Graphics()->LoadTextureRaw(Width, Height, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, 0); + FontMemoryUsage += Width*Height; + } pSizeData->m_NumXChars = Xchars; pSizeData->m_NumYChars = Ychars; pSizeData->m_TextureWidth = Width; pSizeData->m_TextureHeight = Height; pSizeData->m_CurrentCharacter = 0; - - for(int i = 0; i < 2; i++) - { - glBindTexture(GL_TEXTURE_2D, pSizeData->m_aTextures[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, m_FontTextureFormat, Width, Height, 0, m_FontTextureFormat, GL_UNSIGNED_BYTE, pMem); - FontMemoryUsage += Width*Height; - } - + dbg_msg("", "pFont memory usage: %d", FontMemoryUsage); mem_free(pMem); @@ -254,11 +243,16 @@ class CTextRender : public IEngineTextRender int x = (SlotID%pSizeData->m_NumXChars) * (pSizeData->m_TextureWidth/pSizeData->m_NumXChars); int y = (SlotID/pSizeData->m_NumXChars) * (pSizeData->m_TextureHeight/pSizeData->m_NumYChars); + Graphics()->LoadTextureRawSub(pSizeData->m_aTextures[Texnum], x, y, + pSizeData->m_TextureWidth/pSizeData->m_NumXChars, + pSizeData->m_TextureHeight/pSizeData->m_NumYChars, + CImageInfo::FORMAT_ALPHA, pData); + /* glBindTexture(GL_TEXTURE_2D, pSizeData->m_aTextures[Texnum]); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, pSizeData->m_TextureWidth/pSizeData->m_NumXChars, pSizeData->m_TextureHeight/pSizeData->m_NumYChars, - m_FontTextureFormat, GL_UNSIGNED_BYTE, pData); + m_FontTextureFormat, GL_UNSIGNED_BYTE, pData);*/ } // 32k of data used for rendering glyphs @@ -455,7 +449,7 @@ public: m_pDefaultFont = 0; // GL_LUMINANCE can be good for debugging - m_FontTextureFormat = GL_ALPHA; + //m_FontTextureFormat = GL_ALPHA; } virtual void Init() @@ -620,11 +614,10 @@ public: if(pCursor->m_Flags&TEXTFLAG_RENDER) { // TODO: Make this better - glEnable(GL_TEXTURE_2D); if (i == 0) - glBindTexture(GL_TEXTURE_2D, pSizeData->m_aTextures[1]); + Graphics()->TextureSet(pSizeData->m_aTextures[1]); else - glBindTexture(GL_TEXTURE_2D, pSizeData->m_aTextures[0]); + Graphics()->TextureSet(pSizeData->m_aTextures[0]); Graphics()->QuadsBegin(); if (i == 0) diff --git a/src/engine/graphics.h b/src/engine/graphics.h index e1652cbe..cbc6a331 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -80,6 +80,7 @@ public: virtual int UnloadTexture(int Index) = 0; virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) = 0; virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) = 0; + virtual int LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData) = 0; virtual void TextureSet(int TextureID) = 0; struct CLineItem -- cgit 1.4.1 From 7a36a103aec1c0aafc89a45a4c7fb82944e6baba Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 10:04:46 +0100 Subject: fixed so that the rendering can be done async from the input, network and update --- src/engine/client/client.cpp | 17 ++++---- src/engine/client/graphics.cpp | 15 +++++++ src/engine/client/graphics.h | 4 ++ src/engine/client/graphics_threaded.cpp | 70 +++++++++++++++++++++++++++------ src/engine/client/graphics_threaded.h | 11 +++++- src/engine/graphics.h | 7 ++++ src/engine/shared/config_variables.h | 1 + 7 files changed, 106 insertions(+), 19 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index bb888c60..53f60fa8 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1853,19 +1853,22 @@ void CClient::Run() Update(); - if(g_Config.m_DbgStress) + if(!g_Config.m_GfxAsyncRender || m_pGraphics->IsIdle()) { - if((m_Frames%10) == 0) + if(g_Config.m_DbgStress) + { + if((m_Frames%10) == 0) + { + Render(); + m_pGraphics->Swap(); + } + } + else { Render(); m_pGraphics->Swap(); } } - else - { - Render(); - m_pGraphics->Swap(); - } } AutoScreenshot_Cleanup(); diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index b78e5387..03a6e7cd 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -963,4 +963,19 @@ int CGraphics_SDL::GetVideoModes(CVideoMode *pModes, int MaxModes) return NumModes; } +// syncronization +void CGraphics_SDL::InsertSignal(semaphore *pSemaphore) +{ + pSemaphore->signal(); +} + +bool CGraphics_SDL::IsIdle() +{ + return true; +} + +void CGraphics_SDL::WaitForIdle() +{ +} + //extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index d97513f3..37276d36 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -144,6 +144,10 @@ public: virtual int GetVideoModes(CVideoMode *pModes, int MaxModes); + // syncronization + virtual void InsertSignal(semaphore *pSemaphore); + virtual bool IsIdle(); + virtual void WaitForIdle(); }; #endif diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index ade77ef4..e702133a 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -45,6 +45,28 @@ static CVideoMode g_aFakeModes[] = { {2048,1536,5,6,5} }; +class CCommandProcessorFragment_General +{ +public: + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + { + + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_SIGNAL: + { + const CCommandBuffer::SCommand_Signal *pCommand = static_cast(pBaseCommand); + pCommand->m_pSemaphore->signal(); + } break; + default: + return false; + break; + } + + return true; + } +}; + class CCommandProcessorFragment_OpenGL { @@ -154,15 +176,15 @@ public: { case CCommandBuffer::CMD_TEXTURE_CREATE: { - Cmd_Texture_Create((const CCommandBuffer::SCommand_Texture_Create *)pBaseCommand); + Cmd_Texture_Create(static_cast(pBaseCommand)); } break; case CCommandBuffer::CMD_TEXTURE_DESTROY: { - Cmd_Texture_Destroy((const CCommandBuffer::SCommand_Texture_Destroy *)pBaseCommand); + Cmd_Texture_Destroy(static_cast(pBaseCommand)); } break; case CCommandBuffer::CMD_TEXTURE_UPDATE: { - Cmd_Texture_Update((const CCommandBuffer::SCommand_Texture_Update *)pBaseCommand); + Cmd_Texture_Update(static_cast(pBaseCommand)); } break; case CCommandBuffer::CMD_CLEAR: { @@ -172,7 +194,7 @@ public: } break; case CCommandBuffer::CMD_RENDER: { - const CCommandBuffer::SCommand_Render *pCommand = (CCommandBuffer::SCommand_Render *)pBaseCommand; + const CCommandBuffer::SCommand_Render *pCommand = static_cast(pBaseCommand); SetState(pCommand->m_State); glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); @@ -354,7 +376,7 @@ public: break; case CCommandBuffer::CMD_INIT: { - const CCommandBuffer::SCommand_Init *pCommand = (CCommandBuffer::SCommand_Init *)pBaseCommand; + const CCommandBuffer::SCommand_Init *pCommand = static_cast(pBaseCommand); *pCommand->m_pResult = Init(); } break; case CCommandBuffer::CMD_SHUTDOWN: @@ -372,18 +394,18 @@ public: } }; - class CCommandProcessor_SDL_OpenGL : public ICommandProcessor { CCommandProcessorFragment_OpenGL m_OpenGL; CCommandProcessorFragment_SDL m_SDL; + CCommandProcessorFragment_General m_General; public: virtual void RunBuffer(CCommandBuffer *pBuffer) { unsigned CmdIndex = 0; while(1) { - CCommandBuffer::SCommand * const pBaseCommand = pBuffer->GetCommand(&CmdIndex); + const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex); if(pBaseCommand == 0x0) break; @@ -392,6 +414,9 @@ class CCommandProcessor_SDL_OpenGL : public ICommandProcessor if(m_SDL.RunCommand(pBaseCommand)) continue; + + if(m_General.RunCommand(pBaseCommand)) + continue; dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd); } @@ -547,7 +572,10 @@ CGraphics_Threaded::CGraphics_Threaded() m_State.m_Texture = -1; m_State.m_BlendMode = CCommandBuffer::BLEND_NONE; - + m_CurrentCommandBuffer = 0; + m_pCommandBuffer = 0x0; + m_apCommandBuffers[0] = 0x0; + m_apCommandBuffers[1] = 0x0; m_NumVertices = 0; @@ -748,7 +776,7 @@ int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const // m_pCommandBuffer->AddCommand(Cmd); - + // calculate memory usage int MemUsage = MemSize; while(Width > 2 && Height > 2) @@ -1188,14 +1216,34 @@ void CGraphics_Threaded::Swap() m_DoScreenshot = false; }*/ + // add swap command CCommandBuffer::SCommand_Swap Cmd; m_pCommandBuffer->AddCommand(Cmd); - m_Handler.RunBuffer(m_pCommandBuffer); - m_Handler.WaitForIdle(); + + // swap buffer + m_CurrentCommandBuffer ^= 1; + m_pCommandBuffer = m_apCommandBuffers[m_CurrentCommandBuffer]; m_pCommandBuffer->Reset(); } +// syncronization +void CGraphics_Threaded::InsertSignal(semaphore *pSemaphore) +{ + CCommandBuffer::SCommand_Signal Cmd; + Cmd.m_pSemaphore = pSemaphore; + m_pCommandBuffer->AddCommand(Cmd); +} + +bool CGraphics_Threaded::IsIdle() +{ + return m_Handler.IsIdle(); +} + +void CGraphics_Threaded::WaitForIdle() +{ + m_Handler.WaitForIdle(); +} int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) { diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 1ec8c61c..a4c4ab40 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -143,12 +143,17 @@ public: SColor m_Color; }; - struct SCommand_Init : public SCommand { SCommand_Init() : SCommand(CMD_INIT) {} volatile int *m_pResult; }; + + struct SCommand_Signal : public SCommand + { + SCommand_Signal() : SCommand(CMD_SIGNAL) {} + semaphore *m_pSemaphore; + }; struct SCommand_RunBuffer : public SCommand { @@ -393,4 +398,8 @@ public: virtual int GetVideoModes(CVideoMode *pModes, int MaxModes); + // syncronization + virtual void InsertSignal(semaphore *pSemaphore); + virtual bool IsIdle(); + virtual void WaitForIdle(); }; \ No newline at end of file diff --git a/src/engine/graphics.h b/src/engine/graphics.h index cbc6a331..1c79ee15 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -5,6 +5,8 @@ #include "kernel.h" +#include + class CImageInfo { public: @@ -132,6 +134,11 @@ public: virtual int GetVideoModes(CVideoMode *pModes, int MaxModes) = 0; virtual void Swap() = 0; + + // syncronization + virtual void InsertSignal(semaphore *pSemaphore) = 0; + virtual bool IsIdle() = 0; + virtual void WaitForIdle() = 0; }; class IEngineGraphics : public IGraphics diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index c812063a..352cefd8 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -70,6 +70,7 @@ MACRO_CONFIG_INT(GfxTextureQuality, gfx_texture_quality, 1, 0, 1, CFGFLAG_SAVE|C MACRO_CONFIG_INT(GfxFsaaSamples, gfx_fsaa_samples, 0, 0, 16, CFGFLAG_SAVE|CFGFLAG_CLIENT, "FSAA Samples") MACRO_CONFIG_INT(GfxRefreshRate, gfx_refresh_rate, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen refresh rate") MACRO_CONFIG_INT(GfxFinish, gfx_finish, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") +MACRO_CONFIG_INT(GfxAsyncRender, gfx_asyncrender, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Do rendering async from the the update") MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity") -- cgit 1.4.1 From b31abc40537bff7e159091ff61d5af442296c4d9 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 10:29:25 +0100 Subject: fixed so that you can select graphics backend via gfx_threaded --- src/engine/client/client.cpp | 23 +++++++++++++++-------- src/engine/client/graphics.cpp | 2 +- src/engine/client/graphics_threaded.cpp | 2 +- src/engine/graphics.h | 1 + src/engine/shared/config_variables.h | 2 ++ src/game/client/gameclient.cpp | 12 +++++++----- 6 files changed, 27 insertions(+), 15 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 53f60fa8..b54b9084 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1676,7 +1676,7 @@ void CClient::InitInterfaces() // fetch interfaces m_pEngine = Kernel()->RequestInterface(); m_pEditor = Kernel()->RequestInterface(); - m_pGraphics = Kernel()->RequestInterface(); + //m_pGraphics = Kernel()->RequestInterface(); m_pSound = Kernel()->RequestInterface(); m_pGameClient = Kernel()->RequestInterface(); m_pInput = Kernel()->RequestInterface(); @@ -1698,10 +1698,21 @@ void CClient::Run() m_SnapshotParts = 0; // init graphics - if(m_pGraphics->Init() != 0) { - dbg_msg("client", "couldn't init graphics"); - return; + if(g_Config.m_GfxThreaded) + m_pGraphics = CreateEngineGraphicsThreaded(); + else + m_pGraphics = CreateEngineGraphics(); + + bool RegisterFail = false; + RegisterFail = RegisterFail || !Kernel()->RegisterInterface(static_cast(m_pGraphics)); // register graphics as both + RegisterFail = RegisterFail || !Kernel()->RegisterInterface(static_cast(m_pGraphics)); + + if(RegisterFail || m_pGraphics->Init() != 0) + { + dbg_msg("client", "couldn't init graphics"); + return; + } } // open socket @@ -2220,7 +2231,6 @@ int main(int argc, const char **argv) // ignore_convention IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT); IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); // ignore_convention IConfig *pConfig = CreateConfig(); - IEngineGraphics *pEngineGraphics = CreateEngineGraphics(); IEngineSound *pEngineSound = CreateEngineSound(); IEngineInput *pEngineInput = CreateEngineInput(); IEngineTextRender *pEngineTextRender = CreateEngineTextRender(); @@ -2234,9 +2244,6 @@ int main(int argc, const char **argv) // ignore_convention RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConsole); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConfig); - RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineGraphics)); // register graphics as both - RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineGraphics)); - RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineSound)); // register as both RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineSound)); diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 03a6e7cd..fda85312 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -978,4 +978,4 @@ void CGraphics_SDL::WaitForIdle() { } -//extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } +extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); } diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index e702133a..2b9147ff 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -1293,4 +1293,4 @@ int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) } -extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_Threaded(); } +extern IEngineGraphics *CreateEngineGraphicsThreaded() { return new CGraphics_Threaded(); } diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 1c79ee15..be113b2d 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -157,5 +157,6 @@ public: }; extern IEngineGraphics *CreateEngineGraphics(); +extern IEngineGraphics *CreateEngineGraphicsThreaded(); #endif diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 352cefd8..e7b1f7da 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -72,6 +72,8 @@ MACRO_CONFIG_INT(GfxRefreshRate, gfx_refresh_rate, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG MACRO_CONFIG_INT(GfxFinish, gfx_finish, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(GfxAsyncRender, gfx_asyncrender, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Do rendering async from the the update") +MACRO_CONFIG_INT(GfxThreaded, gfx_threaded, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Use the threaded graphics backend") + MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity") MACRO_CONFIG_STR(SvName, sv_name, 128, "unnamed server", CFGFLAG_SERVER, "Server name") diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 2fd1c2f3..d62a16eb 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -95,7 +95,6 @@ void CGameClient::OnConsoleInit() { m_pEngine = Kernel()->RequestInterface(); m_pClient = Kernel()->RequestInterface(); - m_pGraphics = Kernel()->RequestInterface(); m_pTextRender = Kernel()->RequestInterface(); m_pSound = Kernel()->RequestInterface(); m_pInput = Kernel()->RequestInterface(); @@ -196,10 +195,6 @@ void CGameClient::OnConsoleInit() Console()->Register("vote", "r", CFGFLAG_SERVER, 0, 0, "Force a vote to yes/no"); - // propagate pointers - m_UI.SetGraphics(Graphics(), TextRender()); - m_RenderTools.m_pGraphics = Graphics(); - m_RenderTools.m_pUI = UI(); for(int i = 0; i < m_All.m_Num; i++) m_All.m_paComponents[i]->m_pClient = this; @@ -223,6 +218,13 @@ void CGameClient::OnConsoleInit() void CGameClient::OnInit() { + m_pGraphics = Kernel()->RequestInterface(); + + // propagate pointers + m_UI.SetGraphics(Graphics(), TextRender()); + m_RenderTools.m_pGraphics = Graphics(); + m_RenderTools.m_pUI = UI(); + int64 Start = time_get(); // set the language -- cgit 1.4.1 From 6e57620c2ca9042732d67134e2986a4ad96d2534 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 11:18:55 +0100 Subject: added flags for mipmap generation on textures. fixes missing texts --- src/engine/client/graphics.cpp | 15 ++++++++++++--- src/engine/client/graphics_threaded.cpp | 22 +++++++++++++++++++--- src/engine/client/graphics_threaded.h | 3 +++ src/engine/client/text.cpp | 2 +- src/engine/graphics.h | 3 ++- 5 files changed, 37 insertions(+), 8 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index fda85312..d16f10fc 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -349,9 +349,18 @@ int CGraphics_OpenGL::LoadTextureRaw(int Width, int Height, int Format, const vo glGenTextures(1, &m_aTextures[Tex].m_Tex); glBindTexture(GL_TEXTURE_2D, m_aTextures[Tex].m_Tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); + if(Flags&TEXLOAD_NOMIPMAPS) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pData); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } // calculate memory usage { diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 2b9147ff..21e9ef2f 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -163,9 +163,20 @@ public: glGenTextures(1, &m_aTextures[pCommand->m_Slot]); glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + + if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, pCommand->m_Width, pCommand->m_Height, 0, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + } + mem_free(pCommand->m_pData); } @@ -760,6 +771,11 @@ int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const Cmd.m_Format = ImageFormatToTexFormat(Format); Cmd.m_StoreFormat = ImageFormatToTexFormat(StoreFormat); + // flags + Cmd.m_Flags = 0; + if(Flags&IGraphics::TEXLOAD_NOMIPMAPS) + Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NOMIPMAPS; + // calculate memory usage int PixelSize = 4; if(Format == CImageInfo::FORMAT_RGB) diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index a4c4ab40..41565ca2 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -86,6 +86,8 @@ public: TEXFORMAT_RGB, TEXFORMAT_RGBA, TEXFORMAT_ALPHA, + + TEXFLAG_NOMIPMAPS = 1, }; enum @@ -186,6 +188,7 @@ public: int m_Height; int m_Format; int m_StoreFormat; + int m_Flags; void *m_pData; // will be freed by the command processor }; diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index 51eed547..f00247d2 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -157,7 +157,7 @@ class CTextRender : public IEngineTextRender pSizeData->m_aTextures[i] = 0; } - pSizeData->m_aTextures[i] = Graphics()->LoadTextureRaw(Width, Height, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, 0); + pSizeData->m_aTextures[i] = Graphics()->LoadTextureRaw(Width, Height, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS); FontMemoryUsage += Width*Height; } diff --git a/src/engine/graphics.h b/src/engine/graphics.h index be113b2d..94d9c1a2 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -57,7 +57,8 @@ public: */ enum { - TEXLOAD_NORESAMPLE=1, + TEXLOAD_NORESAMPLE = 1, + TEXLOAD_NOMIPMAPS = 2, }; int ScreenWidth() const { return m_ScreenWidth; } -- cgit 1.4.1 From 8b76105cfa70e74b76e38ed2a867e806bba8e0ff Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 31 Dec 2011 14:00:49 +0100 Subject: cleaned up some of the code --- src/engine/client/graphics_threaded.cpp | 354 ++++++++++++++++++++++---------- src/engine/client/graphics_threaded.h | 25 ++- 2 files changed, 264 insertions(+), 115 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 21e9ef2f..febb3b28 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -48,34 +48,27 @@ static CVideoMode g_aFakeModes[] = { class CCommandProcessorFragment_General { public: - bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + void Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand) { + pCommand->m_pSemaphore->signal(); + } + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + { switch(pBaseCommand->m_Cmd) { - case CCommandBuffer::CMD_SIGNAL: - { - const CCommandBuffer::SCommand_Signal *pCommand = static_cast(pBaseCommand); - pCommand->m_pSemaphore->signal(); - } break; - default: - return false; - break; + case CCommandBuffer::CMD_NOP: break; + case CCommandBuffer::CMD_SIGNAL: Cmd_Signal(static_cast(pBaseCommand)); break; + default: return false; } return true; } }; - class CCommandProcessorFragment_OpenGL { GLuint m_aTextures[CCommandBuffer::MAX_TEXTURES]; -public: - CCommandProcessorFragment_OpenGL() - { - mem_zero(m_aTextures, sizeof(m_aTextures)); - } void SetState(const CCommandBuffer::SState &State) { @@ -121,7 +114,7 @@ public: glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); } - int TexFormatToOpenGLFormat(int TexFormat) + static int TexFormatToOpenGLFormat(int TexFormat) { if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) return GL_RGB; if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) return GL_ALPHA; @@ -180,56 +173,52 @@ public: mem_free(pCommand->m_pData); } - bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) { + glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } - switch(pBaseCommand->m_Cmd) + void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) + { + SetState(pCommand->m_State); + + glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); + glTexCoordPointer(2, 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)*5); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + switch(pCommand->m_PrimType) { - case CCommandBuffer::CMD_TEXTURE_CREATE: - { - Cmd_Texture_Create(static_cast(pBaseCommand)); - } break; - case CCommandBuffer::CMD_TEXTURE_DESTROY: - { - Cmd_Texture_Destroy(static_cast(pBaseCommand)); - } break; - case CCommandBuffer::CMD_TEXTURE_UPDATE: - { - Cmd_Texture_Update(static_cast(pBaseCommand)); - } break; - case CCommandBuffer::CMD_CLEAR: - { - const CCommandBuffer::SCommand_Clear *pCommand = (CCommandBuffer::SCommand_Clear *)pBaseCommand; - glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } break; - case CCommandBuffer::CMD_RENDER: - { - const CCommandBuffer::SCommand_Render *pCommand = static_cast(pBaseCommand); - SetState(pCommand->m_State); - - glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); - glTexCoordPointer(2, 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)*5); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - switch(pCommand->m_PrimType) - { - case CCommandBuffer::PRIMTYPE_QUADS: - glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4); - break; - case CCommandBuffer::PRIMTYPE_LINES: - glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd); - }; - } break; - default: - return false; + case CCommandBuffer::PRIMTYPE_QUADS: + glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4); break; + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd); + }; + } + +public: + CCommandProcessorFragment_OpenGL() + { + mem_zero(m_aTextures, sizeof(m_aTextures)); + } + + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) + { + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_TEXTURE_CREATE: Cmd_Texture_Create(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_TEXTURE_DESTROY: Cmd_Texture_Destroy(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_CLEAR: Cmd_Clear(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER: Cmd_Render(static_cast(pBaseCommand)); break; + default: return false; } return true; @@ -240,7 +229,8 @@ class CCommandProcessorFragment_SDL { // SDL stuff SDL_Surface *m_pScreenSurface; - + bool m_SystemInited; + /* int TryInit() { const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); @@ -345,12 +335,6 @@ class CCommandProcessorFragment_SDL } } - atexit(SDL_Quit); // ignore_convention - - #ifdef CONF_FAMILY_WINDOWS - if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention - putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention - #endif if(InitWindow() != 0) return -1; @@ -369,36 +353,128 @@ class CCommandProcessorFragment_SDL glDepthMask(0); return 0; + }*/ + + void Cmd_Init(const CCommandBuffer::SCommand_Init *pCommand) + { + if(!m_SystemInited) + { + int Systems = SDL_INIT_VIDEO; + + if(g_Config.m_SndEnable) // TODO: remove + Systems |= SDL_INIT_AUDIO; + + if(g_Config.m_ClEventthread) // TODO: remove + Systems |= SDL_INIT_EVENTTHREAD; + + if(SDL_Init(Systems) < 0) + { + dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); + *pCommand->m_pResult = -1; + return; + } + + atexit(SDL_Quit); // ignore_convention + + #ifdef CONF_FAMILY_WINDOWS + if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention + putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention + #endif + + m_SystemInited = true; + } + + const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); + + // set flags + int Flags = SDL_OPENGL; + if(pCommand->m_Flags&CCommandBuffer::INITFLAG_RESIZABLE) + Flags |= SDL_RESIZABLE; + + if(pInfo->hw_available) // ignore_convention + Flags |= SDL_HWSURFACE; + else + Flags |= SDL_SWSURFACE; + + if(pInfo->blit_hw) // ignore_convention + Flags |= SDL_HWACCEL; + + if(pCommand->m_Flags&CCommandBuffer::INITFLAG_FULLSCREEN) + Flags |= SDL_FULLSCREEN; + + // set gl attributes + if(pCommand->m_FsaaSamples) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, pCommand->m_FsaaSamples); + } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, pCommand->m_Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); + + // set caption + SDL_WM_SetCaption(pCommand->m_aName, pCommand->m_aName); + + // create window + m_pScreenSurface = SDL_SetVideoMode(pCommand->m_ScreenWidth, pCommand->m_ScreenHeight, 0, Flags); + if(m_pScreenSurface) + { + SDL_ShowCursor(0); + + // set some default settings + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glAlphaFunc(GL_GREATER, 0); + glEnable(GL_ALPHA_TEST); + glDepthMask(0); + + *pCommand->m_pResult = 0; + } + else + { + dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); + *pCommand->m_pResult = -1; + } + + + //*pCommand->m_pResult = Init(); } + void Cmd_Shutdown(const CCommandBuffer::SCommand_Shutdown *pCommand) + { + + } + + void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand) + { + SDL_GL_SwapBuffers(); + } public: CCommandProcessorFragment_SDL() { + m_SystemInited = false; m_pScreenSurface = 0x0; } bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) { - switch(pBaseCommand->m_Cmd) { - case CCommandBuffer::CMD_NOP: - break; - case CCommandBuffer::CMD_INIT: - { - const CCommandBuffer::SCommand_Init *pCommand = static_cast(pBaseCommand); - *pCommand->m_pResult = Init(); - } break; - case CCommandBuffer::CMD_SHUTDOWN: - break; - case CCommandBuffer::CMD_SWAP: - { - SDL_GL_SwapBuffers(); - } break; - default: - return false; - break; + case CCommandBuffer::CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_SHUTDOWN: Cmd_Shutdown(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast(pBaseCommand)); break; + default: return false; } return true; @@ -1128,6 +1204,66 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, float r, float QuadsEnd(); } +int CGraphics_Threaded::IssueInit() +{ + // issue init command + m_pCommandBuffer->Reset(); + + volatile int Result; + CCommandBuffer::SCommand_Init Cmd; + str_copy(Cmd.m_aName, "Teeworlds", sizeof(Cmd.m_aName)); + Cmd.m_pResult = &Result; + Cmd.m_ScreenWidth = g_Config.m_GfxScreenWidth; + Cmd.m_ScreenHeight = g_Config.m_GfxScreenHeight; + Cmd.m_FsaaSamples = g_Config.m_GfxFsaaSamples; + + Cmd.m_Flags = 0; + if(g_Config.m_GfxFullscreen) Cmd.m_Flags |= CCommandBuffer::INITFLAG_FULLSCREEN; + if(g_Config.m_GfxVsync) Cmd.m_Flags |= CCommandBuffer::INITFLAG_VSYNC; + if(g_Config.m_DbgResizable) Cmd.m_Flags |= CCommandBuffer::INITFLAG_RESIZABLE; + + m_pCommandBuffer->AddCommand(Cmd); + + m_Handler.RunBuffer(m_pCommandBuffer); + m_Handler.WaitForIdle(); + return Result; +} + +int CGraphics_Threaded::InitWindow() +{ + if(IssueInit() == 0) + return 0; + + // try disabling fsaa + while(g_Config.m_GfxFsaaSamples) + { + g_Config.m_GfxFsaaSamples--; + + if(g_Config.m_GfxFsaaSamples) + dbg_msg("gfx", "lowering FSAA to %d and trying again", g_Config.m_GfxFsaaSamples); + else + dbg_msg("gfx", "disabling FSAA and trying again"); + + if(IssueInit() == 0) + return 0; + } + + // try lowering the resolution + if(g_Config.m_GfxScreenWidth != 640 || g_Config.m_GfxScreenHeight != 480) + { + dbg_msg("gfx", "setting resolution to 640x480 and trying again"); + g_Config.m_GfxScreenWidth = 640; + g_Config.m_GfxScreenHeight = 480; + + if(IssueInit() == 0) + return 0; + } + + dbg_msg("gfx", "out of ideas. failed to init graphics"); + + return -1; +} + bool CGraphics_Threaded::Init() { // fetch pointers @@ -1153,34 +1289,24 @@ bool CGraphics_Threaded::Init() m_apCommandBuffers[1] = new CCommandBuffer(1024*512, 1024*1024); m_pCommandBuffer = m_apCommandBuffers[0]; - // issue init command - m_pCommandBuffer->Reset(); - volatile int Result; - CCommandBuffer::SCommand_Init Cmd; - Cmd.m_pResult = &Result; - m_pCommandBuffer->AddCommand(Cmd); - m_Handler.RunBuffer(m_pCommandBuffer); - m_Handler.WaitForIdle(); - - - if(Result == 0) - { - // fetch final resolusion - m_ScreenWidth = g_Config.m_GfxScreenWidth; - m_ScreenHeight = g_Config.m_GfxScreenHeight; - - // create null texture, will get id=0 - static const unsigned char aNullTextureData[] = { - 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, - 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, - 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, - 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, - }; - - m_InvalidTexture = LoadTextureRaw(4,4,CImageInfo::FORMAT_RGBA,aNullTextureData,CImageInfo::FORMAT_RGBA,TEXLOAD_NORESAMPLE); - } - - return Result; + // try to init the window + if(InitWindow() != 0) + return 0; + + // fetch final resolusion + m_ScreenWidth = g_Config.m_GfxScreenWidth; + m_ScreenHeight = g_Config.m_GfxScreenHeight; + + // create null texture, will get id=0 + static const unsigned char aNullTextureData[] = { + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, + }; + + m_InvalidTexture = LoadTextureRaw(4,4,CImageInfo::FORMAT_RGBA,aNullTextureData,CImageInfo::FORMAT_RGBA,TEXLOAD_NORESAMPLE); + return 0; } void CGraphics_Threaded::Shutdown() diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 41565ca2..54455d6d 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -90,6 +90,13 @@ public: TEXFLAG_NOMIPMAPS = 1, }; + enum + { + INITFLAG_FULLSCREEN = 1, + INITFLAG_VSYNC = 2, + INITFLAG_RESIZABLE = 4, + }; + enum { // @@ -148,9 +155,22 @@ public: struct SCommand_Init : public SCommand { SCommand_Init() : SCommand(CMD_INIT) {} + + char m_aName[256]; + + int m_ScreenWidth; + int m_ScreenHeight; + int m_FsaaSamples; + int m_Flags; + volatile int *m_pResult; }; - + + struct SCommand_Shutdown : public SCommand + { + SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {} + }; + struct SCommand_Signal : public SCommand { SCommand_Signal() : SCommand(CMD_SIGNAL) {} @@ -337,6 +357,9 @@ class CGraphics_Threaded : public IEngineGraphics static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); + + int IssueInit(); + int InitWindow(); public: CGraphics_Threaded(); -- cgit 1.4.1 From c1942ca6cbafb605e3ebc8e8cfabf982144f388f Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 1 Jan 2012 13:38:46 +0100 Subject: fixed the render frame time and cleaned up some more code --- src/engine/client.h | 4 +- src/engine/client/client.cpp | 60 ++++++++------- src/engine/client/client.h | 9 ++- src/engine/client/graphics_threaded.cpp | 132 +------------------------------- src/engine/client/graphics_threaded.h | 10 +++ src/game/client/components/hud.cpp | 2 +- src/game/client/components/items.cpp | 3 - 7 files changed, 54 insertions(+), 166 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client.h b/src/engine/client.h index 966e8f61..e9076b76 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -23,7 +23,7 @@ protected: float m_PredIntraTick; float m_LocalTime; - float m_FrameTime; + float m_RenderFrameTime; int m_GameTickSpeed; public: @@ -68,7 +68,7 @@ public: inline int GameTickSpeed() const { return m_GameTickSpeed; } // other time access - inline float FrameTime() const { return m_FrameTime; } + inline float RenderFrameTime() const { return m_RenderFrameTime; } inline float LocalTime() const { return m_LocalTime; } // actions diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index b54b9084..b7244db4 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -244,10 +244,11 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD m_pMap = 0; m_pConsole = 0; - m_FrameTime = 0.0001f; - m_FrameTimeLow = 1.0f; - m_FrameTimeHigh = 0.0f; - m_Frames = 0; + m_RenderFrameTime = 0.0001f; + m_RenderFrameTimeLow = 1.0f; + m_RenderFrameTimeHigh = 0.0f; + m_RenderFrames = 0; + m_LastRenderTime = time_get(); m_GameTickSpeed = SERVER_TICK_SPEED; @@ -681,13 +682,13 @@ void CClient::DebugRender() udp = 8 total = 42 */ - FrameTimeAvg = FrameTimeAvg*0.9f + m_FrameTime*0.1f; + FrameTimeAvg = FrameTimeAvg*0.9f + m_RenderFrameTime*0.1f; str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d mem %dk %d gfxmem: %dk fps: %3d", m_CurGameTick, m_PredTick, mem_stats()->allocated/1024, mem_stats()->total_allocations, Graphics()->MemoryUsage()/1024, - (int)(1.0f/FrameTimeAvg)); + (int)(1.0f/FrameTimeAvg + 0.5f)); Graphics()->QuadsText(2, 2, 16, 1,1,1,1, aBuffer); @@ -1691,9 +1692,6 @@ void CClient::InitInterfaces() void CClient::Run() { - int64 ReportTime = time_get(); - int64 ReportInterval = time_freq()*1; - m_LocalStartTime = time_get(); m_SnapshotParts = 0; @@ -1772,9 +1770,6 @@ void CClient::Run() while (1) { - int64 FrameStartTime = time_get(); - m_Frames++; - // VersionUpdate(); @@ -1866,9 +1861,22 @@ void CClient::Run() if(!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) + m_RenderFrameTimeHigh = m_RenderFrameTime; + m_FpsGraph.Add(1.0f/m_RenderFrameTime, 1,1,1); + + m_LastRenderTime = Now; + if(g_Config.m_DbgStress) { - if((m_Frames%10) == 0) + if((m_RenderFrames%10) == 0) { Render(); m_pGraphics->Swap(); @@ -1879,6 +1887,9 @@ void CClient::Run() Render(); m_pGraphics->Swap(); } + + + } } @@ -1900,32 +1911,25 @@ void CClient::Run() g_Config.m_DbgHitch = 0; } + /* if(ReportTime < time_get()) { if(0 && g_Config.m_Debug) { dbg_msg("client/report", "fps=%.02f (%.02f %.02f) netstate=%d", m_Frames/(float)(ReportInterval/time_freq()), - 1.0f/m_FrameTimeHigh, - 1.0f/m_FrameTimeLow, + 1.0f/m_RenderFrameTimeHigh, + 1.0f/m_RenderFrameTimeLow, m_NetClient.State()); } - m_FrameTimeLow = 1; - m_FrameTimeHigh = 0; - m_Frames = 0; + m_RenderFrameTimeLow = 1; + m_RenderFrameTimeHigh = 0; + m_RenderFrames = 0; ReportTime += ReportInterval; - } - - // update frametime - m_FrameTime = (time_get()-FrameStartTime)/(float)time_freq(); - if(m_FrameTime < m_FrameTimeLow) - m_FrameTimeLow = m_FrameTime; - if(m_FrameTime > m_FrameTimeHigh) - m_FrameTimeHigh = m_FrameTime; + }*/ + // update local time m_LocalTime = (time_get()-m_LocalStartTime)/(float)time_freq(); - - m_FpsGraph.Add(1.0f/m_FrameTime, 1,1,1); } GameClient()->OnShutdown(); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 83553eb4..1849830c 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -84,9 +84,12 @@ class CClient : public IClient, public CDemoPlayer::IListner int64 m_LocalStartTime; int m_DebugFont; - float m_FrameTimeLow; - float m_FrameTimeHigh; - int m_Frames; + + int64 m_LastRenderTime; + float m_RenderFrameTimeLow; + float m_RenderFrameTimeHigh; + int m_RenderFrames; + NETADDR m_ServerAddress; int m_WindowMustRefocus; int m_SnapCrcErrors; diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index febb3b28..694ecc71 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -230,130 +230,6 @@ class CCommandProcessorFragment_SDL // SDL stuff SDL_Surface *m_pScreenSurface; bool m_SystemInited; - /* - int TryInit() - { - const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - - // set flags - int Flags = SDL_OPENGL; - if(g_Config.m_DbgResizable) - Flags |= SDL_RESIZABLE; - - if(pInfo->hw_available) // ignore_convention - Flags |= SDL_HWSURFACE; - else - Flags |= SDL_SWSURFACE; - - if(pInfo->blit_hw) // ignore_convention - Flags |= SDL_HWACCEL; - - if(g_Config.m_GfxFullscreen) - Flags |= SDL_FULLSCREEN; - - // set gl attributes - if(g_Config.m_GfxFsaaSamples) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, g_Config.m_GfxFsaaSamples); - } - else - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); - } - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, g_Config.m_GfxVsync); - - // set caption - SDL_WM_SetCaption("Teeworlds", "Teeworlds"); - - // create window - m_pScreenSurface = SDL_SetVideoMode(g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, 0, Flags); - if(m_pScreenSurface == NULL) - { - dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); - return -1; - } - - return 0; - } - - - int InitWindow() - { - if(TryInit() == 0) - return 0; - - // try disabling fsaa - while(g_Config.m_GfxFsaaSamples) - { - g_Config.m_GfxFsaaSamples--; - - if(g_Config.m_GfxFsaaSamples) - dbg_msg("gfx", "lowering FSAA to %d and trying again", g_Config.m_GfxFsaaSamples); - else - dbg_msg("gfx", "disabling FSAA and trying again"); - - if(TryInit() == 0) - return 0; - } - - // try lowering the resolution - if(g_Config.m_GfxScreenWidth != 640 || g_Config.m_GfxScreenHeight != 480) - { - dbg_msg("gfx", "setting resolution to 640x480 and trying again"); - g_Config.m_GfxScreenWidth = 640; - g_Config.m_GfxScreenHeight = 480; - - if(TryInit() == 0) - return 0; - } - - dbg_msg("gfx", "out of ideas. failed to init graphics"); - - return -1; - } - - int Init() - { - { - int Systems = SDL_INIT_VIDEO; - - if(g_Config.m_SndEnable) - Systems |= SDL_INIT_AUDIO; - - if(g_Config.m_ClEventthread) - Systems |= SDL_INIT_EVENTTHREAD; - - if(SDL_Init(Systems) < 0) - { - dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); - return -1; - } - } - - - if(InitWindow() != 0) - return -1; - - SDL_ShowCursor(0); - - // set some default settings - glEnable(GL_BLEND); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glAlphaFunc(GL_GREATER, 0); - glEnable(GL_ALPHA_TEST); - glDepthMask(0); - - return 0; - }*/ void Cmd_Init(const CCommandBuffer::SCommand_Init *pCommand) { @@ -445,14 +321,11 @@ class CCommandProcessorFragment_SDL dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); *pCommand->m_pResult = -1; } - - - //*pCommand->m_pResult = Init(); } void Cmd_Shutdown(const CCommandBuffer::SCommand_Shutdown *pCommand) { - + SDL_Quit(); } void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand) @@ -1312,7 +1185,8 @@ bool CGraphics_Threaded::Init() void CGraphics_Threaded::Shutdown() { // TODO: SDL, is this correct? - SDL_Quit(); + + // } void CGraphics_Threaded::Minimize() diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 54455d6d..1ea84ea9 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -78,6 +78,9 @@ public: // swap CMD_SWAP, + + // + CMD_SCREENSHOT, }; enum @@ -192,6 +195,13 @@ public: SVertex *m_pVertices; }; + struct SCommand_Screenshot : public SCommand + { + SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {} + + CImageInfo *m_pImage; // processor will fill this out + }; + struct SCommand_Swap : public SCommand { SCommand_Swap() : SCommand(CMD_SWAP) {} diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 17365116..df3afdea 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -248,7 +248,7 @@ void CHud::RenderFps() if(g_Config.m_ClShowfps) { // calculate avg. fps - float FPS = 1.0f / Client()->FrameTime(); + float FPS = 1.0f / Client()->RenderFrameTime(); m_AverageFPS = (m_AverageFPS*(1.0f-(1.0f/m_AverageFPS))) + (FPS*(1.0f/m_AverageFPS)); char Buf[512]; str_format(Buf, sizeof(Buf), "%d", (int)m_AverageFPS); diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp index 1c338994..9f787a4b 100644 --- a/src/game/client/components/items.cpp +++ b/src/game/client/components/items.cpp @@ -22,7 +22,6 @@ void CItems::OnReset() void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID) { - // get positions float Curvature = 0; float Speed = 0; @@ -64,7 +63,6 @@ void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID) if(pCurrent->m_Type == WEAPON_GRENADE) { m_pClient->m_pEffects->SmokeTrail(Pos, Vel*-1); - m_pClient->m_pFlow->Add(Pos, Vel*1000*Client()->FrameTime(), 10.0f); if(Client()->State() == IClient::STATE_DEMOPLAYBACK) { @@ -85,7 +83,6 @@ void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID) else { m_pClient->m_pEffects->BulletTrail(Pos); - m_pClient->m_pFlow->Add(Pos, Vel*1000*Client()->FrameTime(), 10.0f); if(length(Vel) > 0.00001f) Graphics()->QuadsSetRotation(GetAngle(Vel)); -- cgit 1.4.1 From d7fe3ddaab7662cd53db7a1e272ad64c2ba861ae Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 1 Jan 2012 14:15:35 +0100 Subject: fixed shutdown and screenshot functionallity --- src/engine/client/graphics_threaded.cpp | 137 +++++++++++++++++++++----------- src/engine/client/graphics_threaded.h | 12 ++- 2 files changed, 98 insertions(+), 51 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 694ecc71..a87e4d62 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -203,6 +203,43 @@ class CCommandProcessorFragment_OpenGL }; } + void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) + { + // fetch image data + GLint aViewport[4] = {0,0,0,0}; + glGetIntegerv(GL_VIEWPORT, aViewport); + + int w = aViewport[2]; + int h = aViewport[3]; + + dbg_msg("graphics", "grabbing %d x %d", w, h); + + // 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 *pTempRow = pPixelData+w*h*3; + + // fetch the pixels + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0,0, 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++) + { + 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); + } + + // fill in the information + pCommand->m_pImage->m_Width = w; + pCommand->m_pImage->m_Height = h; + pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; + pCommand->m_pImage->m_pData = pPixelData; + } + public: CCommandProcessorFragment_OpenGL() { @@ -218,6 +255,7 @@ public: case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_CLEAR: Cmd_Clear(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_RENDER: Cmd_Render(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_SCREENSHOT: Cmd_Screenshot(static_cast(pBaseCommand)); break; default: return false; } @@ -415,6 +453,14 @@ void CCommandProcessorHandler::Start(ICommandProcessor *pProcessor) m_BufferDone.signal(); } +void CCommandProcessorHandler::Stop() +{ + m_Shutdown = true; + m_Activity.signal(); + thread_wait(m_pThread); + thread_destroy(m_pThread); +} + void CCommandProcessorHandler::RunBuffer(CCommandBuffer *pBuffer) { WaitForIdle(); @@ -428,7 +474,7 @@ void CCommandProcessorHandler::WaitForIdle() m_BufferDone.wait(); } -void CGraphics_Threaded::Flush() +void CGraphics_Threaded::FlushVertices() { if(m_NumVertices == 0) return; @@ -464,7 +510,7 @@ void CGraphics_Threaded::AddVertices(int Count) { m_NumVertices += Count; if((m_NumVertices + Count) >= MAX_VERTICES) - Flush(); + FlushVertices(); } void CGraphics_Threaded::Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints) @@ -622,7 +668,7 @@ void CGraphics_Threaded::LinesBegin() void CGraphics_Threaded::LinesEnd() { dbg_assert(m_Drawing == DRAWING_LINES, "called Graphics()->LinesEnd without begin"); - Flush(); + FlushVertices(); m_Drawing = 0; } @@ -828,34 +874,33 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto return 1; } +void CGraphics_Threaded::KickCommandBuffer() +{ + m_Handler.RunBuffer(m_pCommandBuffer); + + // swap buffer + m_CurrentCommandBuffer ^= 1; + m_pCommandBuffer = m_apCommandBuffers[m_CurrentCommandBuffer]; + m_pCommandBuffer->Reset(); +} + void CGraphics_Threaded::ScreenshotDirect(const char *pFilename) { - // TODO: screenshot support - return; + // add swap command + CImageInfo Image; + mem_zero(&Image, sizeof(Image)); - /* - // fetch image data - int y; - int w = m_ScreenWidth; - int h = m_ScreenHeight; - unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1); - unsigned char *pTempRow = pPixelData+w*h*3; - GLint Alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); - glPixelStorei(GL_PACK_ALIGNMENT, Alignment); - - // flip the pixel because opengl works from bottom left corner - for(y = 0; y < h/2; y++) - { - 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); - } + CCommandBuffer::SCommand_Screenshot Cmd; + Cmd.m_pImage = &Image; + m_pCommandBuffer->AddCommand(Cmd); + + // kick the buffer and wait for the result + KickCommandBuffer(); + WaitForIdle(); - // find filename + if(Image.m_pData) { + // find filename char aWholePath[1024]; png_t Png; // ignore_convention @@ -868,13 +913,11 @@ void CGraphics_Threaded::ScreenshotDirect(const char *pFilename) str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); png_open_file_write(&Png, aWholePath); // ignore_convention - png_set_data(&Png, w, h, 8, PNG_TRUECOLOR, (unsigned char *)pPixelData); // ignore_convention + png_set_data(&Png, Image.m_Width, Image.m_Height, 8, PNG_TRUECOLOR, (unsigned char *)Image.m_pData); // ignore_convention png_close_file(&Png); // ignore_convention - } - // clean up - mem_free(pPixelData); - */ + mem_free(Image.m_pData); + } } void CGraphics_Threaded::TextureSet(int TextureID) @@ -906,7 +949,7 @@ void CGraphics_Threaded::QuadsBegin() void CGraphics_Threaded::QuadsEnd() { dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsEnd without begin"); - Flush(); + FlushVertices(); m_Drawing = 0; } @@ -1154,8 +1197,8 @@ bool CGraphics_Threaded::Init() m_aTextures[MAX_TEXTURES-1].m_Next = -1; // start the command processor - ICommandProcessor *pProcessor = new CCommandProcessor_SDL_OpenGL; - m_Handler.Start(pProcessor); + m_pProcessor = new CCommandProcessor_SDL_OpenGL; + m_Handler.Start(m_pProcessor); // create command buffers m_apCommandBuffers[0] = new CCommandBuffer(1024*512, 1024*1024); @@ -1184,9 +1227,16 @@ bool CGraphics_Threaded::Init() void CGraphics_Threaded::Shutdown() { - // TODO: SDL, is this correct? - - // + // add swap command + CCommandBuffer::SCommand_Shutdown Cmd; + m_pCommandBuffer->AddCommand(Cmd); + m_Handler.RunBuffer(m_pCommandBuffer); + + // wait for everything to process and then stop the command processor + m_Handler.WaitForIdle(); + m_Handler.Stop(); + delete m_pProcessor; + m_pProcessor = 0; } void CGraphics_Threaded::Minimize() @@ -1213,34 +1263,27 @@ int CGraphics_Threaded::WindowOpen() void CGraphics_Threaded::TakeScreenshot(const char *pFilename) { // TODO: screenshot support - return; - /* char aDate[20]; str_timestamp(aDate, sizeof(aDate)); str_format(m_aScreenshotName, sizeof(m_aScreenshotName), "screenshots/%s_%s.png", pFilename?pFilename:"screenshot", aDate); m_DoScreenshot = true; - */ } void CGraphics_Threaded::Swap() { // TODO: screenshot support - /* if(m_DoScreenshot) { ScreenshotDirect(m_aScreenshotName); m_DoScreenshot = false; - }*/ + } // add swap command CCommandBuffer::SCommand_Swap Cmd; m_pCommandBuffer->AddCommand(Cmd); - m_Handler.RunBuffer(m_pCommandBuffer); - // swap buffer - m_CurrentCommandBuffer ^= 1; - m_pCommandBuffer = m_apCommandBuffers[m_CurrentCommandBuffer]; - m_pCommandBuffer->Reset(); + // kick the command buffer + KickCommandBuffer(); } // syncronization diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 1ea84ea9..1e69674d 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -124,7 +124,7 @@ public: SPoint m_Pos; STexCoord m_Tex; SColor m_Color; - } ; + }; struct SCommand { @@ -198,8 +198,7 @@ public: struct SCommand_Screenshot : public SCommand { SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {} - - CImageInfo *m_pImage; // processor will fill this out + CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well }; struct SCommand_Swap : public SCommand @@ -307,6 +306,8 @@ class CCommandProcessorHandler public: CCommandProcessorHandler(); void Start(ICommandProcessor *pProcessor); + void Stop(); + void RunBuffer(CCommandBuffer *pBuffer); bool IsIdle() const { return m_pBuffer == 0; } void WaitForIdle(); @@ -316,6 +317,7 @@ class CGraphics_Threaded : public IEngineGraphics { CCommandBuffer::SState m_State; CCommandProcessorHandler m_Handler; + ICommandProcessor *m_pProcessor; CCommandBuffer *m_apCommandBuffers[2]; CCommandBuffer *m_pCommandBuffer; @@ -361,13 +363,15 @@ class CGraphics_Threaded : public IEngineGraphics int m_FirstFreeTexture; int m_TextureMemoryUsage; - void Flush(); + void FlushVertices(); void AddVertices(int Count); void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints); static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); + void KickCommandBuffer(); + int IssueInit(); int InitWindow(); public: -- cgit 1.4.1 From c31c82a5840640b0c7f4b07eb90e681b88b0a330 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 1 Jan 2012 14:30:45 +0100 Subject: added support for video modes --- src/engine/client/graphics_threaded.cpp | 82 +++++++++++++++++++-------------- src/engine/client/graphics_threaded.h | 14 +++++- 2 files changed, 60 insertions(+), 36 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index a87e4d62..947f3960 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -371,6 +371,39 @@ class CCommandProcessorFragment_SDL SDL_GL_SwapBuffers(); } + void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand) + { + // TODO: fix this code on osx or windows + SDL_Rect **ppModes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); + if(ppModes == NULL) + { + // no modes + *pCommand->m_pNumModes = 0; + } + else if(ppModes == (SDL_Rect**)-1) + { + // no modes + *pCommand->m_pNumModes = 0; + } + else + { + int NumModes = 0; + for(int i = 0; ppModes[i]; ++i) + { + if(NumModes == pCommand->m_MaxModes) + break; + pCommand->m_pModes[NumModes].m_Width = ppModes[i]->w; + pCommand->m_pModes[NumModes].m_Height = ppModes[i]->h; + pCommand->m_pModes[NumModes].m_Red = 8; + pCommand->m_pModes[NumModes].m_Green = 8; + pCommand->m_pModes[NumModes].m_Blue = 8; + NumModes++; + } + + *pCommand->m_pNumModes = NumModes; + } + } + public: CCommandProcessorFragment_SDL() { @@ -385,6 +418,7 @@ public: case CCommandBuffer::CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_SHUTDOWN: Cmd_Shutdown(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast(pBaseCommand)); break; default: return false; } @@ -1306,11 +1340,7 @@ void CGraphics_Threaded::WaitForIdle() int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) { - // TODO: fix support for video modes, using fake modes for now - //int NumModes = sizeof(g_aFakeModes)/sizeof(CVideoMode); - //SDL_Rect **ppModes; - - //if(g_Config.m_GfxDisplayAllModes) + if(g_Config.m_GfxDisplayAllModes) { int Count = sizeof(g_aFakeModes)/sizeof(CVideoMode); mem_copy(pModes, g_aFakeModes, sizeof(g_aFakeModes)); @@ -1319,37 +1349,21 @@ int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) return Count; } - // TODO: fix this code on osx or windows - /* + // add videomodes command + CImageInfo Image; + mem_zero(&Image, sizeof(Image)); - ppModes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); - if(ppModes == NULL) - { - // no modes - NumModes = 0; - } - else if(ppModes == (SDL_Rect**)-1) - { - // all modes - } - else - { - NumModes = 0; - for(int i = 0; ppModes[i]; ++i) - { - if(NumModes == MaxModes) - break; - pModes[NumModes].m_Width = ppModes[i]->w; - pModes[NumModes].m_Height = ppModes[i]->h; - pModes[NumModes].m_Red = 8; - pModes[NumModes].m_Green = 8; - pModes[NumModes].m_Blue = 8; - NumModes++; - } - } + int NumModes = 0; + CCommandBuffer::SCommand_VideoModes Cmd; + Cmd.m_pModes = pModes; + Cmd.m_MaxModes = MaxModes; + Cmd.m_pNumModes = &NumModes; + m_pCommandBuffer->AddCommand(Cmd); - return NumModes;*/ + // kick the buffer and wait for the result and return it + KickCommandBuffer(); + WaitForIdle(); + return NumModes; } - extern IEngineGraphics *CreateEngineGraphicsThreaded() { return new CGraphics_Threaded(); } diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 1e69674d..8b1c772d 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -79,8 +79,9 @@ public: // swap CMD_SWAP, - // + // misc CMD_SCREENSHOT, + CMD_VIDEOMODES, }; enum @@ -192,7 +193,7 @@ public: SState m_State; unsigned m_PrimType; unsigned m_PrimCount; - SVertex *m_pVertices; + SVertex *m_pVertices; // you should use the command buffer data to allocate vertices for this command }; struct SCommand_Screenshot : public SCommand @@ -201,6 +202,15 @@ public: 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() : 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 + int *m_pNumModes; // processor will write to this pointer + }; + struct SCommand_Swap : public SCommand { SCommand_Swap() : SCommand(CMD_SWAP) {} -- cgit 1.4.1 From 50d872531aae6640f57da98e8dcf6dbae1f9cd82 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Tue, 3 Jan 2012 21:39:10 +0100 Subject: cleaned up the code. fixed so that SDL is inited on main thread and then transfers the gl context to the render thread --- src/engine/client/backend_sdl.cpp | 495 +++++++++++++++++++++++++++++ src/engine/client/backend_sdl.h | 180 +++++++++++ src/engine/client/client.cpp | 23 +- src/engine/client/graphics.cpp | 12 +- src/engine/client/graphics.h | 4 +- src/engine/client/graphics_threaded.cpp | 539 ++------------------------------ src/engine/client/graphics_threaded.h | 84 ++--- src/engine/client/sound.cpp | 7 + src/engine/graphics.h | 2 +- 9 files changed, 770 insertions(+), 576 deletions(-) create mode 100644 src/engine/client/backend_sdl.cpp create mode 100644 src/engine/client/backend_sdl.h (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp new file mode 100644 index 00000000..691d193c --- /dev/null +++ b/src/engine/client/backend_sdl.cpp @@ -0,0 +1,495 @@ + +#include "SDL.h" +#include "SDL_opengl.h" + +#include "graphics_threaded.h" +#include "backend_sdl.h" + +// ------------ CGraphicsBackend_Threaded + +void CGraphicsBackend_Threaded::ThreadFunc(void *pUser) +{ + CGraphicsBackend_Threaded *pThis = (CGraphicsBackend_Threaded *)pUser; + + while(!pThis->m_Shutdown) + { + pThis->m_Activity.wait(); + if(pThis->m_pBuffer) + { + pThis->m_pProcessor->RunBuffer(pThis->m_pBuffer); + sync_barrier(); + pThis->m_pBuffer = 0x0; + pThis->m_BufferDone.signal(); + } + } +} + +CGraphicsBackend_Threaded::CGraphicsBackend_Threaded() +{ + m_pBuffer = 0x0; + m_pProcessor = 0x0; + m_pThread = 0x0; +} + +void CGraphicsBackend_Threaded::StartProcessor(ICommandProcessor *pProcessor) +{ + m_Shutdown = false; + m_pProcessor = pProcessor; + m_pThread = thread_create(ThreadFunc, this); + m_BufferDone.signal(); +} + +void CGraphicsBackend_Threaded::StopProcessor() +{ + m_Shutdown = true; + m_Activity.signal(); + thread_wait(m_pThread); + thread_destroy(m_pThread); +} + +void CGraphicsBackend_Threaded::RunBuffer(CCommandBuffer *pBuffer) +{ + WaitForIdle(); + m_pBuffer = pBuffer; + m_Activity.signal(); +} + +bool CGraphicsBackend_Threaded::IsIdle() const +{ + return m_pBuffer == 0x0; +} + +void CGraphicsBackend_Threaded::WaitForIdle() +{ + while(m_pBuffer != 0x0) + m_BufferDone.wait(); +} + + +// ------------ CCommandProcessorFragment_General + +void CCommandProcessorFragment_General::Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand) +{ + pCommand->m_pSemaphore->signal(); +} + +bool CCommandProcessorFragment_General::RunCommand(const CCommandBuffer::SCommand * pBaseCommand) +{ + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_NOP: break; + case CCommandBuffer::CMD_SIGNAL: Cmd_Signal(static_cast(pBaseCommand)); break; + default: return false; + } + + return true; +} + +// ------------ CCommandProcessorFragment_OpenGL + +int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat) +{ + if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) return GL_RGB; + if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) return GL_ALPHA; + if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) return GL_RGBA; + return GL_RGBA; +} + +void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State) +{ + // blend + switch(State.m_BlendMode) + { + case CCommandBuffer::BLEND_NONE: + glDisable(GL_BLEND); + break; + case CCommandBuffer::BLEND_ALPHA: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case CCommandBuffer::BLEND_ADDITIVE: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + default: + dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); + }; + + // clip + if(State.m_ClipEnable) + { + glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); + glEnable(GL_SCISSOR_TEST); + } + else + glDisable(GL_SCISSOR_TEST); + + // texture + if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture]); + } + else + glDisable(GL_TEXTURE_2D); + + // screen mapping + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) +{ + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, + TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData); + mem_free(pCommand->m_pData); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) +{ + glDeleteTextures(1, &m_aTextures[pCommand->m_Slot]); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) +{ + int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); + int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); + + glGenTextures(1, &m_aTextures[pCommand->m_Slot]); + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + + if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, pCommand->m_Width, pCommand->m_Height, 0, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + } + + mem_free(pCommand->m_pData); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) +{ + glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) +{ + SetState(pCommand->m_State); + + glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); + glTexCoordPointer(2, 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)*5); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + switch(pCommand->m_PrimType) + { + case CCommandBuffer::PRIMTYPE_QUADS: + glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4); + break; + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd); + }; +} + +void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) +{ + // fetch image data + GLint aViewport[4] = {0,0,0,0}; + glGetIntegerv(GL_VIEWPORT, aViewport); + + int w = aViewport[2]; + int h = aViewport[3]; + + // 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 *pTempRow = pPixelData+w*h*3; + + // fetch the pixels + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0,0, 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++) + { + 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); + } + + // fill in the information + pCommand->m_pImage->m_Width = w; + pCommand->m_pImage->m_Height = h; + pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; + pCommand->m_pImage->m_pData = pPixelData; +} + +CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL() +{ + mem_zero(m_aTextures, sizeof(m_aTextures)); +} + +bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand * pBaseCommand) +{ + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_TEXTURE_CREATE: Cmd_Texture_Create(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_TEXTURE_DESTROY: Cmd_Texture_Destroy(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_CLEAR: Cmd_Clear(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER: Cmd_Render(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_SCREENSHOT: Cmd_Screenshot(static_cast(pBaseCommand)); break; + default: return false; + } + + return true; +} + + +// ------------ CCommandProcessorFragment_SDL + +void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) +{ + m_GLContext = pCommand->m_Context; + GL_MakeCurrent(m_GLContext); + + // set some default settings + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glAlphaFunc(GL_GREATER, 0); + glEnable(GL_ALPHA_TEST); + glDepthMask(0); +} + +void CCommandProcessorFragment_SDL::Cmd_Shutdown(const SCommand_Shutdown *pCommand) +{ + GL_ReleaseContext(m_GLContext); +} + +void CCommandProcessorFragment_SDL::Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand) +{ + GL_SwapBuffers(m_GLContext); +} + +void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand) +{ + // TODO: fix this code on osx or windows + SDL_Rect **ppModes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); + if(ppModes == NULL) + { + // no modes + *pCommand->m_pNumModes = 0; + } + else if(ppModes == (SDL_Rect**)-1) + { + // no modes + *pCommand->m_pNumModes = 0; + } + else + { + int NumModes = 0; + for(int i = 0; ppModes[i]; ++i) + { + if(NumModes == pCommand->m_MaxModes) + break; + pCommand->m_pModes[NumModes].m_Width = ppModes[i]->w; + pCommand->m_pModes[NumModes].m_Height = ppModes[i]->h; + pCommand->m_pModes[NumModes].m_Red = 8; + pCommand->m_pModes[NumModes].m_Green = 8; + pCommand->m_pModes[NumModes].m_Blue = 8; + NumModes++; + } + + *pCommand->m_pNumModes = NumModes; + } +} + +CCommandProcessorFragment_SDL::CCommandProcessorFragment_SDL() +{ +} + +bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand) +{ + switch(pBaseCommand->m_Cmd) + { + case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast(pBaseCommand)); break; + case CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; + case CMD_SHUTDOWN: Cmd_Shutdown(static_cast(pBaseCommand)); break; + default: return false; + } + + return true; +} + +// ------------ CCommandProcessor_SDL_OpenGL + +void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer) +{ + unsigned CmdIndex = 0; + while(1) + { + const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex); + if(pBaseCommand == 0x0) + break; + + if(m_OpenGL.RunCommand(pBaseCommand)) + continue; + + if(m_SDL.RunCommand(pBaseCommand)) + continue; + + if(m_General.RunCommand(pBaseCommand)) + continue; + + dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd); + } +} + +// ------------ CGraphicsBackend_SDL_OpenGL + +int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) +{ + if(!SDL_WasInit(SDL_INIT_VIDEO)) + { + if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) + { + 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=8,27"); // ignore_convention + #endif + } + + const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); + + // set flags + int SdlFlags = SDL_OPENGL; + if(Flags&IGraphicsBackend::INITFLAG_RESIZABLE) + SdlFlags |= SDL_RESIZABLE; + + if(pInfo->hw_available) // ignore_convention + SdlFlags |= SDL_HWSURFACE; + else + SdlFlags |= SDL_SWSURFACE; + + if(pInfo->blit_hw) // ignore_convention + SdlFlags |= SDL_HWACCEL; + + if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) + SdlFlags |= SDL_FULLSCREEN; + + // set gl attributes + if(FsaaSamples) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FsaaSamples); + } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); + + // set caption + SDL_WM_SetCaption(pName, pName); + + // create window + m_pScreenSurface = SDL_SetVideoMode(Width, Height, 0, SdlFlags); + if(!m_pScreenSurface) + { + dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); + //*pCommand->m_pResult = -1; + return -1; + } + + SDL_ShowCursor(0); + + // fetch gl contexts and release the context from this thread + m_GLContext = GL_GetCurrentContext(); + GL_ReleaseContext(m_GLContext); + + // start the command processor + m_pProcessor = new CCommandProcessor_SDL_OpenGL; + StartProcessor(m_pProcessor); + + // issue a init command + CCommandBuffer CmdBuffer(1024, 512); + CCommandProcessorFragment_SDL::SCommand_Init Cmd; + Cmd.m_Context = m_GLContext; + CmdBuffer.AddCommand(Cmd); + RunBuffer(&CmdBuffer); + WaitForIdle(); + + // return + return 0; +} + +int CGraphicsBackend_SDL_OpenGL::Shutdown() +{ + // issue a shutdown command + CCommandBuffer CmdBuffer(1024, 512); + CCommandProcessorFragment_SDL::SCommand_Shutdown Cmd; + CmdBuffer.AddCommand(Cmd); + RunBuffer(&CmdBuffer); + WaitForIdle(); + + // stop and delete the processor + StopProcessor(); + delete m_pProcessor; + m_pProcessor = 0; + + SDL_QuitSubSystem(SDL_INIT_VIDEO); + return 0; +} + +void CGraphicsBackend_SDL_OpenGL::Minimize() +{ + SDL_WM_IconifyWindow(); +} + +void CGraphicsBackend_SDL_OpenGL::Maximize() +{ + // TODO: SDL +} + +int CGraphicsBackend_SDL_OpenGL::WindowActive() +{ + return SDL_GetAppState()&SDL_APPINPUTFOCUS; +} + +int CGraphicsBackend_SDL_OpenGL::WindowOpen() +{ + return SDL_GetAppState()&SDL_APPACTIVE; + +} + + +IGraphicsBackend *CreateGraphicsBackend() { return new CGraphicsBackend_SDL_OpenGL; } diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h new file mode 100644 index 00000000..de0c6bd4 --- /dev/null +++ b/src/engine/client/backend_sdl.h @@ -0,0 +1,180 @@ + +#include "SDL.h" +#include "SDL_opengl.h" + +#include "graphics_threaded.h" + + + +// platform dependent implementations for transfering render context from the main thread to the graphics thread +// TODO: when SDL 1.3 comes, this can be removed +#if defined(CONF_FAMILY_WINDOWS) + struct SGLContext + { + HDC m_hDC; + HGLRC m_hGLRC; + }; + + static SGLContext GL_GetCurrentContext() + { + SGLContext Context; + Context.m_hDC = wglGetCurrentDC(); + Context.m_hGLRC = wglGetCurrentContext(); + return Context; + } + + static void GL_MakeCurrent(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, Context.m_hGLRC); } + static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, NULL); } + static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } +#elif defined(CONF_PLATFORM_MACOSX) + #error missing implementation +#elif defined(CONF_FAMILY_UNIX) + + #include + + struct SGLContext + { + Display *m_pDisplay; + GLXDrawable m_Drawable; + GLXContext m_Context; + }; + + static SGLContext GL_GetCurrentContext() + { + SGLContext Context; + Context.m_pDisplay = glXGetCurrentDisplay(); + Context.m_Drawable = glXGetCurrentDrawable(); + Context.m_Context = glXGetCurrentContext(); + return Context; + } + + static void GL_MakeCurrent(const SGLContext &Context) { glXMakeCurrent(Context.m_pDisplay, Context.m_Drawable, Context.m_Context); } + static void GL_ReleaseContext(const SGLContext &Context) { glXMakeCurrent(Context.m_pDisplay, None, 0x0); } + static void GL_SwapBuffers(const SGLContext &Context) { glXSwapBuffers(Context.m_pDisplay, Context.m_Drawable); } +#else + #error missing implementation +#endif + + +// basic threaded backend, abstract, missing init and shutdown functions +class CGraphicsBackend_Threaded : public IGraphicsBackend +{ +public: + // constructed on the main thread, the rest of the functions is runned on the render thread + class ICommandProcessor + { + public: + virtual ~ICommandProcessor() {} + virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; + }; + + CGraphicsBackend_Threaded(); + + virtual void RunBuffer(CCommandBuffer *pBuffer); + virtual bool IsIdle() const; + virtual void WaitForIdle(); + +protected: + void StartProcessor(ICommandProcessor *pProcessor); + void StopProcessor(); + +private: + ICommandProcessor *m_pProcessor; + CCommandBuffer * volatile m_pBuffer; + volatile bool m_Shutdown; + semaphore m_Activity; + semaphore m_BufferDone; + void *m_pThread; + + static void ThreadFunc(void *pUser); +}; + +// takes care of implementation independent operations +class CCommandProcessorFragment_General +{ + void Cmd_Nop(); + void Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand); +public: + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand); +}; + +// takes care of opengl related rendering +class CCommandProcessorFragment_OpenGL +{ + GLuint m_aTextures[CCommandBuffer::MAX_TEXTURES]; + static int TexFormatToOpenGLFormat(int TexFormat); + + void SetState(const CCommandBuffer::SState &State); + + void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand); + void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand); + void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand); + void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand); + void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand); + void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand); + +public: + CCommandProcessorFragment_OpenGL(); + + bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand); +}; + +// takes care of sdl related commands +class CCommandProcessorFragment_SDL +{ + // SDL stuff + SGLContext m_GLContext; +public: + enum + { + CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM, + CMD_SHUTDOWN, + }; + + struct SCommand_Init : public CCommandBuffer::SCommand + { + SCommand_Init() : SCommand(CMD_INIT) {} + SGLContext m_Context; + }; + + struct SCommand_Shutdown : public CCommandBuffer::SCommand + { + SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {} + }; + +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_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand); +public: + CCommandProcessorFragment_SDL(); + + bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); +}; + +// command processor impelementation, uses the fragments to combine into one processor +class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandProcessor +{ + CCommandProcessorFragment_OpenGL m_OpenGL; + CCommandProcessorFragment_SDL m_SDL; + CCommandProcessorFragment_General m_General; + public: + virtual void RunBuffer(CCommandBuffer *pBuffer); +}; + +// graphics backend implemented with SDL and OpenGL +class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded +{ + SDL_Surface *m_pScreenSurface; + ICommandProcessor *m_pProcessor; + SGLContext m_GLContext; +public: + virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags); + virtual int Shutdown(); + + virtual void Minimize(); + virtual void Maximize(); + virtual int WindowActive(); + virtual int WindowOpen(); +}; diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index b7244db4..5067f8b2 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1690,11 +1690,24 @@ void CClient::InitInterfaces() m_Friends.Init(); } +#include "SDL.h" + void CClient::Run() { m_LocalStartTime = time_get(); m_SnapshotParts = 0; + // init SDL + { + if(SDL_Init(0) < 0) + { + dbg_msg("client", "unable to init SDL base: %s", SDL_GetError()); + return; + } + + atexit(SDL_Quit); // ignore_convention + } + // init graphics { if(g_Config.m_GfxThreaded) @@ -1713,6 +1726,9 @@ void CClient::Run() } } + // init sound, allowed to fail + m_SoundInitFailed = Sound()->Init() != 0; + // open socket { NETADDR BindAddr; @@ -1737,8 +1753,6 @@ void CClient::Run() // init the editor //m_pEditor->Init(); - // init sound, allowed to fail - m_SoundInitFailed = Sound()->Init() != 0; // load data if(!LoadData()) @@ -1937,6 +1951,11 @@ void CClient::Run() m_pGraphics->Shutdown(); m_pSound->Shutdown(); + + // shutdown SDL + { + SDL_Quit(); + } } diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index d16f10fc..ad3926f2 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -707,7 +707,7 @@ void CGraphics_OpenGL::QuadsText(float x, float y, float Size, float r, float g, QuadsEnd(); } -bool CGraphics_OpenGL::Init() +int CGraphics_OpenGL::Init() { m_pStorage = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); @@ -743,7 +743,7 @@ bool CGraphics_OpenGL::Init() m_InvalidTexture = LoadTextureRaw(4,4,CImageInfo::FORMAT_RGBA,aNullTextureData,CImageInfo::FORMAT_RGBA,TEXLOAD_NORESAMPLE); - return true; + return 0; } int CGraphics_SDL::TryInit() @@ -841,7 +841,7 @@ CGraphics_SDL::CGraphics_SDL() m_pScreenSurface = 0; } -bool CGraphics_SDL::Init() +int CGraphics_SDL::Init() { { int Systems = SDL_INIT_VIDEO; @@ -855,7 +855,7 @@ bool CGraphics_SDL::Init() if(SDL_Init(Systems) < 0) { dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); - return true; + return -1; } } @@ -867,14 +867,14 @@ bool CGraphics_SDL::Init() #endif if(InitWindow() != 0) - return true; + return -1; SDL_ShowCursor(0); CGraphics_OpenGL::Init(); MapScreen(0,0,g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight); - return false; + return 0; } void CGraphics_SDL::Shutdown() diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index 37276d36..3ab550dc 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -118,7 +118,7 @@ public: virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); - virtual bool Init(); + virtual int Init(); }; class CGraphics_SDL : public CGraphics_OpenGL @@ -130,7 +130,7 @@ class CGraphics_SDL : public CGraphics_OpenGL public: CGraphics_SDL(); - virtual bool Init(); + virtual int Init(); virtual void Shutdown(); virtual void Minimize(); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 947f3960..d1d09d38 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -4,9 +4,6 @@ #include #include -#include "SDL.h" -#include "SDL_opengl.h" - #include #include @@ -20,7 +17,6 @@ #include "graphics_threaded.h" - static CVideoMode g_aFakeModes[] = { {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8}, @@ -45,469 +41,6 @@ static CVideoMode g_aFakeModes[] = { {2048,1536,5,6,5} }; -class CCommandProcessorFragment_General -{ -public: - void Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand) - { - pCommand->m_pSemaphore->signal(); - } - - bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) - { - switch(pBaseCommand->m_Cmd) - { - case CCommandBuffer::CMD_NOP: break; - case CCommandBuffer::CMD_SIGNAL: Cmd_Signal(static_cast(pBaseCommand)); break; - default: return false; - } - - return true; - } -}; - -class CCommandProcessorFragment_OpenGL -{ - GLuint m_aTextures[CCommandBuffer::MAX_TEXTURES]; - - void SetState(const CCommandBuffer::SState &State) - { - // blend - switch(State.m_BlendMode) - { - case CCommandBuffer::BLEND_NONE: - glDisable(GL_BLEND); - break; - case CCommandBuffer::BLEND_ALPHA: - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case CCommandBuffer::BLEND_ADDITIVE: - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - default: - dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); - }; - - // clip - if(State.m_ClipEnable) - { - glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); - glEnable(GL_SCISSOR_TEST); - } - else - glDisable(GL_SCISSOR_TEST); - - // texture - if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture]); - } - else - glDisable(GL_TEXTURE_2D); - - // screen mapping - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); - } - - static int TexFormatToOpenGLFormat(int TexFormat) - { - if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) return GL_RGB; - if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) return GL_ALPHA; - if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) return GL_RGBA; - return GL_RGBA; - } - - void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) - { - glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); - glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, - TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData); - mem_free(pCommand->m_pData); - } - - void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) - { - glDeleteTextures(1, &m_aTextures[pCommand->m_Slot]); - } - - void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) - { - int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); - - // upload texture - int StoreOglformat = Oglformat; - if(g_Config.m_GfxTextureCompression) - { - StoreOglformat = GL_COMPRESSED_RGBA_ARB; - if(pCommand->m_StoreFormat == CCommandBuffer::TEXFORMAT_RGB) - StoreOglformat = GL_COMPRESSED_RGB_ARB; - else if(Oglformat == CCommandBuffer::TEXFORMAT_ALPHA) - StoreOglformat = GL_COMPRESSED_ALPHA_ARB; - } - else - { - StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); - } - - glGenTextures(1, &m_aTextures[pCommand->m_Slot]); - glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); - - if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, pCommand->m_Width, pCommand->m_Height, 0, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); - } - else - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); - } - - mem_free(pCommand->m_pData); - } - - void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) - { - glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) - { - SetState(pCommand->m_State); - - glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices); - glTexCoordPointer(2, 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)*5); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - switch(pCommand->m_PrimType) - { - case CCommandBuffer::PRIMTYPE_QUADS: - glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4); - break; - case CCommandBuffer::PRIMTYPE_LINES: - glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd); - }; - } - - void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) - { - // fetch image data - GLint aViewport[4] = {0,0,0,0}; - glGetIntegerv(GL_VIEWPORT, aViewport); - - int w = aViewport[2]; - int h = aViewport[3]; - - dbg_msg("graphics", "grabbing %d x %d", w, h); - - // 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 *pTempRow = pPixelData+w*h*3; - - // fetch the pixels - GLint Alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0,0, 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++) - { - 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); - } - - // fill in the information - pCommand->m_pImage->m_Width = w; - pCommand->m_pImage->m_Height = h; - pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; - pCommand->m_pImage->m_pData = pPixelData; - } - -public: - CCommandProcessorFragment_OpenGL() - { - mem_zero(m_aTextures, sizeof(m_aTextures)); - } - - bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand) - { - switch(pBaseCommand->m_Cmd) - { - case CCommandBuffer::CMD_TEXTURE_CREATE: Cmd_Texture_Create(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_TEXTURE_DESTROY: Cmd_Texture_Destroy(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_CLEAR: Cmd_Clear(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER: Cmd_Render(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_SCREENSHOT: Cmd_Screenshot(static_cast(pBaseCommand)); break; - default: return false; - } - - return true; - } -}; - -class CCommandProcessorFragment_SDL -{ - // SDL stuff - SDL_Surface *m_pScreenSurface; - bool m_SystemInited; - - void Cmd_Init(const CCommandBuffer::SCommand_Init *pCommand) - { - if(!m_SystemInited) - { - int Systems = SDL_INIT_VIDEO; - - if(g_Config.m_SndEnable) // TODO: remove - Systems |= SDL_INIT_AUDIO; - - if(g_Config.m_ClEventthread) // TODO: remove - Systems |= SDL_INIT_EVENTTHREAD; - - if(SDL_Init(Systems) < 0) - { - dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError()); - *pCommand->m_pResult = -1; - return; - } - - atexit(SDL_Quit); // ignore_convention - - #ifdef CONF_FAMILY_WINDOWS - if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention - putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention - #endif - - m_SystemInited = true; - } - - const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - - // set flags - int Flags = SDL_OPENGL; - if(pCommand->m_Flags&CCommandBuffer::INITFLAG_RESIZABLE) - Flags |= SDL_RESIZABLE; - - if(pInfo->hw_available) // ignore_convention - Flags |= SDL_HWSURFACE; - else - Flags |= SDL_SWSURFACE; - - if(pInfo->blit_hw) // ignore_convention - Flags |= SDL_HWACCEL; - - if(pCommand->m_Flags&CCommandBuffer::INITFLAG_FULLSCREEN) - Flags |= SDL_FULLSCREEN; - - // set gl attributes - if(pCommand->m_FsaaSamples) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, pCommand->m_FsaaSamples); - } - else - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); - } - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, pCommand->m_Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); - - // set caption - SDL_WM_SetCaption(pCommand->m_aName, pCommand->m_aName); - - // create window - m_pScreenSurface = SDL_SetVideoMode(pCommand->m_ScreenWidth, pCommand->m_ScreenHeight, 0, Flags); - if(m_pScreenSurface) - { - SDL_ShowCursor(0); - - // set some default settings - glEnable(GL_BLEND); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glAlphaFunc(GL_GREATER, 0); - glEnable(GL_ALPHA_TEST); - glDepthMask(0); - - *pCommand->m_pResult = 0; - } - else - { - dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); - *pCommand->m_pResult = -1; - } - } - - void Cmd_Shutdown(const CCommandBuffer::SCommand_Shutdown *pCommand) - { - SDL_Quit(); - } - - void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand) - { - SDL_GL_SwapBuffers(); - } - - void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand) - { - // TODO: fix this code on osx or windows - SDL_Rect **ppModes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN); - if(ppModes == NULL) - { - // no modes - *pCommand->m_pNumModes = 0; - } - else if(ppModes == (SDL_Rect**)-1) - { - // no modes - *pCommand->m_pNumModes = 0; - } - else - { - int NumModes = 0; - for(int i = 0; ppModes[i]; ++i) - { - if(NumModes == pCommand->m_MaxModes) - break; - pCommand->m_pModes[NumModes].m_Width = ppModes[i]->w; - pCommand->m_pModes[NumModes].m_Height = ppModes[i]->h; - pCommand->m_pModes[NumModes].m_Red = 8; - pCommand->m_pModes[NumModes].m_Green = 8; - pCommand->m_pModes[NumModes].m_Blue = 8; - NumModes++; - } - - *pCommand->m_pNumModes = NumModes; - } - } - -public: - CCommandProcessorFragment_SDL() - { - m_SystemInited = false; - m_pScreenSurface = 0x0; - } - - bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) - { - switch(pBaseCommand->m_Cmd) - { - case CCommandBuffer::CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_SHUTDOWN: Cmd_Shutdown(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast(pBaseCommand)); break; - default: return false; - } - - return true; - } -}; - -class CCommandProcessor_SDL_OpenGL : public ICommandProcessor -{ - CCommandProcessorFragment_OpenGL m_OpenGL; - CCommandProcessorFragment_SDL m_SDL; - CCommandProcessorFragment_General m_General; - public: - virtual void RunBuffer(CCommandBuffer *pBuffer) - { - unsigned CmdIndex = 0; - while(1) - { - const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex); - if(pBaseCommand == 0x0) - break; - - if(m_OpenGL.RunCommand(pBaseCommand)) - continue; - - if(m_SDL.RunCommand(pBaseCommand)) - continue; - - if(m_General.RunCommand(pBaseCommand)) - continue; - - dbg_msg("graphics", "unknown command %d", pBaseCommand->m_Cmd); - } - } -}; - -void CCommandProcessorHandler::ThreadFunc(void *pUser) -{ - CCommandProcessorHandler *pThis = (CCommandProcessorHandler *)pUser; - - while(!pThis->m_Shutdown) - { - pThis->m_Activity.wait(); - if(pThis->m_pBuffer) - { - pThis->m_pProcessor->RunBuffer(pThis->m_pBuffer); - sync_barrier(); - pThis->m_pBuffer = 0x0; - pThis->m_BufferDone.signal(); - } - } -} - -CCommandProcessorHandler::CCommandProcessorHandler() -{ - m_pBuffer = 0x0; - m_pProcessor = 0x0; - m_pThread = 0x0; -} - -void CCommandProcessorHandler::Start(ICommandProcessor *pProcessor) -{ - m_Shutdown = false; - m_pProcessor = pProcessor; - m_pThread = thread_create(ThreadFunc, this); - m_BufferDone.signal(); -} - -void CCommandProcessorHandler::Stop() -{ - m_Shutdown = true; - m_Activity.signal(); - thread_wait(m_pThread); - thread_destroy(m_pThread); -} - -void CCommandProcessorHandler::RunBuffer(CCommandBuffer *pBuffer) -{ - WaitForIdle(); - m_pBuffer = pBuffer; - m_Activity.signal(); -} - -void CCommandProcessorHandler::WaitForIdle() -{ - while(m_pBuffer != 0x0) - m_BufferDone.wait(); -} - void CGraphics_Threaded::FlushVertices() { if(m_NumVertices == 0) @@ -910,7 +443,7 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto void CGraphics_Threaded::KickCommandBuffer() { - m_Handler.RunBuffer(m_pCommandBuffer); + m_pBackend->RunBuffer(m_pCommandBuffer); // swap buffer m_CurrentCommandBuffer ^= 1; @@ -1156,27 +689,12 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, float r, float int CGraphics_Threaded::IssueInit() { - // issue init command - m_pCommandBuffer->Reset(); - - volatile int Result; - CCommandBuffer::SCommand_Init Cmd; - str_copy(Cmd.m_aName, "Teeworlds", sizeof(Cmd.m_aName)); - Cmd.m_pResult = &Result; - Cmd.m_ScreenWidth = g_Config.m_GfxScreenWidth; - Cmd.m_ScreenHeight = g_Config.m_GfxScreenHeight; - Cmd.m_FsaaSamples = g_Config.m_GfxFsaaSamples; - - Cmd.m_Flags = 0; - if(g_Config.m_GfxFullscreen) Cmd.m_Flags |= CCommandBuffer::INITFLAG_FULLSCREEN; - if(g_Config.m_GfxVsync) Cmd.m_Flags |= CCommandBuffer::INITFLAG_VSYNC; - if(g_Config.m_DbgResizable) Cmd.m_Flags |= CCommandBuffer::INITFLAG_RESIZABLE; - - m_pCommandBuffer->AddCommand(Cmd); + int Flags = 0; + 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; - m_Handler.RunBuffer(m_pCommandBuffer); - m_Handler.WaitForIdle(); - return Result; + return m_pBackend->Init("Teeworlds", g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags); } int CGraphics_Threaded::InitWindow() @@ -1214,7 +732,7 @@ int CGraphics_Threaded::InitWindow() return -1; } -bool CGraphics_Threaded::Init() +int CGraphics_Threaded::Init() { // fetch pointers m_pStorage = Kernel()->RequestInterface(); @@ -1230,23 +748,19 @@ bool CGraphics_Threaded::Init() m_aTextures[i].m_Next = i+1; m_aTextures[MAX_TEXTURES-1].m_Next = -1; - // start the command processor - m_pProcessor = new CCommandProcessor_SDL_OpenGL; - m_Handler.Start(m_pProcessor); + m_pBackend = CreateGraphicsBackend(); + if(InitWindow() != 0) + return -1; + + // fetch final resolusion + m_ScreenWidth = g_Config.m_GfxScreenWidth; + m_ScreenHeight = g_Config.m_GfxScreenHeight; // create command buffers m_apCommandBuffers[0] = new CCommandBuffer(1024*512, 1024*1024); m_apCommandBuffers[1] = new CCommandBuffer(1024*512, 1024*1024); m_pCommandBuffer = m_apCommandBuffers[0]; - // try to init the window - if(InitWindow() != 0) - return 0; - - // fetch final resolusion - m_ScreenWidth = g_Config.m_GfxScreenWidth; - m_ScreenHeight = g_Config.m_GfxScreenHeight; - // create null texture, will get id=0 static const unsigned char aNullTextureData[] = { 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, @@ -1261,36 +775,31 @@ bool CGraphics_Threaded::Init() void CGraphics_Threaded::Shutdown() { - // add swap command - CCommandBuffer::SCommand_Shutdown Cmd; - m_pCommandBuffer->AddCommand(Cmd); - m_Handler.RunBuffer(m_pCommandBuffer); - - // wait for everything to process and then stop the command processor - m_Handler.WaitForIdle(); - m_Handler.Stop(); - delete m_pProcessor; - m_pProcessor = 0; + // shutdown the backend + m_pBackend->Shutdown(); + delete m_pBackend; + m_pBackend = 0x0; } void CGraphics_Threaded::Minimize() { - SDL_WM_IconifyWindow(); + m_pBackend->Minimize(); } void CGraphics_Threaded::Maximize() { // TODO: SDL + m_pBackend->Maximize(); } int CGraphics_Threaded::WindowActive() { - return SDL_GetAppState()&SDL_APPINPUTFOCUS; + return m_pBackend->WindowActive(); } int CGraphics_Threaded::WindowOpen() { - return SDL_GetAppState()&SDL_APPACTIVE; + return m_pBackend->WindowOpen(); } @@ -1330,12 +839,12 @@ void CGraphics_Threaded::InsertSignal(semaphore *pSemaphore) bool CGraphics_Threaded::IsIdle() { - return m_Handler.IsIdle(); + return m_pBackend->IsIdle(); } void CGraphics_Threaded::WaitForIdle() { - m_Handler.WaitForIdle(); + m_pBackend->WaitForIdle(); } int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes) diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 8b1c772d..9f5f442d 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -2,6 +2,8 @@ #include +#include + class CCommandBuffer { class CBuffer @@ -54,12 +56,12 @@ public: enum { - // - CMD_NOP = 0, + // commadn groups + CMDGROUP_CORE = 0, // commands that everyone has to implement + CMDGROUP_PLATFORM = 10000, // commands specific to a platform // - CMD_INIT, - CMD_SHUTDOWN, + CMD_NOP = CMDGROUP_CORE, // CMD_RUNBUFFER, @@ -82,6 +84,7 @@ public: // misc CMD_SCREENSHOT, CMD_VIDEOMODES, + }; enum @@ -155,25 +158,6 @@ public: SCommand_Clear() : SCommand(CMD_CLEAR) {} SColor m_Color; }; - - struct SCommand_Init : public SCommand - { - SCommand_Init() : SCommand(CMD_INIT) {} - - char m_aName[256]; - - int m_ScreenWidth; - int m_ScreenHeight; - int m_FsaaSamples; - int m_Flags; - - volatile int *m_pResult; - }; - - struct SCommand_Shutdown : public SCommand - { - SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {} - }; struct SCommand_Signal : public SCommand { @@ -269,10 +253,13 @@ public: template void AddCommand(const T &Command) { + // make sure that we don't do something stupid like ->AddCommand(&Cmd); + (void)static_cast(&Command); + + // allocate and copy the command into the buffer SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command)); if(!pCmd) return; - mem_copy(pCmd, &Command, sizeof(Command)); pCmd->m_Size = sizeof(Command); } @@ -294,40 +281,35 @@ public: } }; -class ICommandProcessor +// interface for the graphics backend +// all these functions are called on the main thread +class IGraphicsBackend { public: - virtual ~ICommandProcessor() {} - virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; -}; - - -class CCommandProcessorHandler -{ - ICommandProcessor *m_pProcessor; - CCommandBuffer * volatile m_pBuffer; - volatile bool m_Shutdown; - semaphore m_Activity; - semaphore m_BufferDone; - void *m_pThread; + enum + { + INITFLAG_FULLSCREEN = 1, + INITFLAG_VSYNC = 2, + INITFLAG_RESIZABLE = 4, + }; - static void ThreadFunc(void *pUser); + virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) = 0; + virtual int Shutdown() = 0; -public: - CCommandProcessorHandler(); - void Start(ICommandProcessor *pProcessor); - void Stop(); + virtual void Minimize() = 0; + virtual void Maximize() = 0; + virtual int WindowActive() = 0; + virtual int WindowOpen() = 0; - void RunBuffer(CCommandBuffer *pBuffer); - bool IsIdle() const { return m_pBuffer == 0; } - void WaitForIdle(); + virtual void RunBuffer(CCommandBuffer *pBuffer) = 0; + virtual bool IsIdle() const = 0; + virtual void WaitForIdle() = 0; }; class CGraphics_Threaded : public IEngineGraphics { CCommandBuffer::SState m_State; - CCommandProcessorHandler m_Handler; - ICommandProcessor *m_pProcessor; + IGraphicsBackend *m_pBackend; CCommandBuffer *m_apCommandBuffers[2]; CCommandBuffer *m_pCommandBuffer; @@ -440,7 +422,7 @@ public: virtual int WindowActive(); virtual int WindowOpen(); - virtual bool Init(); + virtual int Init(); virtual void Shutdown(); virtual void TakeScreenshot(const char *pFilename); @@ -452,4 +434,6 @@ public: virtual void InsertSignal(semaphore *pSemaphore); virtual bool IsIdle(); virtual void WaitForIdle(); -}; \ No newline at end of file +}; + +extern IGraphicsBackend *CreateGraphicsBackend(); diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index 45404d18..3f3d1a5d 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -209,6 +209,12 @@ int CSound::Init() if(!g_Config.m_SndEnable) return 0; + if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + dbg_msg("gfx", "unable to init SDL audio: %s", SDL_GetError()); + return -1; + } + m_MixingRate = g_Config.m_SndRate; // Set 16-bit stereo audio at 22Khz @@ -256,6 +262,7 @@ int CSound::Update() int CSound::Shutdown() { SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); lock_destroy(m_SoundLock); return 0; } diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 94d9c1a2..6d31060e 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -146,7 +146,7 @@ class IEngineGraphics : public IGraphics { MACRO_INTERFACE("enginegraphics", 0) public: - virtual bool Init() = 0; + virtual int Init() = 0; virtual void Shutdown() = 0; virtual void Minimize() = 0; -- cgit 1.4.1 From 2991f4071e50cca641044376dc2196d9dcfff80d Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Tue, 3 Jan 2012 22:01:37 +0100 Subject: fixed kicking of command buffer if it's full when rendering. fixed compile error on windows --- src/engine/client/client.cpp | 6 ++++-- src/engine/client/graphics_threaded.cpp | 20 +++++++++++++++++--- src/engine/client/graphics_threaded.h | 32 ++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 5067f8b2..f126a09c 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -49,6 +49,10 @@ #include #endif +#include "SDL.h" +#ifdef main +#undef main +#endif void CGraph::Init(float Min, float Max) { @@ -1690,8 +1694,6 @@ void CClient::InitInterfaces() m_Friends.Init(); } -#include "SDL.h" - void CClient::Run() { m_LocalStartTime = time_get(); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index d1d09d38..33670f7b 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -67,7 +67,17 @@ void CGraphics_Threaded::FlushVertices() Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts); if(Cmd.m_pVertices == 0x0) - return; + { + // kick command buffer and try again + KickCommandBuffer(); + + Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts); + if(Cmd.m_pVertices == 0x0) + { + dbg_msg("graphics", "failed to allocate data for vertices"); + return; + } + } mem_copy(Cmd.m_pVertices, m_aVertices, sizeof(CCommandBuffer::SVertex)*NumVerts); m_pCommandBuffer->AddCommand(Cmd); @@ -757,8 +767,8 @@ int CGraphics_Threaded::Init() m_ScreenHeight = g_Config.m_GfxScreenHeight; // create command buffers - m_apCommandBuffers[0] = new CCommandBuffer(1024*512, 1024*1024); - m_apCommandBuffers[1] = new CCommandBuffer(1024*512, 1024*1024); + for(int i = 0; i < NUM_CMDBUFFERS; i++) + m_apCommandBuffers[i] = new CCommandBuffer(128*1024, 2*1024*1024); m_pCommandBuffer = m_apCommandBuffers[0]; // create null texture, will get id=0 @@ -779,6 +789,10 @@ void CGraphics_Threaded::Shutdown() m_pBackend->Shutdown(); delete m_pBackend; m_pBackend = 0x0; + + // delete the command buffers + for(int i = 0; i < NUM_CMDBUFFERS; i++) + delete m_apCommandBuffers[i]; } void CGraphics_Threaded::Minimize() diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 9f5f442d..51148f0f 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -46,9 +46,10 @@ class CCommandBuffer unsigned DataUsed() { return m_Used; } }; +public: CBuffer m_CmdBuffer; CBuffer m_DataBuffer; -public: + enum { MAX_TEXTURES=1024*4, @@ -251,7 +252,7 @@ public: } template - void AddCommand(const T &Command) + bool AddCommand(const T &Command) { // make sure that we don't do something stupid like ->AddCommand(&Cmd); (void)static_cast(&Command); @@ -259,9 +260,10 @@ public: // allocate and copy the command into the buffer SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command)); if(!pCmd) - return; + return false; mem_copy(pCmd, &Command, sizeof(Command)); pCmd->m_Size = sizeof(Command); + return true; } SCommand *GetCommand(unsigned *pIndex) @@ -278,7 +280,7 @@ public: { m_CmdBuffer.Reset(); m_DataBuffer.Reset(); - } + } }; // interface for the graphics backend @@ -308,10 +310,21 @@ public: class CGraphics_Threaded : public IEngineGraphics { + enum + { + NUM_CMDBUFFERS = 2, + + MAX_VERTICES = 32*1024, + MAX_TEXTURES = 1024*4, + + DRAWING_QUADS=1, + DRAWING_LINES=2 + }; + CCommandBuffer::SState m_State; IGraphicsBackend *m_pBackend; - CCommandBuffer *m_apCommandBuffers[2]; + CCommandBuffer *m_apCommandBuffers[NUM_CMDBUFFERS]; CCommandBuffer *m_pCommandBuffer; unsigned m_CurrentCommandBuffer; @@ -319,15 +332,6 @@ class CGraphics_Threaded : public IEngineGraphics class IStorage *m_pStorage; class IConsole *m_pConsole; - enum - { - MAX_VERTICES = 32*1024, - MAX_TEXTURES = 1024*4, - - DRAWING_QUADS=1, - DRAWING_LINES=2 - }; - CCommandBuffer::SVertex m_aVertices[MAX_VERTICES]; int m_NumVertices; -- cgit 1.4.1 From 666401e309e21b30285bc2545038a624c1c023eb Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Tue, 3 Jan 2012 22:49:31 +0100 Subject: added osx implementation. not tested, not even compiled once. hope it works --- src/engine/client/backend_sdl.h | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index de0c6bd4..ca3ae3e5 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -27,7 +27,26 @@ static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, NULL); } static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } #elif defined(CONF_PLATFORM_MACOSX) - #error missing implementation + #warning Untested implementation. I have no Mac OS X machine to test on. Please test, verify, fix and then remove this warning + + struct SGLContext + { + AGLDrawable m_Drawable; + AGLContext m_Context; + }; + + static SGLContext GL_GetCurrentContext() + { + SGLContext Context; + Context.m_Drawable = aglGetCurrentDrawable(); + Context.m_Context = aglGetCurrentContext(); + return Context; + } + + static void GL_MakeCurrent(const SGLContext &Context) { aglMakeCurrent(Context.m_Drawable, Context.m_Context); } + static void GL_ReleaseContext(const SGLContext &Context) { aglMakeCurrent(Context.m_Drawable, NULL); } + static void GL_SwapBuffers(const SGLContext &Context) { aglSwapBuffers(Context.m_Drawable); } + #elif defined(CONF_FAMILY_UNIX) #include -- cgit 1.4.1 From 7393151b6d4cbfd8c4be29145344dcce22aa47d7 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Tue, 3 Jan 2012 22:53:24 +0100 Subject: fixed the osx opengl make current thingie.. I think... --- src/engine/client/backend_sdl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index ca3ae3e5..6e040510 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -24,7 +24,7 @@ } static void GL_MakeCurrent(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, Context.m_hGLRC); } - static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, NULL); } + static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(AGL_NONE, NULL); } static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } #elif defined(CONF_PLATFORM_MACOSX) #warning Untested implementation. I have no Mac OS X machine to test on. Please test, verify, fix and then remove this warning -- cgit 1.4.1 From 213b88835eaa8fb13ae9b6a71283b03f89e057bd Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 4 Jan 2012 00:48:04 +0100 Subject: fixed compiling on windows --- src/engine/client/backend_sdl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 6e040510..5a4488a6 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -24,7 +24,7 @@ } static void GL_MakeCurrent(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, Context.m_hGLRC); } - static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(AGL_NONE, NULL); } + static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(NULL, NULL); } static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } #elif defined(CONF_PLATFORM_MACOSX) #warning Untested implementation. I have no Mac OS X machine to test on. Please test, verify, fix and then remove this warning -- cgit 1.4.1 From cc94472f04f4be1c84679b21624deb0ee352c486 Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 4 Jan 2012 00:52:24 +0100 Subject: fixed mac osx --- src/engine/client/backend_sdl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 5a4488a6..62ac6f7c 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -44,7 +44,7 @@ } static void GL_MakeCurrent(const SGLContext &Context) { aglMakeCurrent(Context.m_Drawable, Context.m_Context); } - static void GL_ReleaseContext(const SGLContext &Context) { aglMakeCurrent(Context.m_Drawable, NULL); } + static void GL_ReleaseContext(const SGLContext &Context) { aglMakeCurrent(AGL_NONE, NULL); } static void GL_SwapBuffers(const SGLContext &Context) { aglSwapBuffers(Context.m_Drawable); } #elif defined(CONF_FAMILY_UNIX) -- cgit 1.4.1 From 12f76e7f8d935443bd4590af4ff12f95a3d4a94b Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 12:55:19 +0100 Subject: made the editor work again. Closes #914 --- src/engine/client/client.cpp | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 5d757c49..35381fdf 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1757,7 +1757,7 @@ void CClient::Run() MasterServer()->RefreshAddresses(m_NetClient.NetType()); // init the editor - //m_pEditor->Init(); + m_pEditor->Init(); // load data @@ -1859,22 +1859,16 @@ void CClient::Run() */ // render - if(g_Config.m_ClEditor) { - if(!m_EditorActive) + if(g_Config.m_ClEditor) { - GameClient()->OnActivateEditor(); - m_EditorActive = true; + if(!m_EditorActive) + { + GameClient()->OnActivateEditor(); + m_EditorActive = true; + } } - - Update(); - m_pEditor->UpdateAndRender(); - DebugRender(); - m_pGraphics->Swap(); - } - else - { - if(m_EditorActive) + else if(m_EditorActive) m_EditorActive = false; Update(); @@ -1898,18 +1892,27 @@ void CClient::Run() { if((m_RenderFrames%10) == 0) { - Render(); + if(!m_EditorActive) + Render(); + else + { + m_pEditor->UpdateAndRender(); + DebugRender(); + } m_pGraphics->Swap(); } } else { - Render(); + if(!m_EditorActive) + Render(); + else + { + m_pEditor->UpdateAndRender(); + DebugRender(); + } m_pGraphics->Swap(); } - - - } } -- cgit 1.4.1 From 71dd0c5aab9b4f2dd50b3e935db764a3868de83e Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 14:12:49 +0100 Subject: made gfx_finish work again --- src/engine/client/backend_sdl.cpp | 3 +++ src/engine/client/graphics_threaded.cpp | 1 + src/engine/client/graphics_threaded.h | 2 ++ 3 files changed, 6 insertions(+) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 691d193c..3f74f87e 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -290,6 +290,9 @@ void CCommandProcessorFragment_SDL::Cmd_Shutdown(const SCommand_Shutdown *pComma void CCommandProcessorFragment_SDL::Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand) { GL_SwapBuffers(m_GLContext); + + if(pCommand->m_Finish) + glFinish(); } void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand) diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 33670f7b..c6947e33 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -837,6 +837,7 @@ void CGraphics_Threaded::Swap() // add swap command CCommandBuffer::SCommand_Swap Cmd; + Cmd.m_Finish = g_Config.m_GfxFinish; m_pCommandBuffer->AddCommand(Cmd); // kick the command buffer diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 51148f0f..f4f17ec2 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -199,6 +199,8 @@ public: struct SCommand_Swap : public SCommand { SCommand_Swap() : SCommand(CMD_SWAP) {} + + int m_Finish; }; struct SCommand_Texture_Create : public SCommand -- cgit 1.4.1 From 78bb0e3d8c6c4ea35bc35aada6dfb780930570b2 Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 16:35:48 +0100 Subject: fixed compiling for macosx --- src/engine/client/backend_sdl.h | 11 +++++------ src/engine/client/client.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 62ac6f7c..c6c2255a 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -27,25 +27,24 @@ static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(NULL, NULL); } static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } #elif defined(CONF_PLATFORM_MACOSX) - #warning Untested implementation. I have no Mac OS X machine to test on. Please test, verify, fix and then remove this warning + + #include struct SGLContext { - AGLDrawable m_Drawable; AGLContext m_Context; }; static SGLContext GL_GetCurrentContext() { SGLContext Context; - Context.m_Drawable = aglGetCurrentDrawable(); Context.m_Context = aglGetCurrentContext(); return Context; } - static void GL_MakeCurrent(const SGLContext &Context) { aglMakeCurrent(Context.m_Drawable, Context.m_Context); } - static void GL_ReleaseContext(const SGLContext &Context) { aglMakeCurrent(AGL_NONE, NULL); } - static void GL_SwapBuffers(const SGLContext &Context) { aglSwapBuffers(Context.m_Drawable); } + static void GL_MakeCurrent(const SGLContext &Context) { aglSetCurrentContext(Context.m_Context); } + static void GL_ReleaseContext(const SGLContext &Context) { aglSetCurrentContext(NULL); } + static void GL_SwapBuffers(const SGLContext &Context) { aglSwapBuffers(Context.m_Context); } #elif defined(CONF_FAMILY_UNIX) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 35381fdf..a9c86060 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2237,11 +2237,13 @@ static CClient *CreateClient() */ #if defined(CONF_PLATFORM_MACOSX) -extern "C" int SDL_main(int argc, const char **argv) // ignore_convention +extern "C" int SDL_main(int argc, char **argv_) // ignore_convention +{ + const char **argv = const_cast(argv_); #else int main(int argc, const char **argv) // ignore_convention -#endif { +#endif #if defined(CONF_FAMILY_WINDOWS) for(int i = 1; i < argc; i++) // ignore_convention { -- cgit 1.4.1 From 29738552a69e5b74410f2667e81243593cc26233 Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 19:17:14 +0100 Subject: made bindaddr config work for client and master too. Closes #909 --- src/engine/client/client.cpp | 7 ++++-- src/engine/server/server.cpp | 2 +- src/engine/shared/config_variables.h | 2 +- src/mastersrv/mastersrv.cpp | 48 ++++++++++++++++++++++-------------- 4 files changed, 36 insertions(+), 23 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index a9c86060..34923f28 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1738,8 +1738,11 @@ void CClient::Run() // open socket { NETADDR BindAddr; - mem_zero(&BindAddr, sizeof(BindAddr)); - BindAddr.type = NETTYPE_ALL; + if(g_Config.m_Bindaddr[0] == 0 || net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) + { + mem_zero(&BindAddr, sizeof(BindAddr)); + BindAddr.type = NETTYPE_ALL; + } if(!m_NetClient.Open(BindAddr, 0)) { dbg_msg("client", "couldn't start network"); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index de84ad35..6e63f747 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1271,7 +1271,7 @@ int CServer::Run() // start server NETADDR BindAddr; - if(g_Config.m_SvBindaddr[0] && net_host_lookup(g_Config.m_SvBindaddr, &BindAddr, NETTYPE_ALL) == 0) + if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) { // sweet! BindAddr.port = g_Config.m_SvPort; diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index d92073d7..f76e69c8 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -77,7 +77,7 @@ MACRO_CONFIG_INT(GfxThreaded, gfx_threaded, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity") MACRO_CONFIG_STR(SvName, sv_name, 128, "unnamed server", CFGFLAG_SERVER, "Server name") -MACRO_CONFIG_STR(SvBindaddr, sv_bindaddr, 128, "", CFGFLAG_SERVER, "Address to bind the server to") +MACRO_CONFIG_STR(Bindaddr, bindaddr, 128, "", CFGFLAG_CLIENT|CFGFLAG_SERVER|CFGFLAG_MASTER, "Address to bind the client/server to") MACRO_CONFIG_INT(SvPort, sv_port, 8303, 0, 0, CFGFLAG_SERVER, "Port to use for the server") MACRO_CONFIG_INT(SvExternalPort, sv_external_port, 0, 0, 0, CFGFLAG_SERVER, "External port to report to the master servers") MACRO_CONFIG_STR(SvMap, sv_map, 128, "dm1", CFGFLAG_SERVER, "Map to use on the server") diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index 632a524c..c6099139 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -2,6 +2,7 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include +#include #include #include #include @@ -326,16 +327,40 @@ int main(int argc, const char **argv) // ignore_convention dbg_logger_stdout(); net_init(); - mem_zero(&BindAddr, sizeof(BindAddr)); - BindAddr.type = NETTYPE_ALL; - BindAddr.port = MASTERSERVER_PORT; + mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)); + mem_copy(m_CountDataLegacy.m_Header, SERVERBROWSE_COUNT_LEGACY, sizeof(SERVERBROWSE_COUNT_LEGACY)); + + IKernel *pKernel = IKernel::Create(); + IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); + IConfig *pConfig = CreateConfig(); + m_pConsole = CreateConsole(CFGFLAG_MASTER); + + bool RegisterFail = !pKernel->RegisterInterface(pStorage); + RegisterFail |= !pKernel->RegisterInterface(m_pConsole); + RegisterFail |= !pKernel->RegisterInterface(pConfig); + + if(RegisterFail) + return -1; + + pConfig->Init(); + m_NetBan.Init(m_pConsole, pStorage); + if(argc > 1) // ignore_convention + m_pConsole->ParseArguments(argc-1, &argv[1]); // ignore_convention + + if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) + BindAddr.port = MASTERSERVER_PORT; + else + { + mem_zero(&BindAddr, sizeof(BindAddr)); + BindAddr.type = NETTYPE_ALL; + BindAddr.port = MASTERSERVER_PORT; + } if(!m_NetOp.Open(BindAddr, 0)) { dbg_msg("mastersrv", "couldn't start network (op)"); return -1; } - BindAddr.port = MASTERSERVER_PORT+1; if(!m_NetChecker.Open(BindAddr, 0)) { @@ -343,21 +368,6 @@ int main(int argc, const char **argv) // ignore_convention return -1; } - mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)); - mem_copy(m_CountDataLegacy.m_Header, SERVERBROWSE_COUNT_LEGACY, sizeof(SERVERBROWSE_COUNT_LEGACY)); - - IKernel *pKernel = IKernel::Create(); - IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); - - m_pConsole = CreateConsole(CFGFLAG_MASTER); - m_NetBan.Init(m_pConsole, pStorage); - - bool RegisterFail = !pKernel->RegisterInterface(pStorage); - RegisterFail |= !pKernel->RegisterInterface(m_pConsole); - - if(RegisterFail) - return -1; - dbg_msg("mastersrv", "started"); while(1) -- cgit 1.4.1 From 6ad6d59b6fbb7a6625ede9898831a3432a7f90a5 Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 19:27:18 +0100 Subject: fixed memory corruption with snd_buffer_size config --- src/engine/client/sound.cpp | 25 ++++++++++++++++++------- src/engine/shared/config_variables.h | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index 3f3d1a5d..343fa2e8 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -1,8 +1,11 @@ /* (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. */ +#include #include + #include #include + #include #include "SDL.h" @@ -19,8 +22,6 @@ enum NUM_SAMPLES = 512, NUM_VOICES = 64, NUM_CHANNELS = 16, - - MAX_FRAMES = 1024 }; struct CSample @@ -63,7 +64,8 @@ static int m_MixingRate = 48000; static volatile int m_SoundVolume = 100; static int m_NextVoice = 0; - +static int *m_pMixBuffer = 0; // buffer only used by the thread callback function +static unsigned m_MaxFrames = 0; // TODO: there should be a faster way todo this static short Int2Short(int i) @@ -84,8 +86,9 @@ static int IntAbs(int i) static void Mix(short *pFinalOut, unsigned Frames) { - int aMixBuffer[MAX_FRAMES*2] = {0}; int MasterVol; + mem_zero(m_pMixBuffer, m_MaxFrames*2*sizeof(int)); + Frames = min(Frames, m_MaxFrames); // aquire lock while we are mixing lock_wait(m_SoundLock); @@ -98,7 +101,7 @@ static void Mix(short *pFinalOut, unsigned Frames) { // mix voice CVoice *v = &m_aVoices[i]; - int *pOut = aMixBuffer; + int *pOut = m_pMixBuffer; int Step = v->m_pSample->m_Channels; // setup input sources short *pInL = &v->m_pSample->m_pData[v->m_Tick*Step]; @@ -176,8 +179,8 @@ static void Mix(short *pFinalOut, unsigned Frames) for(unsigned i = 0; i < Frames; i++) { int j = i<<1; - int vl = ((aMixBuffer[j]*MasterVol)/101)>>8; - int vr = ((aMixBuffer[j+1]*MasterVol)/101)>>8; + int vl = ((m_pMixBuffer[j]*MasterVol)/101)>>8; + int vr = ((m_pMixBuffer[j+1]*MasterVol)/101)>>8; pFinalOut[j] = Int2Short(vl); pFinalOut[j+1] = Int2Short(vr); @@ -234,6 +237,9 @@ int CSound::Init() else dbg_msg("client/sound", "sound init successful"); + m_MaxFrames = g_Config.m_SndBufferSize*2; + m_pMixBuffer = (int *)mem_alloc(m_MaxFrames*2*sizeof(int), 1); + SDL_PauseAudio(0); m_SoundEnabled = 1; @@ -264,6 +270,11 @@ int CSound::Shutdown() SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); lock_destroy(m_SoundLock); + if(m_pMixBuffer) + { + mem_free(m_pMixBuffer); + m_pMixBuffer = 0; + } return 0; } diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index f76e69c8..dfeeeaf6 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -47,7 +47,7 @@ MACRO_CONFIG_INT(BrSort, br_sort, 0, 0, 256, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(BrSortOrder, br_sort_order, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(BrMaxRequests, br_max_requests, 25, 0, 1000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Number of requests to use when refreshing server browser") -MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound buffer size") +MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound buffer size") MACRO_CONFIG_INT(SndRate, snd_rate, 48000, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound mixing rate") MACRO_CONFIG_INT(SndEnable, snd_enable, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound enable") MACRO_CONFIG_INT(SndMusic, snd_enable_music, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Play background music") -- cgit 1.4.1 From 27852934693bc8e3192bd06378095e457d436e71 Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 6 Jan 2012 20:03:57 +0100 Subject: don't start playing the music again if we're quitting --- src/engine/client/client.cpp | 6 ++++++ src/game/client/components/menus.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 34923f28..8faf1e41 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -461,6 +461,9 @@ int *CClient::GetInput(int Tick) // ------ state handling ----- void CClient::SetState(int s) { + if(m_State == IClient::STATE_QUITING) + return; + int Old = m_State; if(g_Config.m_Debug) { @@ -1842,7 +1845,10 @@ void CClient::Run() // panic quit button if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyPressed('q')) + { + Quit(); break; + } if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown('d')) g_Config.m_Debug ^= 1; diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index a2ccfba4..15837efc 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1403,7 +1403,7 @@ void CMenus::OnStateChange(int NewState, int OldState) if(NewState == IClient::STATE_OFFLINE) { - if(OldState >= IClient::STATE_ONLINE) + if(OldState >= IClient::STATE_ONLINE && NewState < IClient::STATE_QUITING) m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f); m_Popup = POPUP_NONE; if(Client()->ErrorString() && Client()->ErrorString()[0] != 0) -- cgit 1.4.1 From be37147342ff9032f0557d732abfc6cfd2c77efe Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 8 Jan 2012 01:47:53 +0100 Subject: fixed border rendering in the editor's image preview. Closes #908 --- src/engine/client/backend_sdl.cpp | 14 ++++++++++++++ src/engine/client/graphics.cpp | 12 ++++++++++++ src/engine/client/graphics.h | 3 +++ src/engine/client/graphics_threaded.cpp | 11 +++++++++++ src/engine/client/graphics_threaded.h | 10 ++++++++++ src/engine/graphics.h | 2 ++ src/game/editor/editor.cpp | 3 ++- src/game/editor/popups.cpp | 13 +++++++------ 8 files changed, 61 insertions(+), 7 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 3f74f87e..4f738949 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -133,6 +133,20 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St else glDisable(GL_TEXTURE_2D); + switch(State.m_WrapMode) + { + case CCommandBuffer::WRAP_REPEAT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case CCommandBuffer::WRAP_CLAMP: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + default: + dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode); + }; + // screen mapping glMatrixMode(GL_PROJECTION); glLoadIdentity(); diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index ad3926f2..5baff939 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -197,6 +197,18 @@ void CGraphics_OpenGL::BlendAdditive() glBlendFunc(GL_SRC_ALPHA, GL_ONE); } +void CGraphics_OpenGL::WrapNormal() +{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +} + +void CGraphics_OpenGL::WrapClamp() +{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + int CGraphics_OpenGL::MemoryUsage() const { return m_TextureMemoryUsage; diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index 3ab550dc..fdd83aa7 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -78,6 +78,9 @@ public: virtual void BlendNormal(); virtual void BlendAdditive(); + virtual void WrapNormal(); + virtual void WrapClamp(); + virtual int MemoryUsage() const; virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index c6947e33..286428d7 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -154,6 +154,7 @@ CGraphics_Threaded::CGraphics_Threaded() m_State.m_ClipH = 0; m_State.m_Texture = -1; m_State.m_BlendMode = CCommandBuffer::BLEND_NONE; + m_State.m_WrapMode = CCommandBuffer::WRAP_REPEAT; m_CurrentCommandBuffer = 0; m_pCommandBuffer = 0x0; @@ -214,6 +215,16 @@ void CGraphics_Threaded::BlendAdditive() m_State.m_BlendMode = CCommandBuffer::BLEND_ADDITIVE; } +void CGraphics_Threaded::WrapNormal() +{ + m_State.m_WrapMode = CCommandBuffer::WRAP_REPEAT; +} + +void CGraphics_Threaded::WrapClamp() +{ + m_State.m_WrapMode = CCommandBuffer::WRAP_CLAMP; +} + int CGraphics_Threaded::MemoryUsage() const { return m_TextureMemoryUsage; diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index f4f17ec2..3f3bec89 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -120,6 +120,12 @@ public: BLEND_ADDITIVE, }; + enum + { + WRAP_REPEAT = 0, + WRAP_CLAMP, + }; + struct SPoint { float x, y, z; }; struct STexCoord { float u, v; }; struct SColor { float r, g, b, a; }; @@ -142,6 +148,7 @@ public: struct SState { int m_BlendMode; + int m_WrapMode; int m_Texture; SPoint m_ScreenTL; SPoint m_ScreenBR; @@ -382,6 +389,9 @@ public: virtual void BlendNormal(); virtual void BlendAdditive(); + virtual void WrapNormal(); + virtual void WrapClamp(); + virtual int MemoryUsage() const; virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY); diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 6d31060e..46750e03 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -77,6 +77,8 @@ public: virtual void BlendNone() = 0; virtual void BlendNormal() = 0; virtual void BlendAdditive() = 0; + virtual void WrapNormal() = 0; + virtual void WrapClamp() = 0; virtual int MemoryUsage() const = 0; virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) = 0; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index c19fc86f..6b0a401c 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -2679,11 +2679,12 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) r.h *= m_Map.m_lImages[i]->m_Height/Max; Graphics()->TextureSet(m_Map.m_lImages[i]->m_TexID); Graphics()->BlendNormal(); + Graphics()->WrapClamp(); Graphics()->QuadsBegin(); IGraphics::CQuadItem QuadItem(r.x, r.y, r.w, r.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); - + Graphics()->WrapNormal(); } } diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index c19adb82..64d0c799 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -742,13 +742,14 @@ int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View) ImageView.w *= pEditor->m_Map.m_lImages[ShowImage]->m_Width/Max; ImageView.h *= pEditor->m_Map.m_lImages[ShowImage]->m_Height/Max; pEditor->Graphics()->TextureSet(pEditor->m_Map.m_lImages[ShowImage]->m_TexID); + pEditor->Graphics()->BlendNormal(); + pEditor->Graphics()->WrapClamp(); + pEditor->Graphics()->QuadsBegin(); + IGraphics::CQuadItem QuadItem(ImageView.x, ImageView.y, ImageView.w, ImageView.h); + pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); + pEditor->Graphics()->QuadsEnd(); + pEditor->Graphics()->WrapNormal(); } - else - pEditor->Graphics()->TextureSet(-1); - pEditor->Graphics()->QuadsBegin(); - IGraphics::CQuadItem QuadItem(ImageView.x, ImageView.y, ImageView.w, ImageView.h); - pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); - pEditor->Graphics()->QuadsEnd(); return 0; } -- cgit 1.4.1 From 672b70e9b98fa7718570047d03dddb3212a119ff Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 8 Jan 2012 13:57:40 +0100 Subject: fixed some line endings --- src/engine/client/backend_sdl.cpp | 4 ++-- src/engine/client/graphics.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 4f738949..4d77ff3e 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -136,11 +136,11 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St switch(State.m_WrapMode) { case CCommandBuffer::WRAP_REPEAT: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); break; case CCommandBuffer::WRAP_CLAMP: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); break; default: diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 5baff939..bb52e1b8 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -199,13 +199,13 @@ void CGraphics_OpenGL::BlendAdditive() void CGraphics_OpenGL::WrapNormal() { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } void CGraphics_OpenGL::WrapClamp() { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -- cgit 1.4.1 From 40735202143f8c4d2a539d1d81362c0c22e9324b Mon Sep 17 00:00:00 2001 From: oy Date: Mon, 9 Jan 2012 01:38:45 +0100 Subject: cleaned up content folder creation. Closes #845 --- src/engine/client/client.cpp | 2 +- src/engine/server/server.cpp | 2 +- src/engine/shared/storage.cpp | 21 ++++++++++++--------- src/engine/storage.h | 8 ++++++-- src/mastersrv/mastersrv.cpp | 2 +- src/tools/map_resave.cpp | 4 ++-- src/tools/map_version.cpp | 2 +- 7 files changed, 24 insertions(+), 17 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 8faf1e41..0e380e40 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2272,7 +2272,7 @@ int main(int argc, const char **argv) // ignore_convention // create the components IEngine *pEngine = CreateEngine("Teeworlds"); IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT); - IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); // ignore_convention + IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_CLIENT, argc, argv); // ignore_convention IConfig *pConfig = CreateConfig(); IEngineSound *pEngineSound = CreateEngineSound(); IEngineInput *pEngineInput = CreateEngineInput(); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index c15cc96e..5fa265f2 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1675,7 +1675,7 @@ int main(int argc, const char **argv) // ignore_convention IGameServer *pGameServer = CreateGameServer(); IConsole *pConsole = CreateConsole(CFGFLAG_SERVER|CFGFLAG_ECON); IEngineMasterServer *pEngineMasterServer = CreateEngineMasterServer(); - IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); // ignore_convention + IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_SERVER, argc, argv); // ignore_convention IConfig *pConfig = CreateConfig(); pServer->InitRegister(&pServer->m_NetServer, pEngineMasterServer, pConsole); diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index c1888188..a9ccdc49 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -30,7 +30,7 @@ public: m_aUserdir[0] = 0; } - int Init(const char *pApplicationName, int NumArgs, const char **ppArguments) + int Init(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments) { // get userdir fs_storage_path(pApplicationName, m_aUserdir, sizeof(m_aUserdir)); @@ -52,14 +52,17 @@ public: } // add save directories - if(m_NumPaths && (!m_aaStoragePaths[TYPE_SAVE][0] || !fs_makedir(m_aaStoragePaths[TYPE_SAVE]))) + if(StorageType != STORAGETYPE_BASIC && m_NumPaths && (!m_aaStoragePaths[TYPE_SAVE][0] || !fs_makedir(m_aaStoragePaths[TYPE_SAVE]))) { char aPath[MAX_PATH_LENGTH]; - fs_makedir(GetPath(TYPE_SAVE, "screenshots", aPath, sizeof(aPath))); - fs_makedir(GetPath(TYPE_SAVE, "screenshots/auto", aPath, sizeof(aPath))); - fs_makedir(GetPath(TYPE_SAVE, "maps", aPath, sizeof(aPath))); + if(StorageType == STORAGETYPE_CLIENT) + { + fs_makedir(GetPath(TYPE_SAVE, "screenshots", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "screenshots/auto", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "maps", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "downloadedmaps", aPath, sizeof(aPath))); + } fs_makedir(GetPath(TYPE_SAVE, "dumps", aPath, sizeof(aPath))); - fs_makedir(GetPath(TYPE_SAVE, "downloadedmaps", aPath, sizeof(aPath))); fs_makedir(GetPath(TYPE_SAVE, "demos", aPath, sizeof(aPath))); fs_makedir(GetPath(TYPE_SAVE, "demos/auto", aPath, sizeof(aPath))); } @@ -389,10 +392,10 @@ public: GetPath(Type, pDir, pBuffer, BufferSize); } - static IStorage *Create(const char *pApplicationName, int NumArgs, const char **ppArguments) + static IStorage *Create(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments) { CStorage *p = new CStorage(); - if(p && p->Init(pApplicationName, NumArgs, ppArguments)) + if(p && p->Init(pApplicationName, StorageType, NumArgs, ppArguments)) { dbg_msg("storage", "initialisation failed"); delete p; @@ -402,4 +405,4 @@ public: } }; -IStorage *CreateStorage(const char *pApplicationName, int NumArgs, const char **ppArguments) { return CStorage::Create(pApplicationName, NumArgs, ppArguments); } +IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments) { return CStorage::Create(pApplicationName, StorageType, NumArgs, ppArguments); } diff --git a/src/engine/storage.h b/src/engine/storage.h index bcfb9ce2..25aa8b3e 100644 --- a/src/engine/storage.h +++ b/src/engine/storage.h @@ -12,7 +12,11 @@ public: enum { TYPE_SAVE = 0, - TYPE_ALL = -1 + TYPE_ALL = -1, + + STORAGETYPE_BASIC = 0, + STORAGETYPE_SERVER, + STORAGETYPE_CLIENT, }; virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0; @@ -24,7 +28,7 @@ public: virtual void GetCompletePath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize) = 0; }; -extern IStorage *CreateStorage(const char *pApplicationName, int NumArgs, const char **ppArguments); +extern IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments); #endif diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index c6099139..c88a9e78 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -331,7 +331,7 @@ int main(int argc, const char **argv) // ignore_convention mem_copy(m_CountDataLegacy.m_Header, SERVERBROWSE_COUNT_LEGACY, sizeof(SERVERBROWSE_COUNT_LEGACY)); IKernel *pKernel = IKernel::Create(); - IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); + IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_BASIC, argc, argv); IConfig *pConfig = CreateConfig(); m_pConsole = CreateConsole(CFGFLAG_MASTER); diff --git a/src/tools/map_resave.cpp b/src/tools/map_resave.cpp index a536f021..0a624b0f 100644 --- a/src/tools/map_resave.cpp +++ b/src/tools/map_resave.cpp @@ -6,7 +6,7 @@ int main(int argc, const char **argv) { - IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); + IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_BASIC, argc, argv); int Index, ID = 0, Type = 0, Size; void *pPtr; char aFileName[1024]; @@ -16,7 +16,7 @@ int main(int argc, const char **argv) if(!pStorage || argc != 3) return -1; - str_format(aFileName, sizeof(aFileName), "maps/%s", argv[2]); + str_format(aFileName, sizeof(aFileName), "%s", argv[2]); if(!DataFile.Open(pStorage, argv[1], IStorage::TYPE_ALL)) return -1; diff --git a/src/tools/map_version.cpp b/src/tools/map_version.cpp index 4acc51e0..8d8c59e3 100644 --- a/src/tools/map_version.cpp +++ b/src/tools/map_version.cpp @@ -44,7 +44,7 @@ int MaplistCallback(const char *pName, int IsDir, int DirType, void *pUser) int main(int argc, const char **argv) // ignore_convention { IKernel *pKernel = IKernel::Create(); - s_pStorage = CreateStorage("Teeworlds", argc, argv); + s_pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_BASIC, argc, argv); s_pEngineMap = CreateEngineMap(); bool RegisterFail = !pKernel->RegisterInterface(s_pStorage); -- cgit 1.4.1 From 590dbac239768d9ddb8712111b60c783431021d5 Mon Sep 17 00:00:00 2001 From: oy Date: Mon, 9 Jan 2012 02:02:02 +0100 Subject: put the game version constants all together in one file. Closes #870 --- src/engine/client/client.cpp | 19 ++++++++++++------- src/game/version.h | 1 + src/versionsrv/versionsrv.cpp | 6 ++++-- src/versionsrv/versionsrv.h | 2 -- 4 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 0e380e40..b115a9ac 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -36,6 +36,8 @@ #include #include +#include + #include #include @@ -859,23 +861,26 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket) if(m_VersionInfo.m_State == CVersionInfo::STATE_READY && net_addr_comp(&pPacket->m_Address, &m_VersionInfo.m_VersionServeraddr.m_Addr) == 0) { // version info - if(pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_VERSION) + sizeof(VERSION_DATA)) && + if(pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_VERSION) + sizeof(GAME_RELEASE_VERSION)) && mem_comp(pPacket->m_pData, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION)) == 0) { - unsigned char *pVersionData = (unsigned char*)pPacket->m_pData + sizeof(VERSIONSRV_VERSION); - int VersionMatch = !mem_comp(pVersionData, VERSION_DATA, sizeof(VERSION_DATA)); + char *pVersionData = (char*)pPacket->m_pData + sizeof(VERSIONSRV_VERSION); + int VersionMatch = !mem_comp(pVersionData, GAME_RELEASE_VERSION, sizeof(GAME_RELEASE_VERSION)); + + char aVersion[sizeof(GAME_RELEASE_VERSION)]; + str_copy(aVersion, pVersionData, sizeof(aVersion)); char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "version does %s (%d.%d.%d)", + str_format(aBuf, sizeof(aBuf), "version does %s (%s)", VersionMatch ? "match" : "NOT match", - pVersionData[1], pVersionData[2], pVersionData[3]); + aVersion); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/version", aBuf); // assume version is out of date when version-data doesn't match - if (!VersionMatch) + if(!VersionMatch) { - str_format(m_aVersionStr, sizeof(m_aVersionStr), "%d.%d.%d", pVersionData[1], pVersionData[2], pVersionData[3]); + str_copy(m_aVersionStr, aVersion, sizeof(m_aVersionStr)); } // request the map version list now diff --git a/src/game/version.h b/src/game/version.h index c7f04b75..3d909e36 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -5,4 +5,5 @@ #include "generated/nethash.cpp" #define GAME_VERSION "0.6 trunk" #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH +static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '1', 0}; #endif diff --git a/src/versionsrv/versionsrv.cpp b/src/versionsrv/versionsrv.cpp index ac5883f9..da55e717 100644 --- a/src/versionsrv/versionsrv.cpp +++ b/src/versionsrv/versionsrv.cpp @@ -4,6 +4,8 @@ #include +#include + #include "versionsrv.h" enum { @@ -57,10 +59,10 @@ void BuildPackets() void SendVer(NETADDR *pAddr) { CNetChunk p; - unsigned char aData[sizeof(VERSIONSRV_VERSION) + sizeof(VERSION_DATA)]; + unsigned char aData[sizeof(VERSIONSRV_VERSION) + sizeof(GAME_RELEASE_VERSION)]; mem_copy(aData, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION)); - mem_copy(aData + sizeof(VERSIONSRV_VERSION), VERSION_DATA, sizeof(VERSION_DATA)); + mem_copy(aData + sizeof(VERSIONSRV_VERSION), GAME_RELEASE_VERSION, sizeof(GAME_RELEASE_VERSION)); p.m_ClientID = -1; p.m_Address = *pAddr; diff --git a/src/versionsrv/versionsrv.h b/src/versionsrv/versionsrv.h index 006a8e4d..383f1ac4 100644 --- a/src/versionsrv/versionsrv.h +++ b/src/versionsrv/versionsrv.h @@ -28,8 +28,6 @@ static CMapVersion s_aMapVersionList[] = { }; static const int s_NumMapVersionItems = sizeof(s_aMapVersionList)/sizeof(CMapVersion); -static const unsigned char VERSION_DATA[] = {0x00, 0, 6, 0}; - static const unsigned char VERSIONSRV_GETVERSION[] = {255, 255, 255, 255, 'v', 'e', 'r', 'g'}; static const unsigned char VERSIONSRV_VERSION[] = {255, 255, 255, 255, 'v', 'e', 'r', 's'}; -- cgit 1.4.1 From fa81141110ad46fc65860091c065bb932916fef4 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 10 Jan 2012 23:13:19 +0100 Subject: added demo markers by Choupom. Closes #837 --- src/engine/client/client.cpp | 12 +++++++ src/engine/client/client.h | 2 ++ src/engine/demo.h | 12 ++++++- src/engine/shared/demo.cpp | 53 ++++++++++++++++++++++++++++++- src/engine/shared/demo.h | 5 ++- src/game/client/components/menus_demo.cpp | 17 ++++++++-- src/game/client/ui.cpp | 5 +++ src/game/client/ui.h | 1 + 8 files changed, 102 insertions(+), 5 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index b115a9ac..d5da647b 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2169,6 +2169,11 @@ void CClient::DemoRecorder_Stop() m_DemoRecorder.Stop(); } +void CClient::DemoRecorder_AddDemoMarker() +{ + m_DemoRecorder.AddDemoMarker(); +} + void CClient::Con_Record(IConsole::IResult *pResult, void *pUserData) { CClient *pSelf = (CClient *)pUserData; @@ -2184,6 +2189,12 @@ void CClient::Con_StopRecord(IConsole::IResult *pResult, void *pUserData) pSelf->DemoRecorder_Stop(); } +void CClient::Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData) +{ + CClient *pSelf = (CClient *)pUserData; + pSelf->DemoRecorder_AddDemoMarker(); +} + void CClient::ServerBrowserUpdate() { m_ResortServerBrowser = true; @@ -2222,6 +2233,7 @@ void CClient::RegisterCommands() m_pConsole->Register("play", "r", CFGFLAG_CLIENT|CFGFLAG_STORE, Con_Play, this, "Play the file specified"); m_pConsole->Register("record", "?s", CFGFLAG_CLIENT, Con_Record, this, "Record to the file"); m_pConsole->Register("stoprecord", "", CFGFLAG_CLIENT, Con_StopRecord, this, "Stop recording"); + m_pConsole->Register("add_demomarker", "", CFGFLAG_CLIENT, Con_AddDemoMarker, this, "Add demo timeline marker"); m_pConsole->Register("add_favorite", "s", CFGFLAG_CLIENT, Con_AddFavorite, this, "Add a server as a favorite"); m_pConsole->Register("remove_favorite", "s", CFGFLAG_CLIENT, Con_RemoveFavorite, this, "Remove a server from favorites"); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 1849830c..d958b49a 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -289,6 +289,7 @@ public: static void Con_Play(IConsole::IResult *pResult, void *pUserData); static void Con_Record(IConsole::IResult *pResult, void *pUserData); 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); void RegisterCommands(); @@ -297,6 +298,7 @@ public: void DemoRecorder_Start(const char *pFilename, bool WithTimestamp); void DemoRecorder_HandleAutoStart(); void DemoRecorder_Stop(); + void DemoRecorder_AddDemoMarker(); void AutoScreenshot_Start(); void AutoScreenshot_Cleanup(); diff --git a/src/engine/demo.h b/src/engine/demo.h index a9e4f700..7b7365c7 100644 --- a/src/engine/demo.h +++ b/src/engine/demo.h @@ -5,6 +5,11 @@ #include "kernel.h" +enum +{ + MAX_TIMELINE_MARKERS=64 +}; + struct CDemoHeader { unsigned char m_aMarker[7]; @@ -16,6 +21,8 @@ struct CDemoHeader char m_aType[8]; char m_aLength[4]; char m_aTimestamp[20]; + char m_aNumTimelineMarkers[4]; + char m_aTimelineMarkers[MAX_TIMELINE_MARKERS][4]; }; class IDemoPlayer : public IInterface @@ -31,6 +38,9 @@ public: int m_FirstTick; int m_CurrentTick; int m_LastTick; + + int m_NumTimelineMarkers; + int m_aTimelineMarkers[MAX_TIMELINE_MARKERS]; }; enum @@ -42,7 +52,7 @@ public: ~IDemoPlayer() {} virtual void SetSpeed(float Speed) = 0; - virtual int SetPos(float Precent) = 0; + virtual int SetPos(float Percent) = 0; virtual void Pause() = 0; virtual void Unpause() = 0; virtual const CInfo *BaseInfo() const = 0; diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 2bd7c28a..37c82cce 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -13,8 +13,9 @@ #include "snapshot.h" static const unsigned char gs_aHeaderMarker[7] = {'T', 'W', 'D', 'E', 'M', 'O', 0}; -static const unsigned char gs_ActVersion = 3; +static const unsigned char gs_ActVersion = 4; static const int gs_LengthOffset = 152; +static const int gs_NumMarkersOffset = 176; CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta) @@ -89,6 +90,8 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con str_copy(Header.m_aType, pType, sizeof(Header.m_aType)); // Header.m_Length - add this on stop str_timestamp(Header.m_aTimestamp, sizeof(Header.m_aTimestamp)); + // Header.m_aNumTimelineMarkers - add this on stop + // Header.m_aTimelineMarkers - add this on stop io_write(DemoFile, &Header, sizeof(Header)); // write map data @@ -105,6 +108,7 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con m_LastKeyFrame = -1; m_LastTickMarker = -1; m_FirstTick = -1; + m_NumTimelineMarkers = 0; char aBuf[256]; str_format(aBuf, sizeof(aBuf), "Recording to '%s'", pFilename); @@ -266,6 +270,25 @@ int CDemoRecorder::Stop() aLength[3] = (DemoLength)&0xff; io_write(m_File, aLength, sizeof(aLength)); + // add the timeline markers to the header + io_seek(m_File, gs_NumMarkersOffset, IOSEEK_START); + char aNumMarkers[4]; + aNumMarkers[0] = (m_NumTimelineMarkers>>24)&0xff; + aNumMarkers[1] = (m_NumTimelineMarkers>>16)&0xff; + aNumMarkers[2] = (m_NumTimelineMarkers>>8)&0xff; + aNumMarkers[3] = (m_NumTimelineMarkers)&0xff; + io_write(m_File, aNumMarkers, sizeof(aNumMarkers)); + for(int i = 0; i < m_NumTimelineMarkers; i++) + { + int Marker = m_aTimelineMarkers[i]; + char aMarker[4]; + aMarker[0] = (Marker>>24)&0xff; + aMarker[1] = (Marker>>16)&0xff; + aMarker[2] = (Marker>>8)&0xff; + aMarker[3] = (Marker)&0xff; + io_write(m_File, aMarker, sizeof(aMarker)); + } + io_close(m_File); m_File = 0; m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording"); @@ -273,6 +296,24 @@ int CDemoRecorder::Stop() return 0; } +void CDemoRecorder::AddDemoMarker() +{ + if(m_LastTickMarker < 0 || m_NumTimelineMarkers >= MAX_TIMELINE_MARKERS) + return; + + // not more than 1 marker in a second + if(m_NumTimelineMarkers > 0) + { + int Diff = m_LastTickMarker - m_aTimelineMarkers[m_NumTimelineMarkers-1]; + if(Diff < SERVER_TICK_SPEED*1.0f) + return; + } + + m_aTimelineMarkers[m_NumTimelineMarkers++] = m_LastTickMarker; + + m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Added timeline marker"); +} + CDemoPlayer::CDemoPlayer(class CSnapshotDelta *pSnapshotDelta) @@ -622,6 +663,16 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const mem_free(pMapData); } + // get timeline markers + int Num = ((m_Info.m_Header.m_aNumTimelineMarkers[0]<<24)&0xFF000000) | ((m_Info.m_Header.m_aNumTimelineMarkers[1]<<16)&0xFF0000) | + ((m_Info.m_Header.m_aNumTimelineMarkers[2]<<8)&0xFF00) | (m_Info.m_Header.m_aNumTimelineMarkers[3]&0xFF); + m_Info.m_Info.m_NumTimelineMarkers = Num; + for(int i = 0; i < Num && i < MAX_TIMELINE_MARKERS; i++) + { + char *pTimelineMarker = m_Info.m_Header.m_aTimelineMarkers[i]; + m_Info.m_Info.m_aTimelineMarkers[i] = ((pTimelineMarker[0]<<24)&0xFF000000) | ((pTimelineMarker[1]<<16)&0xFF0000) | + ((pTimelineMarker[2]<<8)&0xFF00) | (pTimelineMarker[3]&0xFF); + } // scan the file for interessting points ScanFile(); diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index f4ac5685..760e7256 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -17,6 +17,8 @@ class CDemoRecorder : public IDemoRecorder int m_FirstTick; unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE]; class CSnapshotDelta *m_pSnapshotDelta; + int m_NumTimelineMarkers; + int m_aTimelineMarkers[MAX_TIMELINE_MARKERS]; void WriteTickMarker(int Tick, int Keyframe); void Write(int Type, const void *pData, int Size); @@ -25,6 +27,7 @@ public: int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType); int Stop(); + void AddDemoMarker(); void RecordSnapshot(int Tick, const void *pData, int Size); void RecordMessage(const void *pData, int Size); @@ -108,7 +111,7 @@ public: void Unpause(); int Stop(); void SetSpeed(float Speed); - int SetPos(float Precent); + int SetPos(float Percent); const CInfo *BaseInfo() const { return &m_Info.m_Info; } void GetDemoName(char *pBuffer, int BufferSize) const; bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader) const; diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index ec3e648c..40a9e5b5 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -86,15 +86,28 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) void *id = &s_SeekBarID; char aBuffer[128]; + // draw seek bar RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f); + // draw filled bar float Amount = CurrentTick/(float)TotalTicks; - CUIRect FilledBar = SeekBar; FilledBar.w = 10.0f + (FilledBar.w-10.0f)*Amount; - RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f); + // draw markers + for(int i = 0; i < pInfo->m_NumTimelineMarkers; i++) + { + float Ratio = (pInfo->m_aTimelineMarkers[i]-pInfo->m_FirstTick) / (float)TotalTicks; + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + IGraphics::CQuadItem QuadItem(SeekBar.x + (SeekBar.w-10.0f)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + } + + // draw time str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d", CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60, TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60); diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp index 00a30c15..c5219575 100644 --- a/src/game/client/ui.cpp +++ b/src/game/client/ui.cpp @@ -74,6 +74,11 @@ CUIRect *CUI::Screen() return &m_Screen; } +float CUI::PixelSize() +{ + return Screen()->w/Graphics()->ScreenWidth(); +} + void CUI::SetScale(float s) { g_Config.m_UiScale = (int)(s*100.0f); diff --git a/src/game/client/ui.h b/src/game/client/ui.h index 7cd78d6f..daba5d51 100644 --- a/src/game/client/ui.h +++ b/src/game/client/ui.h @@ -82,6 +82,7 @@ public: void ConvertMouseMove(float *x, float *y); CUIRect *Screen(); + float PixelSize(); void ClipEnable(const CUIRect *pRect); void ClipDisable(); -- cgit 1.4.1 From 0c05b3bfa1f64239e9beddd9c97f8ef0844da165 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 5 Feb 2012 13:22:39 +0100 Subject: fixed compiling with vs2008 (#932) --- src/engine/client/backend_sdl.cpp | 2 ++ src/engine/client/graphics.cpp | 1 + src/engine/client/graphics_threaded.cpp | 1 + src/engine/client/graphics_threaded.h | 2 -- src/engine/graphics.h | 3 +-- 5 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 4d77ff3e..a8617748 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -2,6 +2,8 @@ #include "SDL.h" #include "SDL_opengl.h" +#include + #include "graphics_threaded.h" #include "backend_sdl.h" diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index bb52e1b8..2fff2931 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "SDL.h" #include "SDL_opengl.h" diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 286428d7..b19e8a83 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 3f3bec89..f90f818d 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -1,7 +1,5 @@ #pragma once -#include - #include class CCommandBuffer diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 46750e03..7f272497 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -5,7 +5,6 @@ #include "kernel.h" -#include class CImageInfo { @@ -139,7 +138,7 @@ public: virtual void Swap() = 0; // syncronization - virtual void InsertSignal(semaphore *pSemaphore) = 0; + virtual void InsertSignal(class semaphore *pSemaphore) = 0; virtual bool IsIdle() = 0; virtual void WaitForIdle() = 0; }; -- cgit 1.4.1 From 27daa26b991d3fc92609a915f23eadbbd68cd9e9 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 5 Feb 2012 13:28:35 +0100 Subject: fixed stuck mouse cursor when loosing fullscreen focus on windows --- src/engine/client/backend_sdl.cpp | 1 + src/engine/client/graphics.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/engine/client') diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index a8617748..e7975aca 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -405,6 +405,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, } const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows // set flags int SdlFlags = SDL_OPENGL; diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 2fff2931..2111703e 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -765,7 +765,7 @@ int CGraphics_SDL::TryInit() m_ScreenHeight = g_Config.m_GfxScreenHeight; const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows // set flags int Flags = SDL_OPENGL; -- cgit 1.4.1