From 34719e8d586ad7bc943bffd687553a65450770a2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 5 Jan 2007 04:21:14 +0000 Subject: [PATCH] - Added simulation of Hexen's startup screen (currently minus net notches). SVN r436 (trunk) --- docs/rh-log.txt | 3 + src/sdl/st_start.cpp | 67 ++++-- src/st_start.h | 16 +- src/win32/i_main.cpp | 43 +++- src/win32/resource.h | 4 +- src/win32/st_start.cpp | 448 +++++++++++++++++++++++++++++++++++++---- 6 files changed, 513 insertions(+), 68 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 94d4afa23..36bc04f4d 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,6 @@ +January 4, 2007 +- Added simulation of Hexen's startup screen (currently minus net notches). + January 2, 2007 (Changes by Graf Zahl) - Fixed: The ANIMATED parser must read the bytes for the speed as unsigned bytes. - Fixed: The screen wipe must be disabled for Heretic's underwater ending. If diff --git a/src/sdl/st_start.cpp b/src/sdl/st_start.cpp index 0a7f4ca5d..160be85c9 100644 --- a/src/sdl/st_start.cpp +++ b/src/sdl/st_start.cpp @@ -3,7 +3,7 @@ ** Handles the startup screen. ** **--------------------------------------------------------------------------- -** Copyright 2006 Randy Heit +** Copyright 2006-2007 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -32,6 +32,8 @@ ** */ +// HEADER FILES ------------------------------------------------------------ + #include #include #include @@ -41,12 +43,46 @@ #include "doomdef.h" #include "i_system.h" +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void ST_TTY_Done (); +static void ST_TTY_Progress (); +static void ST_TTY_NetInit (const char *message, int numplayers); +static void ST_TTY_NetProgress (int count); +static void ST_TTY_NetMessage (const char *format, ...); +static void ST_TTY_NetDone (); +static bool ST_TTY_NetLoop (bool (*timer_callback)(void *), void *userdata); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +void (*ST_Done)(); +void (*ST_Progress)(); +void (*ST_NetInit)(const char *message, int numplayers); +void (*ST_NetProgress)(int count); +void (*ST_NetMessage)(const char *format, ...); +void (*ST_NetDone)(); +bool (*ST_NetLoop)(bool (*timer_callback)(void *), void *userdata); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + static termios OldTermIOS; static bool DidNetInit; static int NetProgressMax, NetProgressTicker; static const char *NetMessage; static char SpinnyProgressChars[8] = { '|', '/', '-', '\\', '|', '/', '-', '\\' }; +// CODE -------------------------------------------------------------------- + //=========================================================================== // // ST_Init @@ -57,43 +93,50 @@ static char SpinnyProgressChars[8] = { '|', '/', '-', '\\', '|', '/', '-', '\\' void ST_Init(int maxProgress) { + ST_Done = ST_TTY_Done; + ST_Progress = ST_TTY_Progress; + ST_NetInit = ST_TTY_NetInit; + ST_NetProgress = ST_TTY_NetProgress; + ST_NetMessage = ST_TTY_NetMessage; + ST_NetDone = ST_TTY_NetDone; + ST_NetLoop = ST_TTY_NetLoop; } //=========================================================================== // -// ST_Done +// ST_TTY_Done // // Called just before entering graphics mode to deconstruct the startup // screen. // //=========================================================================== -void ST_Done() +static void ST_TTY_Done() { } //=========================================================================== // -// ST_Progress +// ST_TTY_Progress // // Bumps the progress meter one notch. // //=========================================================================== -void ST_Progress() +static void ST_TTY_Progress() { } //=========================================================================== // -// ST_NetInit +// ST_TTY_NetInit // // Sets stdin for unbuffered I/O, displays the given message, and shows // a progress meter. // //=========================================================================== -void ST_NetInit(const char *message, int numplayers) +static void ST_TTY_NetInit(const char *message, int numplayers) { if (!DidNetInit) { @@ -127,13 +170,13 @@ void ST_NetInit(const char *message, int numplayers) //=========================================================================== // -// ST_NetDone +// ST_TTY_NetDone // // Restores the old stdin tty settings. // //=========================================================================== -void ST_NetDone() +static void ST_TTY_NetDone() { // Restore stdin settings if (DidNetInit) @@ -154,7 +197,7 @@ void ST_NetDone() // //=========================================================================== -void ST_NetMessage(const char *format, ...) +static void ST_TTY_NetMessage(const char *format, ...) { FString str; va_list argptr; @@ -174,7 +217,7 @@ void ST_NetMessage(const char *format, ...) // //=========================================================================== -void ST_NetProgress(int count) +static void ST_TTY_NetProgress(int count) { int i; @@ -219,7 +262,7 @@ void ST_NetProgress(int count) // //=========================================================================== -bool ST_NetLoop(bool (*timer_callback)(void *), void *userdata) +static bool ST_TTY_NetLoop(bool (*timer_callback)(void *), void *userdata) { fd_set rfds; struct timeval tv; diff --git a/src/st_start.h b/src/st_start.h index 1e79c3256..5c151d65f 100644 --- a/src/st_start.h +++ b/src/st_start.h @@ -3,7 +3,7 @@ ** Interface for the startup screen. ** **--------------------------------------------------------------------------- -** Copyright 2006 Randy Heit +** Copyright 2006-2007 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -35,10 +35,10 @@ */ extern void ST_Init(int maxProgress); -extern void ST_Done(); -extern void ST_Progress(); -extern void ST_NetInit(const char *message, int numplayers); -extern void ST_NetProgress(int count); -extern void ST_NetMessage(const char *format, ...); // cover for printf() -extern void ST_NetDone(); -extern bool ST_NetLoop(bool (*timer_callback)(void *), void *userdata); +extern void (*ST_Done)(); +extern void (*ST_Progress)(); +extern void (*ST_NetInit)(const char *message, int numplayers); +extern void (*ST_NetProgress)(int count); +extern void (*ST_NetMessage)(const char *format, ...); // cover for printf() +extern void (*ST_NetDone)(); +extern bool (*ST_NetLoop)(bool (*timer_callback)(void *), void *userdata); diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 2eb69257b..9737c9a8f 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -95,11 +95,18 @@ HWND Window; // The subwindows used for startup and error output HWND ConWindow, GameTitleWindow; -HWND ErrorPane, ProgressBar, NetStartPane; +HWND ErrorPane, ProgressBar, NetStartPane, StartupScreen; HFONT GameTitleFont; LONG GameTitleFontHeight; +extern struct +{ + BITMAPINFOHEADER Header; + RGBQUAD Colors[16]; +} StartupBitmapInfo; +extern BYTE *StartupBitmapBits; + HMODULE hwtsapi32; // handle to wtsapi32.dll extern UINT TimerPeriod; @@ -366,9 +373,20 @@ void LayoutMainWindow (HWND hWnd, HWND pane) GetClientRect (NetStartPane, &foo); foo.bottom = foo.bottom;; } - // The log window uses whatever space is left. - MoveWindow (ConWindow, 0, errorpaneheight + bannerheight, w, - h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); + // If there is a startup screen, it covers the log window + if (StartupScreen != NULL) + { + SetWindowPos (StartupScreen, HWND_TOP, 0, errorpaneheight + bannerheight, w, + h - bannerheight - errorpaneheight - progressheight - netpaneheight, SWP_SHOWWINDOW); + InvalidateRect (StartupScreen, NULL, FALSE); + MoveWindow (ConWindow, 0, 0, 0, 0, TRUE); + } + else + { + // The log window uses whatever space is left. + MoveWindow (ConWindow, 0, errorpaneheight + bannerheight, w, + h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); + } } //=========================================================================== @@ -436,6 +454,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { return -1; } + SetWindowLong (view, GWL_ID, IDC_STATIC_TITLE); GameTitleWindow = view; return 0; @@ -448,7 +467,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; case WM_DRAWITEM: - if (DoomStartupInfo != NULL) + if (wParam == IDC_STATIC_TITLE && DoomStartupInfo != NULL) { const PalEntry *c; @@ -477,6 +496,20 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) SelectObject (drawitem->hDC, oldfont); return TRUE; } + else if (wParam == IDC_STATIC_STARTUP) + { + if (StartupScreen != NULL) + { + drawitem = (LPDRAWITEMSTRUCT)lParam; + + rect = drawitem->rcItem; + // Windows expects DIBs to be bottom-up but ours is top-down, + // so flip it vertically while drawing it. + StretchDIBits (drawitem->hDC, rect.left, rect.bottom - 1, rect.right - rect.left, rect.top - rect.bottom, + 0, 0, StartupBitmapInfo.Header.biWidth, StartupBitmapInfo.Header.biHeight, + StartupBitmapBits, (BITMAPINFO *)&StartupBitmapInfo, DIB_RGB_COLORS, SRCCOPY); + } + } return FALSE; case WM_CLOSE: diff --git a/src/win32/resource.h b/src/win32/resource.h index eeb2e6334..ff17a0cfd 100644 --- a/src/win32/resource.h +++ b/src/win32/resource.h @@ -99,6 +99,8 @@ #define IDC_NETSTARTPROGRESS 1079 #define IDC_NETSTARTMESSAGE 1080 #define IDC_NETSTARTCOUNT 1081 +#define IDC_STATIC_TITLE 1082 +#define IDC_STATIC_STARTUP 1083 #define IDCE_ENVIRONMENTDIFFUSION 1085 #define IDCS_ENVIRONMENTDIFFUSION 1086 #define IDCE_ROOM 1087 @@ -158,7 +160,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 150 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1082 +#define _APS_NEXT_CONTROL_VALUE 1084 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index 94c806cfe..e35a8c5ca 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -3,7 +3,7 @@ ** Handles the startup screen. ** **--------------------------------------------------------------------------- -** Copyright 2006 Randy Heit +** Copyright 2006-2007 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -32,58 +32,207 @@ ** */ +// HEADER FILES ------------------------------------------------------------ + #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0501 // required to get the MARQUEE defines #include #include #include +#include "resource.h" #define USE_WINDOWS_DWORD #include "st_start.h" #include "resource.h" #include "templates.h" #include "i_system.h" +#include "i_input.h" +#include "gi.h" +#include "w_wad.h" +#include "s_sound.h" + +// MACROS ------------------------------------------------------------------ + +#define ST_MAX_NOTCHES 32 +#define ST_NOTCH_WIDTH 16 +#define ST_NOTCH_HEIGHT 23 +#define ST_PROGRESS_X 64 // Start of notches x screen pos. +#define ST_PROGRESS_Y 441 // Start of notches y screen pos. + +#define ST_NETPROGRESS_X 288 +#define ST_NETPROGRESS_Y 32 +#define ST_NETNOTCH_WIDTH 4 +#define ST_NETNOTCH_HEIGHT 16 +#define ST_MAX_NETNOTCHES 8 + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern void ST_Util_PlanarToChunky4 (BYTE *dest, const BYTE *src, int width, int height); +extern void ST_Util_DrawBlock (BYTE *dest, const BYTE *src, int bytewidth, int height, int destpitch); + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +static void ST_Basic_Init (); +static void ST_Basic_Done (); +static void ST_Basic_Progress (); +static void ST_Basic_NetInit (const char *message, int numplayers); +static void ST_Basic_NetProgress (int count); +static void ST_Basic_NetMessage (const char *format, ...); +static void ST_Basic_NetDone (); +static bool ST_Basic_NetLoop (bool (*timer_callback)(void *), void *userdata); + +static void ST_Hexen_Init (); +static void ST_Hexen_Done (); +static void ST_Hexen_Progress (); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern HINSTANCE g_hInst; -extern HWND Window, ConWindow, ProgressBar, NetStartPane; +extern HWND Window, ConWindow, ProgressBar, NetStartPane, StartupScreen; extern void LayoutMainWindow (HWND hWnd, HWND pane); -INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); +// PUBLIC DATA DEFINITIONS ------------------------------------------------- -int MaxPos, CurPos; -int NetMaxPos, NetCurPos; -LRESULT NetMarqueeMode; +void (*ST_Done)(); +void (*ST_Progress)(); +void (*ST_NetInit)(const char *message, int numplayers); +void (*ST_NetProgress)(int count); +void (*ST_NetMessage)(const char *format, ...); +void (*ST_NetDone)(); +bool (*ST_NetLoop)(bool (*timer_callback)(void *), void *userdata); -//=========================================================================== +struct +{ + BITMAPINFOHEADER Header; + RGBQUAD Colors[16]; +} StartupBitmapInfo; +BYTE *StartupBitmapBits; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static int MaxPos, CurPos, NotchPos; +static int NetMaxPos, NetCurPos; +static LRESULT NetMarqueeMode; +static RGBQUAD StartupPalette[16]; + +// Hexen's notch graphics, converted to chunky pixels. + +static const BYTE NotchBits[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68, 0x86, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd7, 0x7d, 0x60, 0x00, 0x00, + 0x00, 0x66, 0x99, 0x99, 0x96, 0x69, 0x66, 0x00, + 0x00, 0x69, 0x96, 0x99, 0x69, 0x96, 0x96, 0x00, + 0x06, 0x9d, 0x99, 0x69, 0x96, 0xd9, 0x79, 0x60, + 0x06, 0x7d, 0xdd, 0xdd, 0xdd, 0xdd, 0x77, 0x60, + 0x06, 0x78, 0x88, 0x88, 0x88, 0x88, 0xd6, 0x60, + 0x06, 0x7a, 0xaa, 0xaa, 0xaa, 0xaa, 0xd6, 0x60, + 0x06, 0x7a, 0x77, 0x77, 0x77, 0xa7, 0x96, 0x60, + 0x06, 0x77, 0xa7, 0x77, 0x77, 0xa7, 0x96, 0x60, + 0x06, 0x97, 0xa7, 0x79, 0x77, 0x77, 0x96, 0x60, + 0x00, 0x67, 0x79, 0x99, 0x99, 0xd7, 0x96, 0x60, + 0x00, 0x69, 0x99, 0x66, 0x69, 0x69, 0x66, 0x00 +}; + +static const BYTE NetNotchBits[] = +{ + 0x52, 0x20, + 0x23, 0x25, + 0x33, 0x25, + 0x31, 0x35, + 0x31, 0x35, + 0x31, 0x35, + 0x33, 0x35, + 0x31, 0x35, + 0x31, 0x35, + 0x31, 0x25, + 0x33, 0x35, + 0x31, 0x20, + 0x21, 0x35, + 0x23, 0x25, + 0x52, 0x20, + 0x05, 0x50 +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== // // ST_Init // +// Initializes the startup screen for the detected game. // Sets the size of the progress bar and displays the startup screen. // -//=========================================================================== +//========================================================================== void ST_Init(int maxProgress) +{ + MaxPos = maxProgress; + CurPos = 0; + NotchPos = 0; + + if (gameinfo.gametype == GAME_Hexen) + { + ST_Hexen_Init (); + } + else + { + ST_Basic_Init (); + } +} + +//========================================================================== +// +// ST_Basic_Init +// +// Shows a progress bar at the bottom of the window. +// +//========================================================================== + +static void ST_Basic_Init () { ProgressBar = CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, 0, 0, Window, 0, g_hInst, NULL); - SendMessage (ProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0,maxProgress)); + SendMessage (ProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0,MaxPos)); LayoutMainWindow (Window, NULL); - MaxPos = maxProgress; - CurPos = 0; + + ST_Done = ST_Basic_Done; + ST_Progress = ST_Basic_Progress; + ST_NetInit = ST_Basic_NetInit; + ST_NetProgress = ST_Basic_NetProgress; + ST_NetMessage = ST_Basic_NetMessage; + ST_NetDone = ST_Basic_NetDone; + ST_NetLoop = ST_Basic_NetLoop; } -//=========================================================================== +//========================================================================== // -// ST_Done +// ST_Basic_Done // // Called just before entering graphics mode to deconstruct the startup // screen. // -//=========================================================================== +//========================================================================== -void ST_Done() +static void ST_Basic_Done() { if (ProgressBar != NULL) { @@ -93,15 +242,15 @@ void ST_Done() } } -//=========================================================================== +//========================================================================== // -// ST_Progress +// ST_Basic_Progress // // Bumps the progress meter one notch. // -//=========================================================================== +//========================================================================== -void ST_Progress() +static void ST_Basic_Progress() { if (CurPos < MaxPos) { @@ -110,9 +259,9 @@ void ST_Progress() } } -//=========================================================================== +//========================================================================== // -// ST_NetInit +// ST_Basic_NetInit // // Shows the network startup pane if it isn't visible. Sets the message in // the pane to the one provided. If numplayers is 0, then the progress bar @@ -120,9 +269,9 @@ void ST_Progress() // is just a full bar. If numplayers is >= 2, then the progress bar is a // normal one, and a progress count is also shown in the pane. // -//=========================================================================== +//========================================================================== -void ST_NetInit(const char *message, int numplayers) +static void ST_Basic_NetInit(const char *message, int numplayers) { NetMaxPos = numplayers; if (NetStartPane == NULL) @@ -181,15 +330,15 @@ void ST_NetInit(const char *message, int numplayers) ST_NetProgress(1); // You always know about yourself } -//=========================================================================== +//========================================================================== // -// ST_NetDone +// ST_Basic_NetDone // // Removes the network startup pane. // -//=========================================================================== +//========================================================================== -void ST_NetDone() +static void ST_Basic_NetDone() { if (NetStartPane != NULL) { @@ -199,17 +348,17 @@ void ST_NetDone() } } -//=========================================================================== +//========================================================================== // -// ST_NetMessage +// ST_Basic_NetMessage // // Call this between ST_NetInit() and ST_NetDone() instead of Printf() to // display messages, in case the progress meter is mixed in the same output // stream as normal messages. // -//=========================================================================== +//========================================================================== -void ST_NetMessage(const char *format, ...) +static void ST_Basic_NetMessage(const char *format, ...) { FString str; va_list argptr; @@ -220,16 +369,16 @@ void ST_NetMessage(const char *format, ...) Printf ("%s\n", str.GetChars()); } -//=========================================================================== +//========================================================================== // -// ST_NetProgress +// ST_Basic_NetProgress // // Sets the network progress meter. If count is 0, it gets bumped by 1. // Otherwise, it is set to count. // -//=========================================================================== +//========================================================================== -void ST_NetProgress(int count) +static void ST_Basic_NetProgress(int count) { if (count == 0) { @@ -258,9 +407,9 @@ void ST_NetProgress(int count) } } -//=========================================================================== +//========================================================================== // -// ST_NetLoop +// ST_Basic_NetLoop // // The timer_callback function is called at least two times per second // and passed the userdata value. It should return true to stop the loop and @@ -270,9 +419,9 @@ void ST_NetProgress(int count) // false if the loop was halted because the user wants to abort the // network synchronization. // -//=========================================================================== +//========================================================================== -bool ST_NetLoop(bool (*timer_callback)(void *), void *userdata) +static bool ST_Basic_NetLoop(bool (*timer_callback)(void *), void *userdata) { BOOL bRet; MSG msg; @@ -310,16 +459,16 @@ bool ST_NetLoop(bool (*timer_callback)(void *), void *userdata) return false; } -//=========================================================================== +//========================================================================== // // NetStartPaneProc // // DialogProc for the network startup pane. It just waits for somebody to // click a button, and the only button available is the abort one. // -//=========================================================================== +//========================================================================== -INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +static INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED) { @@ -328,3 +477,218 @@ INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP } return FALSE; } + +//========================================================================== +// +// ST_Hexen_Init +// +// Shows the Hexen startup screen. If the screen doesn't appear to be +// valid, it falls back to ST_Basic_Init. +// +// The startup graphic is a planar, 4-bit 640x480 graphic preceded by a +// 16 entry (48 byte) VGA palette. +// +//========================================================================== + +static void ST_Hexen_Init () +{ + int startup_lump = Wads.CheckNumForName ("STARTUP"); + + if (startup_lump < 0 || Wads.LumpLength (startup_lump) != 153648) + { + ST_Basic_Init (); + return; + } + + StartupScreen = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, g_hInst, NULL); + if (StartupScreen == NULL) + { + ST_Basic_Init (); + return; + } + SetWindowLong (StartupScreen, GWL_ID, IDC_STATIC_STARTUP); + + BYTE startup_screen[153648]; + union + { + RGBQUAD color; + DWORD quad; + }; + + Wads.ReadLump (startup_lump, startup_screen); + + color.rgbReserved = 0; + + // Initialize the bitmap info header. + StartupBitmapInfo.Header.biSize = sizeof(BITMAPINFOHEADER); + StartupBitmapInfo.Header.biWidth = 640; + StartupBitmapInfo.Header.biHeight = 480; + StartupBitmapInfo.Header.biPlanes = 1; + StartupBitmapInfo.Header.biBitCount = 4; + StartupBitmapInfo.Header.biCompression = 0; + StartupBitmapInfo.Header.biSizeImage = 153600; + StartupBitmapInfo.Header.biXPelsPerMeter = 0; + StartupBitmapInfo.Header.biYPelsPerMeter = 0; + StartupBitmapInfo.Header.biClrUsed = 16; + StartupBitmapInfo.Header.biClrImportant = 16; + + // Initialize the bitmap header. + for (int i = 0; i < 16; ++i) + { + color.rgbRed = startup_screen[i*3+0]; + color.rgbGreen = startup_screen[i*3+1]; + color.rgbBlue = startup_screen[i*3+2]; + // Convert from 6-bit per component to 8-bit per component. + quad = (quad << 2) | ((quad >> 4) & 0x03030303); + StartupBitmapInfo.Colors[i] = color; + } + + // Fill in the bitmap data. Convert to chunky, because I can't figure out + // if Windows actually supports planar images or not, despite the presence + // of biPlanes in the BITMAPINFOHEADER. + StartupBitmapBits = new BYTE[640*480/2]; + ST_Util_PlanarToChunky4 (StartupBitmapBits, startup_screen + 48, 640, 480); + + LayoutMainWindow (Window, NULL); + InvalidateRect (StartupScreen, NULL, TRUE); + + ST_Done = ST_Hexen_Done; + ST_Progress = ST_Hexen_Progress; + ST_NetInit = ST_Basic_NetInit; + ST_NetProgress = ST_Basic_NetProgress; + ST_NetMessage = ST_Basic_NetMessage; + ST_NetDone = ST_Basic_NetDone; + ST_NetLoop = ST_Basic_NetLoop; + + // Not that this screen will be around long enough for anyone to + // really hear the music, but start it anyway. + S_ChangeMusic ("orb", true, true); +} + +//========================================================================== +// +// ST_Hexen_Done +// +// Called just before entering graphics mode to deconstruct the startup +// screen. +// +//========================================================================== + +static void ST_Hexen_Done() +{ + if (StartupScreen != NULL) + { + DestroyWindow (StartupScreen); + StartupScreen = NULL; + } +} + +//========================================================================== +// +// ST_Hexen_Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +static void ST_Hexen_Progress() +{ + int notch_pos, x, y; + RECT rect; + + if (CurPos < MaxPos) + { + CurPos++; + notch_pos = (CurPos * ST_MAX_NOTCHES) / MaxPos; + if (notch_pos != NotchPos) + { // Time to draw another notch. + for (; NotchPos < notch_pos; NotchPos++) + { + x = ST_PROGRESS_X + ST_NOTCH_WIDTH * NotchPos; + y = ST_PROGRESS_Y; + ST_Util_DrawBlock (StartupBitmapBits + x / 2 + y * 320, NotchBits, ST_NOTCH_WIDTH / 2, ST_NOTCH_HEIGHT, 320); + GetClientRect (StartupScreen, &rect); + rect.left = x * rect.right / 640 - 1; + rect.top = y * rect.bottom / 480 - 1; + rect.right = (x + ST_NOTCH_WIDTH) * rect.right / 640 + 1; + rect.bottom = (y + ST_NOTCH_HEIGHT) * rect.bottom / 480 + 1; + InvalidateRect (StartupScreen, &rect, FALSE); + } + S_Sound (CHAN_BODY, "StartupTick", 1, ATTN_NONE); + } + } + I_GetEvent (); +} + +//========================================================================== +// +// ST_Util_PlanarToChunky4 +// +// Convert a 4-bpp planar image to chunky pixels. +// +//========================================================================== + +void ST_Util_PlanarToChunky4 (BYTE *dest, const BYTE *src, int width, int height) +{ + int y, x; + const BYTE *src1, *src2, *src3, *src4; + size_t plane_size = width / 8 * height; + + src1 = src; + src2 = src1 + plane_size; + src3 = src2 + plane_size; + src4 = src3 + plane_size; + + for (y = height; y > 0; --y) + { + for (x = width; x > 0; x -= 8) + { + // Pixels 0 and 1 + dest[0] = (*src4 & 0x80) | ((*src3 & 0x80) >> 1) | ((*src2 & 0x80) >> 2) | ((*src1 & 0x80) >> 3) | + ((*src4 & 0x40) >> 3) | ((*src3 & 0x40) >> 4) | ((*src2 & 0x40) >> 5) | ((*src1 & 0x40) >> 6); + // Pixels 2 and 3 + dest[1] = ((*src4 & 0x20) << 2) | ((*src3 & 0x20) << 1) | ((*src2 & 0x20)) | ((*src1 & 0x20) >> 1) | + ((*src4 & 0x10) >> 1) | ((*src3 & 0x10) >> 2) | ((*src2 & 0x10) >> 3) | ((*src1 & 0x10) >> 4); + // Pixels 4 and 5 + dest[2] = ((*src4 & 0x08) << 4) | ((*src3 & 0x08) << 3) | ((*src2 & 0x08) << 2) | ((*src1 & 0x08) << 1) | + ((*src4 & 0x04) << 1) | ((*src3 & 0x04)) | ((*src2 & 0x04) >> 1) | ((*src1 & 0x04) >> 2); + // Pixels 6 and 7 + dest[3] = ((*src4 & 0x02) << 6) | ((*src3 & 0x02) << 5) | ((*src2 & 0x02) << 4) | ((*src1 & 0x02) << 3) | + ((*src4 & 0x01) << 3) | ((*src3 & 0x01) << 2) | ((*src2 & 0x01) << 1) | ((*src1 & 0x01)); + dest += 4; + src1 += 1; + src2 += 1; + src3 += 1; + src4 += 1; + } + } +} + +//========================================================================== +// +// ST_Util_DrawBlock +// +//========================================================================== + +void ST_Util_DrawBlock (BYTE *dest, const BYTE *src, int bytewidth, int height, int destpitch) +{ + if (bytewidth == 8) + { // progress notches + for (; height > 0; --height) + { + ((DWORD *)dest)[0] = ((const DWORD *)src)[0]; + ((DWORD *)dest)[1] = ((const DWORD *)src)[1]; + dest += destpitch; + src += 8; + } + } + else if (bytewidth == 2) + { // net progress notches + for (; height > 0; --height) + { + *((WORD *)dest) = *((const WORD *)src); + dest += destpitch; + src += 2; + } + } +}