commits
tags
#include "wj_menu.h"
#include "wj_server.h"
#include "wj_qr.h"
#include "wj_qrtexture.h"
#include "wj_input.h"
#include "doomstat.h"
#include "d_player.h"
#include "v_draw.h"
#include "v_video.h"
#include "v_font.h"
#include "gametexture.h"
#include "menu.h"
#include "vm.h"
#include "c_dispatch.h"
EXTERN_CVAR(Bool, ui_classic)
namespace
{
WJQRTexture *g_qrTex = nullptr;
FGameTexture *g_qrGameTex = nullptr;
std::string g_qrForUrl;
void EnsureQRTexture(const std::string &url)
{
if (g_qrGameTex != nullptr && g_qrForUrl == url)
return;
if (g_qrGameTex != nullptr)
{
delete g_qrGameTex; // ref-counted Base releases g_qrTex too
g_qrGameTex = nullptr;
g_qrTex = nullptr;
}
WJQRImage img = WJ_MakeQRCode(url, 6);
if (img.width == 0)
return;
g_qrTex = new WJQRTexture();
g_qrTex->SetImage(img.width, img.width, img.rgba.data());
g_qrGameTex = MakeGameTexture(g_qrTex, nullptr, ETextureType::Override);
g_qrForUrl = url;
}
}
void WJ_LobbyOpen()
{
WJ_StartServer(0);
}
void WJ_LobbyDrawer()
{
FFont *font = ui_classic ? SmallFont : NewSmallFont;
int width = twod->GetWidth();
int height = twod->GetHeight();
int y = 12;
const char *title = "Scan to join";
DrawText(twod, BigFont, CR_WHITE, (width - BigFont->StringWidth(title)) / 2, y, title, TAG_DONE);
y += BigFont->GetHeight() + 8;
if (!WJ_IsServerRunning() || WJ_GetJoinURLCount() == 0)
{
const char *msg = !WJ_IsServerRunning()
? "Could not start the join server."
: "No network address found -- connect to Wi-Fi and reopen this screen.";
DrawText(twod, font, CR_RED, (width - font->StringWidth(msg)) / 2, y, msg, TAG_DONE);
y += font->GetHeight() + 12;
}
else
{
std::string url = WJ_GetJoinURL(0);
EnsureQRTexture(url);
if (g_qrGameTex != nullptr)
{
int qrSize = (width < height ? width : height) / 2;
int qx = (width - qrSize) / 2;
// DTA_VirtualWidth/Height must accompany DTA_DestWidth/Height --
// see the comment in r_splitscreen.cpp's grid draw for why
// leaving them unset produces an undefined (often tiny/
// mispositioned) destination rect.
DrawTexture(twod, g_qrGameTex, qx, y,
DTA_DestWidth, qrSize, DTA_DestHeight, qrSize,
DTA_VirtualWidth, width, DTA_VirtualHeight, height,
DTA_TopLeft, true, TAG_DONE);
y += qrSize + 8;
}
DrawText(twod, font, CR_WHITE, (width - font->StringWidth(url.c_str())) / 2, y, url.c_str(), TAG_DONE);
y += font->GetHeight() + 12;
}
const char *rosterHeader = "Players";
DrawText(twod, font, CR_GOLD, (width - font->StringWidth(rosterHeader)) / 2, y, rosterHeader, TAG_DONE);
y += font->GetHeight() + 4;
for (int i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
bool remote = players[i].RemoteInputSlot;
bool connected = true;
if (remote)
{
WJRemoteInput &ri = wj_remoteInput[i];
std::lock_guard<std::mutex> lock(ri.mtx);
connected = ri.connected;
}
FString line;
line.Format("%s%s", players[i].userinfo.GetName(),
remote ? (connected ? " (phone)" : " (disconnected)") : " (this PC)");
int color = (remote && !connected) ? CR_GREY : CR_WHITE;
DrawText(twod, font, color, (width - font->StringWidth(line.GetChars())) / 2, y, line.GetChars(), TAG_DONE);
y += font->GetHeight() + 2;
}
const char *prompt = "Press ENTER or ESC to close this screen";
DrawText(twod, font, CR_GREY, (width - font->StringWidth(prompt)) / 2, height - font->GetHeight() - 8, prompt, TAG_DONE);
}
DEFINE_ACTION_FUNCTION_NATIVE(DMenu, WJ_LobbyOpen, WJ_LobbyOpen)
{
PARAM_PROLOGUE;
WJ_LobbyOpen();
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DMenu, WJ_LobbyDrawer, WJ_LobbyDrawer)
{
PARAM_PROLOGUE;
WJ_LobbyDrawer();
return 0;
}
CCMD(webjoin_lobby)
{
M_StartControlPanel(true);
M_SetMenu("PhoneJoinLobbyMenu");
}