diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj
index 64d6196cf..b290c015b 100644
--- a/src/ClassiCube.vcxproj
+++ b/src/ClassiCube.vcxproj
@@ -270,6 +270,7 @@
+
diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters
index ba84133cd..c8c976dad 100644
--- a/src/ClassiCube.vcxproj.filters
+++ b/src/ClassiCube.vcxproj.filters
@@ -121,6 +121,9 @@
{6b1102a4-29d5-4c01-8f32-b9d9cb19b8aa}
+
+ {a46e060c-8a75-436f-ac18-f35d184735af}
+
@@ -539,5 +542,8 @@
Source Files\Platform
+
+ Source Files\Launcher
+
\ No newline at end of file
diff --git a/src/Launcher.c b/src/Launcher.c
new file mode 100644
index 000000000..12a3c1a3b
--- /dev/null
+++ b/src/Launcher.c
@@ -0,0 +1,213 @@
+#include "Launcher.h"
+#include "Drawer2D.h"
+#include "Game.h"
+#include "Deflate.h"
+#include "Stream.h"
+
+struct LSCreen* Launcher_Screen;
+bool Launcher_Dirty, Launcher_PendingRedraw;
+Rect2D Launcher_DirtyArea;
+Bitmap Launcher_Framebuffer;
+ bool Launcher_ClassicBackground;
+
+bool Launcher_ShouldExit, Launcher_ShouldUpdate;
+TimeMS Launcher_PatchTime;
+struct ServerListEntry* Launcher_PublicServers;
+int Launcher_NumServers;
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Colours/Skin-----------------------------------------------------*
+*#########################################################################################################################*/
+BitmapCol Launcher_BackgroundCol = BITMAPCOL_CONST(153, 127, 172, 255);
+BitmapCol Launcher_ButtonBorderCol = BITMAPCOL_CONST( 97, 81, 110, 255);
+BitmapCol Launcher_ButtonForeActiveCol = BITMAPCOL_CONST(189, 168, 206, 255);
+BitmapCol Launcher_ButtonForeCol = BITMAPCOL_CONST(141, 114, 165, 255);
+BitmapCol Launcher_ButtonHighlightCol = BITMAPCOL_CONST(162, 131, 186, 255);
+
+void Launcher_ResetSkin(void) {
+ /* Have to duplicate it here, sigh */
+ BitmapCol defaultBackgroundCol = BITMAPCOL_CONST(153, 127, 172, 255);
+ BitmapCol defaultButtonBorderCol = BITMAPCOL_CONST( 97, 81, 110, 255);
+ BitmapCol defaultButtonForeActiveCol = BITMAPCOL_CONST(189, 168, 206, 255);
+ BitmapCol defaultButtonForeCol = BITMAPCOL_CONST(141, 114, 165, 255);
+ BitmapCol defaultButtonHighlightCol = BITMAPCOL_CONST(162, 131, 186, 255);
+
+ Launcher_BackgroundCol = defaultBackgroundCol;
+ Launcher_ButtonBorderCol = defaultButtonBorderCol;
+ Launcher_ButtonForeActiveCol = defaultButtonForeActiveCol;
+ Launcher_ButtonForeCol = defaultButtonForeCol;
+ Launcher_ButtonHighlightCol = defaultButtonHighlightCol;
+}
+
+/*CC_NOINLINE static void Launcher_GetCol(const char* key, BitmapCol* col) {
+ PackedCol tmp;
+ string value = Options.Get(key, null);
+ if (String.IsNullOrEmpty(value)) return;
+
+ if (!PackedCol.TryParse(value, out col))
+ col = defaultCol;
+}
+
+void Launcher_LoadSkin(void) {
+ Launcher_GetCol("launcher-back-col", &Launcher_BackgroundCol);
+ Launcher_GetCol("launcher-btn-border-col", &Launcher_ButtonBorderCol);
+ Launcher_GetCol("launcher-btn-fore-active-col", &Launcher_ButtonForeActiveCol);
+ Launcher_GetCol("launcher-btn-fore-inactive-col", &Launcher_ButtonForeCol);
+ Launcher_GetCol("launcher-btn-highlight-inactive-col", &Launcher_ButtonHighlightCol);
+}
+
+CC_NOINLINE static void Launcher_SetCol(const char* key, BitmapCol col) {
+ PackedCol tmp;
+ string value = Options.Get(key, null);
+ if (String.IsNullOrEmpty(value)) return;
+
+ if (!PackedCol.TryParse(value, out col))
+ col = defaultCol;
+}
+
+void Launcher_SaveSkin(void) {
+ Launcher_SetCol("launcher-back-col", Launcher_BackgroundCol);
+ Launcher_SetCol("launcher-btn-border-col", Launcher_ButtonBorderCol);
+ Launcher_SetCol("launcher-btn-fore-active-col", Launcher_ButtonForeActiveCol);
+ Launcher_SetCol("launcher-btn-fore-inactive-col", Launcher_ButtonForeCol);
+ Launcher_SetCol("launcher-btn-highlight-inactive-col", Launcher_ButtonHighlightCol);
+}*/
+
+
+/*########################################################################################################################*
+*----------------------------------------------------------Background-----------------------------------------------------*
+*#########################################################################################################################*/
+static FontDesc logoFont;
+static bool useBitmappedFont;
+static Bitmap terrainBmp, fontBmp;
+#define TILESIZE 48
+
+static bool Launcher_SelectZipEntry(const String* path) {
+ return
+ String_CaselessEqualsConst(path, "default.png") ||
+ String_CaselessEqualsConst(path, "terrain.png");
+}
+
+static void Launcher_LoadTextures(Bitmap* bmp) {
+ int tileSize = bmp->Width / 16;
+ Bitmap_Allocate(&terrainBmp, TILESIZE * 2, TILESIZE);
+
+ /* Precompute the scaled background */
+ Drawer2D_BmpScaled(&terrainBmp, TILESIZE, 0, TILESIZE, TILESIZE,
+ bmp, 2 * tileSize, 0, tileSize, tileSize,
+ TILESIZE, TILESIZE, 128, 64);
+ Drawer2D_BmpScaled(&terrainBmp, 0, 0, TILESIZE, TILESIZE,
+ bmp, 1 * tileSize, 0, tileSize, tileSize,
+ TILESIZE, TILESIZE, 96, 96);
+}
+
+static void Launcher_ProcessZipEntry(const String* path, struct Stream* data, struct ZipEntry* entry) {
+ Bitmap bmp;
+ ReturnCode res;
+
+ if (String_CaselessEqualsConst(path, "default.png")) {
+ if (fontBmp.Scan0) return;
+ res = Png_Decode(&fontBmp, data);
+
+ if (res) {
+ Launcher_ShowError(res, "decoding default.png"); return;
+ } else {
+ Drawer2D_SetFontBitmap(&fontBmp);
+ useBitmappedFont = !Options_GetBool(OPT_USE_CHAT_FONT, false);
+ }
+ } else if (String_CaselessEqualsConst(path, "terrain.png")) {
+ if (terrainBmp.Scan0) return;
+ res = Png_Decode(&bmp, data);
+
+ if (res) {
+ Launcher_ShowError(res, "decoding default.png"); return;
+ } else {
+ Drawer2D_SetFontBitmap(&bmp);
+ Launcher_LoadTextures(&bmp);
+ }
+ }
+}
+
+static void Launcher_ExtractTexturePack(const String* path) {
+ struct ZipState state;
+ struct Stream stream;
+ ReturnCode res;
+
+ res = Stream_OpenFile(&stream, path);
+ if (res) {
+ Launcher_ShowError(res, "opening texture pack"); return;
+ }
+
+ Zip_Init(&state, &stream);
+ state.SelectEntry = Launcher_SelectZipEntry;
+ state.ProcessEntry = Launcher_ProcessZipEntry;
+ res = Zip_Extract(&state);
+
+ if (res) {
+ Launcher_ShowError(res, "extracting texture pack");
+ }
+ stream.Close(&stream);
+}
+
+/*void Launcher_TryLoadTexturePack(void) {
+ if (Options.Get("nostalgia-classicbg", null) != null) {
+ Launcher_ClassicBackground = Options_GetBool("nostalgia-classicbg", false);
+ } else {
+ Launcher_ClassicBackground = Options_GetBool(OPT_CLASSIC_MODE, false);
+ }
+
+ string texPack = Options.Get(OptionsKey.DefaultTexturePack, "default.zip");
+ string texPath = Path.Combine("texpacks", texPack);
+
+ if (!Platform_FileExists(texPath)) {
+ texPath = Path.Combine("texpacks", "default.zip");
+ }
+ if (!Platform_FileExists(texPath)) return;
+
+ Launcher_ExtractTexturePack(texPath);
+ // user selected texture pack is missing some required .png files
+ if (!fontBmp.Scan0 || !terrainBmp.Scan0) {
+ texPath = Path.Combine("texpacks", "default.zip");
+ ExtractTexturePack(texPath);
+ }
+}*/
+
+static void Launcher_ClearTile(int x, int y, int width, int height, int srcX) {
+ Drawer2D_BmpTiled(&Launcher_Framebuffer, x, y, width, height,
+ &terrainBmp, srcX, 0, TILESIZE, TILESIZE);
+}
+
+void Launcher_ResetArea(int x, int y, int width, int height) {
+ if (Launcher_ClassicBackground && terrainBmp.Scan0) {
+ Launcher_ClearTile(x, y, width, height, 0);
+ } else {
+ Gradient_Noise(&Launcher_Framebuffer, x, y, width, height, Launcher_BackgroundCol, 6);
+ }
+}
+
+void Launcher_ResetPixels(void) {
+ static String title_fore = String_FromConst("&eClassi&fCube");
+ static String title_back = String_FromConst("&0Classi&0Cube");
+ struct DrawTextArgs args;
+ int x;
+
+ if (Launcher_ClassicBackground && terrainBmp.Scan0) {
+ Launcher_ClearTile(0, 0, Game_Width, TILESIZE, TILESIZE);
+ Launcher_ClearTile(0, TILESIZE, Game_Width, Game_Height - TILESIZE, 0);
+ } else {
+ Launcher_ResetArea(0, 0, Game_Width, Game_Height);
+ }
+
+ Drawer2D_BitmappedText = (useBitmappedFont || Launcher_ClassicBackground) && fontBmp.Scan0;
+ DrawTextArgs_Make(&args, &title_fore, &logoFont, false);
+ x = Game_Width / 2 - Drawer2D_MeasureText(&args).Width / 2;
+
+ args.Text = title_back;
+ Drawer2D_DrawText(&Launcher_Framebuffer, &args, x + 4, 4);
+ args.Text = title_fore;
+ Drawer2D_DrawText(&Launcher_Framebuffer, &args, x, 0);
+
+ Drawer2D_BitmappedText = false;
+ Launcher_Dirty = true;
+}
diff --git a/src/Launcher.h b/src/Launcher.h
index 0c1b7d9ca..f94be7448 100644
--- a/src/Launcher.h
+++ b/src/Launcher.h
@@ -4,53 +4,72 @@
#include "String.h"
struct LScreen;
-TimeMS Launcher_PatchTime;
-
-extern BitmapCol Launcher_BackgroundCol = BITMAPCOL_CONST(153, 127, 172, 255);
-extern BitmapCol Launcher_ButtonBorderCol = BITMAPCOL_CONST( 97, 81, 110, 255);
-extern BitmapCol Launcher_ButtonForeActiveCol = BITMAPCOL_CONST(189, 168, 206, 255);
-extern BitmapCol Launcher_ButtonForeCol = BITMAPCOL_CONST(141, 114, 165, 255);
-extern BitmapCol Launcher_ButtonHighlightCol = BITMAPCOL_CONST(162, 131, 186, 255);
-
-void Launcher_ResetSkin(void);
-void Launcher_LoadSkin(void);
-void Launcher_SaveSkin(void);
-
-void Launcher_UpdateAsync(void);
-
-extern bool Launcher_ClassicBackground;
-
-void Launcher_TryLoadTexturePack(void);
-void Launcher_RedrawBackground(void);
-
-/* Redraws the specified region with the background pixels. */
-void Launcher_ResetArea(int x, int y, int width, int height);
+/* Currently active screen/menu. */
extern struct LSCreen* Launcher_Screen;
/* Whether the client drawing area needs to be redrawn/presented to the screen. */
extern bool Launcher_Dirty, Launcher_PendingRedraw;
/* The specific area/region of the window that needs to be redrawn. */
extern Rect2D Launcher_DirtyArea;
-String Username;
-extern int Launcher_Width, Launcher_Height;
+/* Pixels containing contents of the window.*/
extern Bitmap Launcher_Framebuffer;
+/* Whether to use stone tile background like minecraft.net. */
+extern bool Launcher_ClassicBackground;
/* Whether at the next tick, the launcher window should proceed to stop displaying frames and subsequently exit. */
extern bool Launcher_ShouldExit;
/* Whether update script should be asynchronously run on exit. */
extern bool Launcher_ShouldUpdate;
+/* Time which updated executable's "modified" time should be set to. */
+extern TimeMS Launcher_PatchTime;
+/* Base colour of pixels before any widgets are drawn. */
+extern BitmapCol Launcher_BackgroundCol;
+/* Colour of pixels on the 4 line borders around buttons. */
+extern BitmapCol Launcher_ButtonBorderCol;
+/* Colour of button when user has mouse over it. */
+extern BitmapCol Launcher_ButtonForeActiveCol;
+/* Colour of button when user does not have mouse over it. */
+extern BitmapCol Launcher_ButtonForeCol;
+/* Colour of line at top of buttons to give them a less flat look.*/
+extern BitmapCol Launcher_ButtonHighlightCol;
+
+/* Resets colours to default. */
+void Launcher_ResetSkin(void);
+/* Loads colours from options. */
+void Launcher_LoadSkin(void);
+/* Saves the colours to options. */
+/* NOTE: Does not save options file itself. */
+void Launcher_SaveSkin(void);
+
+/* Attempts to load font and terrain from texture pack. */
+void Launcher_TryLoadTexturePack(void);
+/* Redraws all pixels with default background. */
+/* NOTE: Also draws titlebar at top, if active screen permits it. */
+void Launcher_ResetPixels(void);
+/* Redraws the specified region with the background pixels. */
+void Launcher_ResetArea(int x, int y, int width, int height);
+
+/* Represents all known details about a server. */
struct ServerListEntry {
String Hash, Name, Players, MaxPlayers, Flag;
String Uptime, IPAddress, Port, Mppass, Software;
bool Featured;
};
-extern struct ServerListEntry* Launcher_Servers;
+/* List of all public servers on classicube.net server list. */
+extern struct ServerListEntry* Launcher_PublicServers;
+/* Number of public servers */
+extern int Launcher_NumServers;
-extern String Launcher_FontName;
+/* Sets currently active screen/menu, freeing old one. */
void Launcher_SetScreen(struct LScreen* screen);
+/* Attempts to start the game by connecting to the given server. */
bool Launcher_ConnectToServer(const String* hash);
+/* Launcher main loop. */
void Launcher_Run();
+/* Shows a message box for an error. */
+void Launcher_ShowError(ReturnCode res, const char* place);
+/* Starts the game from the given arguments. */
bool Launcher_StartGame(const String* user, const String* mppass, const String* ip, const String* port, const String* server);
#endif