mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
"snapshotmaps" command
Takes two screenshots for a list of maps that have an "Alternate View Point" thing with tag 0 -- one intended for level select pictures and another for Discord Rich Presence. If no view point exists, the map is skipped.
This commit is contained in:
parent
00b0b7b848
commit
6b87b586d2
20 changed files with 278 additions and 15 deletions
|
|
@ -1887,7 +1887,7 @@ void CON_Drawer(void)
|
|||
{
|
||||
Lock_state();
|
||||
|
||||
if (!con_started || !graphics_started)
|
||||
if (!con_started || !graphics_started || g_takemapthumbnail != TMT_NO)
|
||||
{
|
||||
Unlock_state();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -365,6 +365,11 @@ static bool D_Display(bool world)
|
|||
|
||||
ZoneScoped;
|
||||
|
||||
if (g_takemapthumbnail != TMT_NO)
|
||||
{
|
||||
forcerefresh = true;
|
||||
}
|
||||
|
||||
if (!dedicated)
|
||||
{
|
||||
if (nodrawers)
|
||||
|
|
@ -638,6 +643,7 @@ static bool D_Display(bool world)
|
|||
|
||||
// rhi: display the software framebuffer to the screen
|
||||
//if (rendermode == render_soft)
|
||||
if (g_takemapthumbnail == TMT_NO)
|
||||
{
|
||||
// TODO: THIS SHOULD IDEALLY BE IN REGULAR HUD CODE !!
|
||||
// (st_stuff.c ST_Drawer, also duplicated in k_podium.c)
|
||||
|
|
@ -671,11 +677,11 @@ static bool D_Display(bool world)
|
|||
V_DrawCustomFadeScreen("FADEMAP0", fade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
VID_DisplaySoftwareScreen();
|
||||
}
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
VID_DisplaySoftwareScreen();
|
||||
}
|
||||
|
||||
if (lastdraw)
|
||||
|
|
@ -2319,3 +2325,58 @@ const char *D_Home(void)
|
|||
if (usehome) return userhome;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
void D_TakeMapSnapshots(void)
|
||||
{
|
||||
// This function sucks ass!
|
||||
|
||||
const INT32 old_mode = vid.modenum;
|
||||
player_t *const player = &players[consoleplayer];
|
||||
mobj_t *newViewMobj = NULL;
|
||||
|
||||
newViewMobj = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, 0);
|
||||
if (newViewMobj == NULL)
|
||||
{
|
||||
// No camera? Skip.
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Map %s does not have an Alternate View Point with tag 0. Unable to create thumbnails.\n"), G_BuildMapName(gamemap));
|
||||
return;
|
||||
}
|
||||
|
||||
P_SetTarget(&player->awayview.mobj, newViewMobj);
|
||||
player->awayview.tics = -1;
|
||||
R_ResetViewInterpolation(0);
|
||||
|
||||
camera[0].x = player->awayview.mobj->x;
|
||||
camera[0].y = player->awayview.mobj->y;
|
||||
camera[0].z = player->awayview.mobj->z;
|
||||
camera[0].angle = player->awayview.mobj->angle;
|
||||
camera[0].aiming = player->awayview.mobj->pitch;
|
||||
camera[0].subsector = player->awayview.mobj->subsector;
|
||||
|
||||
// Force Software mode
|
||||
if (rendermode != 0)
|
||||
{
|
||||
setrenderneeded = 0;
|
||||
D_Display(true);
|
||||
}
|
||||
|
||||
// Render snapshot at game resolution (level select)
|
||||
g_takemapthumbnail = TMT_PICTURE;
|
||||
setmodeneeded = VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT) + 1;
|
||||
D_Display(true);
|
||||
I_CaptureVideoFrame();
|
||||
|
||||
// Render snapshot at 1024x1024 (rich presence)
|
||||
g_takemapthumbnail = TMT_RICHPRES;
|
||||
setmodeneeded = VID_GetModeForSize(1024, 1024) + 1;
|
||||
D_Display(true);
|
||||
I_CaptureVideoFrame();
|
||||
|
||||
// Revert mode to user preference
|
||||
if (vid.modenum != old_mode)
|
||||
{
|
||||
setmodeneeded = old_mode + 1;
|
||||
D_Display(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ void D_ProcessEvents(boolean callresponders);
|
|||
|
||||
const char *D_Home(void);
|
||||
|
||||
void D_TakeMapSnapshots(void);
|
||||
|
||||
//
|
||||
// BASE LEVEL
|
||||
//
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ static void Command_Automate_Set(void);
|
|||
static void Command_Eval(void);
|
||||
|
||||
static void Command_WriteTextmap(void);
|
||||
static void Command_SnapshotMaps(void);
|
||||
|
||||
#ifdef DEVELOP
|
||||
static void Command_FastForward(void);
|
||||
|
|
@ -446,6 +447,7 @@ void D_RegisterServerCommands(void)
|
|||
COM_AddDebugCommand("eval", Command_Eval);
|
||||
|
||||
COM_AddCommand("writetextmap", Command_WriteTextmap);
|
||||
COM_AddCommand("snapshotmaps", Command_SnapshotMaps);
|
||||
|
||||
// for master server connection
|
||||
AddMServCommands();
|
||||
|
|
@ -6823,6 +6825,76 @@ ROUNDQUEUE_MAX
|
|||
CON_ToggleOff();
|
||||
}
|
||||
|
||||
static void Command_SnapshotMaps(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(
|
||||
"snapshotmaps <map> [map2...]: Create a thumbnail screenshot for the specified levels.\n"
|
||||
"- Use the full map name, e.g. RR_TestRun.\n"
|
||||
"- You can give this command UP TO %d map names and it will create images for all of them.\n"
|
||||
"- This command generates two images -- one 320x200 for the PICTURE lump, another 1024x1024 for rich presence.\n"
|
||||
"- The map requires a \"snapshot camera\" object to have been placed.\n"
|
||||
"- The location of the generated images will appear in the console.\n",
|
||||
ROUNDQUEUE_MAX
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Playing())
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "This command cannot be used in-game. Return to the titlescreen first!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (COM_Argc() - 1 > ROUNDQUEUE_MAX)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Cannot snapshot more than %d maps. Try again.\n", ROUNDQUEUE_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start up a "minor" grand prix session
|
||||
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
||||
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||
|
||||
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
|
||||
grandprixinfo.masterbots = false;
|
||||
|
||||
grandprixinfo.gp = true;
|
||||
grandprixinfo.cup = NULL;
|
||||
grandprixinfo.wonround = false;
|
||||
|
||||
grandprixinfo.initalize = true;
|
||||
|
||||
roundqueue.position = 1;
|
||||
roundqueue.roundnum = 1;
|
||||
roundqueue.snapshotmaps = true;
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 1; i < COM_Argc(); ++i)
|
||||
{
|
||||
INT32 map = G_MapNumber(COM_Argv(i));
|
||||
|
||||
if (map < 0 || map >= nummapheaders)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "%s: Map doesn't exist. Not doing anything.\n", COM_Argv(i));
|
||||
|
||||
// clear round queue (to be safe)
|
||||
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||
return;
|
||||
}
|
||||
|
||||
INT32 gt = G_GuessGametypeByTOL(mapheaderinfo[map]->typeoflevel);
|
||||
|
||||
G_MapIntoRoundQueue(map, gt != -1 ? gt : GT_RACE, false, false);
|
||||
}
|
||||
|
||||
D_MapChange(1 + roundqueue.entries[0].mapnum, roundqueue.entries[0].gametype, false, true, 1, false, false);
|
||||
|
||||
CON_ToggleOff();
|
||||
}
|
||||
|
||||
#ifdef DEVELOP
|
||||
static void Command_FastForward(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1296,6 +1296,10 @@ void G_PreLevelTitleCard(void)
|
|||
//
|
||||
boolean G_IsTitleCardAvailable(void)
|
||||
{
|
||||
// We're trying to take map pictures dude
|
||||
if (roundqueue.snapshotmaps == true)
|
||||
return false;
|
||||
|
||||
// Don't show for attract demos
|
||||
if (demo.attract)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ extern struct roundqueue
|
|||
UINT8 size; // Number of entries in the round queue
|
||||
boolean netcommunicate; // As server, should we net-communicate this in XD_MAP?
|
||||
boolean writetextmap; // This queue is for automated map conversion
|
||||
boolean snapshotmaps; // This queue is for automated map thumbnails
|
||||
roundentry_t entries[ROUNDQUEUE_MAX]; // Entries in the round queue
|
||||
} roundqueue;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ ScreenshotPass::~ScreenshotPass() = default;
|
|||
|
||||
void ScreenshotPass::capture(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
bool doing_screenshot = takescreenshot || moviemode != MM_OFF;
|
||||
bool doing_screenshot = takescreenshot || moviemode != MM_OFF || g_takemapthumbnail != TMT_NO;
|
||||
|
||||
if (!doing_screenshot)
|
||||
{
|
||||
|
|
@ -48,6 +48,11 @@ void ScreenshotPass::capture(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
std::move(&pixel_data_[pixel_data_row * read_stride], &pixel_data_[pixel_data_row * read_stride + stride], &packed_data_[row * stride]);
|
||||
}
|
||||
|
||||
if (g_takemapthumbnail != TMT_NO)
|
||||
{
|
||||
M_SaveMapThumbnail(width_, height_, tcb::as_bytes(tcb::span(packed_data_)));
|
||||
}
|
||||
|
||||
if (takescreenshot)
|
||||
{
|
||||
M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(packed_data_)));
|
||||
|
|
|
|||
|
|
@ -6124,7 +6124,7 @@ void K_drawKartHUD(void)
|
|||
K_drawKartPlayerCheck();
|
||||
|
||||
// nametags
|
||||
if (LUA_HudEnabled(hud_names) && cv_drawpickups.value)
|
||||
if (LUA_HudEnabled(hud_names) && R_DrawPickups())
|
||||
K_drawKartNameTags();
|
||||
|
||||
// Draw WANTED status
|
||||
|
|
|
|||
|
|
@ -989,7 +989,7 @@ void M_Drawer(void)
|
|||
}
|
||||
|
||||
// draw pause pic
|
||||
if (paused && !demo.playback && (menuactive || cv_showhud.value))
|
||||
if (paused && !demo.playback && (menuactive || R_ShowHUD()))
|
||||
{
|
||||
M_DrawPausedText(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ boolean takescreenshot = false; // Take a screenshot this tic
|
|||
|
||||
moviemode_t moviemode = MM_OFF;
|
||||
|
||||
g_takemapthumbnail_t g_takemapthumbnail = TMT_NO;
|
||||
|
||||
char joinedIPlist[NUMLOGIP][2][MAX_LOGIP];
|
||||
char joinedIP[MAX_LOGIP];
|
||||
|
||||
|
|
@ -1854,6 +1856,46 @@ failure:
|
|||
#endif
|
||||
}
|
||||
|
||||
void M_SaveMapThumbnail(UINT32 width, UINT32 height, tcb::span<const std::byte> data)
|
||||
{
|
||||
#ifdef USE_PNG
|
||||
#if NUMSCREENS > 2
|
||||
|
||||
char *filepath;
|
||||
switch (g_takemapthumbnail)
|
||||
{
|
||||
case TMT_PICTURE:
|
||||
default:
|
||||
{
|
||||
filepath = va("%s" PATHSEP "PICTURE_%s.png", srb2home, G_BuildMapName(gamemap));
|
||||
break;
|
||||
}
|
||||
case TMT_RICHPRES:
|
||||
{
|
||||
filepath = va("%s" PATHSEP "map_%s.png", srb2home, G_BuildMapName(gamemap));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save the file
|
||||
const void* pixel_data = static_cast<const void*>(data.data());
|
||||
boolean ret = M_SavePNG(filepath, pixel_data, width, height, NULL);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
CONS_Printf(M_GetText("Created thumbnail at \"%s\"\n"), filepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Couldn't create %s\n"), filepath);
|
||||
}
|
||||
|
||||
g_takemapthumbnail = TMT_NO;
|
||||
|
||||
#endif // #ifdef USE_PNG
|
||||
#endif // #if NUMSCREENS > 2
|
||||
}
|
||||
|
||||
void M_ScreenshotTicker(void)
|
||||
{
|
||||
const UINT8 pid = 0; // TODO: should splitscreen players be allowed to use this too?
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
void M_DoScreenShot(uint32_t width, uint32_t height, tcb::span<const std::byte> data);
|
||||
void M_SaveFrame(uint32_t width, uint32_t height, tcb::span<const std::byte> data);
|
||||
|
||||
void M_SaveMapThumbnail(uint32_t width, uint32_t height, tcb::span<const std::byte> data);
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
|
@ -43,6 +45,13 @@ typedef enum {
|
|||
} moviemode_t;
|
||||
extern moviemode_t moviemode;
|
||||
|
||||
typedef enum {
|
||||
TMT_NO = 0,
|
||||
TMT_PICTURE,
|
||||
TMT_RICHPRES,
|
||||
} g_takemapthumbnail_t;
|
||||
extern g_takemapthumbnail_t g_takemapthumbnail;
|
||||
|
||||
extern consvar_t cv_screenshot_colorprofile;
|
||||
extern consvar_t cv_lossless_recorder;
|
||||
extern consvar_t cv_zlib_memory, cv_zlib_level, cv_zlib_strategy, cv_zlib_window_bits;
|
||||
|
|
|
|||
16
src/p_mobj.c
16
src/p_mobj.c
|
|
@ -14090,6 +14090,17 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
|
|||
return mobj;
|
||||
}
|
||||
|
||||
static boolean P_DoomEdNumIsNOP(UINT16 type)
|
||||
{
|
||||
if (type == EDITOR_CAM_DOOMEDNUM)
|
||||
{
|
||||
// 3D Mode start Thing
|
||||
return true;
|
||||
}
|
||||
|
||||
return (type == 0);
|
||||
}
|
||||
|
||||
//
|
||||
// P_SpawnMapThing
|
||||
// The fields of the mapthing should
|
||||
|
|
@ -14101,12 +14112,9 @@ mobj_t *P_SpawnMapThing(mapthing_t *mthing)
|
|||
mobj_t *mobj = NULL;
|
||||
fixed_t x, y, z;
|
||||
|
||||
if (!mthing->type)
|
||||
if (P_DoomEdNumIsNOP(mthing->type))
|
||||
return mobj; // Ignore type-0 things as NOPs
|
||||
|
||||
if (mthing->type == 3328) // 3D Mode start Thing
|
||||
return mobj;
|
||||
|
||||
if (!objectplacing && P_SpawnNonMobjMapThing(mthing))
|
||||
return mobj;
|
||||
|
||||
|
|
|
|||
|
|
@ -595,6 +595,8 @@ extern INT32 numcheatchecks;
|
|||
extern UINT16 bossdisabled;
|
||||
extern boolean stoppedclock;
|
||||
|
||||
#define EDITOR_CAM_DOOMEDNUM (3328)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8920,6 +8920,35 @@ void P_PostLoadLevel(void)
|
|||
// We're now done loading the level.
|
||||
levelloading = false;
|
||||
|
||||
if (roundqueue.snapshotmaps == true)
|
||||
{
|
||||
if (roundqueue.size > 0)
|
||||
{
|
||||
D_TakeMapSnapshots();
|
||||
|
||||
G_GetNextMap();
|
||||
|
||||
// roundqueue is wiped after the last round, but
|
||||
// preserve this to track state into the Podium!
|
||||
roundqueue.snapshotmaps = true;
|
||||
|
||||
G_NextLevel();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Podium: snapshotmaps is finished. Yay!
|
||||
HU_DoTitlecardCEcho(NULL, va("Congratulations,\\%s!\\Check the console!", cv_playername[0].string), true);
|
||||
|
||||
livestudioaudience_timer = 0;
|
||||
LiveStudioAudience();
|
||||
|
||||
CONS_Printf("\n\n\x83""snapshotmaps: Find your images in %s\n", srb2home);
|
||||
|
||||
roundqueue.snapshotmaps = false;
|
||||
}
|
||||
}
|
||||
|
||||
TracyCZoneEnd(__zone);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3200,6 +3200,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
thiscam->old_angle = thiscam->angle;
|
||||
thiscam->old_aiming = thiscam->aiming;
|
||||
|
||||
if (roundqueue.snapshotmaps == true)
|
||||
return true;
|
||||
|
||||
// We probably shouldn't move the camera if there is no player or player mobj somehow
|
||||
if (!player || !player->mo)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
|
||||
#include "r_fps.h" // Frame interpolation/uncapped
|
||||
#include "core/thread_pool.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_main.h"
|
||||
|
|
@ -969,6 +970,16 @@ void R_CheckFOV(void)
|
|||
}
|
||||
}
|
||||
|
||||
boolean R_ShowHUD(void)
|
||||
{
|
||||
if (g_takemapthumbnail != TMT_NO)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (boolean)cv_showhud.value;
|
||||
}
|
||||
|
||||
//
|
||||
// R_ExecuteSetViewSize
|
||||
//
|
||||
|
|
@ -988,7 +999,7 @@ void R_ExecuteSetViewSize(void)
|
|||
return;
|
||||
|
||||
// status bar overlay
|
||||
st_overlay = cv_showhud.value;
|
||||
st_overlay = R_ShowHUD();
|
||||
|
||||
scaledviewwidth = vid.width;
|
||||
viewheight = vid.height;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,8 @@ void R_ExecuteSetViewSize(void);
|
|||
fixed_t R_FOV(int split);
|
||||
void R_CheckFOV(void);
|
||||
|
||||
boolean R_ShowHUD(void);
|
||||
|
||||
void R_SetupFrame(int split);
|
||||
void R_SkyboxFrame(int split);
|
||||
|
||||
|
|
|
|||
|
|
@ -3765,13 +3765,23 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
|
|||
}
|
||||
}
|
||||
|
||||
boolean R_DrawPickups(void)
|
||||
{
|
||||
if (g_takemapthumbnail != TMT_NO)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (boolean)cv_drawpickups.value;
|
||||
}
|
||||
|
||||
/* Check if thing may be drawn from our current view. */
|
||||
boolean R_ThingVisible (mobj_t *thing)
|
||||
{
|
||||
if (thing->sprite == SPR_NULL)
|
||||
return false;
|
||||
|
||||
if (!cv_drawpickups.value)
|
||||
if (!R_DrawPickups())
|
||||
{
|
||||
switch (thing->type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ void R_ClearSprites(void);
|
|||
UINT8 R_GetBoundingBoxColor(mobj_t *thing);
|
||||
boolean R_ThingBoundingBoxVisible(mobj_t *thing);
|
||||
|
||||
boolean R_DrawPickups(void);
|
||||
boolean R_ThingVisible (mobj_t *thing);
|
||||
|
||||
boolean R_ThingWithinDist (mobj_t *thing,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
#endif
|
||||
|
||||
// maximum number of windowed modes (see windowedModes[][])
|
||||
#define MAXWINMODES (18)
|
||||
#define MAXWINMODES (19)
|
||||
|
||||
using namespace srb2;
|
||||
|
||||
|
|
@ -158,6 +158,7 @@ static INT32 windowedModes[MAXWINMODES][2] =
|
|||
{1280, 800}, // 1.60,4.00
|
||||
{1280, 720}, // 1.66
|
||||
{1152, 864}, // 1.33,3.60
|
||||
{1024,1024}, // SPECIAL, for snapshot taker
|
||||
{1024, 768}, // 1.33,3.20
|
||||
{ 800, 600}, // 1.33,2.50
|
||||
{ 640, 480}, // 1.33,2.00
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue