void CScoreboard::OnRender() { if(!Active()) return; // if the score board is active, then we should clear the motd message aswell if(m_pClient->m_pMotd->IsActive()) m_pClient->m_pMotd->Clear(); float Width = 400*3.0f*Graphics()->ScreenAspect(); float Height = 400*3.0f; Graphics()->MapScreen(0, 0, Width, Height); m_pClient->m_pLua->m_pEventListener->OnEvent("OnScoreboardRender"); if (m_pClient->m_pLua->m_pEventListener->m_Returns.m_aVars[0].GetInteger() == 1) return; float w = 700.0f; if(m_pClient->m_Snap.m_pGameInfoObj) { if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)) RenderScoreboard(Width/2-w/2, 150.0f, w, 0, 0); else { const char *pRedClanName = GetClanName(TEAM_RED); const char *pBlueClanName = GetClanName(TEAM_BLUE); if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER && m_pClient->m_Snap.m_pGameDataObj) { char aText[256]; str_copy(aText, Localize("Draw!"), sizeof(aText)); if(m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed > m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue) { if(pRedClanName) str_format(aText, sizeof(aText), Localize("%s wins!"), pRedClanName); else str_copy(aText, Localize("Red team wins!"), sizeof(aText)); } else if(m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue > m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed) { if(pBlueClanName) str_format(aText, sizeof(aText), Localize("%s wins!"), pBlueClanName); else str_copy(aText, Localize("Blue team wins!"), sizeof(aText)); } float w = TextRender()->TextWidth(0, 86.0f, aText, -1); TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1); } RenderScoreboard(Width/2-w-5.0f, 150.0f, w, TEAM_RED, pRedClanName ? pRedClanName : Localize("Red team")); RenderScoreboard(Width/2+5.0f, 150.0f, w, TEAM_BLUE, pBlueClanName ? pBlueClanName : Localize("Blue team")); } } RenderGoals(Width/2-w/2, 150+760+10, w); RenderSpectators(Width/2-w/2, 150+760+10+50+10, w); RenderRecordingNotification((Width/7)*4); }
void CHud::RenderScoreHud() { // render small score hud if(!(m_pClient->m_Snap.m_pGameData->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) { int GameFlags = m_pClient->m_GameInfo.m_GameFlags; float Whole = 300*Graphics()->ScreenAspect(); float StartY = 229.0f; if(GameFlags&GAMEFLAG_TEAMS && m_pClient->m_Snap.m_pGameDataTeam) { char aScoreTeam[2][32]; str_format(aScoreTeam[TEAM_RED], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameDataTeam->m_TeamscoreRed); str_format(aScoreTeam[TEAM_BLUE], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameDataTeam->m_TeamscoreBlue); float aScoreTeamWidth[2] = { TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_RED], -1), TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_BLUE], -1) }; float ScoreWidthMax = max(max(aScoreTeamWidth[TEAM_RED], aScoreTeamWidth[TEAM_BLUE]), TextRender()->TextWidth(0, 14.0f, "100", -1)); float Split = 3.0f; float ImageSize = GameFlags&GAMEFLAG_FLAGS ? 16.0f : Split; for(int t = 0; t < NUM_TEAMS; t++) { // draw box CUIRect Rect = {Whole-ScoreWidthMax-ImageSize-2*Split, StartY+t*20, ScoreWidthMax+ImageSize+2*Split, 18.0f}; Graphics()->BlendNormal(); RenderTools()->DrawUIRect(&Rect, t == 0 ? vec4(1.0f, 0.0f, 0.0f, 0.25f) : vec4(0.0f, 0.0f, 1.0f, 0.25f), CUI::CORNER_L, 5.0f); // draw score TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreTeamWidth[t])/2-Split, StartY+t*20, 14.0f, aScoreTeam[t], -1); if(GameFlags&GAMEFLAG_SURVIVAL) { // draw number of alive players char aBuf[32]; str_format(aBuf, sizeof(aBuf), m_pClient->m_Snap.m_AliveCount[t]==1 ? Localize("%d player left") : Localize("%d players left"), m_pClient->m_Snap.m_AliveCount[t]); float w = TextRender()->TextWidth(0, 8.0f, aBuf, -1); TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, aBuf, -1); } StartY += 8.0f; } if(GameFlags&GAMEFLAG_FLAGS && m_pClient->m_Snap.m_pGameDataFlag) { int FlagCarrier[2] = { m_pClient->m_Snap.m_pGameDataFlag->m_FlagCarrierRed, m_pClient->m_Snap.m_pGameDataFlag->m_FlagCarrierBlue }; int FlagDropTick[2] = { m_pClient->m_Snap.m_pGameDataFlag->m_FlagDropTickRed, m_pClient->m_Snap.m_pGameDataFlag->m_FlagDropTickBlue }; StartY = 229.0f; for(int t = 0; t < 2; t++) { int BlinkTimer = (FlagDropTick[t] != 0 && (Client()->GameTick()-FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20; if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/BlinkTimer)&1))) { // draw flag Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(t==0?SPRITE_FLAG_RED:SPRITE_FLAG_BLUE); IGraphics::CQuadItem QuadItem(Whole-ScoreWidthMax-ImageSize, StartY+1.0f+t*20, ImageSize/2, ImageSize); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } else if(FlagCarrier[t] >= 0) { // draw name of the flag holder int ID = FlagCarrier[t]%MAX_CLIENTS; char aName[64]; str_format(aName, sizeof(aName), "%2d: %s", ID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : ""); float w = TextRender()->TextWidth(0, 8.0f, aName, -1); TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, aName, -1); // draw tee of the flag holder CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo; Info.m_Size = 18.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20)); } StartY += 8.0f; } } } else { int Local = -1; int aPos[2] = { 1, 2 }; CGameClient::CPlayerInfoItem aPlayerInfo[2] = {{0}}; int i = 0; for(int t = 0; t < 2 && i < MAX_CLIENTS && m_pClient->m_Snap.m_aInfoByScore[i].m_pPlayerInfo; ++i) { if(m_pClient->m_aClients[m_pClient->m_Snap.m_aInfoByScore[i].m_ClientID].m_Team != TEAM_SPECTATORS) { aPlayerInfo[t] = m_pClient->m_Snap.m_aInfoByScore[i]; if(aPlayerInfo[t].m_ClientID == m_pClient->m_LocalClientID) Local = t; ++t; } } // search local player info if not a spectator, nor within top2 scores if(Local == -1 && m_pClient->m_aClients[m_pClient->m_LocalClientID].m_Team != TEAM_SPECTATORS) { for(; i < MAX_CLIENTS && m_pClient->m_Snap.m_aInfoByScore[i].m_pPlayerInfo; ++i) { if(m_pClient->m_aClients[m_pClient->m_Snap.m_aInfoByScore[i].m_ClientID].m_Team != TEAM_SPECTATORS) ++aPos[1]; if(m_pClient->m_Snap.m_aInfoByScore[i].m_ClientID == m_pClient->m_LocalClientID) { aPlayerInfo[1] = m_pClient->m_Snap.m_aInfoByScore[i]; Local = 1; break; } } } char aScore[2][32]; for(int t = 0; t < 2; ++t) { if(aPlayerInfo[t].m_pPlayerInfo) str_format(aScore[t], sizeof(aScore)/2, "%d", aPlayerInfo[t].m_pPlayerInfo->m_Score); else aScore[t][0] = 0; } float aScoreWidth[2] = {TextRender()->TextWidth(0, 14.0f, aScore[0], -1), TextRender()->TextWidth(0, 14.0f, aScore[1], -1)}; float ScoreWidthMax = max(max(aScoreWidth[0], aScoreWidth[1]), TextRender()->TextWidth(0, 14.0f, "10", -1)); float Split = 3.0f, ImageSize = 16.0f, PosSize = 16.0f; // todo: add core hud for LMS for(int t = 0; t < 2; t++) { // draw box CUIRect Rect = {Whole-ScoreWidthMax-ImageSize-2*Split-PosSize, StartY+t*20, ScoreWidthMax+ImageSize+2*Split+PosSize, 18.0f}; Graphics()->BlendNormal(); RenderTools()->DrawUIRect(&Rect, t == Local ? vec4(1.0f, 1.0f, 1.0f, 0.25f) : vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_L, 5.0f); // draw score TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreWidth[t])/2-Split, StartY+t*20, 14.0f, aScore[t], -1); if(aPlayerInfo[t].m_pPlayerInfo) { // draw name int ID = aPlayerInfo[t].m_ClientID; char aName[64]; str_format(aName, sizeof(aName), "%2d: %s", ID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : ""); float w = TextRender()->TextWidth(0, 8.0f, aName, -1); TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split-PosSize), StartY+(t+1)*20.0f-3.0f, 8.0f, aName, -1); // draw tee CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo; Info.m_Size = 18.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20)); } // draw position char aBuf[32]; str_format(aBuf, sizeof(aBuf), "%d.", aPos[t]); TextRender()->Text(0, Whole-ScoreWidthMax-ImageSize-Split-PosSize, StartY+2.0f+t*20, 10.0f, aBuf, -1); StartY += 8.0f; } } } }
void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags) { //Graphics()->TextureSet(img_get(tmap->image)); float ScreenX0, ScreenY0, ScreenX1, ScreenY1; Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); //Graphics()->MapScreen(screen_x0-50, screen_y0-50, screen_x1+50, screen_y1+50); // calculate the final pixelsize for the tiles float TilePixelSize = 1024/32.0f; float FinalTileSize = Scale/(ScreenX1-ScreenX0) * Graphics()->ScreenWidth(); float FinalTilesetScale = FinalTileSize/TilePixelSize; Graphics()->QuadsBegin(); Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a); int StartY = (int)(ScreenY0/Scale)-1; int StartX = (int)(ScreenX0/Scale)-1; int EndY = (int)(ScreenY1/Scale)+1; int EndX = (int)(ScreenX1/Scale)+1; // adjust the texture shift according to mipmap level float TexSize = 1024.0f; float Frac = (1.25f/TexSize) * (1/FinalTilesetScale); float Nudge = (0.5f/TexSize) * (1/FinalTilesetScale); for(int y = StartY; y < EndY; y++) for(int x = StartX; x < EndX; x++) { int mx = x; int my = y; if(RenderFlags&TILERENDERFLAG_EXTEND) { if(mx<0) mx = 0; if(mx>=w) mx = w-1; if(my<0) my = 0; if(my>=h) my = h-1; } else { if(mx<0) continue; // mx = 0; if(mx>=w) continue; // mx = w-1; if(my<0) continue; // my = 0; if(my>=h) continue; // my = h-1; } int c = mx + my*w; unsigned char Index = pTiles[c].m_Index; if(Index) { unsigned char Flags = pTiles[c].m_Flags; bool Render = false; if(Flags&TILEFLAG_OPAQUE) { if(RenderFlags&LAYERRENDERFLAG_OPAQUE) Render = true; } else { if(RenderFlags&LAYERRENDERFLAG_TRANSPARENT) Render = true; } if(Render) { int tx = Index%16; int ty = Index/16; int Px0 = tx*(1024/16); int Py0 = ty*(1024/16); int Px1 = Px0+(1024/16)-1; int Py1 = Py0+(1024/16)-1; float x0 = Nudge + Px0/TexSize+Frac; float y0 = Nudge + Py0/TexSize+Frac; float x1 = Nudge + Px1/TexSize-Frac; float y1 = Nudge + Py0/TexSize+Frac; float x2 = Nudge + Px1/TexSize-Frac; float y2 = Nudge + Py1/TexSize-Frac; float x3 = Nudge + Px0/TexSize+Frac; float y3 = Nudge + Py1/TexSize-Frac; if(Flags&TILEFLAG_VFLIP) { x0 = x2; x1 = x3; x2 = x3; x3 = x0; } if(Flags&TILEFLAG_HFLIP) { y0 = y3; y2 = y1; y3 = y1; y1 = y0; } if(Flags&TILEFLAG_ROTATE) { float Tmp = x0; x0 = x3; x3 = x2; x2 = x1; x1 = Tmp; Tmp = y0; y0 = y3; y3 = y2; y2 = y1; y1 = Tmp; } Graphics()->QuadsSetSubsetFree(x0, y0, x1, y1, x2, y2, x3, y3); IGraphics::CQuadItem QuadItem(x*Scale, y*Scale, Scale, Scale); Graphics()->QuadsDrawTL(&QuadItem, 1); } } x += pTiles[c].m_Skip; } Graphics()->QuadsEnd(); Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); }
void CKillMessages::OnRender() { float Width = 400*3.0f*Graphics()->ScreenAspect(); float Height = 400*3.0f; Graphics()->MapScreen(0, 0, Width*1.5f, Height*1.5f); float StartX = Width*1.5f-10.0f; float y = 20.0f; for(int i = 0; i < MAX_KILLMSGS; i++) { int r = (m_KillmsgCurrent+i+1)%MAX_KILLMSGS; if(Client()->GameTick() > m_aKillmsgs[r].m_Tick+50*10) continue; float FontSize = 36.0f; float KillerNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aKillerName, -1); float VictimNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aVictimName, -1); float x = StartX; // render victim name x -= VictimNameW; TextRender()->Text(0, x, y, FontSize, m_aKillmsgs[r].m_aVictimName, -1); // render victim tee x -= 24.0f; if(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_FLAGS) { if(m_aKillmsgs[r].m_ModeSpecial&1) { Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); if(m_aKillmsgs[r].m_VictimTeam == 0) RenderTools()->SelectSprite(SPRITE_FLAG_BLUE); else RenderTools()->SelectSprite(SPRITE_FLAG_RED); float Size = 56.0f; IGraphics::CQuadItem QuadItem(x, y-16, Size/2, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } } RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_VictimRenderInfo, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); x -= 32.0f; // render weapon x -= 44.0f; if (m_aKillmsgs[r].m_Weapon >= 0) { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[m_aKillmsgs[r].m_Weapon].m_pSpriteBody); RenderTools()->DrawSprite(x, y+28, 96); Graphics()->QuadsEnd(); } x -= 52.0f; if(m_aKillmsgs[r].m_VictimID != m_aKillmsgs[r].m_KillerID) { if(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_FLAGS) { if(m_aKillmsgs[r].m_ModeSpecial&2) { Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); if(m_aKillmsgs[r].m_KillerTeam == 0) RenderTools()->SelectSprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X); else RenderTools()->SelectSprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); float Size = 56.0f; IGraphics::CQuadItem QuadItem(x-56, y-16, Size/2, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } } // render killer tee x -= 24.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &m_aKillmsgs[r].m_KillerRenderInfo, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); x -= 32.0f; // render killer name x -= KillerNameW; TextRender()->Text(0, x, y, FontSize, m_aKillmsgs[r].m_aKillerName, -1); } y += 44; } }
// stolen from H-Client :3 void CMenus::RenderIRC(CUIRect MainView) { CALLSTACK_ADD(); static float YOffset = -500.0f; // dunno if a constant is optimal... if(!m_IRCActive) { YOffset = -500.0f; return; } smooth_set(&YOffset, 50.0f, 35.0f, Client()->RenderFrameTime()); // small0r MainView.x = 50; MainView.y = YOffset; MainView.w -= 100; MainView.h -= 100; CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); Graphics()->BlendNormal(); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActiveIngame-vec4(0.0f, 0.0f, 0.0f, 0.2f), CUI::CORNER_ALL, 5.0f); MainView.HSplitTop(15.0f, 0, &MainView); MainView.VSplitLeft(15.0f, 0, &MainView); MainView.Margin(5.0f, &MainView); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActiveIngame-vec4(0.0f, 0.0f, 0.0f, 0.2f), CUI::CORNER_ALL, 5.0f); CUIRect MainIRC, EntryBox, Button; MainView.Margin(10.0f, &MainIRC); /*if (m_GamePagePanel != PANEL_CHAT && UI()->MouseInside(&MainView) && Input()->KeyPressed(KEY_MOUSE_1)) { m_GamePagePanel = PANEL_CHAT; }*/ if(m_pClient->IRC()->GetState() == IIRC::STATE_DISCONNECTED) { EntryBox.x = MainIRC.x + (MainIRC.w / 2.0f - 300.0f / 2.0f); EntryBox.w = 300.0f; EntryBox.y = MainIRC.y + (MainIRC.h / 2.0f - 55.0f / 2.0f); EntryBox.h = 55.0f; RenderTools()->DrawUIRect(&EntryBox, ms_ColorTabbarActive-vec4(0.0f, 0.0f, 0.0f, 0.2f), CUI::CORNER_ALL, 10.0f); EntryBox.Margin(5.0f, &EntryBox); EntryBox.HSplitTop(18.0f, &Button, &EntryBox); CUIRect Label; Button.VSplitLeft(40.0f, &Label, &Button); UI()->DoLabelScaled(&Label, Localize("Nick:"), 14.0f, -1); static float OffsetNick; if(g_Config.m_ClIRCNick[0] == 0) { str_copy(g_Config.m_ClIRCNick, g_Config.m_PlayerName, sizeof(g_Config.m_ClIRCNick)); str_irc_sanitize(g_Config.m_ClIRCNick); } //TODO_ here? static CButtonContainer s_EditboxIRCNick; DoEditBox(&s_EditboxIRCNick, &Button, g_Config.m_ClIRCNick, sizeof(g_Config.m_ClIRCNick), 12.0f, &OffsetNick, false, CUI::CORNER_ALL); EntryBox.HSplitTop(5.0f, 0x0, &EntryBox); EntryBox.HSplitTop(20.0f, &Button, &EntryBox); static CButtonContainer s_ButtonConnect; if(DoButton_Menu(&s_ButtonConnect, Localize("Connect"), 0, &Button)) m_pClient->m_pIRCBind->Connect(); } else if(m_pClient->IRC()->GetState() == IIRC::STATE_CONNECTING) { EntryBox.x = MainIRC.x + (MainIRC.w / 2.0f - 300.0f / 2.0f); EntryBox.w = 300.0f; EntryBox.y = MainIRC.y + (MainIRC.h / 2.0f - 25.0f / 2.0f); EntryBox.h = 25.0f; RenderTools()->DrawUIRect(&EntryBox, ms_ColorTabbarActive-vec4(0.0f, 0.0f, 0.0f, 0.2f), CUI::CORNER_ALL, 10.0f); EntryBox.Margin(5.0f, &EntryBox); UI()->DoLabelScaled(&EntryBox, Localize("Connecting, please wait..."), 14.0f, -1); } else if(m_pClient->IRC()->GetState() == IIRC::STATE_CONNECTED) { CUIRect ButtonBox, InputBox; // channel list MainIRC.HSplitTop(20.0f, &ButtonBox, &EntryBox); ButtonBox.VSplitRight(80.0f, &ButtonBox, &Button); static CButtonContainer s_ButtonDisc; if(DoButton_Menu(&s_ButtonDisc, g_Config.m_ClIRCAutoconnect ? Localize("Reconnect") : Localize("Disconnect"), 0, &Button)) m_pClient->m_pIRCBind->Disconnect(g_Config.m_ClIRCLeaveMsg); // scroll through the tabs if(UI()->MouseInside(&ButtonBox) && m_pClient->m_pGameConsole->IsClosed()) { if(m_pClient->Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) m_pClient->IRC()->NextRoom(); else if(m_pClient->Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) m_pClient->IRC()->PrevRoom(); } float LW = (ButtonBox.w - ButtonBox.x) / m_pClient->IRC()->GetNumComs(); static CButtonContainer s_ButsID[64]; for(unsigned i = 0; i < m_pClient->IRC()->GetNumComs(); i++) { CIRCCom *pCom = m_pClient->IRC()->GetCom(i); // if(pCom == m_pClient->IRC()->GetActiveCom()) ButtonBox.VSplitLeft(LW - 25.0f, &Button, &ButtonBox); // else // { // ButtonBox.VSplitLeft(LW, &Button, &ButtonBox); // Button.VSplitRight(2.0f, &Button, 0x0); // } // close using middle mouse button if(UI()->MouseInside(&Button) && m_pClient->Input()->KeyPress(KEY_MOUSE_3) && m_pClient->IRC()->CanCloseCom(m_pClient->IRC()->GetCom(i))) m_pClient->IRC()->Part(g_Config.m_ClIRCLeaveMsg, m_pClient->IRC()->GetCom(i)); if(pCom->GetType() == CIRCCom::TYPE_CHANNEL) { CComChan *pChan = static_cast<CComChan*>(pCom); static float FadeVal[64] = { 0.0f }; static bool Add[64] = { true }; if(Add[i]) smooth_set(&FadeVal[i], 1.0f, 120.0f, Client()->RenderFrameTime()); else smooth_set(&FadeVal[i], 0.0f, 120.0f, Client()->RenderFrameTime()); if(FadeVal[i] >= 0.8f) Add[i] = false; if(FadeVal[i] <= 0.2f) Add[i] = true; char aTab[255]; if(pCom->m_NumUnreadMsg) { str_format(aTab, sizeof(aTab), "%s [%d]", pChan->Channel(), pCom->m_NumUnreadMsg); if(DoButton_MenuTab(&s_ButsID[i], aTab, pCom->m_NumUnreadMsg, &Button, i==m_pClient->IRC()->GetNumComs()-1?CUI::CORNER_R:0, vec4(0.0f, FadeVal[i], 0.0f, 1.0f))) m_pClient->IRC()->SetActiveCom(i); } else { FadeVal[i] = 0.0f; Add[i] = true; str_copy(aTab, pChan->Channel(), sizeof(aTab)); if(DoButton_MenuTab(&s_ButsID[i], aTab, pCom == m_pClient->IRC()->GetActiveCom(), &Button, i==m_pClient->IRC()->GetNumComs()-1?CUI::CORNER_R:0)) m_pClient->IRC()->SetActiveCom(i); } } else if(pCom->GetType() == CIRCCom::TYPE_QUERY) { CComQuery *pQuery = static_cast<CComQuery*>(pCom); static float FadeVal[64] = { 0.0f }; static bool Add[64] = { true }; if(Add[i]) smooth_set(&FadeVal[i], 1.0f, 120.0f, Client()->RenderFrameTime()); else smooth_set(&FadeVal[i], 0.0f, 120.0f, Client()->RenderFrameTime()); if(FadeVal[i] >= 0.8f) Add[i] = false; if(FadeVal[i] <= 0.2f) Add[i] = true; char aTab[255]; if(pCom->m_NumUnreadMsg) { str_format(aTab, sizeof(aTab), "%s [%d]", pQuery->User(), pCom->m_NumUnreadMsg); if(DoButton_MenuTab(&s_ButsID[i], aTab, pCom->m_NumUnreadMsg, &Button, i==m_pClient->IRC()->GetNumComs()-1?CUI::CORNER_R:0, vec4(0.0f, FadeVal[i], 0.0f, 1.0f))) m_pClient->IRC()->SetActiveCom(i); } else { FadeVal[i] = 0.0f; Add[i] = true; str_copy(aTab, pQuery->User(), sizeof(aTab)); if(DoButton_MenuTab(&s_ButsID[i], aTab, pCom == m_pClient->IRC()->GetActiveCom(), &Button, i==m_pClient->IRC()->GetNumComs()-1?CUI::CORNER_R:0)) m_pClient->IRC()->SetActiveCom(i); } } if(i > 0 && pCom == m_pClient->IRC()->GetActiveCom() && m_pClient->IRC()->GetNumComs() > 2 && str_comp_nocase(((CComChan*)pCom)->Channel(), "#AllTheHaxx")) { Button.VSplitRight(ButtonBox.h, 0, &Button); Button.Margin(3.0f, &Button); Button.x -= 5.0f; Button.h = Button.w; static CButtonContainer s_CloseButton; if(DoButton_Menu(&s_CloseButton, "×", 0, &Button, 0, CUI::CORNER_ALL, ms_ColorTabbarActive+vec4(0.3f,0.3f,0.3f,0))) m_pClient->IRC()->Part(g_Config.m_ClIRCLeaveMsg); } } static char aEntryText[512]; static int s_CurrBacklogIndex = -1; bool Update = false; if(Input()->KeyPress(KEY_UP)) { s_CurrBacklogIndex++; Update = true; } if(Input()->KeyPress(KEY_DOWN)) { s_CurrBacklogIndex--; Update = true; } s_CurrBacklogIndex = clamp(s_CurrBacklogIndex, -1, m_aIRCBacklog.size()-1); if(Update) { if(s_CurrBacklogIndex < 0) mem_zero(aEntryText, sizeof(aEntryText)); else if(m_aIRCBacklog.size() > 0) { int ActualEntry = m_aIRCBacklog.size()-1-s_CurrBacklogIndex; if(str_length(m_aIRCBacklog[ActualEntry].c_str()) > 0) str_copy(aEntryText, m_aIRCBacklog[ActualEntry].c_str(), sizeof(aEntryText)); } } // Input Box EntryBox.HSplitBottom(20.0f, &EntryBox, &InputBox); InputBox.VSplitRight(max(50.0f, TextRender()->TextWidth(0, (InputBox.h-2.0f)*ms_FontmodHeight, Localize("Send"), -1)), &InputBox, &Button); //Button.VSplitLeft(5.0f, 0x0, &Button); static float s_Offset; CPointerContainer s_EditboxInput(&m_IRCActive); DoEditBox(&s_EditboxInput, &InputBox, aEntryText, sizeof(aEntryText), 12.0f, &s_Offset, false, CUI::CORNER_L, "", -1); static CButtonContainer s_ButtonSend; if(DoButton_Menu(&s_ButtonSend, Localize("Send"), 0, &Button, 0, CUI::CORNER_R, vec4(1,1,1,0.6f)) || m_EnterPressed) { if(aEntryText[0] == '/'/* || (m_pClient->IRC()->GetActiveCom()->GetType() == CIRCCom::TYPE_QUERY && str_comp_nocase(((CComQuery*)m_pClient->IRC()->GetActiveCom())->m_User, "@Status") == 0)*/) { std::string strCmdRaw; //if(str_comp_nocase(((CComQuery*)m_pClient->IRC()->GetActiveCom())->m_User, "@Status") == 0) // strCmdRaw = aEntryText; //else strCmdRaw = aEntryText + 1; char aCmd[32] = { 0 }, aCmdParams[255] = { 0 }; size_t del = strCmdRaw.find_first_of(" "); if(del != std::string::npos) { str_copy(aCmd, strCmdRaw.substr(0, del).c_str(), sizeof(aCmd)); str_copy(aCmdParams, strCmdRaw.substr(del + 1).c_str(), sizeof(aCmdParams)); } else str_copy(aCmd, strCmdRaw.c_str(), sizeof(aCmd)); if(aCmd[0] != 0) m_pClient->IRC()->ExecuteCommand(aCmd, aCmdParams); } else m_pClient->IRC()->SendMsg(0x0, aEntryText); if(str_length(aEntryText) > 0) m_aIRCBacklog.add(std::string(aEntryText)); s_CurrBacklogIndex = -1; aEntryText[0] = 0; UI()->SetActiveItem(s_EditboxInput.GetID()); } if(!UI()->HotItem()) UI()->SetActiveItem(s_EditboxInput.GetID()); //Channel/Query CIRCCom *pCom = m_pClient->IRC()->GetActiveCom(); if(!pCom) return; if(pCom->GetType() == CIRCCom::TYPE_CHANNEL) { CComChan *pChan = static_cast<CComChan*>(pCom); CUIRect Chat, HorizScrollBar, UserList; EntryBox.Margin(5.0f, &EntryBox); EntryBox.VSplitRight(150.0f, &Chat, &UserList); Chat.HSplitBottom(15.0f, &Chat, &HorizScrollBar); static CButtonContainer s_HScrollbar; static float s_HScrollbarVal = 0.0f; s_HScrollbarVal = DoScrollbarH(&s_HScrollbar, &HorizScrollBar, s_HScrollbarVal); if(Input()->KeyIsPressed(KEY_LSHIFT) && m_pClient->m_pGameConsole->IsClosed()) { if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) // to the right s_HScrollbarVal += 0.1f; if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) // to the left s_HScrollbarVal -= 0.1f; s_HScrollbarVal = clamp(s_HScrollbarVal, 0.0f, 1.0f); } static int Selected = 0; static CButtonContainer s_UsersList; static float s_UsersScrollValue = 0; /*if(!Input()->KeyIsPressed(KEY_LSHIFT) && UI()->MouseInside(&UserList)) { if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) // to the right s_UsersScrollValue -= 0.1f; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) // to the left s_UsersScrollValue += 0.1f; s_UsersScrollValue = clamp(s_UsersScrollValue, 0.0f, 1.0f); }*/ char aBuff[50]; str_format(aBuff, sizeof(aBuff), Localize("Total: %d"), pChan->m_Users.size()); UiDoListboxStart(&s_UsersList, &UserList, 18.0f, Localize("Users"), aBuff, pChan->m_Users.size(), 1, Selected, s_UsersScrollValue, CUI::CORNER_TR); for(int u = 0; u < pChan->m_Users.size(); u++) { std::string& Name = pChan->m_Users[u].m_Nick; CPointerContainer Container(&Name); CListboxItem Item = UiDoListboxNextItem(&Container, false, UI()->MouseInside(&UserList) != 0); if(!Item.m_Visible) continue; // quick join button CUIRect Label, ButtonQS; Item.m_Rect.VSplitRight(Item.m_Rect.h, &Label, &ButtonQS); if(Selected == u) { if(UI()->DoButtonLogic(&Item.m_Selected, "", Selected, &Label)) { if(str_comp_nocase(Name.c_str()+1, m_pClient->IRC()->GetNick()) != 0) m_pClient->IRC()->OpenQuery(Name.c_str()); } } CComChan::CUser *pUser = &(pChan->m_Users[u]); dbg_assert(pUser != NULL, "in render: pChan->m_Users contains invalid pointer"); //DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_JOIN, &ButtonQS/*, vec4(0.47f, 0.58f, 0.72f, 1.0f)*/); CPointerContainer s_JoinButton(pUser); ButtonQS.Margin(2.0f, &ButtonQS); if(!pUser->IsVoice() && !pUser->IsAdmin() && str_comp(pUser->m_Nick.c_str(), m_pClient->IRC()->GetNick()) != 0) if(DoButton_Menu(&s_JoinButton, "→", 0, &ButtonQS, Localize("Join"), CUI::CORNER_ALL, vec4(0, 0, 1, 0.7f))) //if(UI()->DoButtonLogic(&Item.m_Visible, "", Selected, &ButtonQS)) { m_pClient->IRC()->SendGetServer(Name.c_str()); } // colors for admin and voice if(pUser->IsAdmin()) TextRender()->TextColor(0.2f, 0.7f, 0.2f, 1); else if(pUser->IsVoice()) TextRender()->TextColor(0.2f, 0.2f, 0.7f, 1); UI()->DoLabelScaled(&Item.m_Rect, Name.c_str(), 12.0f, -1); TextRender()->TextColor(1,1,1,1); } Selected = UiDoListboxEnd(&s_UsersScrollValue, 0); static CButtonContainer s_Chat; static float s_ChatScrollValue = 1.0f; /*if(!Input()->KeyIsPressed(KEY_LSHIFT) && UI()->MouseInside(&Chat)) { if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) // to the right s_ChatScrollValue -= 0.1f; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) // to the left s_ChatScrollValue += 0.1f; s_ChatScrollValue = clamp(s_ChatScrollValue, 0.0f, 1.0f); }*/ UiDoListboxStart(&s_Chat, &Chat, 12.0f, pChan->m_Topic.c_str()[0] ? pChan->m_Topic.c_str() : "", "", (int)pChan->m_Buffer.size(), 1, -1, s_ChatScrollValue, CUI::CORNER_TL); for(size_t i = 0; i < pChan->m_Buffer.size(); i++) { CPointerContainer Container(&pChan->m_Buffer[i]); CListboxItem Item = UiDoListboxNextItem(&Container, false, !Input()->KeyIsPressed(KEY_LSHIFT) && UI()->MouseInside(&UserList)); if(Item.m_Visible) { Item.m_Rect.x -= 1.7f*Item.m_Rect.w * s_HScrollbarVal; const char *pSearchFrom = str_find(pChan->m_Buffer[i].c_str(), ">"); if(!pSearchFrom) pSearchFrom = pChan->m_Buffer[i].c_str(); if(str_find_nocase(pSearchFrom, m_pClient->IRC()->GetNick())) { vec3 rgb = HslToRgb(vec3((float)g_Config.m_ClMessageHighlightHue/255.0f, (float)g_Config.m_ClMessageHighlightSat/255.0f, (float)g_Config.m_ClMessageHighlightLht/255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, 1.0f); } UI()->DoLabelScaled(&Item.m_Rect, pChan->m_Buffer[i].c_str(), 10.0f, -1); TextRender()->TextColor(1,1,1,1); } } UiDoListboxEnd(&s_ChatScrollValue, 0); } else if(pCom->GetType() == CIRCCom::TYPE_QUERY) { CComQuery *pQuery = static_cast<CComQuery*>(pCom); CUIRect Chat, HorizScrollBar; EntryBox.Margin(5.0f, &Chat); Chat.HSplitBottom(15.0f, &Chat, &HorizScrollBar); static CButtonContainer s_HScrollbar; static float s_HScrollbarVal = 0.0f; s_HScrollbarVal = DoScrollbarH(&s_HScrollbar, &HorizScrollBar, s_HScrollbarVal); if(Input()->KeyIsPressed(KEY_LSHIFT) && m_pClient->m_pGameConsole->IsClosed()) { if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) // to the right s_HScrollbarVal += 0.1f; if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) // to the left s_HScrollbarVal -= 0.1f; s_HScrollbarVal = clamp(s_HScrollbarVal, 0.0f, 1.0f); } static CButtonContainer s_Chat; static float s_ChatScrollValue = 1.0f; /*if(!Input()->KeyIsPressed(KEY_LSHIFT) && UI()->MouseInside(&Chat)) { if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) // to the right s_ChatScrollValue -= 0.1f; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) // to the left s_ChatScrollValue += 0.1f; s_ChatScrollValue = clamp(s_ChatScrollValue, 0.0f, 1.0f); }*/ UiDoListboxStart(&s_Chat, &Chat, 12.0f, pQuery->User(), "", (int)pQuery->m_Buffer.size(), 1, -1, s_ChatScrollValue); for(size_t i = 0; i < pQuery->m_Buffer.size(); i++) { CPointerContainer Container(&pQuery->m_Buffer[i]); CListboxItem Item = UiDoListboxNextItem(&Container, false, !Input()->KeyIsPressed(KEY_LSHIFT) && UI()->MouseInside(&Chat)); if(Item.m_Visible) { Item.m_Rect.x -= 1.7f*Item.m_Rect.w * s_HScrollbarVal; if(pQuery->m_Buffer[i].c_str()) if(str_length(pQuery->m_Buffer[i].c_str())) UI()->DoLabelScaled(&Item.m_Rect, pQuery->m_Buffer[i].c_str(), 10.0f, -1); } } UiDoListboxEnd(&s_ChatScrollValue, 0); // the join button if(str_comp_nocase(pQuery->User(), "@status") != 0 && str_comp(pQuery->User(), m_pClient->IRC()->GetNick()) != 0 && ((CComChan*)m_pClient->IRC()->GetCom(1))->GetUser(std::string(pQuery->User())) && // this is kinda inefficient but whatever... !((CComChan*)m_pClient->IRC()->GetCom(1))->GetUser(std::string(pQuery->User()))->IsVoice() && !((CComChan*)m_pClient->IRC()->GetCom(1))->GetUser(std::string(pQuery->User()))->IsAdmin() ) { CUIRect ButtonQS; Chat.VSplitRight(32.0f, 0x0, &ButtonQS); ButtonQS.h = 32.0f; ButtonQS.x -= 20.0f; ButtonQS.y += 25.0f; RenderTools()->DrawUIRect(&ButtonQS, vec4(0.2f, 0.6f, 0.4f, UI()->MouseInside(&ButtonQS) ? 1.0f : 0.6f), CUI::CORNER_ALL, 15.0f); ButtonQS.x += 5.0f; ButtonQS.y += 7.0f; UI()->DoLabelScaled(&ButtonQS, Localize("Join"), 11.0f, -1); //DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_CONNECT, &ButtonQS, vec4(0.47f, 0.58f, 0.72f, 1.0f)); static int s_ButtonQSLog = 0; if(UI()->DoButtonLogic(&s_ButtonQSLog, "", 0, &ButtonQS)) { m_pClient->IRC()->SendGetServer(pQuery->User()); } } } } }
void CMapLayers::OnRender() { if((Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK && !m_pMenuMap)) return; CLayers *pLayers = 0; if(Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK) pLayers = Layers(); else if(m_pMenuMap->IsLoaded()) pLayers = m_pMenuLayers; if(!pLayers) return; CUIRect Screen; Graphics()->GetScreen(&Screen.x, &Screen.y, &Screen.w, &Screen.h); vec2 Center = m_pClient->m_pCamera->m_Center; //float center_x = gameclient.camera->center.x; //float center_y = gameclient.camera->center.y; bool PassedGameLayer = false; for(int g = 0; g < pLayers->NumGroups(); g++) { CMapItemGroup *pGroup = pLayers->GetGroup(g); if(!g_Config.m_GfxNoclip && pGroup->m_Version >= 2 && pGroup->m_UseClipping) { // set clipping float Points[4]; MapScreenToGroup(Center.x, Center.y, pLayers->GameGroup()); Graphics()->GetScreen(&Points[0], &Points[1], &Points[2], &Points[3]); float x0 = (pGroup->m_ClipX - Points[0]) / (Points[2]-Points[0]); float y0 = (pGroup->m_ClipY - Points[1]) / (Points[3]-Points[1]); float x1 = ((pGroup->m_ClipX+pGroup->m_ClipW) - Points[0]) / (Points[2]-Points[0]); float y1 = ((pGroup->m_ClipY+pGroup->m_ClipH) - Points[1]) / (Points[3]-Points[1]); Graphics()->ClipEnable((int)(x0*Graphics()->ScreenWidth()), (int)(y0*Graphics()->ScreenHeight()), (int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight())); } MapScreenToGroup(Center.x, Center.y, pGroup); for(int l = 0; l < pGroup->m_NumLayers; l++) { CMapItemLayer *pLayer = pLayers->GetLayer(pGroup->m_StartLayer+l); bool Render = false; bool IsGameLayer = false; if(pLayer == (CMapItemLayer*)pLayers->GameLayer()) { IsGameLayer = true; PassedGameLayer = 1; } // skip rendering if detail layers if not wanted if(pLayer->m_Flags&LAYERFLAG_DETAIL && !g_Config.m_GfxHighDetail && !IsGameLayer && (Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK)) continue; if(m_Type == -1) Render = true; else if(m_Type == 0) { if(PassedGameLayer && (Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK)) return; Render = true; } else { if(PassedGameLayer && !IsGameLayer) Render = true; } if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_KP0)) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; CTile *pTiles = (CTile *)pLayers->Map()->GetData(pTMap->m_Data); CServerInfo CurrentServerInfo; Client()->GetServerInfo(&CurrentServerInfo); char aFilename[256]; str_format(aFilename, sizeof(aFilename), "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt", CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height); IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(File) { 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_newline(File); } io_close(File); } } if(Render && !IsGameLayer) { //layershot_begin(); if(pLayer->m_Type == LAYERTYPE_TILES) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; if(pTMap->m_Image == -1) Graphics()->TextureClear(); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pTMap->m_Image)); CTile *pTiles = (CTile *)pLayers->Map()->GetData(pTMap->m_Data); Graphics()->BlendNone(); vec4 Color = vec4(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f); RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset); Graphics()->BlendNormal(); RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset); } else if(pLayer->m_Type == LAYERTYPE_QUADS) { CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; if(pQLayer->m_Image == -1) Graphics()->TextureClear(); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pQLayer->m_Image)); CQuad *pQuads = (CQuad *)pLayers->Map()->GetDataSwapped(pQLayer->m_Data); Graphics()->BlendNone(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this); Graphics()->BlendNormal(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this); } //layershot_end(); } } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); // reset the screen like it was before Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); }
void TSRAlphaPass::SubmitRendering( vector< TSRSceneEntity* >& _renderables ) { PROFILE_FUNCTION( "Alpha Pass" ); Graphics()->SetDepthStencilState( Graphics()->m_DepthTestEnabledWriteDisabled ); Graphics()->CopyBackBufferToTexture( *m_pBackBufferTarget ); // now the screen texture is the back buffer copy TSRGlobalConstants.m_BackBuferTexture.Set( *m_pBackBufferTarget ); Graphics()->SetCurrentPass( TWISTER_PASS_ALPHA ); // LightsManager()->GenerateLightingContexts(); LightsManager()->SetShaderConstants(); // if ( KEYUP( 'P' ) ) { m_pWorld->RenderObjectsAlpha( m_pWorld->GetMainCamera() ); } //#define LINES_TEST #ifdef LINES_TEST Graphics()->SetBlendState( Graphics()->m_BlendAdditiveSrcAlphaInvSrcAlpha ); TSRMaterial whiteMaterial; TSRGlobalConstants.SetMaterial( whiteMaterial ); float fStartX = -400.0f; float fStartY = -400.0f; float fEndX = 400.0f; float fEndY = 400.0f; unsigned int iNumGridLinesX = 20; unsigned int iNumGridLinesY = 20; float fStepX = (fEndX - fStartX) / iNumGridLinesX; float fStepY = (fEndY - fStartY) / iNumGridLinesY; bool bRealLines = false; // Graphics()->SetRasterizerState( Graphics()->m_FillDoubleSidedState ); //Graphics()->SetDepthStencilState( Graphics()->m_DefaultDepthStencilState ); if ( bRealLines ) { TSRImmediateDraw::Begin( TWISTER_RENDERMODE_LINELIST ); TSRImmediateDraw::Color4f( 1.0f, 1.0f, 1.0f, 1.0f ); for (unsigned int i = 0; i < iNumGridLinesX; i++) { TSRImmediateDraw::Vertex3f( fStartX + (i)* fStepX, fStartY, 0.0f ); TSRImmediateDraw::Vertex3f( fStartX + (i)* fStepX, fEndY, 0.0f ); } for (unsigned int i = 0; i < iNumGridLinesY; i++) { TSRImmediateDraw::Vertex3f( fStartX, fStartY + i * fStepY, 0.0f ); TSRImmediateDraw::Vertex3f( fEndX, fStartY + i * fStepY, 0.0f ); } TSRImmediateDraw::End();//( Graphics()->m_pVertexColorShader ); } else { static float fLineWidth = 1.0f; TSRImmediateDraw::BeginLines( fLineWidth + 3.0f ); TSRImmediateDraw::LineColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); for (unsigned int i = 0; i < iNumGridLinesX; i++) { TSRImmediateDraw::LineVertex3f( fStartX + (i)* fStepX, fStartY, 0.0f ); TSRImmediateDraw::LineVertex3f( fStartX + (i)* fStepX, fEndY, 0.0f ); } for (unsigned int i = 0; i < iNumGridLinesY; i++) { TSRImmediateDraw::LineVertex3f( fStartX, fStartY + i * fStepY, 0.0f ); TSRImmediateDraw::LineVertex3f( fEndX, fStartY + i * fStepY, 0.0f ); } TSRImmediateDraw::EndLines();//( Graphics()->m_pVertexColorShader ); } #endif if ( Graphics()->GetCurrentPass() == TWISTER_PASS_ALPHA && m_pBackBufferTarget ) { // now the screen texture is the back buffer copy Graphics()->CopyBackBufferToTexture( *m_pBackBufferTarget ); TSRGlobalConstants.m_BackBuferTexture.Set( *m_pBackBufferTarget ); } }
void CPlayers::RenderHook( const CNetObj_Character *pPrevChar, const CNetObj_Character *pPlayerChar, const CNetObj_PlayerInfo *pPrevInfo, const CNetObj_PlayerInfo *pPlayerInfo ) { CNetObj_Character Prev; CNetObj_Character Player; Prev = *pPrevChar; Player = *pPlayerChar; CNetObj_PlayerInfo pInfo = *pPlayerInfo; CTeeRenderInfo RenderInfo = m_pClient->m_aClients[pInfo.m_ClientId].m_RenderInfo; // check for teamplay modes bool IsTeamplay = false; if(m_pClient->m_Snap.m_pGameobj) IsTeamplay = (m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS) != 0; // check for ninja if (Player.m_Weapon == WEAPON_NINJA) { // change the skin for the player to the ninja int Skin = m_pClient->m_pSkins->Find("x_ninja"); if(Skin != -1) { if(IsTeamplay) RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_ColorTexture; else { RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_OrgTexture; RenderInfo.m_ColorBody = vec4(1,1,1,1); RenderInfo.m_ColorFeet = vec4(1,1,1,1); } } } float IntraTick = Client()->IntraGameTick(); if(Player.m_Health < 0) // dont render dead players return; // set size RenderInfo.m_Size = 64.0f; // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pLocalCharacter->m_Health < 0) || (m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver)) { } else { // apply predicted results m_pClient->m_PredictedChar.Write(&Player); m_pClient->m_PredictedPrevChar.Write(&Prev); IntraTick = Client()->PredIntraGameTick(); } } vec2 Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick); if(Prev.m_Health < 0) // Don't flicker from previous position Position = vec2(Player.m_X, Player.m_Y); // draw hook if (Prev.m_HookState>0 && Player.m_HookState>0) { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); //Graphics()->QuadsBegin(); vec2 Pos = Position; vec2 HookPos; if(pPlayerChar->m_HookedPlayer != -1) { if(m_pClient->m_Snap.m_pLocalInfo && pPlayerChar->m_HookedPlayer == m_pClient->m_Snap.m_pLocalInfo->m_ClientId) { if(Client()->State() == IClient::STATE_DEMOPLAYBACK) // only use prediction if needed HookPos = vec2(m_pClient->m_LocalCharacterPos.x, m_pClient->m_LocalCharacterPos.y); else HookPos = mix(vec2(m_pClient->m_PredictedPrevChar.m_Pos.x, m_pClient->m_PredictedPrevChar.m_Pos.y), vec2(m_pClient->m_PredictedChar.m_Pos.x, m_pClient->m_PredictedChar.m_Pos.y), Client()->PredIntraGameTick()); } else HookPos = mix(vec2(pPrevChar->m_HookX, pPrevChar->m_HookY), vec2(pPlayerChar->m_HookX, pPlayerChar->m_HookY), Client()->IntraGameTick()); } else HookPos = mix(vec2(Prev.m_HookX, Prev.m_HookY), vec2(Player.m_HookX, Player.m_HookY), IntraTick); float d = distance(Pos, HookPos); vec2 Dir = normalize(Pos-HookPos); Graphics()->QuadsSetRotation(GetAngle(Dir)+pi); // render head RenderTools()->SelectSprite(SPRITE_HOOK_HEAD); IGraphics::CQuadItem QuadItem(HookPos.x, HookPos.y, 24,16); Graphics()->QuadsDraw(&QuadItem, 1); // render chain RenderTools()->SelectSprite(SPRITE_HOOK_CHAIN); IGraphics::CQuadItem Array[1024]; int i = 0; for(float f = 24; f < d && i < 1024; f += 24, i++) { vec2 p = HookPos + Dir*f; Array[i] = IGraphics::CQuadItem(p.x, p.y,24,16); } Graphics()->QuadsDraw(Array, i); Graphics()->QuadsSetRotation(0); Graphics()->QuadsEnd(); RenderHand(&RenderInfo, Position, normalize(HookPos-Pos), -pi/2, vec2(20, 0)); } }
void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, bool Alpha) { vec2 Direction = Dir; vec2 Position = Pos; //Graphics()->TextureSet(data->images[IMAGE_CHAR_DEFAULT].id); Graphics()->TextureSet(pInfo->m_Texture); // TODO: FIX ME Graphics()->QuadsBegin(); //Graphics()->QuadsDraw(pos.x, pos.y-128, 128, 128); // first pass we draw the outline // second pass we draw the filling for(int p = 0; p < 2; p++) { int OutLine = p==0 ? 1 : 0; for(int f = 0; f < 2; f++) { float AnimScale = pInfo->m_Size * 1.0f/64.0f; float BaseSize = pInfo->m_Size; if(f == 1) { Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle*pi*2); // draw body if(Alpha) Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, pInfo->m_ColorBody.a); else Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, 1.0f); vec2 BodyPos = Position + vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y)*AnimScale; SelectSprite(OutLine?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0); IGraphics::CQuadItem QuadItem(BodyPos.x, BodyPos.y, BaseSize, BaseSize); Graphics()->QuadsDraw(&QuadItem, 1); // draw eyes if(p == 1) { switch (Emote) { case EMOTE_PAIN: SelectSprite(SPRITE_TEE_EYE_PAIN, 0, 0, 0); break; case EMOTE_HAPPY: SelectSprite(SPRITE_TEE_EYE_HAPPY, 0, 0, 0); break; case EMOTE_SURPRISE: SelectSprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, 0); break; case EMOTE_ANGRY: SelectSprite(SPRITE_TEE_EYE_ANGRY, 0, 0, 0); break; default: SelectSprite(SPRITE_TEE_EYE_NORMAL, 0, 0, 0); break; } float EyeScale = BaseSize*0.40f; float h = Emote == EMOTE_BLINK ? BaseSize*0.15f : EyeScale; float EyeSeparation = (0.075f - 0.010f*absolute(Direction.x))*BaseSize; vec2 Offset = vec2(Direction.x*0.125f, -0.05f+Direction.y*0.10f)*BaseSize; IGraphics::CQuadItem Array[2] = { IGraphics::CQuadItem(BodyPos.x-EyeSeparation+Offset.x, BodyPos.y+Offset.y, EyeScale, h), IGraphics::CQuadItem(BodyPos.x+EyeSeparation+Offset.x, BodyPos.y+Offset.y, -EyeScale, h) }; Graphics()->QuadsDraw(Array, 2); } } // draw feet CAnimKeyframe *pFoot = f ? pAnim->GetFrontFoot() : pAnim->GetBackFoot(); float w = BaseSize; float h = BaseSize/2; Graphics()->QuadsSetRotation(pFoot->m_Angle*pi*2); bool Indicate = !pInfo->m_GotAirJump && g_Config.m_ClAirjumpindicator; float cs = 1.0f; // color scale if(OutLine) SelectSprite(SPRITE_TEE_FOOT_OUTLINE, 0, 0, 0); else { SelectSprite(SPRITE_TEE_FOOT, 0, 0, 0); if(Indicate) cs = 0.5f; } if(Alpha) Graphics()->SetColor(pInfo->m_ColorFeet.r*cs, pInfo->m_ColorFeet.g*cs, pInfo->m_ColorFeet.b*cs, pInfo->m_ColorFeet.a*cs); else Graphics()->SetColor(pInfo->m_ColorFeet.r*cs, pInfo->m_ColorFeet.g*cs, pInfo->m_ColorFeet.b*cs, 1.0f); IGraphics::CQuadItem QuadItem(Position.x+pFoot->m_X*AnimScale, Position.y+pFoot->m_Y*AnimScale, w, h); Graphics()->QuadsDraw(&QuadItem, 1); } } Graphics()->QuadsEnd(); }
void CMapLayers::OnRender() { if (Client()->State() != IClient::STATE_OFFLINE && Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) return; else if (Client()->State() == IClient::STATE_OFFLINE && !Client()->BackgroundLoaded()) return; CUIRect Screen; Graphics()->GetScreen(&Screen.x, &Screen.y, &Screen.w, &Screen.h); vec2 Center = m_pClient->m_pCamera->m_Center; //float center_x = gameclient.camera->center.x; //float center_y = gameclient.camera->center.y; CMapItemLayerTilemap *pGTMap = m_pLayers->GameLayer(); CTile *pGameTiles = (CTile *)m_pLayers->Map()->GetData(pGTMap->m_Data); bool PassedGameLayer = false; for(int g = 0; g < m_pLayers->NumGroups(); g++) { CMapItemGroup *pGroup = m_pLayers->GetGroup(g); if (!pGroup) continue; if(!g_Config.m_GfxNoclip && pGroup->m_Version >= 2 && pGroup->m_UseClipping) { // set clipping float Points[4]; MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup()); Graphics()->GetScreen(&Points[0], &Points[1], &Points[2], &Points[3]); float x0 = (pGroup->m_ClipX - Points[0]) / (Points[2]-Points[0]); float y0 = (pGroup->m_ClipY - Points[1]) / (Points[3]-Points[1]); float x1 = ((pGroup->m_ClipX+pGroup->m_ClipW) - Points[0]) / (Points[2]-Points[0]); float y1 = ((pGroup->m_ClipY+pGroup->m_ClipH) - Points[1]) / (Points[3]-Points[1]); Graphics()->ClipEnable((int)(x0*Graphics()->ScreenWidth()), (int)(y0*Graphics()->ScreenHeight()), (int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight())); } MapScreenToGroup(Center.x, Center.y, pGroup, g==0); for(int l = 0; l < pGroup->m_NumLayers; l++) { CMapItemLayer *pLayer = m_pLayers->GetLayer(pGroup->m_StartLayer+l); bool Render = false; bool IsGameLayer = false; if(pLayer == (CMapItemLayer*)m_pLayers->GameLayer()) { IsGameLayer = true; PassedGameLayer = 1; } // skip rendering if detail layers if not wanted if(pLayer->m_Flags&LAYERFLAG_DETAIL && !g_Config.m_GfxHighDetail && !IsGameLayer) continue; if(m_Type == -1) Render = true; else if(m_Type == 0) { if(PassedGameLayer) return; Render = true; } else { if(PassedGameLayer && !IsGameLayer) Render = true; } if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_KP0)) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data); CServerInfo CurrentServerInfo; Client()->GetServerInfo(&CurrentServerInfo); char aFilename[256]; str_format(aFilename, sizeof(aFilename), "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt", CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height); IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorageTW::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_close(File); } } if(Render && !IsGameLayer) { //layershot_begin(); if(pLayer->m_Type == LAYERTYPE_TILES) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; if(pTMap->m_Image == -1) Graphics()->TextureSet(-1); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pTMap->m_Image)); CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data); Graphics()->BlendNone(); vec4 Color = vec4(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f); CServerInfo Info; Client()->GetServerInfo(&Info); int MineTeeLayer = 0; if (str_find_nocase(Info.m_aGameType, "minetee") || str_find_nocase(Info.m_aGameType, "ctf-break")) { if (pTMap == m_pLayers->MineTeeLayer()) MineTeeLayer = 1; else if (pTMap == m_pLayers->MineTeeBGLayer()) MineTeeLayer = 2; else if (pTMap == m_pLayers->MineTeeFGLayer()) MineTeeLayer = 3; } if (m_pLayers->GameLayer() && g_Config.m_ddrShowHiddenWays && str_find_nocase(Info.m_aGameType, "race")) { Graphics()->BlendNormal(); RenderTools()->RenderTilemap(pGameTiles, pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset, MineTeeLayer, false, m_pClient->m_pEffects); } else { Graphics()->BlendNone(); RenderTools()->RenderTilemap(0x0, pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset, MineTeeLayer, false, m_pClient->m_pEffects); Graphics()->BlendNormal(); RenderTools()->RenderTilemap(0x0, pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset, MineTeeLayer, false, m_pClient->m_pEffects); } if (MineTeeLayer == 1) RenderTools()->RenderTilemap(0x0, pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset, MineTeeLayer, true, 0x0); } else if(pLayer->m_Type == LAYERTYPE_QUADS) { CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; if(pQLayer->m_Image == -1) Graphics()->TextureSet(-1); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pQLayer->m_Image)); CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(pQLayer->m_Data); Graphics()->BlendNone(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this); Graphics()->BlendNormal(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this); } //layershot_end(); } } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); } //H-Client //NIGHT-DAY CServerInfo Info; Client()->GetServerInfo(&Info); if (str_find_nocase(Info.m_aGameType,"minetee") && m_pLayers->TileLights() && m_pLayers->MineTeeLayer() && !Graphics()->Tumbtail()) { CTile *pMTLTiles = 0x0; CTile *pMTTiles = 0x0; static int s_LightLevel = 0; if (300 < 0) s_LightLevel = 0; else { int Time = -1; if (m_pClient->m_Snap.m_pGameInfoObj) Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)Client()->GameTickSpeed(); m_MineTeeIsDay = (static_cast<int>(Time/300)%2)?false:true; float tt = Time; int itt = tt/300; tt/=300; if (tt-itt < 0.02) s_LightLevel=(m_MineTeeIsDay)?0:3; else if (tt-itt < 0.025) s_LightLevel=(m_MineTeeIsDay)?1:2; else if (tt-itt < 0.035) s_LightLevel=(m_MineTeeIsDay)?2:1; else if (tt-itt < 0.045) s_LightLevel=(m_MineTeeIsDay)?3:0; else s_LightLevel=(m_MineTeeIsDay)?4:0; } if (s_LightLevel >= 0) { CMapItemLayerTilemap *pMTMap = m_pLayers->MineTeeLayer(); if (pMTMap) pMTTiles = (CTile *)m_pLayers->Map()->GetData(pMTMap->m_Data); if (pMTTiles) RenderTools()->UpdateLights(Collision(), pMTTiles, m_pLayers->TileLights(), Layers()->Lights()->m_Width, Layers()->Lights()->m_Height, s_LightLevel); } } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); // reset the screen like it was before Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); }
void CPlayers::RenderPlayer( const CNetObj_Character *pPrevChar, const CNetObj_Character *pPlayerChar, const CNetObj_PlayerInfo *pPrevInfo, const CNetObj_PlayerInfo *pPlayerInfo ) { CNetObj_Character Prev; CNetObj_Character Player; Prev = *pPrevChar; Player = *pPlayerChar; CNetObj_PlayerInfo pInfo = *pPlayerInfo; CTeeRenderInfo RenderInfo = m_pClient->m_aClients[pInfo.m_ClientId].m_RenderInfo; // check for teamplay modes bool IsTeamplay = false; bool NewTick = m_pClient->m_NewTick; if(m_pClient->m_Snap.m_pGameobj) IsTeamplay = (m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS) != 0; // check for ninja if (Player.m_Weapon == WEAPON_NINJA) { // change the skin for the player to the ninja int Skin = m_pClient->m_pSkins->Find("x_ninja"); if(Skin != -1) { if(IsTeamplay) RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_ColorTexture; else { RenderInfo.m_Texture = m_pClient->m_pSkins->Get(Skin)->m_OrgTexture; RenderInfo.m_ColorBody = vec4(1,1,1,1); RenderInfo.m_ColorFeet = vec4(1,1,1,1); } } } // set size RenderInfo.m_Size = 64.0f; float IntraTick = Client()->IntraGameTick(); if(Player.m_Health < 0) // dont render dead players return; float Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, IntraTick)/256.0f; //float angle = 0; if(pInfo.m_Local && Client()->State() != IClient::STATE_DEMOPLAYBACK) { // just use the direct input if it's local player we are rendering Angle = GetAngle(m_pClient->m_pControls->m_MousePos); } else { /* float mixspeed = Client()->FrameTime()*2.5f; if(player.attacktick != prev.attacktick) // shooting boosts the mixing speed mixspeed *= 15.0f; // move the delta on a constant speed on a x^2 curve float current = g_GameClient.m_aClients[info.cid].angle; float target = player.angle/256.0f; float delta = angular_distance(current, target); float sign = delta < 0 ? -1 : 1; float new_delta = delta - 2*mixspeed*sqrt(delta*sign)*sign + mixspeed*mixspeed; // make sure that it doesn't vibrate when it's still if(fabs(delta) < 2/256.0f) angle = target; else angle = angular_approach(current, target, fabs(delta-new_delta)); g_GameClient.m_aClients[info.cid].angle = angle;*/ } // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pLocalCharacter->m_Health < 0) || (m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver)) { } else { // apply predicted results m_pClient->m_PredictedChar.Write(&Player); m_pClient->m_PredictedPrevChar.Write(&Prev); IntraTick = Client()->PredIntraGameTick(); NewTick = m_pClient->m_NewPredictedTick; } } vec2 Direction = GetDirection((int)(Angle*256.0f)); vec2 Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick); vec2 Vel = mix(vec2(Prev.m_VelX/256.0f, Prev.m_VelY/256.0f), vec2(Player.m_VelX/256.0f, Player.m_VelY/256.0f), IntraTick); m_pClient->m_pFlow->Add(Position, Vel*100.0f, 10.0f); RenderInfo.m_GotAirJump = Player.m_Jumped&2?0:1; // detect events if(NewTick) { // detect air jump if(!RenderInfo.m_GotAirJump && !(Prev.m_Jumped&2)) m_pClient->m_pEffects->AirJump(Position); } if(Prev.m_Health < 0) // Don't flicker from previous position Position = vec2(Player.m_X, Player.m_Y); bool Stationary = Player.m_VelX <= 1 && Player.m_VelX >= -1; bool InAir = !Collision()->CheckPoint(Player.m_X, Player.m_Y+16); bool WantOtherDir = (Player.m_Direction == -1 && Vel.x > 0) || (Player.m_Direction == 1 && Vel.x < 0); // evaluate animation float WalkTime = fmod(absolute(Position.x), 100.0f)/100.0f; CAnimState State; State.Set(&g_pData->m_aAnimations[ANIM_BASE], 0); if(InAir) State.Add(&g_pData->m_aAnimations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here else if(Stationary) State.Add(&g_pData->m_aAnimations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here else if(!WantOtherDir) State.Add(&g_pData->m_aAnimations[ANIM_WALK], WalkTime, 1.0f); if (Player.m_Weapon == WEAPON_HAMMER) { float ct = (Client()->PrevGameTick()-Player.m_AttackTick)/(float)SERVER_TICK_SPEED + Client()->GameTickTime(); State.Add(&g_pData->m_aAnimations[ANIM_HAMMER_SWING], clamp(ct*5.0f,0.0f,1.0f), 1.0f); } if (Player.m_Weapon == WEAPON_NINJA) { float ct = (Client()->PrevGameTick()-Player.m_AttackTick)/(float)SERVER_TICK_SPEED + Client()->GameTickTime(); State.Add(&g_pData->m_aAnimations[ANIM_NINJA_SWING], clamp(ct*2.0f,0.0f,1.0f), 1.0f); } // do skidding if(!InAir && WantOtherDir && length(Vel*50) > 500.0f) { static int64 SkidSoundTime = 0; if(time_get()-SkidSoundTime > time_freq()/10) { m_pClient->m_pSounds->Play(CSounds::CHN_WORLD, SOUND_PLAYER_SKID, 0.25f, Position); SkidSoundTime = time_get(); } m_pClient->m_pEffects->SkidTrail( Position+vec2(-Player.m_Direction*6,12), vec2(-Player.m_Direction*100*length(Vel),-50) ); } // draw gun { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle*pi*2+Angle); // normal weapons int iw = clamp(Player.m_Weapon, 0, NUM_WEAPONS-1); RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_pSpriteBody, Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); vec2 Dir = Direction; float Recoil = 0.0f; vec2 p; if (Player.m_Weapon == WEAPON_HAMMER) { // Static position for hammer p = Position + vec2(State.GetAttach()->m_X, State.GetAttach()->m_Y); p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; // if attack is under way, bash stuffs if(Direction.x < 0) { Graphics()->QuadsSetRotation(-pi/2-State.GetAttach()->m_Angle*pi*2); p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx; } else { Graphics()->QuadsSetRotation(-pi/2+State.GetAttach()->m_Angle*pi*2); } RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize); } else if (Player.m_Weapon == WEAPON_NINJA) { p = Position; p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; if(Direction.x < 0) { Graphics()->QuadsSetRotation(-pi/2-State.GetAttach()->m_Angle*pi*2); p.x -= g_pData->m_Weapons.m_aId[iw].m_Offsetx; m_pClient->m_pEffects->PowerupShine(p+vec2(32,0), vec2(32,12)); } else { Graphics()->QuadsSetRotation(-pi/2+State.GetAttach()->m_Angle*pi*2); m_pClient->m_pEffects->PowerupShine(p-vec2(32,0), vec2(32,12)); } RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize); // HADOKEN if ((Client()->GameTick()-Player.m_AttackTick) <= (SERVER_TICK_SPEED / 6) && g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles) { int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles; float Alpha = 1.0f; if (Alpha > 0.0f && g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX]) { vec2 Dir = vec2(pPlayerChar->m_X,pPlayerChar->m_Y) - vec2(pPrevChar->m_X, pPrevChar->m_Y); Dir = normalize(Dir); float HadOkenAngle = GetAngle(Dir); Graphics()->QuadsSetRotation(HadOkenAngle ); //float offsety = -data->weapons[iw].muzzleoffsety; RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX], 0); vec2 DirY(-Dir.y,Dir.x); p = Position; float OffsetX = g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx; p -= Dir * OffsetX; RenderTools()->DrawSprite(p.x, p.y, 160.0f); } } } else { // TODO: should be an animation Recoil = 0; float a = (Client()->GameTick()-Player.m_AttackTick+IntraTick)/5.0f; if(a < 1) Recoil = sinf(a*pi); p = Position + Dir * g_pData->m_Weapons.m_aId[iw].m_Offsetx - Dir*Recoil*10.0f; p.y += g_pData->m_Weapons.m_aId[iw].m_Offsety; RenderTools()->DrawSprite(p.x, p.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize); } if (Player.m_Weapon == WEAPON_GUN || Player.m_Weapon == WEAPON_SHOTGUN) { // check if we're firing stuff if(g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles)//prev.attackticks) { float Alpha = 0.0f; int Phase1Tick = (Client()->GameTick() - Player.m_AttackTick); if (Phase1Tick < (g_pData->m_Weapons.m_aId[iw].m_Muzzleduration + 3)) { float t = ((((float)Phase1Tick) + IntraTick)/(float)g_pData->m_Weapons.m_aId[iw].m_Muzzleduration); Alpha = mix(2.0f, 0.0f, min(1.0f,max(0.0f,t))); } int IteX = rand() % g_pData->m_Weapons.m_aId[iw].m_NumSpriteMuzzles; if (Alpha > 0.0f && g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX]) { float OffsetY = -g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsety; RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[iw].m_aSpriteMuzzles[IteX], Direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); if(Direction.x < 0) OffsetY = -OffsetY; vec2 DirY(-Dir.y,Dir.x); vec2 MuzzlePos = p + Dir * g_pData->m_Weapons.m_aId[iw].m_Muzzleoffsetx + DirY * OffsetY; RenderTools()->DrawSprite(MuzzlePos.x, MuzzlePos.y, g_pData->m_Weapons.m_aId[iw].m_VisualSize); } } } Graphics()->QuadsEnd(); switch (Player.m_Weapon) { case WEAPON_GUN: RenderHand(&RenderInfo, p, Direction, -3*pi/4, vec2(-15, 4)); break; case WEAPON_SHOTGUN: RenderHand(&RenderInfo, p, Direction, -pi/2, vec2(-5, 4)); break; case WEAPON_GRENADE: RenderHand(&RenderInfo, p, Direction, -pi/2, vec2(-4, 7)); break; } } //--- Antiping // Draw shadows of enemy tees bool LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_LocalCid].m_Team != -1; bool CurPlayerIsEnemy = IsTeamplay == false || (IsTeamplay && m_pClient->m_aClients[m_pClient->m_Snap.m_LocalCid].m_Team != m_pClient->m_aClients[pPlayerInfo->m_ClientId].m_Team); if (g_Config.m_AntiPing && g_Config.m_AntiPing != 2 && // if == 2, than we should show only grenage shadows LocalPlayerInGame && pInfo.m_Local == false && CurPlayerIsEnemy && pPlayerChar && pPlayerChar->m_PlayerState == PLAYERSTATE_PLAYING) { CCharacterCore ShadowPlayer; CNetObj_CharacterCore buf; m_pClient->m_aClients[pPlayerInfo->m_ClientId].m_Predicted.Write(&buf); CWorldCore world; ShadowPlayer.m_pWorld = &world; ShadowPlayer.Reset(); ShadowPlayer.Read(&buf); CNetObj_CharacterCore next; ShadowPlayer.Write(&next); vec2 Prev = m_pClient->m_aClients[pPlayerInfo->m_ClientId].m_PreviousPrediction; vec2 NextVec = vec2(next.m_X, next.m_Y); vec2 ShadowPosition = NextVec; float dist = distance(NextVec, Prev); if (dist < 0) dist *= -1; if (dist < 300) // like it should be usual ShadowPosition = mix(Prev, NextVec, Client()->PredIntraGameTick()); m_pClient->m_aClients[pPlayerInfo->m_ClientId].m_PreviousPrediction = ShadowPosition; CTeeRenderInfo shadow = RenderInfo; float color_body_mix = (shadow.m_ColorBody.r + shadow.m_ColorBody.g + shadow.m_ColorBody.b) / 2.5f; float color_feet_mix = (shadow.m_ColorFeet.r + shadow.m_ColorFeet.g + shadow.m_ColorFeet.b) / 2.5f; shadow.m_ColorBody.a = 0.25f; shadow.m_ColorFeet.a = 0.25f; shadow.m_ColorBody.r = color_body_mix; shadow.m_ColorBody.g = color_body_mix; shadow.m_ColorBody.b = color_body_mix; shadow.m_ColorFeet.r = color_feet_mix; shadow.m_ColorFeet.g = color_feet_mix; shadow.m_ColorFeet.b = color_feet_mix; shadow.m_Texture = m_pClient->m_pSkins->Get(m_pClient->m_aClients[pPlayerInfo->m_ClientId].m_SkinId)->m_ColorTexture; // Render shadow RenderTools()->RenderTee(&State, &shadow, Player.m_Emote, Direction, ShadowPosition); } //--- // render the "shadow" tee if(pInfo.m_Local && (g_Config.m_ClShowGhost || g_Config.m_Debug)) { vec2 GhostPosition = mix(vec2(pPrevChar->m_X, pPrevChar->m_Y), vec2(pPlayerChar->m_X, pPlayerChar->m_Y), Client()->IntraGameTick()); CTeeRenderInfo Ghost = RenderInfo; Ghost.m_ColorBody.a = 0.5f; Ghost.m_ColorFeet.a = 0.5f; RenderTools()->RenderTee(&State, &Ghost, Player.m_Emote, Direction, GhostPosition); // render ghost } RenderInfo.m_Size = 64.0f; // force some settings RenderInfo.m_ColorBody.a = 1.0f; RenderInfo.m_ColorFeet.a = 1.0f; RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position); if(Player.m_PlayerState == PLAYERSTATE_CHATTING) { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_DOTDOT); IGraphics::CQuadItem QuadItem(Position.x + 24, Position.y - 40, 64,64); Graphics()->QuadsDraw(&QuadItem, 1); Graphics()->QuadsEnd(); } if (m_pClient->m_aClients[pInfo.m_ClientId].m_EmoticonStart != -1 && m_pClient->m_aClients[pInfo.m_ClientId].m_EmoticonStart + 2 * Client()->GameTickSpeed() > Client()->GameTick()) { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id); Graphics()->QuadsBegin(); int SinceStart = Client()->GameTick() - m_pClient->m_aClients[pInfo.m_ClientId].m_EmoticonStart; int FromEnd = m_pClient->m_aClients[pInfo.m_ClientId].m_EmoticonStart + 2 * Client()->GameTickSpeed() - Client()->GameTick(); float a = 1; if (FromEnd < Client()->GameTickSpeed() / 5) a = FromEnd / (Client()->GameTickSpeed() / 5.0); float h = 1; if (SinceStart < Client()->GameTickSpeed() / 10) h = SinceStart / (Client()->GameTickSpeed() / 10.0); float Wiggle = 0; if (SinceStart < Client()->GameTickSpeed() / 5) Wiggle = SinceStart / (Client()->GameTickSpeed() / 5.0); float WiggleAngle = sinf(5*Wiggle); Graphics()->QuadsSetRotation(pi/6*WiggleAngle); Graphics()->SetColor(1.0f,1.0f,1.0f,a); // client_datas::emoticon is an offset from the first emoticon RenderTools()->SelectSprite(SPRITE_OOP + m_pClient->m_aClients[pInfo.m_ClientId].m_Emoticon); IGraphics::CQuadItem QuadItem(Position.x, Position.y - 23 - 32*h, 64, 64*h); Graphics()->QuadsDraw(&QuadItem, 1); Graphics()->QuadsEnd(); } }
void CChat::OnRender() { if (!g_Config.m_ClShowChat) return; // send pending chat messages if(m_PendingChatCounter > 0 && m_LastChatSend+time_freq() < time_get()) { CHistoryEntry *pEntry = m_History.Last(); for(int i = m_PendingChatCounter-1; pEntry; --i, pEntry = m_History.Prev(pEntry)) { if(i == 0) { Say(pEntry->m_Team, pEntry->m_aText); break; } } --m_PendingChatCounter; } float Width = 300.0f*Graphics()->ScreenAspect(); Graphics()->MapScreen(0.0f, 0.0f, Width, 300.0f); float x = 5.0f; float y = 300.0f-20.0f; if(m_Mode != MODE_NONE) { // render chat input CTextCursor Cursor; TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER); Cursor.m_LineWidth = Width-190.0f; Cursor.m_MaxLines = 2; if(m_Mode == MODE_ALL) TextRender()->TextEx(&Cursor, Localize("All"), -1); else if(m_Mode == MODE_TEAM) TextRender()->TextEx(&Cursor, Localize("Team"), -1); else TextRender()->TextEx(&Cursor, Localize("Chat"), -1); TextRender()->TextEx(&Cursor, ": ", -1); // check if the visible text has to be moved if(m_InputUpdate) { if(m_ChatStringOffset > 0 && m_Input.GetLength() < m_OldChatStringLength) m_ChatStringOffset = max(0, m_ChatStringOffset-(m_OldChatStringLength-m_Input.GetLength())); if(m_ChatStringOffset > m_Input.GetCursorOffset()) m_ChatStringOffset -= m_ChatStringOffset-m_Input.GetCursorOffset(); else { CTextCursor Temp = Cursor; Temp.m_Flags = 0; TextRender()->TextEx(&Temp, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); TextRender()->TextEx(&Temp, "|", -1); while(Temp.m_LineCount > 2) { ++m_ChatStringOffset; Temp = Cursor; Temp.m_Flags = 0; TextRender()->TextEx(&Temp, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); TextRender()->TextEx(&Temp, "|", -1); } } m_InputUpdate = false; } TextRender()->TextEx(&Cursor, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); static float MarkerOffset = TextRender()->TextWidth(0, 8.0f, "|", -1)/3; CTextCursor Marker = Cursor; Marker.m_X -= MarkerOffset; TextRender()->TextEx(&Marker, "|", -1); TextRender()->TextEx(&Cursor, m_Input.GetString()+m_Input.GetCursorOffset(), -1); } y -= 8.0f; #if defined(__ANDROID__) x += 120.0f; #endif int64 Now = time_get(); float LineWidth = m_pClient->m_pScoreboard->Active() ? 90.0f : 200.0f; float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_Show ? 50.0f : 200.0f; float Begin = x; #if defined(__ANDROID__) float FontSize = 10.0f; #else float FontSize = 6.0f; #endif CTextCursor Cursor; int OffsetType = m_pClient->m_pScoreboard->Active() ? 1 : 0; for(int i = 0; i < MAX_LINES; i++) { int r = ((m_CurrentLine-i)+MAX_LINES)%MAX_LINES; if(Now > m_aLines[r].m_Time+16*time_freq() && !m_Show) break; // get the y offset (calculate it if we haven't done that yet) if(m_aLines[r].m_YOffset[OffsetType] < 0.0f) { TextRender()->SetCursor(&Cursor, Begin, 0.0f, FontSize, 0); Cursor.m_LineWidth = LineWidth; TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1); TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1); m_aLines[r].m_YOffset[OffsetType] = Cursor.m_Y + Cursor.m_FontSize; } y -= m_aLines[r].m_YOffset[OffsetType]; // cut off if msgs waste too much space if(y < HeightLimit) break; float Blend = Now > m_aLines[r].m_Time+14*time_freq() && !m_Show ? 1.0f-(Now-m_aLines[r].m_Time-14*time_freq())/(2.0f*time_freq()) : 1.0f; // reset the cursor TextRender()->SetCursor(&Cursor, Begin, y, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = LineWidth; // render name if (m_aLines[r].m_ClientID == -1) { //TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system vec3 rgb = HslToRgb(vec3(g_Config.m_ClMessageSystemHue / 255.0f, g_Config.m_ClMessageSystemSat / 255.0f, g_Config.m_ClMessageSystemLht / 255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } else if (m_aLines[r].m_Team) TextRender()->TextColor(0.45f, 0.9f, 0.45f, Blend); // team message else if(m_aLines[r].m_NameColor == TEAM_RED) TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // red else if(m_aLines[r].m_NameColor == TEAM_BLUE) TextRender()->TextColor(0.7f, 0.7f, 1.0f, Blend); // blue else if(m_aLines[r].m_NameColor == TEAM_SPECTATORS) TextRender()->TextColor(0.75f, 0.5f, 0.75f, Blend); // spectator else if(m_aLines[r].m_ClientID >= 0 && g_Config.m_ClChatTeamColors && m_pClient->m_Teams.Team(m_aLines[r].m_ClientID)) { vec3 rgb = HslToRgb(vec3(m_pClient->m_Teams.Team(m_aLines[r].m_ClientID) / 64.0f, 1.0f, 0.75f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } else TextRender()->TextColor(0.8f, 0.8f, 0.8f, Blend); TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1); // render line if (m_aLines[r].m_ClientID == -1) { //TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system vec3 rgb = HslToRgb(vec3(g_Config.m_ClMessageSystemHue / 255.0f, g_Config.m_ClMessageSystemSat / 255.0f, g_Config.m_ClMessageSystemLht / 255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } else if (m_aLines[r].m_Highlighted) { //TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // highlighted vec3 rgb = HslToRgb(vec3(g_Config.m_ClMessageHighlightHue / 255.0f, g_Config.m_ClMessageHighlightSat / 255.0f, g_Config.m_ClMessageHighlightLht / 255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } else if (m_aLines[r].m_Team) { //TextRender()->TextColor(0.65f, 1.0f, 0.65f, Blend); // team message vec3 rgb = HslToRgb(vec3(g_Config.m_ClMessageTeamHue / 255.0f, g_Config.m_ClMessageTeamSat / 255.0f, g_Config.m_ClMessageTeamLht / 255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } else { //TextRender()->TextColor(1.0f, 1.0f, 1.0f, Blend); vec3 rgb = HslToRgb(vec3(g_Config.m_ClMessageHue / 255.0f, g_Config.m_ClMessageSat / 255.0f, g_Config.m_ClMessageLht / 255.0f)); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, Blend); } TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1); } TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); #if defined(__ANDROID__) static int deferEvent = 0; if( UI()->AndroidTextInputShown() ) { if(m_Mode == MODE_NONE) { deferEvent++; if( deferEvent > 2 ) EnableMode(0); } else deferEvent = 0; } else { if(m_Mode != MODE_NONE) { deferEvent++; if( deferEvent > 2 ) { IInput::CEvent Event; Event.m_Flags = IInput::FLAG_PRESS; Event.m_Key = KEY_RETURN; OnInput(Event); } } else deferEvent = 0; } #endif }
void CChat::AddLine(int ClientID, int Team, const char *pLine) { if(*pLine == 0 || (ClientID != -1 && (m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client m_pClient->m_aClients[ClientID].m_ChatIgnore || (m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend) || (m_pClient->m_Snap.m_LocalClientID != ClientID && m_pClient->m_aClients[ClientID].m_Foe)))) return; // trim right and set maximum length to 256 utf8-characters int Length = 0; const char *pStr = pLine; const char *pEnd = 0; while(*pStr) { const char *pStrOld = pStr; int Code = str_utf8_decode(&pStr); // check if unicode is not empty if(str_utf8_isspace(Code)) { pEnd = 0; } else if(pEnd == 0) pEnd = pStrOld; if(++Length >= 256) { *(const_cast<char *>(pStr)) = 0; break; } } if(pEnd != 0) *(const_cast<char *>(pEnd)) = 0; bool Highlighted = false; char *p = const_cast<char*>(pLine); while(*p) { Highlighted = false; pLine = p; // find line seperator and strip multiline while(*p) { if(*p++ == '\n') { *(p-1) = 0; break; } } m_CurrentLine = (m_CurrentLine+1)%MAX_LINES; m_aLines[m_CurrentLine].m_Time = time_get(); m_aLines[m_CurrentLine].m_YOffset[0] = -1.0f; m_aLines[m_CurrentLine].m_YOffset[1] = -1.0f; 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 if (Client()->State() != IClient::STATE_DEMOPLAYBACK) { if(ClientID != m_pClient->Client()->m_LocalIDs[0]) { // main character if (LineShouldHighlight(pLine, m_pClient->m_aClients[m_pClient->Client()->m_LocalIDs[0]].m_aName)) Highlighted = true; // dummy if(m_pClient->Client()->DummyConnected() && LineShouldHighlight(pLine, m_pClient->m_aClients[m_pClient->Client()->m_LocalIDs[1]].m_aName)) Highlighted = true; } } else { // on demo playback use local id from snap directly, // since m_LocalIDs isn't valid there if (LineShouldHighlight(pLine, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aName)) Highlighted = true; } m_aLines[m_CurrentLine].m_Highlighted = Highlighted; if(ClientID == -1) // server message { str_copy(m_aLines[m_CurrentLine].m_aName, "*** ", sizeof(m_aLines[m_CurrentLine].m_aName)); str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "%s", pLine); } else { if(m_pClient->m_aClients[ClientID].m_Team == TEAM_SPECTATORS) m_aLines[m_CurrentLine].m_NameColor = TEAM_SPECTATORS; if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) { if(m_pClient->m_aClients[ClientID].m_Team == TEAM_RED) m_aLines[m_CurrentLine].m_NameColor = TEAM_RED; else if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE) m_aLines[m_CurrentLine].m_NameColor = TEAM_BLUE; } if (Team == 2) // whisper send { str_format(m_aLines[m_CurrentLine].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName), "→ %s", m_pClient->m_aClients[ClientID].m_aName); m_aLines[m_CurrentLine].m_NameColor = TEAM_BLUE; m_aLines[m_CurrentLine].m_Highlighted = false; m_aLines[m_CurrentLine].m_Team = 0; Highlighted = false; } else if (Team == 3) // whisper recv { str_format(m_aLines[m_CurrentLine].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName), "← %s", m_pClient->m_aClients[ClientID].m_aName); m_aLines[m_CurrentLine].m_NameColor = TEAM_RED; m_aLines[m_CurrentLine].m_Highlighted = true; m_aLines[m_CurrentLine].m_Team = 0; Highlighted = true; } else { str_copy(m_aLines[m_CurrentLine].m_aName, m_pClient->m_aClients[ClientID].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName)); } str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), ": %s", pLine); } char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, Team >= 2?"whisper":(m_aLines[m_CurrentLine].m_Team?"teamchat":"chat"), aBuf, Highlighted); } // play sound int64 Now = time_get(); if(ClientID == -1) { if(Now-m_aLastSoundPlayed[CHAT_SERVER] >= time_freq()*3/10) { if(g_Config.m_SndServerMessage) { m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_SERVER, 0); m_aLastSoundPlayed[CHAT_SERVER] = Now; } } } else if(Highlighted) { if(Now-m_aLastSoundPlayed[CHAT_HIGHLIGHT] >= time_freq()*3/10) { #ifdef CONF_PLATFORM_MACOSX char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText); CNotification::notify("DDNet-Chat", aBuf); #else Graphics()->NotifyWindow(); #endif if(g_Config.m_SndHighlight) { m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_HIGHLIGHT, 0); m_aLastSoundPlayed[CHAT_HIGHLIGHT] = Now; } } } else if(Team != 2) { if(Now-m_aLastSoundPlayed[CHAT_CLIENT] >= time_freq()*3/10) { if ((g_Config.m_SndTeamChat || !m_aLines[m_CurrentLine].m_Team) && (g_Config.m_SndChat || m_aLines[m_CurrentLine].m_Team)) { m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_CLIENT, 0); m_aLastSoundPlayed[CHAT_CLIENT] = Now; } } } }
void CChat::OnRender() { // send pending chat messages if(m_PendingChatCounter > 0 && m_LastChatSend+time_freq() < time_get()) { CHistoryEntry *pEntry = m_History.Last(); for(int i = m_PendingChatCounter-1; pEntry; --i, pEntry = m_History.Prev(pEntry)) { if(i == 0) { Say(pEntry->m_Team, pEntry->m_aText); break; } } --m_PendingChatCounter; } // dont render chat if the menu is active if(m_pClient->m_pMenus->IsActive()) return; float Width = 300.0f*Graphics()->ScreenAspect(); Graphics()->MapScreen(0.0f, 0.0f, Width, 300.0f); float x = 5.0f; float y = 300.0f-20.0f; if(m_Mode != MODE_NONE) { // render chat input CTextCursor Cursor; TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER); Cursor.m_LineWidth = Width-190.0f; Cursor.m_MaxLines = 2; if(m_Mode == MODE_ALL) TextRender()->TextEx(&Cursor, Localize("All"), -1); else if(m_Mode == MODE_TEAM) TextRender()->TextEx(&Cursor, Localize("Team"), -1); else TextRender()->TextEx(&Cursor, Localize("Chat"), -1); TextRender()->TextEx(&Cursor, ": ", -1); // check if the visible text has to be moved if(m_InputUpdate) { if(m_ChatStringOffset > 0 && m_Input.GetLength() < m_OldChatStringLength) m_ChatStringOffset = max(0, m_ChatStringOffset-(m_OldChatStringLength-m_Input.GetLength())); if(m_ChatStringOffset > m_Input.GetCursorOffset()) m_ChatStringOffset -= m_ChatStringOffset-m_Input.GetCursorOffset(); else { CTextCursor Temp = Cursor; Temp.m_Flags = 0; TextRender()->TextEx(&Temp, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); TextRender()->TextEx(&Temp, "|", -1); while(Temp.m_LineCount > 2) { ++m_ChatStringOffset; Temp = Cursor; Temp.m_Flags = 0; TextRender()->TextEx(&Temp, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); TextRender()->TextEx(&Temp, "|", -1); } } m_InputUpdate = false; } TextRender()->TextEx(&Cursor, m_Input.GetString()+m_ChatStringOffset, m_Input.GetCursorOffset()-m_ChatStringOffset); static float MarkerOffset = TextRender()->TextWidth(0, 8.0f, "|", -1)/3; CTextCursor Marker = Cursor; Marker.m_X -= MarkerOffset; TextRender()->TextEx(&Marker, "|", -1); TextRender()->TextEx(&Cursor, m_Input.GetString()+m_Input.GetCursorOffset(), -1); } y -= 8.0f; int64 Now = time_get(); float LineWidth = m_pClient->m_pScoreboard->Active() ? 90.0f : 200.0f; float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_Show ? 50.0f : 200.0f; float Begin = x; float FontSize = 6.0f; CTextCursor Cursor; int OffsetType = m_pClient->m_pScoreboard->Active() ? 1 : 0; for(int i = 0; i < MAX_LINES; i++) { int r = ((m_CurrentLine-i)+MAX_LINES)%MAX_LINES; if(Now > m_aLines[r].m_Time+16*time_freq() && !m_Show) break; // get the y offset (calculate it if we haven't done that yet) if(m_aLines[r].m_YOffset[OffsetType] < 0.0f) { TextRender()->SetCursor(&Cursor, Begin, 0.0f, FontSize, 0); Cursor.m_LineWidth = LineWidth; TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1); TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1); m_aLines[r].m_YOffset[OffsetType] = Cursor.m_Y + Cursor.m_FontSize; } y -= m_aLines[r].m_YOffset[OffsetType]; // cut off if msgs waste too much space if(y < HeightLimit) break; float Blend = Now > m_aLines[r].m_Time+14*time_freq() && !m_Show ? 1.0f-(Now-m_aLines[r].m_Time-14*time_freq())/(2.0f*time_freq()) : 1.0f; // reset the cursor TextRender()->SetCursor(&Cursor, Begin, y, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = LineWidth; // render name if(m_aLines[r].m_ClientID == -1) TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system else if(m_aLines[r].m_Team) TextRender()->TextColor(0.45f, 0.9f, 0.45f, Blend); // team message else if(m_aLines[r].m_NameColor == TEAM_RED) TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // red else if(m_aLines[r].m_NameColor == TEAM_BLUE) TextRender()->TextColor(0.7f, 0.7f, 1.0f, Blend); // blue else if(m_aLines[r].m_NameColor == TEAM_SPECTATORS) TextRender()->TextColor(0.75f, 0.5f, 0.75f, Blend); // spectator else TextRender()->TextColor(0.8f, 0.8f, 0.8f, Blend); TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1); // render line if(m_aLines[r].m_ClientID == -1) TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system else if(m_aLines[r].m_Highlighted) TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // highlighted else if(m_aLines[r].m_Team) TextRender()->TextColor(0.65f, 1.0f, 0.65f, Blend); // team message else TextRender()->TextColor(1.0f, 1.0f, 1.0f, Blend); TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1); } TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); }
void CMenus::RenderSettingsPlayer(CUIRect MainView) { CUIRect Button; CUIRect LeftView, RightView; MainView.VSplitMid(&LeftView, &RightView); LeftView.HSplitTop(20.0f, &Button, &LeftView); // render settings { char aBuf[128]; LeftView.HSplitTop(20.0f, &Button, &LeftView); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Name")); UI()->DoLabel(&Button, aBuf, 14.0, -1); Button.VSplitLeft(80.0f, 0, &Button); Button.VSplitLeft(180.0f, &Button, 0); static float Offset = 0.0f; if(DoEditBox(g_Config.m_PlayerName, &Button, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 14.0f, &Offset)) m_NeedSendinfo = true; // extra spacing LeftView.HSplitTop(10.0f, 0, &LeftView); static int s_DynamicCameraButton = 0; LeftView.HSplitTop(20.0f, &Button, &LeftView); if(DoButton_CheckBox(&s_DynamicCameraButton, Localize("Dynamic Camera"), g_Config.m_ClMouseDeadzone != 0, &Button)) { if(g_Config.m_ClMouseDeadzone) { g_Config.m_ClMouseFollowfactor = 0; g_Config.m_ClMouseMaxDistance = 400; g_Config.m_ClMouseDeadzone = 0; } else { g_Config.m_ClMouseFollowfactor = 60; g_Config.m_ClMouseMaxDistance = 1000; g_Config.m_ClMouseDeadzone = 300; } } LeftView.HSplitTop(20.0f, &Button, &LeftView); if(DoButton_CheckBox(&g_Config.m_ClAutoswitchWeapons, Localize("Switch weapon on pickup"), g_Config.m_ClAutoswitchWeapons, &Button)) g_Config.m_ClAutoswitchWeapons ^= 1; LeftView.HSplitTop(20.0f, &Button, &LeftView); if(DoButton_CheckBox(&g_Config.m_ClNameplates, Localize("Show name plates"), g_Config.m_ClNameplates, &Button)) g_Config.m_ClNameplates ^= 1; LeftView.HSplitTop(20.0f, &Button, &LeftView); if(g_Config.m_ClNameplates) { Button.VSplitLeft(15.0f, 0, &Button); if(DoButton_CheckBox(&g_Config.m_ClNameplatesAlways, Localize("Always show name plates"), g_Config.m_ClNameplatesAlways, &Button)) g_Config.m_ClNameplatesAlways ^= 1; // draw nameplates size slider CUIRect Label; LeftView.HSplitTop(20.0f, &Button, &LeftView); Button.VSplitLeft(15.0f, 0, &Button); Button.VSplitRight(10.0f, &Button, 0); Button.VSplitLeft(140.0f, &Label, &Button); Button.HMargin(2.0f, &Button); UI()->DoLabel(&Label, Localize("Name plates size"), 13.0f, -1); g_Config.m_ClNameplatesSize = (int)(DoScrollbarH(&g_Config.m_ClNameplatesSize, &Button, g_Config.m_ClNameplatesSize/100.0f)*100.0f+0.1f); } else LeftView.HSplitTop(20.0f, &Button, &LeftView); { const CSkins::CSkin *pOwnSkin = m_pClient->m_pSkins->Get(max(0, m_pClient->m_pSkins->Find(g_Config.m_PlayerSkin))); CTeeRenderInfo OwnSkinInfo; OwnSkinInfo.m_Texture = pOwnSkin->m_OrgTexture; OwnSkinInfo.m_ColorBody = vec4(1, 1, 1, 1); OwnSkinInfo.m_ColorFeet = vec4(1, 1, 1, 1); if(g_Config.m_PlayerUseCustomColor) { OwnSkinInfo.m_ColorBody = m_pClient->m_pSkins->GetColorV4(g_Config.m_PlayerColorBody); OwnSkinInfo.m_ColorFeet = m_pClient->m_pSkins->GetColorV4(g_Config.m_PlayerColorFeet); OwnSkinInfo.m_Texture = pOwnSkin->m_ColorTexture; } OwnSkinInfo.m_Size = 50.0f*UI()->Scale(); LeftView.HSplitTop(20.0f, &Button, &LeftView); LeftView.HSplitTop(20.0f, &Button, &LeftView); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Your skin")); UI()->DoLabelScaled(&Button, aBuf, 14.0f, -1); CUIRect SkinRect; LeftView.VSplitLeft(LeftView.w/1.2f/UI()->Scale(), &SkinRect, 0); SkinRect.HSplitTop(50.0f, &SkinRect, 0); RenderTools()->DrawUIRect(&SkinRect, vec4(1, 1, 1, 0.25f), CUI::CORNER_ALL, 10.0f); Button.VSplitLeft(30.0f, 0, &Button); Button.HSplitTop(50.0f, 0, &Button); RenderTools()->RenderTee(CAnimState::GetIdle(), &OwnSkinInfo, 0, vec2(1, 0), vec2(Button.x, Button.y)); LeftView.HSplitTop(20.0f, &Button, &LeftView); Button.HSplitTop(15.0f, 0, &Button); Button.VSplitLeft(100.0f, 0, &Button); str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_PlayerSkin); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 14.0f*UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = SkinRect.w-(Button.x-SkinRect.x)-5.0f; TextRender()->TextEx(&Cursor, aBuf, -1); } RightView.HSplitTop(20.0f, &Button, &RightView); RightView.HSplitTop(20.0f, &Button, &RightView); if(DoButton_CheckBox(&g_Config.m_PlayerColorBody, Localize("Custom colors"), g_Config.m_PlayerUseCustomColor, &Button)) { g_Config.m_PlayerUseCustomColor = g_Config.m_PlayerUseCustomColor?0:1; m_NeedSendinfo = true; } if(g_Config.m_PlayerUseCustomColor) { int *paColors[2]; paColors[0] = &g_Config.m_PlayerColorBody; paColors[1] = &g_Config.m_PlayerColorFeet; const char *paParts[] = { Localize("Body"), Localize("Feet") }; const char *paLabels[] = { Localize("Hue"), Localize("Sat."), Localize("Lht.") }; static int s_aColorSlider[2][3] = {{0}}; //static float v[2][3] = {{0, 0.5f, 0.25f}, {0, 0.5f, 0.25f}}; for(int i = 0; i < 2; i++) { CUIRect Text; RightView.HSplitTop(20.0f, &Text, &RightView); Text.VSplitLeft(15.0f, 0, &Text); UI()->DoLabelScaled(&Text, paParts[i], 14.0f, -1); int PrevColor = *paColors[i]; int Color = 0; for(int s = 0; s < 3; s++) { CUIRect Text; RightView.HSplitTop(19.0f, &Button, &RightView); Button.VSplitLeft(30.0f, 0, &Button); Button.VSplitLeft(70.0f, &Text, &Button); Button.VSplitRight(5.0f, &Button, 0); Button.HSplitTop(4.0f, 0, &Button); float k = ((PrevColor>>((2-s)*8))&0xff) / 255.0f; k = DoScrollbarH(&s_aColorSlider[i][s], &Button, k); Color <<= 8; Color += clamp((int)(k*255), 0, 255); UI()->DoLabelScaled(&Text, paLabels[s], 15.0f, -1); } if(*paColors[i] != Color) m_NeedSendinfo = true; *paColors[i] = Color; RightView.HSplitTop(5.0f, 0, &RightView); } } MainView.HSplitTop(MainView.h/2, 0, &MainView); // render skinselector static bool s_InitSkinlist = true; static sorted_array<const CSkins::CSkin *> s_paSkinList; static float s_ScrollValue = 0; if(s_InitSkinlist) { s_paSkinList.clear(); for(int i = 0; i < m_pClient->m_pSkins->Num(); ++i) { const CSkins::CSkin *s = m_pClient->m_pSkins->Get(i); // no special skins if(s->m_aName[0] == 'x' && s->m_aName[1] == '_') continue; s_paSkinList.add(s); } s_InitSkinlist = false; } int OldSelected = -1; UiDoListboxStart(&s_InitSkinlist, &MainView, 50.0f, Localize("Skins"), "", s_paSkinList.size(), 4, OldSelected, s_ScrollValue); for(int i = 0; i < s_paSkinList.size(); ++i) { const CSkins::CSkin *s = s_paSkinList[i]; if(s == 0) continue; if(str_comp(s->m_aName, g_Config.m_PlayerSkin) == 0) OldSelected = i; CListboxItem Item = UiDoListboxNextItem(&s_paSkinList[i], OldSelected == i); if(Item.m_Visible) { CTeeRenderInfo Info; Info.m_Texture = s->m_OrgTexture; Info.m_ColorBody = vec4(1, 1, 1, 1); Info.m_ColorFeet = vec4(1, 1, 1, 1); if(g_Config.m_PlayerUseCustomColor) { Info.m_ColorBody = m_pClient->m_pSkins->GetColorV4(g_Config.m_PlayerColorBody); Info.m_ColorFeet = m_pClient->m_pSkins->GetColorV4(g_Config.m_PlayerColorFeet); Info.m_Texture = s->m_ColorTexture; } Info.m_Size = UI()->Scale()*50.0f; Item.m_Rect.HSplitTop(5.0f, 0, &Item.m_Rect); // some margin from the top RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, 0, vec2(1, 0), vec2(Item.m_Rect.x+Item.m_Rect.w/2, Item.m_Rect.y+Item.m_Rect.h/2)); if(g_Config.m_Debug) { vec3 BloodColor = g_Config.m_PlayerUseCustomColor ? m_pClient->m_pSkins->GetColorV3(g_Config.m_PlayerColorBody) : s->m_BloodColor; Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(BloodColor.r, BloodColor.g, BloodColor.b, 1.0f); IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, 12, 12); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } } } const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0); if(OldSelected != NewSelected) { mem_copy(g_Config.m_PlayerSkin, s_paSkinList[NewSelected]->m_aName, sizeof(g_Config.m_PlayerSkin)); m_NeedSendinfo = true; } }
void CRenderTools::DrawSprite(float x, float y, float Size) { IGraphics::CQuadItem QuadItem(x, y, Size*gs_SpriteWScale, Size*gs_SpriteHScale); Graphics()->QuadsDraw(&QuadItem, 1); }
void CHud::RenderScoreHud() { // render small score hud if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { int GameFlags = m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags; float Whole = 300*Graphics()->ScreenAspect(); float StartY = 229.0f; if(GameFlags&GAMEFLAG_TEAMS && m_pClient->m_Snap.m_pGameDataObj) { char aScoreTeam[2][32]; str_format(aScoreTeam[TEAM_RED], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed); str_format(aScoreTeam[TEAM_BLUE], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue); float aScoreTeamWidth[2] = { TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_RED], -1), TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_BLUE], -1) }; int FlagCarrier[2] = { m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed, m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue }; float ScoreWidthMax = max(max(aScoreTeamWidth[TEAM_RED], aScoreTeamWidth[TEAM_BLUE]), TextRender()->TextWidth(0, 14.0f, "100", -1)); float Split = 3.0f; float ImageSize = GameFlags&GAMEFLAG_FLAGS ? 16.0f : Split; for(int t = 0; t < 2; t++) { // draw box Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); if(t == 0) Graphics()->SetColor(1.0f, 0.0f, 0.0f, 0.25f); else Graphics()->SetColor(0.0f, 0.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRectExt(Whole-ScoreWidthMax-ImageSize-2*Split, StartY+t*20, ScoreWidthMax+ImageSize+2*Split, 18.0f, 5.0f, CUI::CORNER_L); Graphics()->QuadsEnd(); // draw score TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreTeamWidth[t])/2-Split, StartY+t*20, 14.0f, aScoreTeam[t], -1); if(GameFlags&GAMEFLAG_FLAGS) { 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))) { // draw flag Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(t==0?SPRITE_FLAG_RED:SPRITE_FLAG_BLUE); IGraphics::CQuadItem QuadItem(Whole-ScoreWidthMax-ImageSize, StartY+1.0f+t*20, ImageSize/2, ImageSize); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } else if(FlagCarrier[t] >= 0) { // draw name of the flag holder int ID = FlagCarrier[t]%MAX_CLIENTS; const char *pName = m_pClient->m_aClients[ID].m_aName; float w = TextRender()->TextWidth(0, 8.0f, pName, -1); TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, pName, -1); // draw tee of the flag holder CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo; Info.m_Size = 18.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20)); } } StartY += 8.0f; } } else { int Local = -1; int aPos[2] = { 1, 2 }; const CNetObj_PlayerInfo *apPlayerInfo[2] = { 0, 0 }; int i = 0; for(int t = 0; t < 2 && i < MAX_CLIENTS && m_pClient->m_Snap.m_paInfoByScore[i]; ++i) { if(m_pClient->m_Snap.m_paInfoByScore[i]->m_Team != TEAM_SPECTATORS) { apPlayerInfo[t] = m_pClient->m_Snap.m_paInfoByScore[i]; if(apPlayerInfo[t]->m_ClientID == m_pClient->m_Snap.m_LocalClientID) Local = t; ++t; } } // search local player info if not a spectator, nor within top2 scores if(Local == -1 && m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS) { for(; i < MAX_CLIENTS && m_pClient->m_Snap.m_paInfoByScore[i]; ++i) { if(m_pClient->m_Snap.m_paInfoByScore[i]->m_Team != TEAM_SPECTATORS) ++aPos[1]; if(m_pClient->m_Snap.m_paInfoByScore[i]->m_ClientID == m_pClient->m_Snap.m_LocalClientID) { apPlayerInfo[1] = m_pClient->m_Snap.m_paInfoByScore[i]; Local = 1; break; } } } char aScore[2][32]; for(int t = 0; t < 2; ++t) { if(apPlayerInfo[t]) str_format(aScore[t], sizeof(aScore)/2, "%d", apPlayerInfo[t]->m_Score); else aScore[t][0] = 0; } float aScoreWidth[2] = {TextRender()->TextWidth(0, 14.0f, aScore[0], -1), TextRender()->TextWidth(0, 14.0f, aScore[1], -1)}; float ScoreWidthMax = max(max(aScoreWidth[0], aScoreWidth[1]), TextRender()->TextWidth(0, 14.0f, "10", -1)); float Split = 3.0f, ImageSize = 16.0f, PosSize = 16.0f; for(int t = 0; t < 2; t++) { // draw box Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); if(t == Local) Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); else Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.25f); RenderTools()->DrawRoundRectExt(Whole-ScoreWidthMax-ImageSize-2*Split-PosSize, StartY+t*20, ScoreWidthMax+ImageSize+2*Split+PosSize, 18.0f, 5.0f, CUI::CORNER_L); Graphics()->QuadsEnd(); // draw score TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreWidth[t])/2-Split, StartY+t*20, 14.0f, aScore[t], -1); if(apPlayerInfo[t]) { // draw name int ID = apPlayerInfo[t]->m_ClientID; const char *pName = m_pClient->m_aClients[ID].m_aName; float w = TextRender()->TextWidth(0, 8.0f, pName, -1); TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split-PosSize), StartY+(t+1)*20.0f-3.0f, 8.0f, pName, -1); // draw tee CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo; Info.m_Size = 18.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20)); } // draw position char aBuf[32]; str_format(aBuf, sizeof(aBuf), "%d.", aPos[t]); TextRender()->Text(0, Whole-ScoreWidthMax-ImageSize-Split-PosSize, StartY+2.0f+t*20, 10.0f, aBuf, -1); StartY += 8.0f; } } } }
void CRenderTools::DrawRoundRectExt(float x, float y, float w, float h, float r, int Corners) { IGraphics::CFreeformItem ArrayF[32]; int NumItems = 0; int Num = 8; for(int i = 0; i < Num; i+=2) { float a1 = i/(float)Num * pi/2; float a2 = (i+1)/(float)Num * pi/2; float a3 = (i+2)/(float)Num * pi/2; float Ca1 = cosf(a1); float Ca2 = cosf(a2); float Ca3 = cosf(a3); float Sa1 = sinf(a1); float Sa2 = sinf(a2); float Sa3 = sinf(a3); if(Corners&1) // TL ArrayF[NumItems++] = IGraphics::CFreeformItem( x+r, y+r, x+(1-Ca1)*r, y+(1-Sa1)*r, x+(1-Ca3)*r, y+(1-Sa3)*r, x+(1-Ca2)*r, y+(1-Sa2)*r); if(Corners&2) // TR ArrayF[NumItems++] = IGraphics::CFreeformItem( x+w-r, y+r, x+w-r+Ca1*r, y+(1-Sa1)*r, x+w-r+Ca3*r, y+(1-Sa3)*r, x+w-r+Ca2*r, y+(1-Sa2)*r); if(Corners&4) // BL ArrayF[NumItems++] = IGraphics::CFreeformItem( x+r, y+h-r, x+(1-Ca1)*r, y+h-r+Sa1*r, x+(1-Ca3)*r, y+h-r+Sa3*r, x+(1-Ca2)*r, y+h-r+Sa2*r); if(Corners&8) // BR ArrayF[NumItems++] = IGraphics::CFreeformItem( x+w-r, y+h-r, x+w-r+Ca1*r, y+h-r+Sa1*r, x+w-r+Ca3*r, y+h-r+Sa3*r, x+w-r+Ca2*r, y+h-r+Sa2*r); } Graphics()->QuadsDrawFreeform(ArrayF, NumItems); IGraphics::CQuadItem ArrayQ[9]; NumItems = 0; ArrayQ[NumItems++] = IGraphics::CQuadItem(x+r, y+r, w-r*2, h-r*2); // center ArrayQ[NumItems++] = IGraphics::CQuadItem(x+r, y, w-r*2, r); // top ArrayQ[NumItems++] = IGraphics::CQuadItem(x+r, y+h-r, w-r*2, r); // bottom ArrayQ[NumItems++] = IGraphics::CQuadItem(x, y+r, r, h-r*2); // left ArrayQ[NumItems++] = IGraphics::CQuadItem(x+w-r, y+r, r, h-r*2); // right if(!(Corners&1)) ArrayQ[NumItems++] = IGraphics::CQuadItem(x, y, r, r); // TL if(!(Corners&2)) ArrayQ[NumItems++] = IGraphics::CQuadItem(x+w, y, -r, r); // TR if(!(Corners&4)) ArrayQ[NumItems++] = IGraphics::CQuadItem(x, y+h, r, -r); // BL if(!(Corners&8)) ArrayQ[NumItems++] = IGraphics::CQuadItem(x+w, y+h, -r, -r); // BR Graphics()->QuadsDrawTL(ArrayQ, NumItems); }
void CGameClient::OnConsoleInit() { m_pEngine = Kernel()->RequestInterface<IEngine>(); m_pClient = Kernel()->RequestInterface<IClient>(); m_pGraphics = Kernel()->RequestInterface<IGraphics>(); m_pTextRender = Kernel()->RequestInterface<ITextRender>(); m_pSound = Kernel()->RequestInterface<ISound>(); m_pInput = Kernel()->RequestInterface<IInput>(); m_pConsole = Kernel()->RequestInterface<IConsole>(); m_pStorage = Kernel()->RequestInterface<IStorage>(); m_pDemoPlayer = Kernel()->RequestInterface<IDemoPlayer>(); m_pDemoRecorder = Kernel()->RequestInterface<IDemoRecorder>(); m_pServerBrowser = Kernel()->RequestInterface<IServerBrowser>(); m_pEditor = Kernel()->RequestInterface<IEditor>(); m_pFriends = Kernel()->RequestInterface<IFriends>(); // setup pointers m_pBinds = &::gs_Binds; m_pGameConsole = &::gs_GameConsole; m_pParticles = &::gs_Particles; m_pMenus = &::gs_Menus; m_pSkins = &::gs_Skins; m_pCountryFlags = &::gs_CountryFlags; m_pChat = &::gs_Chat; m_pFlow = &::gs_Flow; m_pCamera = &::gs_Camera; m_pControls = &::gs_Controls; m_pEffects = &::gs_Effects; m_pSounds = &::gs_Sounds; m_pMotd = &::gs_Motd; m_pDamageind = &::gsDamageInd; m_pMapimages = &::gs_MapImages; m_pVoting = &::gs_Voting; m_pScoreboard = &::gs_Scoreboard; m_pItems = &::gs_Items; // make a list of all the systems, make sure to add them in the corrent render order m_All.Add(m_pSkins); m_All.Add(m_pCountryFlags); m_All.Add(m_pMapimages); m_All.Add(m_pEffects); // doesn't render anything, just updates effects m_All.Add(m_pParticles); m_All.Add(m_pBinds); m_All.Add(m_pControls); m_All.Add(m_pCamera); m_All.Add(m_pSounds); m_All.Add(m_pVoting); m_All.Add(m_pParticles); // doesn't render anything, just updates all the particles m_All.Add(&gs_MapLayersBackGround); // first to render m_All.Add(&m_pParticles->m_RenderTrail); m_All.Add(m_pItems); m_All.Add(&gs_Players); m_All.Add(&gs_MapLayersForeGround); m_All.Add(&m_pParticles->m_RenderExplosions); m_All.Add(&gs_NamePlates); m_All.Add(&m_pParticles->m_RenderGeneral); m_All.Add(m_pDamageind); m_All.Add(&gs_Hud); m_All.Add(&gs_Spectator); m_All.Add(&gs_Emoticon); m_All.Add(&gs_KillMessages); m_All.Add(m_pChat); m_All.Add(&gs_Broadcast); m_All.Add(&gs_DebugHud); m_All.Add(&gs_Scoreboard); m_All.Add(m_pMotd); m_All.Add(m_pMenus); m_All.Add(m_pGameConsole); // build the input stack m_Input.Add(&m_pMenus->m_Binder); // this will take over all input when we want to bind a key m_Input.Add(&m_pBinds->m_SpecialBinds); m_Input.Add(m_pGameConsole); m_Input.Add(m_pChat); // chat has higher prio due to tha you can quit it by pressing esc m_Input.Add(m_pMotd); // for pressing esc to remove it m_Input.Add(m_pMenus); m_Input.Add(&gs_Spectator); m_Input.Add(&gs_Emoticon); m_Input.Add(m_pControls); m_Input.Add(m_pBinds); // add the some console commands Console()->Register("team", "i", CFGFLAG_CLIENT, ConTeam, this, "Switch team"); Console()->Register("kill", "", CFGFLAG_CLIENT, ConKill, this, "Kill yourself"); // register server dummy commands for tab completion Console()->Register("tune", "si", CFGFLAG_SERVER, 0, 0, "Tune variable to value"); Console()->Register("tune_reset", "", CFGFLAG_SERVER, 0, 0, "Reset tuning"); Console()->Register("tune_dump", "", CFGFLAG_SERVER, 0, 0, "Dump tuning"); Console()->Register("change_map", "?r", CFGFLAG_SERVER, 0, 0, "Change map"); Console()->Register("restart", "?i", CFGFLAG_SERVER, 0, 0, "Restart in x seconds"); Console()->Register("broadcast", "r", CFGFLAG_SERVER, 0, 0, "Broadcast message"); Console()->Register("say", "r", CFGFLAG_SERVER, 0, 0, "Say in chat"); Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, 0, 0, "Set team of player to team"); Console()->Register("set_team_all", "i", CFGFLAG_SERVER, 0, 0, "Set team of all players to team"); Console()->Register("add_vote", "sr", CFGFLAG_SERVER, 0, 0, "Add a voting option"); Console()->Register("remove_vote", "s", CFGFLAG_SERVER, 0, 0, "remove a voting option"); Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, 0, 0, "Force a voting option"); Console()->Register("clear_votes", "", CFGFLAG_SERVER, 0, 0, "Clears the voting options"); 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; // let all the other components register their console commands for(int i = 0; i < m_All.m_Num; i++) m_All.m_paComponents[i]->OnConsoleInit(); // Console()->Chain("player_name", ConchainSpecialInfoupdate, this); Console()->Chain("player_clan", ConchainSpecialInfoupdate, this); Console()->Chain("player_country", ConchainSpecialInfoupdate, this); Console()->Chain("player_use_custom_color", ConchainSpecialInfoupdate, this); Console()->Chain("player_color_body", ConchainSpecialInfoupdate, this); Console()->Chain("player_color_feet", ConchainSpecialInfoupdate, this); Console()->Chain("player_skin", ConchainSpecialInfoupdate, this); // m_SuppressEvents = false; }
void CMenus::OnRender() { /* // text rendering test stuff render_background(); CTextCursor cursor; TextRender()->SetCursor(&cursor, 10, 10, 20, TEXTFLAG_RENDER); TextRender()->TextEx(&cursor, "ようこそ - ガイド", -1); TextRender()->SetCursor(&cursor, 10, 30, 15, TEXTFLAG_RENDER); TextRender()->TextEx(&cursor, "ようこそ - ガイド", -1); //Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->QuadsDrawTL(60, 60, 5000, 5000); Graphics()->QuadsEnd(); return;*/ if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) SetActive(true); if(Client()->State() == IClient::STATE_DEMOPLAYBACK) { CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); RenderDemoPlayer(Screen); } if(Client()->State() == IClient::STATE_ONLINE && m_pClient->m_ServerMode == m_pClient->SERVERMODE_PUREMOD) { Client()->Disconnect(); SetActive(true); m_Popup = POPUP_PURE; } if(!IsActive()) { m_EscapePressed = false; m_EnterPressed = false; m_DeletePressed = false; m_NumInputEvents = 0; return; } // update colors vec3 Rgb = HslToRgb(vec3(g_Config.m_UiColorHue/255.0f, g_Config.m_UiColorSat/255.0f, g_Config.m_UiColorLht/255.0f)); ms_GuiColor = vec4(Rgb.r, Rgb.g, Rgb.b, g_Config.m_UiColorAlpha/255.0f); ms_ColorTabbarInactiveOutgame = vec4(0,0,0,0.25f); ms_ColorTabbarActiveOutgame = vec4(0,0,0,0.5f); float ColorIngameScaleI = 0.5f; float ColorIngameAcaleA = 0.2f; ms_ColorTabbarInactiveIngame = vec4( ms_GuiColor.r*ColorIngameScaleI, ms_GuiColor.g*ColorIngameScaleI, ms_GuiColor.b*ColorIngameScaleI, ms_GuiColor.a*0.8f); ms_ColorTabbarActiveIngame = vec4( ms_GuiColor.r*ColorIngameAcaleA, ms_GuiColor.g*ColorIngameAcaleA, ms_GuiColor.b*ColorIngameAcaleA, ms_GuiColor.a); // update the ui CUIRect *pScreen = UI()->Screen(); float mx = (m_MousePos.x/(float)Graphics()->ScreenWidth())*pScreen->w; float my = (m_MousePos.y/(float)Graphics()->ScreenHeight())*pScreen->h; int Buttons = 0; if(m_UseMouseButtons) { if(Input()->KeyPressed(KEY_MOUSE_1)) Buttons |= 1; if(Input()->KeyPressed(KEY_MOUSE_2)) Buttons |= 2; if(Input()->KeyPressed(KEY_MOUSE_3)) Buttons |= 4; } UI()->Update(mx,my,mx*3.0f,my*3.0f,Buttons); // render if(Client()->State() != IClient::STATE_DEMOPLAYBACK) Render(); // render cursor Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1,1,1,1); IGraphics::CQuadItem QuadItem(mx, my, 24, 24); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // render debug information if(g_Config.m_Debug) { CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%p %p %p", UI()->HotItem(), UI()->ActiveItem(), UI()->LastActiveItem()); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, 10, 10, 10, TEXTFLAG_RENDER); TextRender()->TextEx(&Cursor, aBuf, -1); } m_EscapePressed = false; m_EnterPressed = false; m_DeletePressed = false; m_NumInputEvents = 0; }
TSRAlphaPass::TSRAlphaPass( TSRSceneWorldInterface* _pWorld ): m_pWorld( _pWorld ) { m_pBackBufferTarget = new TSRRenderTarget( Graphics()->m_uiWidth, Graphics()->m_uiHeight, TWISTER_TEXTUREFORMAT_A8R8G8B8 ); }
void CMenus::RenderBackground() { //Graphics()->Clear(1,1,1); //render_sunrays(0,0); if(gs_TextureBlob == -1) gs_TextureBlob = Graphics()->LoadTexture("blob.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); float sw = 300*Graphics()->ScreenAspect(); float sh = 300; Graphics()->MapScreen(0, 0, sw, sh); // render background color Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); //vec4 bottom(gui_color.r*0.3f, gui_color.g*0.3f, gui_color.b*0.3f, 1.0f); //vec4 bottom(0, 0, 0, 1.0f); vec4 Bottom(ms_GuiColor.r, ms_GuiColor.g, ms_GuiColor.b, 1.0f); vec4 Top(ms_GuiColor.r, ms_GuiColor.g, ms_GuiColor.b, 1.0f); IGraphics::CColorVertex Array[4] = { IGraphics::CColorVertex(0, Top.r, Top.g, Top.b, Top.a), IGraphics::CColorVertex(1, Top.r, Top.g, Top.b, Top.a), IGraphics::CColorVertex(2, Bottom.r, Bottom.g, Bottom.b, Bottom.a), IGraphics::CColorVertex(3, Bottom.r, Bottom.g, Bottom.b, Bottom.a)}; Graphics()->SetColorVertex(Array, 4); IGraphics::CQuadItem QuadItem(0, 0, sw, sh); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // render the tiles Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); float Size = 15.0f; float OffsetTime = fmod(Client()->LocalTime()*0.15f, 2.0f); for(int y = -2; y < (int)(sw/Size); y++) for(int x = -2; x < (int)(sh/Size); x++) { Graphics()->SetColor(0,0,0,0.045f); IGraphics::CQuadItem QuadItem((x-OffsetTime)*Size*2+(y&1)*Size, (y+OffsetTime)*Size, Size, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); } Graphics()->QuadsEnd(); // render border fade Graphics()->TextureSet(gs_TextureBlob); Graphics()->QuadsBegin(); Graphics()->SetColor(0,0,0,0.5f); QuadItem = IGraphics::CQuadItem(-100, -100, sw+200, sh+200); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // restore screen {CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h);} }
void CMapLayers::OnRender() { if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) return; CUIRect Screen; Graphics()->GetScreen(&Screen.x, &Screen.y, &Screen.w, &Screen.h); vec2 Center = m_pClient->m_pCamera->m_Center; //float center_x = gameclient.camera->center.x; //float center_y = gameclient.camera->center.y; bool PassedGameLayer = false; for(int g = 0; g < m_pLayers->NumGroups(); g++) { CMapItemGroup *pGroup = m_pLayers->GetGroup(g); if(!pGroup) { dbg_msg("MapLayers", "Error:Group was null, Group Number = %d, Total Groups = %d", g, m_pLayers->NumGroups()); dbg_msg("MapLayers", "This is here to prevent a crash but the source of this is unknown, please report this for it to get fixed"); dbg_msg("MapLayers", "we need mapname and crc and the map that caused this if possible, and anymore info you think is relevant"); continue; } if(!g_Config.m_GfxNoclip && pGroup->m_Version >= 2 && pGroup->m_UseClipping) { // set clipping float Points[4]; MapScreenToGroup(Center.x, Center.y, m_pLayers->GameGroup(), m_pClient->m_pCamera->m_Zoom); Graphics()->GetScreen(&Points[0], &Points[1], &Points[2], &Points[3]); float x0 = (pGroup->m_ClipX - Points[0]) / (Points[2]-Points[0]); float y0 = (pGroup->m_ClipY - Points[1]) / (Points[3]-Points[1]); float x1 = ((pGroup->m_ClipX+pGroup->m_ClipW) - Points[0]) / (Points[2]-Points[0]); float y1 = ((pGroup->m_ClipY+pGroup->m_ClipH) - Points[1]) / (Points[3]-Points[1]); Graphics()->ClipEnable((int)(x0*Graphics()->ScreenWidth()), (int)(y0*Graphics()->ScreenHeight()), (int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight())); } MapScreenToGroup(Center.x, Center.y, pGroup, m_pClient->m_pCamera->m_Zoom); for(int l = 0; l < pGroup->m_NumLayers; l++) { CMapItemLayer *pLayer = m_pLayers->GetLayer(pGroup->m_StartLayer+l); bool Render = false; bool IsGameLayer = false; if(pLayer == (CMapItemLayer*)m_pLayers->GameLayer()) { IsGameLayer = true; PassedGameLayer = 1; } // skip rendering if detail layers if not wanted if(pLayer->m_Flags&LAYERFLAG_DETAIL && !g_Config.m_GfxHighDetail && !IsGameLayer) continue; if(m_Type == -1) Render = true; else if(m_Type == 0) { if(PassedGameLayer) return; Render = true; } else { if(PassedGameLayer && !IsGameLayer) Render = true; } if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_KP0)) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data); CServerInfo CurrentServerInfo; Client()->GetServerInfo(&CurrentServerInfo); char aFilename[256]; str_format(aFilename, sizeof(aFilename), "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt", CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height); 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_close(File); } } if(Render && !IsGameLayer) { //layershot_begin(); if(pLayer->m_Type == LAYERTYPE_TILES) { CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; if(pTMap->m_Image == -1) Graphics()->TextureSet(-1); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pTMap->m_Image)); CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data); Graphics()->BlendNone(); vec4 Color = vec4(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f); RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); Graphics()->BlendNormal(); RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); } else if(pLayer->m_Type == LAYERTYPE_QUADS) { CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; if(pQLayer->m_Image == -1) Graphics()->TextureSet(-1); else Graphics()->TextureSet(m_pClient->m_pMapimages->Get(pQLayer->m_Image)); CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(pQLayer->m_Data); Graphics()->BlendNone(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this); Graphics()->BlendNormal(); RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this); } //layershot_end(); } } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); } if(!g_Config.m_GfxNoclip) Graphics()->ClipDisable(); // reset the screen like it was before Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); }
void CMenus::RenderLoading() { static int64 LastLoadRender = 0; float Percent = m_LoadCurrent++/(float)m_LoadTotal; // make sure that we don't render for each little thing we load // because that will slow down loading if we have vsync if(time_get()-LastLoadRender < time_freq()/60) return; LastLoadRender = time_get(); // need up date this here to get correct vec3 Rgb = HslToRgb(vec3(g_Config.m_UiColorHue/255.0f, g_Config.m_UiColorSat/255.0f, g_Config.m_UiColorLht/255.0f)); ms_GuiColor = vec4(Rgb.r, Rgb.g, Rgb.b, g_Config.m_UiColorAlpha/255.0f); CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); RenderBackground(); float tw; float w = 700; float h = 200; float x = Screen.w/2-w/2; float y = Screen.h/2-h/2; Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(0,0,0,0.50f); RenderTools()->DrawRoundRect(x, y, w, h, 40.0f); Graphics()->QuadsEnd(); const char *pCaption = Localize("Loading"); tw = TextRender()->TextWidth(0, 48.0f, pCaption, -1); CUIRect r; r.x = x; r.y = y+20; r.w = w; r.h = h; UI()->DoLabel(&r, pCaption, 48.0f, 0, -1); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1,1,1,0.75f); RenderTools()->DrawRoundRect(x+40, y+h-75, (w-80)*Percent, 25, 5.0f); Graphics()->QuadsEnd(); Graphics()->Swap(); }
void CSpectator::OnRender() { if(!m_Active) { if(m_WasActive) { if(m_SelectedSpectatorID != NO_SELECTION) Spectate(m_SelectedSpectatorID); m_WasActive = false; } return; } m_WasActive = true; m_SelectedSpectatorID = NO_SELECTION; // draw background float Width = 400*3.0f*Graphics()->ScreenAspect(); float Height = 400*3.0f; Graphics()->MapScreen(0, 0, Width, Height); Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.3f); RenderTools()->DrawRoundRect(Width/2.0f-300.0f, Height/2.0f-300.0f, 600.0f, 600.0f, 20.0f); Graphics()->QuadsEnd(); // clamp mouse position to selector area m_SelectorMouse.x = clamp(m_SelectorMouse.x, -280.0f, 280.0f); m_SelectorMouse.y = clamp(m_SelectorMouse.y, -280.0f, 280.0f); // draw selections float FontSize = 20.0f; float StartY = -190.0f; float LineHeight = 60.0f; bool Selected = false; if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f); Graphics()->QuadsEnd(); } if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f && m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f) { m_SelectedSpectatorID = SPEC_FREEVIEW; Selected = true; } TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f); TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1); float x = -270.0f, y = StartY; for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) { if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS) continue; if(++Count%9 == 0) { x += 290.0f; y = StartY; } if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == i) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRect(Width/2.0f+x-10.0f, Height/2.0f+y-10.0f, 270.0f, 60.0f, 20.0f); Graphics()->QuadsEnd(); } Selected = false; if(m_SelectorMouse.x >= x-10.0f && m_SelectorMouse.x <= x+260.0f && m_SelectorMouse.y >= y-10.0f && m_SelectorMouse.y <= y+50.0f) { m_SelectedSpectatorID = i; Selected = true; } TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f); TextRender()->Text(0, Width/2.0f+x+50.0f, Height/2.0f+y+5.0f, FontSize, m_pClient->m_aClients[i].m_aName, 220.0f); // flag if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS && m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == m_pClient->m_Snap.m_paPlayerInfos[i]->m_ClientID || m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == m_pClient->m_Snap.m_paPlayerInfos[i]->m_ClientID)) { Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); float Size = LineHeight; IGraphics::CQuadItem QuadItem(Width/2.0f+x-LineHeight/5.0f, Height/2.0f+y-LineHeight/3.0f, Size/2.0f, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } CTeeRenderInfo TeeInfo = m_pClient->m_aClients[i].m_RenderInfo; RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Width/2.0f+x+20.0f, Height/2.0f+y+20.0f)); y += LineHeight; } TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); // draw cursor Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); IGraphics::CQuadItem QuadItem(m_SelectorMouse.x+Width/2.0f, m_SelectorMouse.y+Height/2.0f, 48.0f, 48.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); }
int CMenus::Render() { CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); static bool s_First = true; if(s_First) { if(g_Config.m_UiPage == PAGE_INTERNET) ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); else if(g_Config.m_UiPage == PAGE_LAN) ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); else if(g_Config.m_UiPage == PAGE_FAVORITES) ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES); s_First = false; } if(Client()->State() == IClient::STATE_ONLINE) { ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame; ms_ColorTabbarActive = ms_ColorTabbarActiveIngame; } else { RenderBackground(); ms_ColorTabbarInactive = ms_ColorTabbarInactiveOutgame; ms_ColorTabbarActive = ms_ColorTabbarActiveOutgame; } CUIRect TabBar; CUIRect MainView; // some margin around the screen Screen.Margin(10.0f, &Screen); static bool s_SoundCheck = false; if(!s_SoundCheck && m_Popup == POPUP_NONE) { if(Client()->SoundInitFailed()) m_Popup = POPUP_SOUNDERROR; s_SoundCheck = true; } if(m_Popup == POPUP_NONE) { // do tab bar Screen.HSplitTop(24.0f, &TabBar, &MainView); TabBar.VMargin(20.0f, &TabBar); RenderMenubar(TabBar); // news is not implemented yet if(g_Config.m_UiPage <= PAGE_NEWS || g_Config.m_UiPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiPage >= PAGE_GAME && g_Config.m_UiPage <= PAGE_CALLVOTE)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); g_Config.m_UiPage = PAGE_INTERNET; } // render current page if(Client()->State() != IClient::STATE_OFFLINE) { if(m_GamePage == PAGE_GAME) RenderGame(MainView); else if(m_GamePage == PAGE_PLAYERS) RenderPlayers(MainView); else if(m_GamePage == PAGE_SERVER_INFO) RenderServerInfo(MainView); else if(m_GamePage == PAGE_CALLVOTE) RenderServerControl(MainView); else if(m_GamePage == PAGE_SETTINGS) RenderSettings(MainView); } else if(g_Config.m_UiPage == PAGE_NEWS) RenderNews(MainView); else if(g_Config.m_UiPage == PAGE_INTERNET) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_LAN) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_DEMOS) RenderDemoList(MainView); else if(g_Config.m_UiPage == PAGE_FAVORITES) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_SETTINGS) RenderSettings(MainView); } else { // make sure that other windows doesn't do anything funnay! //UI()->SetHotItem(0); //UI()->SetActiveItem(0); char aBuf[128]; const char *pTitle = ""; const char *pExtraText = ""; const char *pButtonText = ""; int ExtraAlign = 0; if(m_Popup == POPUP_MESSAGE) { pTitle = m_aMessageTopic; pExtraText = m_aMessageBody; pButtonText = m_aMessageButton; } else if(m_Popup == POPUP_CONNECTING) { pTitle = Localize("Connecting to"); pExtraText = g_Config.m_UiServerAddress; // TODO: query the client about the address pButtonText = Localize("Abort"); if(Client()->MapDownloadTotalsize() > 0) { pTitle = Localize("Downloading map"); pExtraText = ""; } } else if(m_Popup == POPUP_DISCONNECTED) { pTitle = Localize("Disconnected"); pExtraText = Client()->ErrorString(); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PURE) { pTitle = Localize("Disconnected"); pExtraText = Localize("The server is running a non-standard tuning on a pure game type."); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_DELETE_DEMO) { pTitle = Localize("Delete demo"); pExtraText = Localize("Are you sure that you want to delete the demo?"); ExtraAlign = -1; } else if(m_Popup == POPUP_RENAME_DEMO) { pTitle = Localize("Rename demo"); pExtraText = ""; ExtraAlign = -1; } else if(m_Popup == POPUP_REMOVE_FRIEND) { pTitle = Localize("Remove friend"); pExtraText = Localize("Are you sure that you want to remove the player from your friends list?"); ExtraAlign = -1; } else if(m_Popup == POPUP_SOUNDERROR) { pTitle = Localize("Sound error"); pExtraText = Localize("The audio device couldn't be initialised."); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PASSWORD) { pTitle = Localize("Password incorrect"); pExtraText = ""; pButtonText = Localize("Try again"); } else if(m_Popup == POPUP_QUIT) { pTitle = Localize("Quit"); pExtraText = Localize("Are you sure that you want to quit?"); ExtraAlign = -1; } else if(m_Popup == POPUP_FIRST_LAUNCH) { pTitle = Localize("Welcome to Teeworlds"); pExtraText = Localize("As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server."); pButtonText = Localize("Ok"); ExtraAlign = -1; } CUIRect Box, Part; Box = Screen; Box.VMargin(150.0f/UI()->Scale(), &Box); Box.HMargin(150.0f/UI()->Scale(), &Box); // render the box RenderTools()->DrawUIRect(&Box, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); UI()->DoLabelScaled(&Part, pTitle, 24.f, 0); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); Part.VMargin(20.f/UI()->Scale(), &Part); if(ExtraAlign == -1) UI()->DoLabelScaled(&Part, pExtraText, 20.f, -1, (int)Part.w); else UI()->DoLabelScaled(&Part, pExtraText, 20.f, 0, -1); if(m_Popup == POPUP_QUIT) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); // additional info Box.HSplitTop(10.0f, 0, &Box); Box.VMargin(20.f/UI()->Scale(), &Box); if(m_pClient->Editor()->HasUnsavedData()) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "%s\n%s", Localize("There's an unsaved map in the editor, you might want to save it before you quit the game."), Localize("Quit anyway?")); UI()->DoLabelScaled(&Box, aBuf, 20.f, -1, Part.w-20.0f); } // buttons Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) Client()->Quit(); } else if(m_Popup == POPUP_PASSWORD) { CUIRect Label, TextBox, TryAgain, Abort; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &TryAgain); TryAgain.VMargin(20.0f, &TryAgain); Abort.VMargin(20.0f, &Abort); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Try again"), 0, &TryAgain) || m_EnterPressed) { Client()->Connect(g_Config.m_UiServerAddress); } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Password"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &Offset, true); } else if(m_Popup == POPUP_CONNECTING) { Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed) { Client()->Disconnect(); m_Popup = POPUP_NONE; } if(Client()->MapDownloadTotalsize() > 0) { int64 Now = time_get(); if(Now-m_DownloadLastCheckTime >= time_freq()) { if(m_DownloadLastCheckSize > Client()->MapDownloadAmount()) { // map downloaded restarted m_DownloadLastCheckSize = 0; } // update download speed float Diff = (Client()->MapDownloadAmount()-m_DownloadLastCheckSize)/1024.0f; m_DownloadSpeed = absolute((m_DownloadSpeed*(1.0f-(1.0f/m_DownloadSpeed))) + (Diff*(1.0f/m_DownloadSpeed))); m_DownloadLastCheckTime = Now; m_DownloadLastCheckSize = Client()->MapDownloadAmount(); } Box.HSplitTop(64.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); str_format(aBuf, sizeof(aBuf), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount()/1024, Client()->MapDownloadTotalsize()/1024, m_DownloadSpeed); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // time left const char *pTimeLeftString; int TimeLeft = (Client()->MapDownloadTotalsize()-Client()->MapDownloadAmount())/(m_DownloadSpeed*1024)+1; if(TimeLeft >= 60) { TimeLeft /= 60; pTimeLeftString = TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"); } else pTimeLeftString = TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"); Box.HSplitTop(20.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); str_format(aBuf, sizeof(aBuf), pTimeLeftString, TimeLeft); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // progress bar Box.HSplitTop(20.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); Part.VMargin(40.0f, &Part); RenderTools()->DrawUIRect(&Part, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 5.0f); Part.w = max(10.0f, (Part.w*Client()->MapDownloadAmount())/Client()->MapDownloadTotalsize()); RenderTools()->DrawUIRect(&Part, vec4(1.0f, 1.0f, 1.0f, 0.5f), CUI::CORNER_ALL, 5.0f); } } else if(m_Popup == POPUP_LANGUAGE) { Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); Box.HSplitTop(20.f, &Part, &Box); Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Box.HSplitBottom(20.f, &Box, 0); Box.VMargin(20.0f, &Box); RenderLanguageSelection(Box); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Part) || m_EscapePressed || m_EnterPressed) m_Popup = POPUP_FIRST_LAUNCH; } else if(m_Popup == POPUP_DELETE_DEMO) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) { m_Popup = POPUP_NONE; // delete demo if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); if(Storage()->RemoveFile(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } else PopupMessage(Localize("Error"), Localize("Unable to delete the demo"), Localize("Ok")); } } } else if(m_Popup == POPUP_RENAME_DEMO) { CUIRect Label, TextBox, Ok, Abort; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &Ok); Ok.VMargin(20.0f, &Ok); Abort.VMargin(20.0f, &Abort); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonOk = 0; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || m_EnterPressed) { m_Popup = POPUP_NONE; // rename demo if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBufOld[512]; str_format(aBufOld, sizeof(aBufOld), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); int Length = str_length(m_aCurrentDemoFile); char aBufNew[512]; if(Length <= 4 || m_aCurrentDemoFile[Length-5] != '.' || str_comp_nocase(m_aCurrentDemoFile+Length-4, "demo")) str_format(aBufNew, sizeof(aBufNew), "%s/%s.demo", m_aCurrentDemoFolder, m_aCurrentDemoFile); else str_format(aBufNew, sizeof(aBufNew), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); if(Storage()->RenameFile(aBufOld, aBufNew, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } else PopupMessage(Localize("Error"), Localize("Unable to rename the demo"), Localize("Ok")); } } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(120.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("New name:"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset); } else if(m_Popup == POPUP_REMOVE_FRIEND) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) { m_Popup = POPUP_NONE; // remove friend if(m_FriendlistSelectedIndex >= 0) { m_pClient->Friends()->RemoveFriend(m_FriendlistSelectedIndex); Client()->ServerBrowserUpdate(); } } } else if(m_Popup == POPUP_FIRST_LAUNCH) { CUIRect Label, TextBox; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); static int s_EnterButton = 0; if(DoButton_Menu(&s_EnterButton, Localize("Enter"), 0, &Part) || m_EnterPressed) m_Popup = POPUP_NONE; Box.HSplitBottom(40.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Nickname"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &Offset); } else { Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed) m_Popup = POPUP_NONE; } } return 0; }
void CHud::RenderHealthAndAmmo(const CNetObj_Character *pCharacter) { if(!pCharacter) return; float x = 5; float y = 5; int i; IGraphics::CQuadItem Array[10]; // render ammo if(pCharacter->m_Weapon == WEAPON_NINJA) { CUIRect Rect = {x, y+24.0f, 118.0f, 10.0f}; RenderTools()->DrawUIRect(&Rect, vec4(0.8f, 0.8f, 0.8f, 0.5f), 0, 0.0f); int Max = g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000; Rect.x = x+1.0f; Rect.y = y+25.0f; Rect.w = 116.0f * clamp(pCharacter->m_AmmoCount-Client()->GameTick(), 0, Max) / Max; Rect.h = 8.0f; RenderTools()->DrawUIRect(&Rect, vec4(0.9f, 0.2f, 0.2f, 0.85f), 0, 0.0f); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[WEAPON_NINJA].m_pSpriteBody); Array[0] = IGraphics::CQuadItem(x+40.0f,y+25, 32.0f, 8.0f); Graphics()->QuadsDrawTL(Array, 1); } else { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[pCharacter->m_Weapon%NUM_WEAPONS].m_pSpriteProj); for(i = 0; i < min(pCharacter->m_AmmoCount, 10); i++) Array[i] = IGraphics::CQuadItem(x+i*12,y+24,10,10); Graphics()->QuadsDrawTL(Array, i); } int h = 0; // render health RenderTools()->SelectSprite(SPRITE_HEALTH_FULL); for(; h < min(pCharacter->m_Health, 10); h++) Array[h] = IGraphics::CQuadItem(x+h*12,y,10,10); Graphics()->QuadsDrawTL(Array, h); i = 0; RenderTools()->SelectSprite(SPRITE_HEALTH_EMPTY); for(; h < 10; h++) Array[i++] = IGraphics::CQuadItem(x+h*12,y,10,10); Graphics()->QuadsDrawTL(Array, i); // render armor meter h = 0; RenderTools()->SelectSprite(SPRITE_ARMOR_FULL); for(; h < min(pCharacter->m_Armor, 10); h++) Array[h] = IGraphics::CQuadItem(x+h*12,y+12,10,10); Graphics()->QuadsDrawTL(Array, h); i = 0; RenderTools()->SelectSprite(SPRITE_ARMOR_EMPTY); for(; h < 10; h++) Array[i++] = IGraphics::CQuadItem(x+h*12,y+12,10,10); Graphics()->QuadsDrawTL(Array, i); Graphics()->QuadsEnd(); }
void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser) { Graphics()->QuadsBegin(); float Conv = 1/255.0f; for(int i = 0; i < NumQuads; i++) { CQuad *q = &pQuads[i]; float r=1, g=1, b=1, a=1; if(q->m_ColorEnv >= 0) { float aChannels[4]; pfnEval(q->m_ColorEnvOffset/1000.0f, q->m_ColorEnv, aChannels, pUser); r = aChannels[0]; g = aChannels[1]; b = aChannels[2]; a = aChannels[3]; } bool Opaque = false; /* TODO: Analyze quadtexture if(a < 0.01f || (q->m_aColors[0].a < 0.01f && q->m_aColors[1].a < 0.01f && q->m_aColors[2].a < 0.01f && q->m_aColors[3].a < 0.01f)) Opaque = true; */ if(Opaque && !(RenderFlags&LAYERRENDERFLAG_OPAQUE)) continue; if(!Opaque && !(RenderFlags&LAYERRENDERFLAG_TRANSPARENT)) continue; Graphics()->QuadsSetSubsetFree( fx2f(q->m_aTexcoords[0].x), fx2f(q->m_aTexcoords[0].y), fx2f(q->m_aTexcoords[1].x), fx2f(q->m_aTexcoords[1].y), fx2f(q->m_aTexcoords[2].x), fx2f(q->m_aTexcoords[2].y), fx2f(q->m_aTexcoords[3].x), fx2f(q->m_aTexcoords[3].y) ); float OffsetX = 0; float OffsetY = 0; float Rot = 0; // TODO: fix this if(q->m_PosEnv >= 0) { float aChannels[4]; pfnEval(q->m_PosEnvOffset/1000.0f, q->m_PosEnv, aChannels, pUser); OffsetX = aChannels[0]; OffsetY = aChannels[1]; Rot = aChannels[2]/360.0f*pi*2; } IGraphics::CColorVertex Array[4] = { IGraphics::CColorVertex(0, q->m_aColors[0].r*Conv*r, q->m_aColors[0].g*Conv*g, q->m_aColors[0].b*Conv*b, q->m_aColors[0].a*Conv*a), IGraphics::CColorVertex(1, q->m_aColors[1].r*Conv*r, q->m_aColors[1].g*Conv*g, q->m_aColors[1].b*Conv*b, q->m_aColors[1].a*Conv*a), IGraphics::CColorVertex(2, q->m_aColors[2].r*Conv*r, q->m_aColors[2].g*Conv*g, q->m_aColors[2].b*Conv*b, q->m_aColors[2].a*Conv*a), IGraphics::CColorVertex(3, q->m_aColors[3].r*Conv*r, q->m_aColors[3].g*Conv*g, q->m_aColors[3].b*Conv*b, q->m_aColors[3].a*Conv*a)}; Graphics()->SetColorVertex(Array, 4); CPoint *pPoints = q->m_aPoints; if(Rot != 0) { static CPoint aRotated[4]; aRotated[0] = q->m_aPoints[0]; aRotated[1] = q->m_aPoints[1]; aRotated[2] = q->m_aPoints[2]; aRotated[3] = q->m_aPoints[3]; pPoints = aRotated; Rotate(&q->m_aPoints[4], &aRotated[0], Rot); Rotate(&q->m_aPoints[4], &aRotated[1], Rot); Rotate(&q->m_aPoints[4], &aRotated[2], Rot); Rotate(&q->m_aPoints[4], &aRotated[3], Rot); } IGraphics::CFreeformItem Freeform( fx2f(pPoints[0].x)+OffsetX, fx2f(pPoints[0].y)+OffsetY, fx2f(pPoints[1].x)+OffsetX, fx2f(pPoints[1].y)+OffsetY, fx2f(pPoints[2].x)+OffsetX, fx2f(pPoints[2].y)+OffsetY, fx2f(pPoints[3].x)+OffsetX, fx2f(pPoints[3].y)+OffsetY); Graphics()->QuadsDrawFreeform(&Freeform, 1); } Graphics()->QuadsEnd(); }
void CRenderTools::RenderTelemap(CTeleTile *pTele, int w, int h, float Scale, vec4 Color, int RenderFlags) { float ScreenX0, ScreenY0, ScreenX1, ScreenY1; Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); // calculate the final pixelsize for the tiles float TilePixelSize = 1024/32.0f; float FinalTileSize = Scale/(ScreenX1-ScreenX0) * Graphics()->ScreenWidth(); float FinalTilesetScale = FinalTileSize/TilePixelSize; Graphics()->QuadsBegin(); Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a); int StartY = (int)(ScreenY0/Scale)-1; int StartX = (int)(ScreenX0/Scale)-1; int EndY = (int)(ScreenY1/Scale)+1; int EndX = (int)(ScreenX1/Scale)+1; // adjust the texture shift according to mipmap level float TexSize = 1024.0f; float Frac = (1.25f/TexSize) * (1/FinalTilesetScale); float Nudge = (0.5f/TexSize) * (1/FinalTilesetScale); for(int y = StartY; y < EndY; y++) for(int x = StartX; x < EndX; x++) { int mx = x; int my = y; if(RenderFlags&TILERENDERFLAG_EXTEND) { if(mx<0) mx = 0; if(mx>=w) mx = w-1; if(my<0) my = 0; if(my>=h) my = h-1; } else { if(mx<0) continue; // mx = 0; if(mx>=w) continue; // mx = w-1; if(my<0) continue; // my = 0; if(my>=h) continue; // my = h-1; } int c = mx + my*w; unsigned char Index = pTele[c].m_Type; if(Index) { bool Render = false; if(RenderFlags&LAYERRENDERFLAG_TRANSPARENT) Render = true; if(Render) { int tx = Index%16; int ty = Index/16; int Px0 = tx*(1024/16); int Py0 = ty*(1024/16); int Px1 = Px0+(1024/16)-1; int Py1 = Py0+(1024/16)-1; float x0 = Nudge + Px0/TexSize+Frac; float y0 = Nudge + Py0/TexSize+Frac; float x1 = Nudge + Px1/TexSize-Frac; float y1 = Nudge + Py0/TexSize+Frac; float x2 = Nudge + Px1/TexSize-Frac; float y2 = Nudge + Py1/TexSize-Frac; float x3 = Nudge + Px0/TexSize+Frac; float y3 = Nudge + Py1/TexSize-Frac; Graphics()->QuadsSetSubsetFree(x0, y0, x1, y1, x2, y2, x3, y3); IGraphics::CQuadItem QuadItem(x*Scale, y*Scale, Scale, Scale); Graphics()->QuadsDrawTL(&QuadItem, 1); } } } Graphics()->QuadsEnd(); Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); }
void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const char *pTitle) { if(Team == TEAM_SPECTATORS) return; float h = 760.0f; // background Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.5f); RenderTools()->DrawRoundRect(x, y, w, h, 17.0f); Graphics()->QuadsEnd(); // render title float TitleFontsize = 40.0f; if(!pTitle) { if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) pTitle = Localize("Game over"); else pTitle = Localize("Score board"); } TextRender()->Text(0, x+20.0f, y, TitleFontsize, pTitle, -1); char aBuf[128] = {0}; if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) { if(m_pClient->m_Snap.m_pGameDataObj) { int Score = Team == TEAM_RED ? m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed : m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue; str_format(aBuf, sizeof(aBuf), "%d", Score); } } else { if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID]) { int Score = m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID]->m_Score; str_format(aBuf, sizeof(aBuf), "%d", Score); } else if(m_pClient->m_Snap.m_pLocalInfo) { int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score; str_format(aBuf, sizeof(aBuf), "%d", Score); } } float tw = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1); TextRender()->Text(0, x+w-tw-20.0f, y, TitleFontsize, aBuf, -1); // calculate measurements x += 10.0f; float LineHeight = 60.0f; float TeeSizeMod = 1.0f; float Spacing = 16.0f; if(m_pClient->m_Snap.m_aTeamSize[Team] > 12) { LineHeight = 40.0f; TeeSizeMod = 0.8f; Spacing = 0.0f; } else if(m_pClient->m_Snap.m_aTeamSize[Team] > 8) { LineHeight = 50.0f; TeeSizeMod = 0.9f; Spacing = 8.0f; } float ScoreOffset = x+10.0f, ScoreLength = 60.0f; float TeeOffset = ScoreOffset+ScoreLength, TeeLength = 60*TeeSizeMod; float NameOffset = TeeOffset+TeeLength, NameLength = 300.0f-TeeLength; float PingOffset = x+610.0f, PingLength = 65.0f; float CountryOffset = PingOffset-(LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f, CountryLength = (LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f; float ClanOffset = x+370.0f, ClanLength = 230.0f-CountryLength; // render headlines y += 50.0f; float HeadlineFontsize = 22.0f; tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Score"), -1); TextRender()->Text(0, ScoreOffset+ScoreLength-tw, y, HeadlineFontsize, Localize("Score"), -1); TextRender()->Text(0, NameOffset, y, HeadlineFontsize, Localize("Name"), -1); tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Clan"), -1); TextRender()->Text(0, ClanOffset+ClanLength/2-tw/2, y, HeadlineFontsize, Localize("Clan"), -1); tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Ping"), -1); TextRender()->Text(0, PingOffset+PingLength-tw, y, HeadlineFontsize, Localize("Ping"), -1); // render player entries y += HeadlineFontsize*2.0f; float FontSize = 24.0f; CTextCursor Cursor; for(int i = 0; i < MAX_CLIENTS; i++) { // make sure that we render the correct team const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i]; if(!pInfo || pInfo->m_Team != Team) continue; // background so it's easy to find the local player or the followed one in spectator mode if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID)) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, 15.0f); Graphics()->QuadsEnd(); } // score str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ScoreLength; TextRender()->TextEx(&Cursor, aBuf, -1); // flag if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS && m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID || m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID)) { Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); float Size = LineHeight; IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // avatar CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo; TeeInfo.m_Size *= TeeSizeMod; RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2)); // name TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = NameLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); // clan tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ClanLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); // country flag Graphics()->TextureSet(m_pClient->m_pCountryFlags->GetByCountryCode(m_pClient->m_aClients[pInfo->m_ClientID].m_Country)->m_Texture); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f); IGraphics::CQuadItem QuadItem(CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // ping str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = PingLength; TextRender()->TextEx(&Cursor, aBuf, -1); y += LineHeight+Spacing; } }