diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 064177169..119a941d2 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -831,12 +831,16 @@ set (PCH_SOURCES common/menu/menuinput.cpp common/menu/messagebox.cpp common/menu/optionmenu.cpp + common/menu/resolutionmenu.cpp - common/input/i_gui.cpp - common/input/i_joystick.cpp - common/input/i_input.cpp + #common/input/i_joystick.cpp + #common/input/i_input.cpp common/input/m_joy.cpp common/input/input.cpp + + common/rendering/v_video.cpp + common/rendering/v_framebuffer.cpp + common/rendering/r_videoscale.cpp ) if( MSVC ) diff --git a/source/build/include/baselayer.h b/source/build/include/baselayer.h index 281e1ba62..7432eb850 100644 --- a/source/build/include/baselayer.h +++ b/source/build/include/baselayer.h @@ -128,23 +128,23 @@ extern int32_t qsetmode; #define in3dmode() (qsetmode==200) -int32_t initsystem(void); -void uninitsystem(void); void system_getcvars(void); extern int32_t g_logFlushWindow; -int32_t handleevents(void); +void I_GetEvent(); + +inline int32_t handleevents(void) +{ + I_GetEvent(); + return 0; +} + int32_t handleevents_peekkeys(void); int32_t initinput(void); void uninitinput(void); -void joySetCallback(void (*callback)(int32_t,int32_t)); -const char *joyGetName(int32_t what, int32_t num); // what: 0=axis, 1=button, 2=hat -void joyScanDevices(void); -void mouseInit(void); -void mouseUninit(void); void mouseGrabInput(bool grab); void mouseLockToWindow(bool a); void mouseMoveToCenter(void); diff --git a/source/build/src/baselayer.cpp b/source/build/src/baselayer.cpp index b184438db..e6ccc17b3 100644 --- a/source/build/src/baselayer.cpp +++ b/source/build/src/baselayer.cpp @@ -12,15 +12,6 @@ #include "d_event.h" #include "../../glbackend/glbackend.h" -// video -#ifdef _WIN32 -extern "C" -{ - __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 0x00000001; - __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; -} -#endif // _WIN32 - int32_t g_borderless=2; int GUICapture = false; diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index 7fb996d04..95532ba0d 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -8100,8 +8100,6 @@ void engineUnInit(void) Bmemset(basepaltable, 0, sizeof(basepaltable)); basepaltable[0] = palette; - uninitsystem(); - for (bssize_t i = 0; i < num_usermaphacks; i++) { Xfree(usermaphacks[i].mhkfile); diff --git a/source/build/src/sdlayer.cpp b/source/build/src/sdlayer.cpp index def9b5945..8be2cb70d 100644 --- a/source/build/src/sdlayer.cpp +++ b/source/build/src/sdlayer.cpp @@ -76,7 +76,6 @@ static SDL_version linked; double g_beforeSwapTime; GameInterface* gi; -FArgs* Args; void buildkeytranslationtable();; @@ -156,72 +155,6 @@ uint16_t joydead[9], joysatur[9]; #define MAX_ERRORTEXT 4096 -//========================================================================== -// -// CalculateCPUSpeed -// -// Make a decent guess at how much time elapses between TSC steps. This can -// vary over runtime depending on power management settings, so should not -// be used anywhere that truely accurate timing actually matters. -// -//========================================================================== - -double PerfToSec, PerfToMillisec; -#include "stats.h" - -static void CalculateCPUSpeed() -{ - LARGE_INTEGER freq; - - QueryPerformanceFrequency(&freq); - - if (freq.QuadPart != 0) - { - LARGE_INTEGER count1, count2; - cycle_t ClockCalibration; - DWORD min_diff; - - ClockCalibration.Reset(); - - // Count cycles for at least 55 milliseconds. - // The performance counter may be very low resolution compared to CPU - // speeds today, so the longer we count, the more accurate our estimate. - // On the other hand, we don't want to count too long, because we don't - // want the user to notice us spend time here, since most users will - // probably never use the performance statistics. - min_diff = freq.LowPart * 11 / 200; - - // Minimize the chance of task switching during the testing by going very - // high priority. This is another reason to avoid timing for too long. - SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - - // Make sure we start timing on a counter boundary. - QueryPerformanceCounter(&count1); - do - { - QueryPerformanceCounter(&count2); - } while (count1.QuadPart == count2.QuadPart); - - // Do the timing loop. - ClockCalibration.Clock(); - do - { - QueryPerformanceCounter(&count1); - } while ((count1.QuadPart - count2.QuadPart) < min_diff); - ClockCalibration.Unclock(); - - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); - - PerfToSec = double(count1.QuadPart - count2.QuadPart) / (double(ClockCalibration.GetRawCounter()) * freq.QuadPart); - PerfToMillisec = PerfToSec * 1000.0; - } -} - - - - //========================================================================== // // I_Error @@ -578,6 +511,7 @@ static void sighandler(int signum) int GameMain(); +#if 0 #ifdef _WIN32 int WINAPI WinMain(HINSTANCE , HINSTANCE , LPSTR , int ) @@ -585,59 +519,8 @@ int WINAPI WinMain(HINSTANCE , HINSTANCE , LPSTR , int ) int main(int argc, char *argv[]) #endif { -#ifdef _WIN32 - char* argvbuf; - int32_t buildargc = win_buildargs(&argvbuf); - const char** buildargv = (const char**)Xmalloc(sizeof(char*) * (buildargc + 1)); - char* wp = argvbuf; - - for (bssize_t i = 0; i < buildargc; i++, wp++) - { - buildargv[i] = wp; - while (*wp) wp++; - } - buildargv[buildargc] = NULL; -#else - auto buildargc = argc; - auto buildargv = argv; -#endif - - Args = new FArgs(buildargc, buildargv); - -#if defined _WIN32 && defined SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING - // Thread naming interferes with debugging using MinGW-w64's GDB. - SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1"); -#endif - - int32_t r; - - -#ifndef _WIN32 - setenv("__GL_THREADED_OPTIMIZATIONS", "1", 0); -#endif - CalculateCPUSpeed(); - buildkeytranslationtable(); -#ifndef _WIN32 // catching signals is not really helpful on Windows. - signal(SIGSEGV, sighandler); - signal(SIGILL, sighandler); /* clang -fcatch-undefined-behavior uses an ill. insn */ - signal(SIGABRT, sighandler); - signal(SIGFPE, sighandler); -#endif - - -#if defined(HAVE_GTK2) - // Pre-initialize SDL video system in order to make sure XInitThreads() is called - // before GTK starts talking to X11. - uint32_t inited = SDL_WasInit(SDL_INIT_VIDEO); - if (inited == 0) - SDL_Init(SDL_INIT_VIDEO); - else if (!(inited & SDL_INIT_VIDEO)) - SDL_InitSubSystem(SDL_INIT_VIDEO); - gtkbuild_init(&argc, &argv); -#endif - if (initsystem()) Bexit(9); SDL_StartTextInput(); @@ -648,6 +531,7 @@ int main(int argc, char *argv[]) #endif return r; } +#endif // The resourge manager in cache1d is far too broken to add some arbitrary file without some adjustment. // For now, keep this file here, until the resource management can be redone in a more workable fashion. @@ -696,117 +580,6 @@ int32_t videoSetVsync(int32_t newSync) } #endif -int32_t sdlayer_checkversion(void); -#if SDL_MAJOR_VERSION != 1 -int32_t sdlayer_checkversion(void) -{ -#if 0 - SDL_version compiled; - - SDL_GetVersion(&linked); - SDL_VERSION(&compiled); - - if (!Bmemcmp(&compiled, &linked, sizeof(SDL_version))) - initprintf("Initializing SDL %d.%d.%d\n", - compiled.major, compiled.minor, compiled.patch); - else - initprintf("Initializing SDL %d.%d.%d" - " (built against SDL version %d.%d.%d)\n", - linked.major, linked.minor, linked.patch, compiled.major, compiled.minor, compiled.patch); - - if (SDL_VERSIONNUM(linked.major, linked.minor, linked.patch) < SDL_REQUIREDVERSION) - { - /*reject running under SDL versions older than what is stated in sdl_inc.h */ - initprintf("You need at least v%d.%d.%d of SDL to run this game\n",SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z); - return -1; - } - -#endif - return 0; -} - -// -// initsystem() -- init SDL systems -// -int32_t initsystem(void) -{ - const int sdlinitflags = SDL_INIT_VIDEO; - - if (sdlayer_checkversion()) - return -1; - - int32_t err = 0; - uint32_t inited = SDL_WasInit(sdlinitflags); - if (inited == 0) - err = SDL_Init(sdlinitflags); - else if ((inited & sdlinitflags) != sdlinitflags) - err = SDL_InitSubSystem(sdlinitflags & ~inited); - - if (err) - { - initprintf("Initialization failed! (%s)\nNon-interactive mode enabled\n", SDL_GetError()); - novideo = 1; -#ifdef USE_OPENGL - nogl = 1; -#endif - } - -#if SDL_MAJOR_VERSION > 1 - SDL_StopTextInput(); -#endif - - atexit(uninitsystem); - - frameplace = 0; - lockcount = 0; - - if (!novideo) - { -#ifdef USE_OPENGL - if (SDL_GL_LoadLibrary(0)) - { - initprintf("Failed loading OpenGL Driver. GL modes will be unavailable. Error: %s\n", SDL_GetError()); - nogl = 1; - } -#endif - -#ifndef _WIN32 - const char *drvname = SDL_GetVideoDriver(0); - - if (drvname) - initprintf("Using \"%s\" video driver\n", drvname); -#endif - } - - return 0; -} -#endif - - -// -// uninitsystem() -- uninit SDL systems -// -void uninitsystem(void) -{ - uninitinput(); - timerUninit(); - - if (appicon) - { - SDL_FreeSurface(appicon); - appicon = NULL; - } - - SDL_Quit(); - -#ifdef USE_OPENGL -# if SDL_MAJOR_VERSION!=1 - SDL_GL_UnloadLibrary(); -# endif -#endif -} - - // // system_getcvars() -- propagate any cvars that are read post-initialization // @@ -1007,8 +780,6 @@ int32_t initinput(void) // void uninitinput(void) { - mouseUninit(); - if (controller) { SDL_GameControllerClose(controller); diff --git a/source/common/2d/drawparms.h b/source/common/2d/drawparms.h index cd1498ab5..c7b97a62f 100644 --- a/source/common/2d/drawparms.h +++ b/source/common/2d/drawparms.h @@ -178,19 +178,3 @@ struct Va_List va_list list; }; -int CheckRatio (int width, int height, int *trueratio=NULL); -static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } -inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } - -float ActiveRatio (int width, int height, float *trueratio = NULL); -static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } - -int AspectBaseWidth(float aspect); -int AspectBaseHeight(float aspect); -double AspectPspriteOffset(float aspect); -int AspectMultiplier(float aspect); -bool AspectTallerThanWide(float aspect); -void ScaleWithAspect(int &w, int &h, int Width, int Height); - -int GetUIScale(int altval); -int GetConScale(int altval); diff --git a/source/common/2d/v_draw.cpp b/source/common/2d/v_draw.cpp index 3de2fbded..8a0a03da9 100644 --- a/source/common/2d/v_draw.cpp +++ b/source/common/2d/v_draw.cpp @@ -39,8 +39,7 @@ #include "drawparms.h" #include "templates.h" #include "v_draw.h" - -ScreenDummy* screen; +#include "v_video.h" CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) { @@ -52,8 +51,6 @@ CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) //setsizeneeded = true; } -CVAR(Int, vid_aspect, 0, 0) - int GetUIScale(int altval) { int scaleval; @@ -107,36 +104,6 @@ int CleanWidth, CleanHeight; int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; -void V_UpdateModeSize(int width, int height) -{ - // This calculates the menu scale. - // The optimal scale will always be to fit a virtual 640 pixel wide display onto the screen. - // Exceptions are made for a few ranges where the available virtual width is > 480. - - // This reference size is being used so that on 800x450 (small 16:9) a scale of 2 gets used. - - CleanXfac = std::max(std::min(screen->GetWidth() / 400, screen->GetHeight() / 240), 1); - if (CleanXfac >= 4) CleanXfac--; // Otherwise we do not have enough space for the episode/skill menus in some languages. - CleanYfac = CleanXfac; - CleanWidth = screen->GetWidth() / CleanXfac; - CleanHeight = screen->GetHeight() / CleanYfac; - - int w = screen->GetWidth(); - int factor; - if (w < 640) factor = 1; - else if (w >= 1024 && w < 1280) factor = 2; - else if (w >= 1600 && w < 1920) factor = 3; - else factor = w / 640; - - if (w < 1360) factor = 1; - else if (w < 1920) factor = 2; - else factor = int(factor * 0.7); - - CleanYfac_1 = CleanXfac_1 = factor;// MAX(1, int(factor * 0.7)); - CleanWidth_1 = width / CleanXfac_1; - CleanHeight_1 = height / CleanYfac_1; -} - //========================================================================== // // Draw parameter parsing @@ -749,156 +716,3 @@ void VirtualToRealCoords(double &x, double &y, double &w, double &h, } } - -// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. -int ActiveFakeRatio(int width, int height) -{ - int fakeratio = -1; - if ((vid_aspect >= 1) && (vid_aspect <= 6)) - { - // [SP] User wants to force aspect ratio; let them. - fakeratio = int(vid_aspect); - if (fakeratio == 3) - { - fakeratio = 0; - } - else if (fakeratio == 5) - { - fakeratio = 3; - } - } - else if (vid_aspect == 0)// && ViewportIsScaled43()) - { - fakeratio = 0; - } - return fakeratio; -} - -// Active screen ratio based on cvars and size -float ActiveRatio(int width, int height, float* trueratio) -{ - static float forcedRatioTypes[] = - { - 4 / 3.0f, - 16 / 9.0f, - 16 / 10.0f, - 17 / 10.0f, - 5 / 4.0f, - 17 / 10.0f, - 21 / 9.0f - }; - - float ratio = width / (float)height; - int fakeratio = ActiveFakeRatio(width, height); - - if (trueratio) - *trueratio = ratio; - return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio; -} - -// Tries to guess the physical dimensions of the screen based on the -// screen's pixel dimensions. Can return: -// 0: 4:3 -// 1: 16:9 -// 2: 16:10 -// 3: 17:10 -// 4: 5:4 -// 5: 17:10 (redundant, never returned) -// 6: 21:9 -int CheckRatio(int width, int height, int* trueratio) -{ - float aspect = width / (float)height; - - static std::pair ratioTypes[] = - { - { 21 / 9.0f , 6 }, - { 16 / 9.0f , 1 }, - { 17 / 10.0f , 3 }, - { 16 / 10.0f , 2 }, - { 4 / 3.0f , 0 }, - { 5 / 4.0f , 4 }, - { 0.0f, 0 } - }; - - int ratio = ratioTypes[0].second; - float distance = fabs(ratioTypes[0].first - aspect); - for (int i = 1; ratioTypes[i].first != 0.0f; i++) - { - float d = fabs(ratioTypes[i].first - aspect); - if (d < distance) - { - ratio = ratioTypes[i].second; - distance = d; - } - } - - int fakeratio = ActiveFakeRatio(width, height); - if (fakeratio == -1) - fakeratio = ratio; - - if (trueratio) - *trueratio = ratio; - return fakeratio; -} - -int AspectBaseWidth(float aspect) -{ - return (int)round(240.0f * aspect * 3.0f); -} - -int AspectBaseHeight(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); - else - return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); -} - -double AspectPspriteOffset(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return 0.0; - else - return ((4.0 / 3.0) / aspect - 1.0) * 97.5; -} - -int AspectMultiplier(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); - else - return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); -} - -bool AspectTallerThanWide(float aspect) -{ - return aspect < 1.333f; -} - -void ScaleWithAspect(int& w, int& h, int Width, int Height) -{ - int resRatio = CheckRatio(Width, Height); - int screenRatio; - CheckRatio(w, h, &screenRatio); - if (resRatio == screenRatio) - return; - - double yratio; - switch (resRatio) - { - case 0: yratio = 4. / 3.; break; - case 1: yratio = 16. / 9.; break; - case 2: yratio = 16. / 10.; break; - case 3: yratio = 17. / 10.; break; - case 4: yratio = 5. / 4.; break; - case 6: yratio = 21. / 9.; break; - default: return; - } - double y = w / yratio; - if (y > h) - w = static_cast(h * yratio); - else - h = static_cast(y); -} - - diff --git a/source/common/2d/v_draw.h b/source/common/2d/v_draw.h index a120c0cfe..58cfddb64 100644 --- a/source/common/2d/v_draw.h +++ b/source/common/2d/v_draw.h @@ -2,18 +2,13 @@ #include "drawparms.h" #include "c_cvars.h" +#include "v_video.h" // Undo Windows's forced #defines #ifdef DrawText #undef DrawText #endif extern int32_t xdim, ydim; -struct ScreenDummy -{ - static int GetWidth() { return xdim; } - static int GetHeight() { return ydim; } -}; -extern ScreenDummy* screen; int GetUIScale(int altval); int GetConScale(int altval); @@ -33,7 +28,7 @@ extern int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; bool SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy); bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext); void VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom, bool handleaspect); -int ActiveFakeRatio(int width, int height); +//int ActiveFakeRatio(int width, int height); float ActiveRatio(int width, int height, float* trueratio); int CheckRatio(int width, int height, int* trueratio); int AspectBaseWidth(float aspect);; @@ -53,13 +48,3 @@ void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, in EXTERN_CVAR(Int, con_scaletext) // Scale notify text at high resolutions? EXTERN_CVAR(Int, con_scale) -inline int active_con_scaletext(bool newconfont = false) -{ - return newconfont ? GetConScale(con_scaletext) : GetUIScale(con_scaletext); -} - -inline int active_con_scale() -{ - return GetConScale(con_scale); -} - diff --git a/source/common/fonts/v_font.cpp b/source/common/fonts/v_font.cpp index 50037405c..f13e207b9 100644 --- a/source/common/fonts/v_font.cpp +++ b/source/common/fonts/v_font.cpp @@ -304,7 +304,7 @@ int V_GetColor(const char* cstr) { val[0] = cstr[1 + i * 2]; val[1] = cstr[2 + i * 2]; - c[i] = ParseHex(val); + c[i] = ParseHex(val, nullptr); } } else if (len == 4) @@ -313,7 +313,7 @@ int V_GetColor(const char* cstr) for (i = 0; i < 3; ++i) { val[1] = val[0] = cstr[1 + i]; - c[i] = ParseHex(val); + c[i] = ParseHex(val, nullptr); } } else @@ -366,7 +366,7 @@ int V_GetColor(const char* cstr) { val[1] = val[0]; } - c[i] = ParseHex(val); + c[i] = ParseHex(val, nullptr); } } } diff --git a/source/common/gamecontrol.cpp b/source/common/gamecontrol.cpp index de8b2387a..bbc11e7d8 100644 --- a/source/common/gamecontrol.cpp +++ b/source/common/gamecontrol.cpp @@ -286,8 +286,8 @@ int GameMain() C_InitConsole(1024, 768, true); FStringf logpath("logfile %sdemolition.log", M_GetDocumentsPath().GetChars()); C_DoCommand(logpath); - I_StartupJoysticks(); - mouseInit(); + //I_StartupJoysticks(); + //mouseInit(); #ifndef NETCODE_DISABLE gHaveNetworking = !enet_initialize(); diff --git a/source/common/menu/menu.cpp b/source/common/menu/menu.cpp index c81dcee7a..fd31bb1fb 100644 --- a/source/common/menu/menu.cpp +++ b/source/common/menu/menu.cpp @@ -948,6 +948,22 @@ void M_MenuSound(EMenuSounds snd) // //============================================================================= +void M_PreviousMenu() +{ + if (DMenu::CurrentMenu != nullptr) + { + DMenu* parent = DMenu::CurrentMenu->mParentMenu; + DMenu::CurrentMenu->Destroy(); + DMenu::CurrentMenu = parent; + } +} + +//============================================================================= +// +// +// +//============================================================================= + void M_Init (void) { RegisterDukeMenus(); diff --git a/source/common/menu/menu.h b/source/common/menu/menu.h index 79a809c24..01066b110 100644 --- a/source/common/menu/menu.h +++ b/source/common/menu/menu.h @@ -765,6 +765,7 @@ void M_EnableMenu (bool on) ; bool M_Responder (event_t *ev); void M_Ticker (void); void M_Drawer (void); +void M_PreviousMenu(); void M_Init (void); void M_CreateMenus(); void M_ActivateMenu(DMenu *menu); diff --git a/source/common/input/i_gui.cpp b/source/common/menu/resolutionmenu.cpp similarity index 51% rename from source/common/input/i_gui.cpp rename to source/common/menu/resolutionmenu.cpp index 01a2362ca..3e8141b25 100644 --- a/source/common/input/i_gui.cpp +++ b/source/common/menu/resolutionmenu.cpp @@ -1,8 +1,9 @@ /* -** i_gui.cpp +** resolutionmenu.cpp +** Basic Custom Resolution Selector for the Menu ** **--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit +** Copyright 2018 Rachael Alexanderson ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -31,57 +32,61 @@ ** */ -#include +#include "c_dispatch.h" +#include "c_cvars.h" +#include "v_video.h" +#include "menu/menu.h" -#include +CVAR(Int, menu_resolution_custom_width, 640, 0) +CVAR(Int, menu_resolution_custom_height, 480, 0) -#include "bitmap.h" -//#include "v_palette.h" -#include "textures.h" +EXTERN_CVAR(Bool, vid_fullscreen) +EXTERN_CVAR(Bool, win_maximized) +EXTERN_CVAR(Bool, vid_scale_customlinear) +EXTERN_CVAR(Bool, vid_scale_customstretched) +EXTERN_CVAR(Int, vid_scale_customwidth) +EXTERN_CVAR(Int, vid_scale_customheight) +EXTERN_CVAR(Int, vid_scalemode) +EXTERN_CVAR(Float, vid_scalefactor) -bool I_SetCursor(FTexture *cursorpic) +CCMD (menu_resolution_set_custom) { - static SDL_Cursor *cursor; - static SDL_Surface *cursorSurface; - - if (cursorpic != NULL) + if (argv.argc() > 2) { - auto src = cursorpic->GetBgraBitmap(nullptr); - // Must be no larger than 32x32. - if (src.GetWidth() > 32 || src.GetHeight() > 32) - { - return false; - } - - if (cursorSurface == NULL) - cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0)); - - SDL_LockSurface(cursorSurface); - uint8_t buffer[32*32*4]; - memset(buffer, 0, 32*32*4); - FBitmap bmp(buffer, 32*4, 32, 32); - bmp.Blit(0, 0, src); // expand to 32*32 - memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4); - SDL_UnlockSurface(cursorSurface); - - if (cursor) - SDL_FreeCursor (cursor); - cursor = SDL_CreateColorCursor (cursorSurface, 0, 0); - SDL_SetCursor (cursor); + menu_resolution_custom_width = atoi(argv[1]); + menu_resolution_custom_height = atoi(argv[2]); } else { - if (cursor) - { - SDL_SetCursor (NULL); - SDL_FreeCursor (cursor); - cursor = NULL; - } - if (cursorSurface != NULL) - { - SDL_FreeSurface(cursorSurface); - cursorSurface = NULL; - } + Printf("This command is not meant to be used outside the menu! But if you want to use it, please specify and .\n"); } - return true; + M_PreviousMenu(); } + +CCMD (menu_resolution_commit_changes) +{ + int do_fullscreen = fullscreen; + if (argv.argc() > 1) + { + do_fullscreen = atoi(argv[1]); + } + + if (do_fullscreen == false) + { + vid_scalemode = vid_scale_customlinear; + vid_scalefactor = 1.; + screen->SetWindowSize(menu_resolution_custom_width, menu_resolution_custom_height); + V_OutputResized(screen->GetClientWidth(), screen->GetClientHeight()); + } + else + { + fullscreen = true; + vid_scalemode = 5; + vid_scalefactor = 1.; + vid_scale_customwidth = menu_resolution_custom_width; + vid_scale_customheight = menu_resolution_custom_height; + vid_scale_customstretched = false; + } +} + + diff --git a/source/common/rendering/i_video.h b/source/common/rendering/i_video.h new file mode 100644 index 000000000..d9a9b9701 --- /dev/null +++ b/source/common/rendering/i_video.h @@ -0,0 +1,38 @@ +#ifndef __I_VIDEO_H__ +#define __I_VIDEO_H__ + +#include + +class DFrameBuffer; + + +class IVideo +{ +public: + virtual ~IVideo() {} + + virtual DFrameBuffer *CreateFrameBuffer() = 0; + + bool SetResolution(); + + virtual void DumpAdapters(); +}; + +void I_InitGraphics(); +void I_ShutdownGraphics(); + +extern IVideo *Video; + +void I_PolyPresentInit(); +uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch); +void I_PolyPresentUnlock(int x, int y, int w, int h); +void I_PolyPresentDeinit(); + + +// Pause a bit. +// [RH] Despite the name, it apparently never waited for the VBL, even in +// the original DOS version (if the Heretic/Hexen source is any indicator). +void I_WaitVBL(int count); + + +#endif // __I_VIDEO_H__ diff --git a/source/common/rendering/r_videoscale.cpp b/source/common/rendering/r_videoscale.cpp new file mode 100644 index 000000000..c4ff7a91b --- /dev/null +++ b/source/common/rendering/r_videoscale.cpp @@ -0,0 +1,261 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2017 Magnus Norddahl +// Copyright(C) 2018 Rachael Alexanderson +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include +#include "c_dispatch.h" +#include "c_cvars.h" +#include "v_video.h" +#include "templates.h" +#include "printf.h" + +#define NUMSCALEMODES 7 + +bool setsizeneeded; + +EXTERN_CVAR(Int, vid_aspect) +CUSTOM_CVAR(Int, vid_scale_customwidth, VID_MIN_WIDTH, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < VID_MIN_WIDTH) + self = VID_MIN_WIDTH; + setsizeneeded = true; +} +CUSTOM_CVAR(Int, vid_scale_customheight, VID_MIN_HEIGHT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < VID_MIN_HEIGHT) + self = VID_MIN_HEIGHT; + setsizeneeded = true; +} +CVAR(Bool, vid_scale_customlinear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Bool, vid_scale_customstretched, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + setsizeneeded = true; +} + +namespace +{ + struct v_ScaleTable + { + bool isValid; + bool isLinear; + uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); + uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); + bool isScaled43; + bool isCustom; + }; + + float v_MinimumToFill(uint32_t inwidth, uint32_t inheight) + { + // sx = screen x dimension, sy = same for y + float sx = (float)inwidth, sy = (float)inheight; + static float lastsx = 0., lastsy = 0., result = 0.; + if (lastsx != sx || lastsy != sy) + { + if (sx <= 0. || sy <= 0.) + return 1.; // prevent x/0 error + // set absolute minimum scale to fill the entire screen but get as close to 640x400 as possible + float ssx = (float)(VID_MIN_WIDTH) / sx, ssy = (float)(VID_MIN_HEIGHT) / sy; + result = (ssx < ssy) ? ssy : ssx; + lastsx = sx; + lastsy = sy; + } + return result; + } + inline uint32_t v_mfillX(uint32_t inwidth, uint32_t inheight) + { + return (uint32_t)((float)inwidth * v_MinimumToFill(inwidth, inheight)); + } + inline uint32_t v_mfillY(uint32_t inwidth, uint32_t inheight) + { + return (uint32_t)((float)inheight * v_MinimumToFill(inwidth, inheight)); + } + + v_ScaleTable vScaleTable[NUMSCALEMODES] = + { + // isValid, isLinear, GetScaledWidth(), GetScaledHeight(), isScaled43, isCustom + { true, false, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, false, false }, // 0 - Native + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, false, false }, // 1 - Native (Linear) + { true, false, [](uint32_t Width, uint32_t Height)->uint32_t { return 640; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 400; }, true, false }, // 2 - 640x400 (formerly 320x200) + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return 960; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 600; }, true, false }, // 3 - 960x600 (formerly 640x400) + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, true, false }, // 4 - 1280x800 + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, true, true }, // 5 - Custom + { true, true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX(Width, Height); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY(Width, Height); }, false, false }, // 6 - Minimum Scale to Fill Entire Screen + }; + bool isOutOfBounds(int x) + { + return (x < 0 || x >= NUMSCALEMODES || vScaleTable[x].isValid == false); + } +} + +void R_ShowCurrentScaling(); +CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + setsizeneeded = true; + if (self < 0.05 || self > 2.0) + self = 1.0; + if (self != 1.0) + R_ShowCurrentScaling(); +} + +CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + setsizeneeded = true; + if (isOutOfBounds(self)) + self = 0; +} + +CUSTOM_CVAR(Bool, vid_cropaspect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + setsizeneeded = true; +} + +bool ViewportLinearScale() +{ + if (isOutOfBounds(vid_scalemode)) + vid_scalemode = 0; + // hack - use custom scaling if in "custom" mode + if (vScaleTable[vid_scalemode].isCustom) + return vid_scale_customlinear; + // vid_scalefactor > 1 == forced linear scale + return (vid_scalefactor > 1.0) ? true : vScaleTable[vid_scalemode].isLinear; +} + +int ViewportScaledWidth(int width, int height) +{ + if (isOutOfBounds(vid_scalemode)) + vid_scalemode = 0; + if (vid_cropaspect && height > 0) + { + width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; + height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; + } + return (int)std::max((int32_t)VID_MIN_WIDTH, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width, height))); +} + +int ViewportScaledHeight(int width, int height) +{ + if (isOutOfBounds(vid_scalemode)) + vid_scalemode = 0; + if (vid_cropaspect && height > 0) + { + height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; + width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; + } + return (int)std::max((int32_t)VID_MIN_HEIGHT, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(width, height))); +} + +bool ViewportIsScaled43() +{ + if (isOutOfBounds(vid_scalemode)) + vid_scalemode = 0; + // hack - use custom scaling if in "custom" mode + if (vScaleTable[vid_scalemode].isCustom) + return vid_scale_customstretched; + return vScaleTable[vid_scalemode].isScaled43; +} + +void R_ShowCurrentScaling() +{ + int x1 = screen->GetClientWidth(), y1 = screen->GetClientHeight(), x2 = ViewportScaledWidth(x1, y1), y2 = ViewportScaledHeight(x1, y1); + Printf("Current vid_scalefactor: %f\n", (float)(vid_scalefactor)); + Printf("Real resolution: %i x %i\nEmulated resolution: %i x %i\n", x1, y1, x2, y2); +} + +CCMD (vid_showcurrentscaling) +{ + R_ShowCurrentScaling(); +} + +CCMD (vid_scaletowidth) +{ + if (argv.argc() > 1) + { + // the following enables the use of ViewportScaledWidth to get the proper dimensions in custom scale modes + vid_scalefactor = 1; + vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledWidth(screen->GetClientWidth(), screen->GetClientHeight())); + } +} + +CCMD (vid_scaletoheight) +{ + if (argv.argc() > 1) + { + vid_scalefactor = 1; + vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledHeight(screen->GetClientWidth(), screen->GetClientHeight())); + } +} + +inline bool atob(char* I) +{ + if (stricmp (I, "true") == 0 || stricmp (I, "1") == 0) + return true; + return false; +} + +CCMD (vid_setscale) +{ + if (argv.argc() > 2) + { + vid_scale_customwidth = atoi(argv[1]); + vid_scale_customheight = atoi(argv[2]); + if (argv.argc() > 3) + { + vid_scale_customlinear = atob(argv[3]); + if (argv.argc() > 4) + { + vid_scale_customstretched = atob(argv[4]); + } + } + vid_scalemode = 5; + vid_scalefactor = 1.0; + } + else + { + Printf("Usage: vid_setscale [bool linear] [bool long-pixel-shape]\nThis command will create a custom viewport scaling mode.\n"); + } +} + +CCMD (vid_scaletolowest) +{ + uint32_t method = 0; + if (argv.argc() > 1) + method = atoi(argv[1]); + switch (method) + { + case 1: // Method 1: set a custom video scaling + vid_scalemode = 5; + vid_scalefactor = 1.0; + vid_scale_customlinear = 1; + vid_scale_customstretched = 0; + vid_scale_customwidth = v_mfillX(screen->GetClientWidth(), screen->GetClientHeight()); + vid_scale_customheight = v_mfillY(screen->GetClientWidth(), screen->GetClientHeight()); + break; + case 2: // Method 2: use the actual downscaling mode directly + vid_scalemode = 6; + vid_scalefactor = 1.0; + break; + default: // Default method: use vid_scalefactor to achieve the result on a default scaling mode + vid_scalemode = 1; + vid_scalefactor = v_MinimumToFill(screen->GetClientWidth(), screen->GetClientHeight()); + break; + } +} diff --git a/source/common/rendering/r_videoscale.h b/source/common/rendering/r_videoscale.h new file mode 100644 index 000000000..2fcbbc85b --- /dev/null +++ b/source/common/rendering/r_videoscale.h @@ -0,0 +1,31 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2017 Magnus Norddahl +// Copyright(C) 2017 Rachael Alexanderson +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#ifndef __VIDEOSCALE_H__ +#define __VIDEOSCALE_H__ +EXTERN_CVAR (Int, vid_scalemode) +bool ViewportLinearScale(); +int ViewportScaledWidth(int width, int height); +int ViewportScaledHeight(int width, int height); +bool ViewportIsScaled43(); +#endif //__VIDEOSCALE_H__ \ No newline at end of file diff --git a/source/common/rendering/v_framebuffer.cpp b/source/common/rendering/v_framebuffer.cpp new file mode 100644 index 000000000..10f9d8aac --- /dev/null +++ b/source/common/rendering/v_framebuffer.cpp @@ -0,0 +1,389 @@ +/* +** The base framebuffer class +** +**--------------------------------------------------------------------------- +** Copyright 1999-2016 Randy Heit +** Copyright 2005-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include + + +#include "v_video.h" + +#include "c_dispatch.h" +#include "hardware.h" +#include "r_videoscale.h" +#include "i_time.h" +#include "v_font.h" +#include "v_draw.h" +#include "i_time.h" +#include "v_2ddrawer.h" +/* +#include "hwrenderer/scene/hw_portal.h" +#include "hwrenderer/utility/hw_clock.h" +#include "hwrenderer/data/flatvertices.h" +*/ + +#include +#include + + +CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE); +CVAR(Bool, vid_fps, false, 0) +CVAR(Int, vid_showpalette, 0, 0) + +EXTERN_CVAR(Bool, ticker) +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Int, vid_maxfps) +EXTERN_CVAR(Bool, cl_capfps) +EXTERN_CVAR(Int, screenblocks) + +//========================================================================== +// +// DCanvas :: CalcGamma +// +//========================================================================== + +void DFrameBuffer::CalcGamma (float gamma, uint8_t gammalookup[256]) +{ + // I found this formula on the web at + // , + // but that page no longer exits. + double invgamma = 1.f / gamma; + int i; + + for (i = 0; i < 256; i++) + { + gammalookup[i] = (uint8_t)(255.0 * pow (i / 255.0, invgamma) + 0.5); + } +} + +//========================================================================== +// +// DFrameBuffer Constructor +// +// A frame buffer canvas is the most common and represents the image that +// gets drawn to the screen. +// +//========================================================================== + +DFrameBuffer::DFrameBuffer (int width, int height) +{ + SetSize(width, height); + //mPortalState = new FPortalSceneState; +} + +DFrameBuffer::~DFrameBuffer() +{ + //delete mPortalState; +} + +void DFrameBuffer::SetSize(int width, int height) +{ + Width = ViewportScaledWidth(width, height); + Height = ViewportScaledHeight(width, height); +} + +//========================================================================== +// +// DFrameBuffer :: DrawRateStuff +// +// Draws the fps counter, dot ticker, and palette debug. +// +//========================================================================== + +void DFrameBuffer::DrawRateStuff () +{ + // Draws frame time and cumulative fps + if (vid_fps) + { + uint64_t ms = screen->FrameTime; + uint64_t howlong = ms - LastMS; + if ((signed)howlong >= 0) + { + char fpsbuff[40]; + int chars; + int rate_x; + + int textScale = active_con_scale(); + + chars = snprintf (fpsbuff, countof(fpsbuff), "%2llu ms (%3llu fps)", (unsigned long long)howlong, (unsigned long long)LastCount); + rate_x = Width / textScale - NewConsoleFont->StringWidth(&fpsbuff[0]); + twod.AddColorOnlyQuad(rate_x * textScale, 0, Width, NewConsoleFont->GetHeight() * textScale, 0); + DrawText (&twod, NewConsoleFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + + uint32_t thisSec = (uint32_t)(ms/1000); + if (LastSec < thisSec) + { + LastCount = FrameCount / (thisSec - LastSec); + LastSec = thisSec; + FrameCount = 0; + } + FrameCount++; + } + LastMS = ms; + } +} + +//========================================================================== +// +// Palette stuff. +// +//========================================================================== + +void DFrameBuffer::Update() +{ + //CheckBench(); + + int initialWidth = GetClientWidth(); + int initialHeight = GetClientHeight(); + int clientWidth = ViewportScaledWidth(initialWidth, initialHeight); + int clientHeight = ViewportScaledHeight(initialWidth, initialHeight); + if (clientWidth < VID_MIN_WIDTH) clientWidth = VID_MIN_WIDTH; + if (clientHeight < VID_MIN_HEIGHT) clientHeight = VID_MIN_HEIGHT; + if (clientWidth > 0 && clientHeight > 0 && (GetWidth() != clientWidth || GetHeight() != clientHeight)) + { + SetVirtualSize(clientWidth, clientHeight); + V_OutputResized(clientWidth, clientHeight); + //mVertexData->OutputResized(clientWidth, clientHeight); + } +} + +//========================================================================== +// +// DFrameBuffer :: SetVSync +// +// Turns vertical sync on and off, if supported. +// +//========================================================================== + +void DFrameBuffer::SetVSync (bool vsync) +{ +} + +//========================================================================== +// +// DFrameBuffer :: WipeStartScreen +// +// Grabs a copy of the screen currently displayed to serve as the initial +// frame of a screen wipe. Also determines which screenwipe will be +// performed. +// +//========================================================================== + +FTexture *DFrameBuffer::WipeStartScreen() +{ + return nullptr; +} + +//========================================================================== +// +// DFrameBuffer :: WipeEndScreen +// +// Grabs a copy of the most-recently drawn, but not yet displayed, screen +// to serve as the final frame of a screen wipe. +// +//========================================================================== + +FTexture *DFrameBuffer::WipeEndScreen() +{ + return nullptr; +} + +//========================================================================== +// +// DFrameBuffer :: GetCaps +// +//========================================================================== + +EXTERN_CVAR(Bool, r_drawvoxels) + +void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) +{ + //SWRenderer->WriteSavePic(player, file, width, height); +} + + +//========================================================================== +// +// Calculates the viewport values needed for 2D and 3D operations +// +//========================================================================== + +void DFrameBuffer::SetViewportRects(IntRect *bounds) +{ + if (bounds) + { + //mSceneViewport = *bounds; + mScreenViewport = *bounds; + mOutputLetterbox = *bounds; + return; + } + +#if 0 + // Special handling so the view with a visible status bar displays properly + int height, width; + if (screenblocks >= 10) + { + height = GetHeight(); + width = GetWidth(); + } + else + { + height = (screenblocks*GetHeight() / 10) & ~7; + width = (screenblocks*GetWidth() / 10); + } +#endif + + // Back buffer letterbox for the final output + int clientWidth = GetClientWidth(); + int clientHeight = GetClientHeight(); + if (clientWidth == 0 || clientHeight == 0) + { + // When window is minimized there may not be any client area. + // Pretend to the rest of the render code that we just have a very small window. + clientWidth = 160; + clientHeight = 120; + } + int screenWidth = GetWidth(); + int screenHeight = GetHeight(); + float scaleX, scaleY; + if (ViewportIsScaled43()) + { + scaleX = std::min(clientWidth / (float)screenWidth, clientHeight / (screenHeight * 1.2f)); + scaleY = scaleX * 1.2f; + } + else + { + scaleX = std::min(clientWidth / (float)screenWidth, clientHeight / (float)screenHeight); + scaleY = scaleX; + } + mOutputLetterbox.width = (int)round(screenWidth * scaleX); + mOutputLetterbox.height = (int)round(screenHeight * scaleY); + mOutputLetterbox.left = (clientWidth - mOutputLetterbox.width) / 2; + mOutputLetterbox.top = (clientHeight - mOutputLetterbox.height) / 2; + + // The entire renderable area, including the 2D HUD + mScreenViewport.left = 0; + mScreenViewport.top = 0; + mScreenViewport.width = screenWidth; + mScreenViewport.height = screenHeight; + +#if 0 + // Viewport for the 3D scene + mSceneViewport.left = viewwindowx; + mSceneViewport.top = screenHeight - (height + viewwindowy - ((height - viewheight) / 2)); + mSceneViewport.width = viewwidth; + mSceneViewport.height = height; +#endif + + // Scale viewports to fit letterbox + bool notScaled = ((mScreenViewport.width == ViewportScaledWidth(mScreenViewport.width, mScreenViewport.height)) && + (mScreenViewport.width == ViewportScaledHeight(mScreenViewport.width, mScreenViewport.height)) && + !ViewportIsScaled43()); + if (gl_scale_viewport && !IsFullscreen() && notScaled) + { + mScreenViewport.width = mOutputLetterbox.width; + mScreenViewport.height = mOutputLetterbox.height; +#if 0 + mSceneViewport.left = (int)round(mSceneViewport.left * scaleX); + mSceneViewport.top = (int)round(mSceneViewport.top * scaleY); + mSceneViewport.width = (int)round(mSceneViewport.width * scaleX); + mSceneViewport.height = (int)round(mSceneViewport.height * scaleY); +#endif + } +} + +//=========================================================================== +// +// Calculates the OpenGL window coordinates for a zdoom screen position +// +//=========================================================================== + +int DFrameBuffer::ScreenToWindowX(int x) +{ + return mScreenViewport.left + (int)round(x * mScreenViewport.width / (float)GetWidth()); +} + +int DFrameBuffer::ScreenToWindowY(int y) +{ + return mScreenViewport.top + mScreenViewport.height - (int)round(y * mScreenViewport.height / (float)GetHeight()); +} + +void DFrameBuffer::ScaleCoordsFromWindow(int16_t &x, int16_t &y) +{ + int letterboxX = mOutputLetterbox.left; + int letterboxY = mOutputLetterbox.top; + int letterboxWidth = mOutputLetterbox.width; + int letterboxHeight = mOutputLetterbox.height; + + x = int16_t((x - letterboxX) * Width / letterboxWidth); + y = int16_t((y - letterboxY) * Height / letterboxHeight); +} + +void DFrameBuffer::FPSLimit() +{ +#if 0 // This doesn't work with Build games. + using namespace std::chrono; + using namespace std::this_thread; + + if (vid_maxfps <= 0 || cl_capfps) + return; + + uint64_t targetWakeTime = fpsLimitTime + 1'000'000 / vid_maxfps; + + while (true) + { + fpsLimitTime = duration_cast(steady_clock::now().time_since_epoch()).count(); + int64_t timeToWait = targetWakeTime - fpsLimitTime; + + if (timeToWait > 1'000'000 || timeToWait <= 0) + { + break; + } + + if (timeToWait <= 2'000) + { + // We are too close to the deadline. OS sleep is not precise enough to wake us before it elapses. + // Yield execution and check time again. + sleep_for(nanoseconds(0)); + } + else + { + // Sleep, but try to wake before deadline. + sleep_for(microseconds(timeToWait - 2'000)); + } + } +#endif +} diff --git a/source/common/rendering/v_video.cpp b/source/common/rendering/v_video.cpp new file mode 100644 index 000000000..1acbb696a --- /dev/null +++ b/source/common/rendering/v_video.cpp @@ -0,0 +1,806 @@ +/* +** Video basics and init code. +** +**--------------------------------------------------------------------------- +** Copyright 1999-2016 Randy Heit +** Copyright 2005-2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + + +#include + +#include "i_system.h" +#include "c_cvars.h" +#include "i_video.h" + +#include "c_console.h" + +#include "m_argv.h" + +#include "v_video.h" +#include "v_text.h" +#include "sc_man.h" + +#include "c_dispatch.h" +#include "cmdlib.h" +#include "hardware.h" +#include "m_png.h" +#include "menu/menu.h" +#include "r_videoscale.h" +#include "i_time.h" +#include "version.h" +#include "filesystem.h" + +EXTERN_CVAR(Int, menu_resolution_custom_width) +EXTERN_CVAR(Int, menu_resolution_custom_height) +CVAR(Int, vid_aspect, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_w, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_h, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, win_maximized, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) + +#if 0 +CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (vid_maxfps < TICRATE && vid_maxfps != 0) + { + vid_maxfps = TICRATE; + } + else if (vid_maxfps > 1000) + { + vid_maxfps = 1000; + } +} +#endif + +CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 0 || self > 4) + { + self = 4; + } + +#if 0 + if (usergame) + { + // [SP] Update pitch limits to the netgame/gamesim. + players[consoleplayer].SendPitchLimits(); + } +#endif + screen->SetTextureFilterMode(); + + // No further checks needed. All this changes now is which scene drawer the render backend calls. +} + +CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + // [SP] This may seem pointless - but I don't want to implement live switching just + // yet - I'm pretty sure it's going to require a lot of reinits and destructions to + // do it right without memory leaks + + switch(self) + { + case 2: + Printf("Selecting SoftPoly backend...\n"); + break; +#ifdef HAVE_VULKAN + case 1: + Printf("Selecting Vulkan backend...\n"); + break; +#endif + default: + Printf("Selecting OpenGL backend...\n"); + } + + Printf("Changing the video backend requires a restart for " GAMENAME ".\n"); +} + +CVAR(Int, vid_renderer, 1, 0) // for some stupid mods which threw caution out of the window... + + +EXTERN_CVAR(Bool, r_blendmethod) + +int active_con_scale(); + +#define DBGBREAK assert(0) + +class DDummyFrameBuffer : public DFrameBuffer +{ + typedef DFrameBuffer Super; +public: + DDummyFrameBuffer (int width, int height) + : DFrameBuffer (0, 0) + { + SetVirtualSize(width, height); + } + // These methods should never be called. + void Update() { DBGBREAK; } + bool IsFullscreen() { DBGBREAK; return 0; } + int GetClientWidth() { DBGBREAK; return 0; } + int GetClientHeight() { DBGBREAK; return 0; } + void InitializeState() override {} + + float Gamma; +}; + +int DisplayWidth, DisplayHeight; + + +// [RH] The framebuffer is no longer a mere byte array. +// There's also only one, not four. +DFrameBuffer *screen; + +CVAR (Int, vid_defwidth, 640, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Int, vid_defheight, 480, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, ticker, false, 0) + +CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (screen != NULL) + { + screen->SetVSync (*self); + } +} + +// [RH] Set true when vid_setmode command has been executed +bool setmodeneeded = false; + +//========================================================================== +// +// DCanvas Constructor +// +//========================================================================== + +DCanvas::DCanvas (int _width, int _height, bool _bgra) +{ + // Init member vars + Width = _width; + Height = _height; + Bgra = _bgra; + Resize(_width, _height); +} + +//========================================================================== +// +// DCanvas Destructor +// +//========================================================================== + +DCanvas::~DCanvas () +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +void DCanvas::Resize(int width, int height, bool optimizepitch) +{ + Width = width; + Height = height; + + // Making the pitch a power of 2 is very bad for performance + // Try to maximize the number of cache lines that can be filled + // for each column drawing operation by making the pitch slightly + // longer than the width. The values used here are all based on + // empirical evidence. + + if (width <= 640 || !optimizepitch) + { + // For low resolutions, just keep the pitch the same as the width. + // Some speedup can be seen using the technique below, but the speedup + // is so marginal that I don't consider it worthwhile. + Pitch = width; + } + else + { +#if 0 + // If we couldn't figure out the CPU's L1 cache line size, assume + // it's 32 bytes wide. + if (CPU.DataL1LineSize == 0) + { + CPU.DataL1LineSize = 32; + } + // The Athlon and P3 have very different caches, apparently. + // I am going to generalize the Athlon's performance to all AMD + // processors and the P3's to all non-AMD processors. I don't know + // how smart that is, but I don't have a vast plethora of + // processors to test with. + if (CPU.bIsAMD) + { + Pitch = width + CPU.DataL1LineSize; + } + else + { + Pitch = width + MAX(0, CPU.DataL1LineSize - 8); + } +#endif + } + int bytes_per_pixel = Bgra ? 4 : 1; + Pixels.Resize(Pitch * height * bytes_per_pixel); + memset (Pixels.Data(), 0, Pixels.Size()); +} + + +//========================================================================== +// +// V_GetColorFromString +// +// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB", +// returns a number representing that color. If palette is non-NULL, the +// index of the best match in the palette is returned, otherwise the +// RRGGBB value is returned directly. +// +//========================================================================== + +int V_GetColorFromString (const uint32_t *palette, const char *cstr, FScriptPosition *sc) +{ + int c[3], i, p; + char val[3]; + + val[2] = '\0'; + + // Check for HTML-style #RRGGBB or #RGB color string + if (cstr[0] == '#') + { + size_t len = strlen (cstr); + + if (len == 7) + { + // Extract each eight-bit component into c[]. + for (i = 0; i < 3; ++i) + { + val[0] = cstr[1 + i*2]; + val[1] = cstr[2 + i*2]; + c[i] = ParseHex (val, sc); + } + } + else if (len == 4) + { + // Extract each four-bit component into c[], expanding to eight bits. + for (i = 0; i < 3; ++i) + { + val[1] = val[0] = cstr[1 + i]; + c[i] = ParseHex (val, sc); + } + } + else + { + // Bad HTML-style; pretend it's black. + c[2] = c[1] = c[0] = 0; + } + } + else + { + if (strlen(cstr) == 6) + { + char *p; + int color = strtol(cstr, &p, 16); + if (*p == 0) + { + // RRGGBB string + c[0] = (color & 0xff0000) >> 16; + c[1] = (color & 0xff00) >> 8; + c[2] = (color & 0xff); + } + else goto normal; + } + else + { +normal: + // Treat it as a space-delimited hexadecimal string + for (i = 0; i < 3; ++i) + { + // Skip leading whitespace + while (*cstr <= ' ' && *cstr != '\0') + { + cstr++; + } + // Extract a component and convert it to eight-bit + for (p = 0; *cstr > ' '; ++p, ++cstr) + { + if (p < 2) + { + val[p] = *cstr; + } + } + if (p == 0) + { + c[i] = 0; + } + else + { + if (p == 1) + { + val[1] = val[0]; + } + c[i] = ParseHex (val, sc); + } + } + } + } + return MAKERGB(c[0], c[1], c[2]); +} + +//========================================================================== +// +// V_GetColorStringByName +// +// Searches for the given color name in x11r6rgb.txt and returns an +// HTML-ish "#RRGGBB" string for it if found or the empty string if not. +// +//========================================================================== + +FString V_GetColorStringByName (const char *name, FScriptPosition *sc) +{ + char *rgbEnd; + char *rgb, *endp; + int rgblump; + int c[3], step; + size_t namelen; + + if (fileSystem.GetNumEntries()==0) return FString(); + + rgblump = fileSystem.FindFile ("demolition/X11R6RGB.txt"); + if (rgblump == -1) + { + if (!sc) Printf ("X11R6RGB lump not found\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump not found"); + return FString(); + } + rgb = (char*)fileSystem.Lock(rgblump); + rgbEnd = rgb + fileSystem.FileLength (rgblump); + step = 0; + namelen = strlen (name); + + while (rgb < rgbEnd) + { + // Skip white space + if (*rgb <= ' ') + { + do + { + rgb++; + } while (rgb < rgbEnd && *rgb <= ' '); + } + else if (step == 0 && *rgb == '!') + { // skip comment lines + do + { + rgb++; + } while (rgb < rgbEnd && *rgb != '\n'); + } + else if (step < 3) + { // collect RGB values + c[step++] = strtoul (rgb, &endp, 10); + if (endp == rgb) + { + break; + } + rgb = endp; + } + else + { // Check color name + endp = rgb; + // Find the end of the line + while (endp < rgbEnd && *endp != '\n') + endp++; + // Back up over any whitespace + while (endp > rgb && *endp <= ' ') + endp--; + if (endp == rgb) + { + break; + } + size_t checklen = ++endp - rgb; + if (checklen == namelen && strnicmp (rgb, name, checklen) == 0) + { + FString descr; + descr.Format ("#%02x%02x%02x", c[0], c[1], c[2]); + return descr; + } + rgb = endp; + step = 0; + } + } + if (rgb < rgbEnd) + { + if (!sc) Printf ("X11R6RGB lump is corrupt\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt"); + } + return FString(); +} + +//========================================================================== +// +// V_GetColor +// +// Works like V_GetColorFromString(), but also understands X11 color names. +// +//========================================================================== + +int V_GetColor (const uint32_t *palette, const char *str, FScriptPosition *sc) +{ + FString string = V_GetColorStringByName (str, sc); + int res; + + if (!string.IsEmpty()) + { + res = V_GetColorFromString (palette, string, sc); + } + else + { + res = V_GetColorFromString (palette, str, sc); + } + return res; +} + +int V_GetColor(const uint32_t *palette, FScanner &sc) +{ + FScriptPosition scc = sc; + return V_GetColor(palette, sc.String, &scc); +} + +CCMD(clean) +{ + Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac); +} + + +void V_UpdateModeSize (int width, int height) +{ + // This calculates the menu scale. + // The optimal scale will always be to fit a virtual 640 pixel wide display onto the screen. + // Exceptions are made for a few ranges where the available virtual width is > 480. + + // This reference size is being used so that on 800x450 (small 16:9) a scale of 2 gets used. + + CleanXfac = std::max(std::min(screen->GetWidth() / 400, screen->GetHeight() / 240), 1); + if (CleanXfac >= 4) CleanXfac--; // Otherwise we do not have enough space for the episode/skill menus in some languages. + CleanYfac = CleanXfac; + CleanWidth = screen->GetWidth() / CleanXfac; + CleanHeight = screen->GetHeight() / CleanYfac; + + int w = screen->GetWidth(); + int factor; + if (w < 640) factor = 1; + else if (w >= 1024 && w < 1280) factor = 2; + else if (w >= 1600 && w < 1920) factor = 3; + else factor = w / 640; + + if (w < 1360) factor = 1; + else if (w < 1920) factor = 2; + else factor = int(factor * 0.7); + + CleanYfac_1 = CleanXfac_1 = factor;// MAX(1, int(factor * 0.7)); + CleanWidth_1 = width / CleanXfac_1; + CleanHeight_1 = height / CleanYfac_1; + + DisplayWidth = width; + DisplayHeight = height; +} + +void V_OutputResized (int width, int height) +{ + V_UpdateModeSize(width, height); +// setsizeneeded = true; + C_NewModeAdjust(); +} + +void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) +{ + if (designheight < 240 && realheight >= 480) designheight = 240; + *cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight); +} + +bool IVideo::SetResolution () +{ + DFrameBuffer *buff = CreateFrameBuffer(); + + if (buff == NULL) // this cannot really happen + { + return false; + } + + screen = buff; + screen->InitializeState(); + screen->SetGamma(); + + V_UpdateModeSize(screen->GetWidth(), screen->GetHeight()); + + return true; +} + +// +// V_Init +// + +void V_InitScreenSize () +{ + const char *i; + int width, height, bits; + + width = height = bits = 0; + + if ( (i = Args->CheckValue ("-width")) ) + width = atoi (i); + + if ( (i = Args->CheckValue ("-height")) ) + height = atoi (i); + + if (width == 0) + { + if (height == 0) + { + width = vid_defwidth; + height = vid_defheight; + } + else + { + width = (height * 8) / 6; + } + } + else if (height == 0) + { + height = (width * 6) / 8; + } + // Remember the passed arguments for the next time the game starts up windowed. + vid_defwidth = width; + vid_defheight = height; +} + +void V_InitScreen() +{ + screen = new DDummyFrameBuffer (vid_defwidth, vid_defheight); +} + +void V_Init2() +{ + float gamma = static_cast(screen)->Gamma; + + { + DFrameBuffer *s = screen; + screen = NULL; + delete s; + } + + UCVarValue val; + + val.Bool = !!Args->CheckParm("-devparm"); + ticker.SetGenericRepDefault(val, CVAR_Bool); + + + I_InitGraphics(); + + Video->SetResolution(); // this only fails via exceptions. + Printf ("Resolution: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); + + // init these for the scaling menu + menu_resolution_custom_width = SCREENWIDTH; + menu_resolution_custom_height = SCREENHEIGHT; + + screen->SetVSync(vid_vsync); + screen->SetGamma (); + FBaseCVar::ResetColors (); + C_NewModeAdjust(); + //setsizeneeded = true; +} + +// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. +static int ActiveFakeRatio(int width, int height) +{ + int fakeratio = -1; + if ((vid_aspect >= 1) && (vid_aspect <= 6)) + { + // [SP] User wants to force aspect ratio; let them. + fakeratio = int(vid_aspect); + if (fakeratio == 3) + { + fakeratio = 0; + } + else if (fakeratio == 5) + { + fakeratio = 3; + } + } + else if (vid_aspect == 0 && ViewportIsScaled43()) + { + fakeratio = 0; + } + return fakeratio; +} + +// Active screen ratio based on cvars and size +float ActiveRatio(int width, int height, float *trueratio) +{ + static float forcedRatioTypes[] = + { + 4 / 3.0f, + 16 / 9.0f, + 16 / 10.0f, + 17 / 10.0f, + 5 / 4.0f, + 17 / 10.0f, + 21 / 9.0f + }; + + float ratio = width / (float)height; + int fakeratio = ActiveFakeRatio(width, height); + + if (trueratio) + *trueratio = ratio; + return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio; +} + + +// Tries to guess the physical dimensions of the screen based on the +// screen's pixel dimensions. Can return: +// 0: 4:3 +// 1: 16:9 +// 2: 16:10 +// 3: 17:10 +// 4: 5:4 +// 5: 17:10 (redundant, never returned) +// 6: 21:9 +int CheckRatio (int width, int height, int *trueratio) +{ + float aspect = width / (float)height; + + static std::pair ratioTypes[] = + { + { 21 / 9.0f , 6 }, + { 16 / 9.0f , 1 }, + { 17 / 10.0f , 3 }, + { 16 / 10.0f , 2 }, + { 4 / 3.0f , 0 }, + { 5 / 4.0f , 4 }, + { 0.0f, 0 } + }; + + int ratio = ratioTypes[0].second; + float distance = fabs(ratioTypes[0].first - aspect); + for (int i = 1; ratioTypes[i].first != 0.0f; i++) + { + float d = fabs(ratioTypes[i].first - aspect); + if (d < distance) + { + ratio = ratioTypes[i].second; + distance = d; + } + } + + int fakeratio = ActiveFakeRatio(width, height); + if (fakeratio == -1) + fakeratio = ratio; + + if (trueratio) + *trueratio = ratio; + return fakeratio; +} + +int AspectBaseWidth(float aspect) +{ + return (int)round(240.0f * aspect * 3.0f); +} + +int AspectBaseHeight(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); + else + return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); +} + +double AspectPspriteOffset(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return 0.0; + else + return ((4.0 / 3.0) / aspect - 1.0) * 97.5; +} + +int AspectMultiplier(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); + else + return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); +} + +bool AspectTallerThanWide(float aspect) +{ + return aspect < 1.333f; +} + +void ScaleWithAspect (int &w, int &h, int Width, int Height) +{ + int resRatio = CheckRatio (Width, Height); + int screenRatio; + CheckRatio (w, h, &screenRatio); + if (resRatio == screenRatio) + return; + + double yratio; + switch(resRatio) + { + case 0: yratio = 4./3.; break; + case 1: yratio = 16./9.; break; + case 2: yratio = 16./10.; break; + case 3: yratio = 17./10.; break; + case 4: yratio = 5./4.; break; + case 6: yratio = 21./9.; break; + default: return; + } + double y = w/yratio; + if (y > h) + w = static_cast(h * yratio); + else + h = static_cast(y); +} + +CCMD(vid_setsize) +{ + if (argv.argc() < 3) + { + Printf("Usage: vid_setsize width height\n"); + } + else + { + screen->SetWindowSize((int)strtol(argv[1], nullptr, 0), (int)strtol(argv[2], nullptr, 0)); + V_OutputResized(screen->GetClientWidth(), screen->GetClientHeight()); + } +} + + +void IVideo::DumpAdapters () +{ + Printf("Multi-monitor support unavailable.\n"); +} + +CUSTOM_CVAR(Bool, vid_fullscreen, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + setmodeneeded = true; +} + +CUSTOM_CVAR(Bool, vid_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CCMD(vid_listadapters) +{ + if (Video != NULL) + Video->DumpAdapters(); +} + +bool vid_hdr_active = false; diff --git a/source/common/rendering/v_video.h b/source/common/rendering/v_video.h new file mode 100644 index 000000000..830b61209 --- /dev/null +++ b/source/common/rendering/v_video.h @@ -0,0 +1,465 @@ +/* +** v_video.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __V_VIDEO_H__ +#define __V_VIDEO_H__ + +#include +#include "basics.h" +#include "vectors.h" +#include "m_png.h" + +//#include "doomdef.h" +//#include "dobject.h" +#include "renderstyle.h" +#include "c_cvars.h" +#include "v_2ddrawer.h" +#include "hwrenderer/dynlights/hw_shadowmap.h" + +static const int VID_MIN_WIDTH = 640; +static const int VID_MIN_HEIGHT = 400; + +struct sector_t; +class FTexture; +struct FPortalSceneState; +class FSkyVertexBuffer; +class IIndexBuffer; +class IVertexBuffer; +class IDataBuffer; +class FFlatVertexBuffer; +class HWViewpointBuffer; +class FLightBuffer; +struct HWDrawInfo; + +enum EHWCaps +{ + // [BB] Added texture compression flags. + RFL_TEXTURE_COMPRESSION = 1, + RFL_TEXTURE_COMPRESSION_S3TC = 2, + + RFL_SHADER_STORAGE_BUFFER = 4, + RFL_BUFFER_STORAGE = 8, + + RFL_NO_CLIP_PLANES = 32, + + RFL_INVALIDATE_BUFFER = 64, + RFL_DEBUG = 128, +}; + + +struct IntRect +{ + int left, top; + int width, height; + + + void Offset(int xofs, int yofs) + { + left += xofs; + top += yofs; + } + + void AddToRect(int x, int y) + { + if (x < left) + left = x; + if (x > left + width) + width = x - left; + + if (y < top) + top = y; + if (y > top + height) + height = y - top; + } + + +}; + + + + + +extern int CleanWidth, CleanHeight, CleanXfac, CleanYfac; +extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; +extern int DisplayWidth, DisplayHeight; + +void V_UpdateModeSize (int width, int height); +void V_OutputResized (int width, int height); +void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *cx1=NULL, int *cx2=NULL); + +EXTERN_CVAR(Int, vid_rendermode) +EXTERN_CVAR(Bool, vid_fullscreen) +EXTERN_CVAR(Int, win_x) +EXTERN_CVAR(Int, win_y) +EXTERN_CVAR(Int, win_w) +EXTERN_CVAR(Int, win_h) +EXTERN_CVAR(Bool, win_maximized) + + +inline bool V_IsHardwareRenderer() +{ + return vid_rendermode == 4; +} + +inline bool V_IsSoftwareRenderer() +{ + return vid_rendermode < 2; +} + +inline bool V_IsPolyRenderer() +{ + return vid_rendermode == 2 || vid_rendermode == 3; +} + +inline bool V_IsTrueColor() +{ + return vid_rendermode == 1 || vid_rendermode == 3 || vid_rendermode == 4; +} + + +class FTexture; +struct FColormap; +class FileWriter; +enum FTextureFormat : uint32_t; +class FModelRenderer; +struct SamplerUniform; + +// TagItem definitions for DrawTexture. As far as I know, tag lists +// originated on the Amiga. +// +// Think of TagItems as an array of the following structure: +// +// struct TagItem { +// uint32_t ti_Tag; +// uint32_t ti_Data; +// }; + +#define TAG_DONE (0) /* Used to indicate the end of the Tag list */ +#define TAG_END (0) /* Ditto */ + /* list pointed to in ti_Data */ + +#define TAG_USER ((uint32_t)(1u<<30)) + + +class FFont; +struct FRemapTable; +class player_t; +typedef uint32_t angle_t; + + +// +// VIDEO +// +// +class DCanvas +{ +public: + DCanvas (int width, int height, bool bgra); + ~DCanvas (); + void Resize(int width, int height, bool optimizepitch = true); + + // Member variable access + inline uint8_t *GetPixels () const { return Pixels.Data(); } + inline int GetWidth () const { return Width; } + inline int GetHeight () const { return Height; } + inline int GetPitch () const { return Pitch; } + inline bool IsBgra() const { return Bgra; } + +protected: + TArray Pixels; + int Width; + int Height; + int Pitch; + bool Bgra; +}; + +class FUniquePalette; +class IHardwareTexture; +class FTexture; + + +class DFrameBuffer +{ +protected: + + void DrawTextureV(FTexture *img, double x, double y, uint32_t tag, va_list tags) = delete; + void DrawTextureParms(FTexture *img, DrawParms &parms); + + template + bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, bool fortext) const; + template + void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const T *string, DrawParms &parms); + + F2DDrawer m2DDrawer; +private: + int Width = 0; + int Height = 0; +protected: + int clipleft = 0, cliptop = 0, clipwidth = -1, clipheight = -1; + +public: + // Hardware render state that needs to be exposed to the API independent part of the renderer. For ease of access this is stored in the base class. + int hwcaps = 0; // Capability flags + float glslversion = 0; // This is here so that the differences between old OpenGL and new OpenGL/Vulkan can be handled by platform independent code. + int instack[2] = { 0,0 }; // this is globally maintained state for portal recursion avoidance. + int stencilValue = 0; // Global stencil test value + unsigned int uniformblockalignment = 256; // Hardware dependent uniform buffer alignment. + unsigned int maxuniformblock = 65536; + const char *vendorstring; // We have to account for some issues with particular vendors. + //FPortalSceneState *mPortalState; // global portal state. + //FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer + //FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data + //HWViewpointBuffer *mViewpoints = nullptr; // Viewpoint render data. + //FLightBuffer *mLights = nullptr; // Dynamic lights + //IShadowMap mShadowMap; + + IntRect mScreenViewport; + //IntRect mSceneViewport; + IntRect mOutputLetterbox; + float mSceneClearColor[4]; + + +public: + DFrameBuffer (int width=1, int height=1); + virtual ~DFrameBuffer(); + virtual void InitializeState() = 0; // For stuff that needs 'screen' set. + virtual bool IsVulkan() { return false; } + virtual bool IsPoly() { return false; } + + virtual DCanvas* GetCanvas() { return nullptr; } + + void SetSize(int width, int height); + void SetVirtualSize(int width, int height) + { + Width = width; + Height = height; + } + inline int GetWidth() const { return Width; } + inline int GetHeight() const { return Height; } + +#if 0 + FVector2 SceneScale() const + { + return { mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height }; + } + + FVector2 SceneOffset() const + { + return { mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height }; + } +#endif + + // Make the surface visible. + virtual void Update (); + + // Stores the palette with flash blended in into 256 dwords + // Mark the palette as changed. It will be updated on the next Update(). + virtual void UpdatePalette() {} + + virtual void SetGamma() {} + + // Returns true if running fullscreen. + virtual bool IsFullscreen () = 0; + virtual void ToggleFullscreen(bool yes) {} + + // Changes the vsync setting, if supported by the device. + virtual void SetVSync (bool vsync); + + // Delete any resources that need to be deleted after restarting with a different IWAD + virtual void CleanForRestart() {} + virtual void SetTextureFilterMode() {} + virtual IHardwareTexture *CreateHardwareTexture() { return nullptr; } + virtual void PrecacheMaterial(FMaterial *mat, int translation) {} + virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; } + virtual void TextureFilterChanged() {} + virtual void BeginFrame() {} + virtual void SetWindowSize(int w, int h) {} + virtual void StartPrecaching() {} + + virtual int GetClientWidth() = 0; + virtual int GetClientHeight() = 0; + virtual void BlurScene(float amount) {} + + // Interface to hardware rendering resources + virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; } + virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; } + virtual IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) { return nullptr; } + bool BuffersArePersistent() { return !!(hwcaps & RFL_BUFFER_STORAGE); } + + // Begin/End 2D drawing operations. + void Begin2D() { isIn2D = true; } + void End2D() { isIn2D = false; } + + void End2DAndUpdate() + { + DrawRateStuff(); + End2D(); + Update(); + } + + + // Returns true if Begin2D has been called and 2D drawing is now active + bool HasBegun2D() { return isIn2D; } + + // This is overridable in case Vulkan does it differently. + virtual bool RenderTextureIsFlipped() const + { + return true; + } + + // Report a game restart + virtual int Backend() { return 0; } + virtual const char* DeviceName() const { return "Unknown"; } + virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height); + virtual sector_t *RenderView(player_t *player) { return nullptr; } + + // Screen wiping + virtual FTexture *WipeStartScreen(); + virtual FTexture *WipeEndScreen(); + + virtual void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); } + + void ScaleCoordsFromWindow(int16_t &x, int16_t &y); + + uint64_t GetLastFPS() const { return LastCount; } + + // 2D Texture drawing + void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; } + void SetClipRect(int x, int y, int w, int h); + void GetClipRect(int *x, int *y, int *w, int *h); + + void VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom = false, bool handleaspect = true) const; + + // Code that uses these (i.e. SBARINFO) should probably be evaluated for using doubles all around instead. + void VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, int vwidth, int vheight, bool vbottom = false, bool handleaspect = true) const; + + // Text drawing functions ----------------------------------------------- + + + // Calculate gamma table + void CalcGamma(float gamma, uint8_t gammalookup[256]); + + virtual void SetViewportRects(IntRect *bounds); + int ScreenToWindowX(int x); + int ScreenToWindowY(int y); + + void FPSLimit(); + + // Retrieves a buffer containing image data for a screenshot. + // Hint: Pitch can be negative for upside-down images, in which case buffer + // points to the last row in the buffer, which will be the first row output. + virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) { return TArray(); } + + static float GetZNear() { return 5.f; } + static float GetZFar() { return 65536.f; } + + // The original size of the framebuffer as selected in the video menu. + uint64_t FrameTime = 0; + +protected: + void DrawRateStuff (); + +private: + uint64_t fpsLimitTime = 0; + + uint64_t LastMS = 0, LastSec = 0, FrameCount = 0, LastCount = 0, LastTic = 0; + + bool isIn2D = false; +}; + + +// This is the screen updated by I_FinishUpdate. +extern DFrameBuffer *screen; + +#define SCREENWIDTH (screen->GetWidth ()) +#define SCREENHEIGHT (screen->GetHeight ()) +#define SCREENPITCH (screen->GetPitch ()) + +EXTERN_CVAR (Float, Gamma) + + +// Allocates buffer screens, call before R_Init. +void V_InitScreenSize(); +void V_InitScreen(); + +// Initializes graphics mode for the first time. +void V_Init2 (); + +void V_Shutdown (); + +class FScanner; +struct FScriptPosition; +// Returns the closest color to the one desired. String +// should be of the form "rr gg bb". +int V_GetColorFromString (const uint32_t *palette, const char *colorstring, FScriptPosition *sc = nullptr); +// Scans through the X11R6RGB lump for a matching color +// and returns a color string suitable for V_GetColorFromString. +FString V_GetColorStringByName (const char *name, FScriptPosition *sc = nullptr); + +// Tries to get color by name, then by string +int V_GetColor (const uint32_t *palette, const char *str, FScriptPosition *sc = nullptr); +int V_GetColor(const uint32_t *palette, FScanner &sc); + +int CheckRatio (int width, int height, int *trueratio=NULL); +static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } +inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } + +float ActiveRatio (int width, int height, float *trueratio = NULL); +static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } + +int AspectBaseWidth(float aspect); +int AspectBaseHeight(float aspect); +double AspectPspriteOffset(float aspect); +int AspectMultiplier(float aspect); +bool AspectTallerThanWide(float aspect); +void ScaleWithAspect(int &w, int &h, int Width, int Height); + +int GetUIScale(int altval); +int GetConScale(int altval); + +EXTERN_CVAR(Int, uiscale); +EXTERN_CVAR(Int, con_scaletext); +EXTERN_CVAR(Int, con_scale); + +inline int active_con_scaletext(bool newconfont = false) +{ + return newconfont? GetConScale(con_scaletext) : GetUIScale(con_scaletext); +} + +inline int active_con_scale() +{ + return GetConScale(con_scale); +} + + +#endif // __V_VIDEO_H__ diff --git a/source/common/st_start.h b/source/common/st_start.h index b084bae51..ac31e5317 100644 --- a/source/common/st_start.h +++ b/source/common/st_start.h @@ -41,18 +41,22 @@ class FStartupScreen public: static FStartupScreen *CreateInstance(int max_progress); - FStartupScreen(int max_progress); - virtual ~FStartupScreen(); + FStartupScreen(int max_progress) + { + MaxPos = max_progress; + CurPos = 0; + NotchPos = 0; + } + + virtual ~FStartupScreen() = default; - virtual void Progress(); - virtual void LoadingStatus(const char *message, int colors); // Used by Heretic only - virtual void AppendStatusLine(const char *status); // Used by Heretic only + virtual void Progress() {} - virtual void NetInit(const char *message, int num_players); - virtual void NetProgress(int count); - virtual void NetMessage(const char *format, ...); // cover for printf - virtual void NetDone(); - virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata); + virtual void NetInit(const char *message, int num_players) {} + virtual void NetProgress(int count) {} + virtual void NetMessage(const char *format, ...) {} // cover for printf + virtual void NetDone() {} + virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata) { return false; } protected: int MaxPos, CurPos, NotchPos; }; @@ -74,17 +78,28 @@ protected: int NetMaxPos, NetCurPos; }; -class FGraphicalStartupScreen : public FBasicStartupScreen -{ -public: - FGraphicalStartupScreen(int max_progress); - ~FGraphicalStartupScreen(); -}; - extern FStartupScreen *StartScreen; -void DeleteStartupScreen(); + + +//=========================================================================== +// +// DeleteStartupScreen +// +// Makes sure the startup screen has been deleted before quitting. +// +//=========================================================================== + +inline void DeleteStartupScreen() +{ + if (StartScreen != nullptr) + { + delete StartScreen; + StartScreen = nullptr; + } +} + extern void ST_Endoom(); // The entire set of functions here uses native Windows types. These are recreations of those types so that the code doesn't need to be changed more than necessary diff --git a/source/common/utility/name.h b/source/common/utility/name.h index 1d7f2a581..9e547a4b8 100644 --- a/source/common/utility/name.h +++ b/source/common/utility/name.h @@ -62,7 +62,6 @@ public: operator const char *() const { return NameData.NameArray[Index].Text; } FName &operator = (const char *text) { Index = NameData.FindName (text, false); return *this; } - FName &operator = (const FString &text); FName &operator = (const FName &other) = default; FName &operator = (ENamedName index) { Index = index; return *this; } diff --git a/source/common/utility/sc_man.cpp b/source/common/utility/sc_man.cpp index 6cd7ff42a..a02cd09a9 100644 --- a/source/common/utility/sc_man.cpp +++ b/source/common/utility/sc_man.cpp @@ -1,14 +1,39 @@ +/* For code that originates from ZDoom the following applies: +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** Copyright 2005-2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + + + -//************************************************************************** -//** -//** sc_man.c : Heretic 2 : Raven Software, Corp. -//** -//** $RCSfile: sc_man.c,v $ -//** $Revision: 1.3 $ -//** $Date: 96/01/06 03:23:43 $ -//** $Author: bgokey $ -//** -//************************************************************************** // HEADER FILES ------------------------------------------------------------ @@ -240,11 +265,11 @@ void FScanner::PrepareScript () { // The scanner requires the file to end with a '\n', so add one if // it doesn't already. - if (ScriptBuffer.Len() == 0 || ScriptBuffer[ScriptBuffer.Len() - 1] != '\n') + if (ScriptBuffer.Len() == 0 || ScriptBuffer.Back() != '\n') { // If the last character in the buffer is a null character, change // it to a newline. Otherwise, append a newline to the end. - if (ScriptBuffer.Len() > 0 && ScriptBuffer[ScriptBuffer.Len() - 1] == '\0') + if (ScriptBuffer.Len() > 0 && ScriptBuffer.Back() == '\0') { ScriptBuffer.LockBuffer()[ScriptBuffer.Len() - 1] = '\n'; ScriptBuffer.UnlockBuffer(); @@ -873,6 +898,76 @@ bool FScanner::Compare (const char *text) return (stricmp (text, String) == 0); } + +//========================================================================== +// +// Convenience helpers that parse an entire number including a leading minus or plus sign +// +//========================================================================== + +bool FScanner::ScanValue(bool allowfloat) +{ + bool neg = false; + if (!GetToken()) + { + return false; + } + if (TokenType == '-' || TokenType == '+') + { + neg = TokenType == '-'; + if (!GetToken()) + { + return false; + } + } + if (TokenType != TK_IntConst && (TokenType != TK_FloatConst || !allowfloat)) + { + return false; + } + if (neg) + { + Number = -Number; + Float = -Float; + } + return true; +} + +bool FScanner::CheckValue(bool allowfloat) +{ + auto savedstate = SavePos(); + bool res = ScanValue(allowfloat); + if (!res) RestorePos(savedstate); + return res; +} + +void FScanner::MustGetValue(bool allowfloat) +{ + if (!ScanValue(allowfloat)) ScriptError(allowfloat ? "Numeric constant expected" : "Integer constant expected"); +} + +bool FScanner::CheckBoolToken() +{ + if (CheckToken(TK_True)) + { + Number = 1; + Float = 1; + return true; + } + if (CheckToken(TK_False)) + { + Number = 0; + Float = 0; + return true; + } + return false; +} + +void FScanner::MustGetBoolToken() +{ + if (!CheckBoolToken()) + ScriptError("Expected true or false"); +} + //========================================================================== // // FScanner :: TokenName @@ -977,7 +1072,7 @@ void FScanner::ScriptMessage (const char *message, ...) va_end (arglist); } - Printf (TEXTCOLOR_RED "Script error, \"%s\" line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + Printf (TEXTCOLOR_RED "Script error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } @@ -991,10 +1086,118 @@ void FScanner::CheckOpen() { if (ScriptOpen == false) { - I_Error ("SC_ call before SC_Open()."); + I_FatalError ("SC_ call before SC_Open()."); } } +//========================================================================== +// +// a class that remembers a parser position +// +//========================================================================== +int FScriptPosition::ErrorCounter; +int FScriptPosition::WarnCounter; +bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors. +bool FScriptPosition::errorout; // call I_Error instead of printing the error itself. + + +FScriptPosition::FScriptPosition(FString fname, int line) +{ + FileName = fname.GetChars(); + ScriptLine = line; +} + +FScriptPosition::FScriptPosition(FScanner &sc) +{ + FileName = sc.ScriptName; + ScriptLine = sc.GetMessageLine(); +} + +FScriptPosition &FScriptPosition::operator=(FScanner &sc) +{ + FileName = sc.ScriptName; + ScriptLine = sc.GetMessageLine(); + return *this; +} + +//========================================================================== +// +// FScriptPosition::Message +// +//========================================================================== + +void FScriptPosition::Message (int severity, const char *message, ...) const +{ + FString composed; + +#if 0 + if (severity == MSG_DEBUGLOG && developer < DMSG_NOTIFY) return; + if (severity == MSG_DEBUGERROR && developer < DMSG_ERROR) return; + if (severity == MSG_DEBUGWARN && developer < DMSG_WARNING) return; + if (severity == MSG_DEBUGMSG && developer < DMSG_NOTIFY) return; +#endif + if (severity == MSG_OPTERROR) + { + severity = StrictErrors ? MSG_ERROR : MSG_WARNING; + } + // This is mainly for catching the error with an exception handler. + if (severity == MSG_ERROR && errorout) severity = MSG_FATAL; + + if (message == NULL) + { + composed = "Bad syntax."; + } + else + { + va_list arglist; + va_start (arglist, message); + composed.VFormat (message, arglist); + va_end (arglist); + } + const char *type = ""; + const char *color; + int level = PRINT_HIGH; + + switch (severity) + { + default: + return; + + case MSG_WARNING: + case MSG_DEBUGWARN: + case MSG_DEBUGERROR: // This is intentionally not being printed as an 'error', the difference to MSG_DEBUGWARN is only the severity level at which it gets triggered. + WarnCounter++; + type = "warning"; + color = TEXTCOLOR_ORANGE; + break; + + case MSG_ERROR: + ErrorCounter++; + type = "error"; + color = TEXTCOLOR_RED; + break; + + case MSG_MESSAGE: + case MSG_DEBUGMSG: + type = "message"; + color = TEXTCOLOR_GREEN; + break; + + case MSG_DEBUGLOG: + case MSG_LOG: + type = "message"; + level = PRINT_LOG; + color = ""; + break; + + case MSG_FATAL: + I_Error ("Script error, \"%s\" line %d:\n%s\n", + FileName.GetChars(), ScriptLine, composed.GetChars()); + return; + } + Printf (level, "%sScript %s, \"%s\" line %d:\n%s%s\n", + color, type, FileName.GetChars(), ScriptLine, color, composed.GetChars()); +} //========================================================================== // @@ -1002,9 +1205,9 @@ void FScanner::CheckOpen() // //========================================================================== -int ParseHex(const char* hex) +int ParseHex(const char* hex, FScriptPosition* sc) { - const char* str; + const char* str; int num; num = 0; @@ -1020,7 +1223,8 @@ int ParseHex(const char* hex) else if (*str >= 'A' && *str <= 'F') num += 10 + *str - 'A'; else { - Printf("Bad hex number: %s\n", hex); + if (sc) sc->Message(MSG_WARNING, "Bad hex number: %s", hex); + else Printf("Bad hex number: %s\n", hex); return 0; } str++; @@ -1029,4 +1233,4 @@ int ParseHex(const char* hex) return num; } - + diff --git a/source/common/utility/sc_man.h b/source/common/utility/sc_man.h index 610356ea2..8dbd443d4 100644 --- a/source/common/utility/sc_man.h +++ b/source/common/utility/sc_man.h @@ -56,6 +56,12 @@ public: bool GetFloat(); void MustGetFloat(); bool CheckFloat(); + + // Token based variant + bool CheckValue(bool allowfloat); + void MustGetValue(bool allowfloat); + bool CheckBoolToken(); + void MustGetBoolToken(); void UnGet(); @@ -103,9 +109,12 @@ protected: const char *LastGotPtr; int LastGotLine; bool CMode; - BYTE StateMode; + uint8_t StateMode; bool StateOptions; bool Escape; + + + bool ScanValue(bool allowfloat); }; enum @@ -137,6 +146,40 @@ enum MSG_MESSAGE }; -int ParseHex(const char* hex); +//========================================================================== +// +// a class that remembers a parser position +// +//========================================================================== + +struct FScriptPosition +{ + static int WarnCounter; + static int ErrorCounter; + static bool StrictErrors; + static bool errorout; + FName FileName; + int ScriptLine; + + FScriptPosition() + { + FileName = NAME_None; + ScriptLine=0; + } + FScriptPosition(const FScriptPosition &other) = default; + FScriptPosition(FString fname, int line); + FScriptPosition(FScanner &sc); + FScriptPosition &operator=(const FScriptPosition &other) = default; + FScriptPosition &operator=(FScanner &sc); + void Message(int severity, const char *message,...) const GCCPRINTF(3,4); + static void ResetErrorCounter() + { + WarnCounter = 0; + ErrorCounter = 0; + } +}; + +int ParseHex(const char* hex, FScriptPosition* sc); + #endif //__SC_MAN_H__ diff --git a/source/duke3d/src/demo.cpp b/source/duke3d/src/demo.cpp index 7025715ce..3cf9cfa46 100644 --- a/source/duke3d/src/demo.cpp +++ b/source/duke3d/src/demo.cpp @@ -791,7 +791,7 @@ nextdemo_nomenu: // draw status Demo_DisplayProfStatus(); - if (handleevents_peekkeys()) + if (I_GeneralTrigger()) Demo_StopProfiling(); } else diff --git a/source/platform/win32/i_input.cpp b/source/platform/win32/i_input.cpp index d6b7a118c..6f03602dd 100644 --- a/source/platform/win32/i_input.cpp +++ b/source/platform/win32/i_input.cpp @@ -131,8 +131,8 @@ static bool noidle = false; LPDIRECTINPUT8 g_pdi; LPDIRECTINPUT g_pdi3; +bool AppActive; -extern bool AppActive; int SessionState = 0; int BlockMouseMove; @@ -144,30 +144,6 @@ CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) extern int chatmodeon; -static void I_CheckGUICapture () -{ -#if 0 - bool wantCapt; - - if (menuactive == MENU_Off) - { - wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; - } - else - { - wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); - } - - if (wantCapt != GUICapture) - { - GUICapture = wantCapt; - if (wantCapt && Keyboard != NULL) - { - Keyboard->AllKeysUp(); - } - } -#endif -} void I_SetMouseCapture() { @@ -762,9 +738,7 @@ void I_StartTic () { BlockMouseMove--; buttonMap.ResetButtonTriggers (); - I_CheckGUICapture (); - EventHandlerResultForNativeMouse = false; - I_CheckNativeMouse (false, EventHandlerResultForNativeMouse); + I_CheckNativeMouse (false, false); I_GetEvent (); } diff --git a/source/platform/win32/i_keyboard.cpp b/source/platform/win32/i_keyboard.cpp index 9567809f5..c4379de55 100644 --- a/source/platform/win32/i_keyboard.cpp +++ b/source/platform/win32/i_keyboard.cpp @@ -40,6 +40,7 @@ #include "i_input.h" #include "d_event.h" +#include "inputstate.h" // MACROS ------------------------------------------------------------------ @@ -90,7 +91,7 @@ protected: extern HWND Window; extern LPDIRECTINPUT8 g_pdi; extern LPDIRECTINPUT g_pdi3; -extern bool GUICapture; + // PRIVATE DATA DEFINITIONS ------------------------------------------------ diff --git a/source/platform/win32/i_mouse.cpp b/source/platform/win32/i_mouse.cpp index 3af4de5f5..503c67983 100644 --- a/source/platform/win32/i_mouse.cpp +++ b/source/platform/win32/i_mouse.cpp @@ -275,38 +275,16 @@ static bool CaptureMode_InGame() // //========================================================================== +static bool grab_mouse; + +void mouseGrabInput(bool grab) +{ + grab_mouse = grab; +} + void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) { - bool windowed = (screen == NULL) || !screen->IsFullscreen(); - bool want_native; - - if (!windowed) - { - // ungrab mouse when in the menu with mouse control on. - want_native = m_use_mouse && (menuactive == MENU_On || menuactive == MENU_OnNoPause); - } - else - { - if ((GetForegroundWindow() != Window) || preferNative || !use_mouse) - { - want_native = true; - } - else if (menuactive == MENU_WaitKey) - { - want_native = false; - } - else - { - want_native = ((!m_use_mouse || menuactive != MENU_WaitKey) && - (!CaptureMode_InGame() || GUICapture /*|| paused || demoplayback*/)); - } - } - - if (!want_native && eventhandlerresult) - want_native = true; - - //Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse); - + bool want_native = !grab_mouse || preferNative; if (want_native != NativeMouse) { if (Mouse != NULL) diff --git a/source/platform/win32/st_start.cpp b/source/platform/win32/st_start.cpp index f57055955..ed20ea4ff 100644 --- a/source/platform/win32/st_start.cpp +++ b/source/platform/win32/st_start.cpp @@ -396,34 +396,6 @@ static INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LP return FALSE; } -//========================================================================== -// -// FGraphicalStartupScreen Constructor -// -// This doesn't really do anything. The subclass is responsible for -// creating the resources that will be freed by this class's destructor. -// -//========================================================================== - -FGraphicalStartupScreen::FGraphicalStartupScreen(int max_progress) -: FBasicStartupScreen(max_progress, false) -{ -} - -//========================================================================== -// -// FGraphicalStartupScreen Destructor -// -//========================================================================== - -FGraphicalStartupScreen::~FGraphicalStartupScreen() -{ - if (StartupScreen != NULL) - { - DestroyWindow (StartupScreen); - StartupScreen = NULL; - } -} //========================================================================== // diff --git a/source/rr/src/demo.cpp b/source/rr/src/demo.cpp index 8dd553223..3f5ca9a63 100644 --- a/source/rr/src/demo.cpp +++ b/source/rr/src/demo.cpp @@ -793,7 +793,7 @@ nextdemo_nomenu: // draw status Demo_DisplayProfStatus(); - if (handleevents_peekkeys()) + if (I_GeneralTrigger()) Demo_StopProfiling(); } else