Merge pull request #160 from BielBdeLuna/envshot

Envshot and cubemap to skymap transforms
This commit is contained in:
Robert Beckebans 2014-08-25 17:17:47 +02:00
commit ce0e83ebca
6 changed files with 364 additions and 24 deletions

View file

@ -31,7 +31,7 @@ If you have questions concerning this license or the applicable additional terms
#pragma hdrstop #pragma hdrstop
#include "Common_local.h" #include "Common_local.h"
#include "../renderer/Image.h" #include "../renderer/Image.h" // now I did it!
#include "../renderer/ImageOpts.h" #include "../renderer/ImageOpts.h"
// RB begin // RB begin
@ -530,14 +530,15 @@ void idCommonLocal::Frame()
// save the screenshot and audio from the last draw if needed // save the screenshot and audio from the last draw if needed
if( aviCaptureMode ) if( aviCaptureMode )
{ {
idStr name = va( "demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ ); idStr name;
renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); name.Format( "demos/%s/%s_%05i", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ );
renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL, TGA );
// remove any printed lines at the top before taking the screenshot // remove any printed lines at the top before taking the screenshot
console->ClearNotifyLines(); console->ClearNotifyLines();
// this will call Draw, possibly multiple times if com_aviDemoSamples is > 1 // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1
renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL, TGA );
} }
//-------------------------------------------- //--------------------------------------------

View file

@ -69,6 +69,13 @@ typedef enum
CF_2D_ARRAY // not a cube map but not a single 2d texture either CF_2D_ARRAY // not a cube map but not a single 2d texture either
} cubeFiles_t; } cubeFiles_t;
enum imageFileType_t
{
TGA,
PNG,
JPG
};
#include "ImageOpts.h" #include "ImageOpts.h"
#include "BinaryImage.h" #include "BinaryImage.h"
@ -390,6 +397,7 @@ void R_BlendOverTexture( byte* data, int pixelCount, const byte blend[4] );
void R_HorizontalFlip( byte* data, int width, int height ); void R_HorizontalFlip( byte* data, int width, int height );
void R_VerticalFlip( byte* data, int width, int height ); void R_VerticalFlip( byte* data, int width, int height );
void R_RotatePic( byte* data, int width ); void R_RotatePic( byte* data, int width );
void R_ApplyCubeMapTransforms( int i, byte* data, int size );
/* /*
==================================================================== ====================================================================

View file

@ -538,6 +538,7 @@ void R_RotatePic( byte* data, int width )
{ {
for( j = 0 ; j < width ; j++ ) for( j = 0 ; j < width ; j++ )
{ {
// apparently rotates the picture and then it flips the picture horitzontally
*( temp + i * width + j ) = *( ( int* )data + j * width + i ); *( temp + i * width + j ) = *( ( int* )data + j * width + i );
} }
} }
@ -547,3 +548,25 @@ void R_RotatePic( byte* data, int width )
R_StaticFree( temp ); R_StaticFree( temp );
} }
// transforms in both ways, the images from a cube map,
// in both the Env map and the Skybox map systems.
void R_ApplyCubeMapTransforms( int iter, byte* data, int size )
{
if( ( iter == 1 ) || ( iter == 2 ) )
{
R_VerticalFlip( data, size, size );
}
if( ( iter == 0 ) || ( iter == 1 ) || ( iter == 4 ) || ( iter == 5 ) )
{
R_RotatePic( data, size ); // apparently not only rotates but also flips horitzontally
}
if( iter == 1 )
{
R_VerticalFlip( data, size, size );
}
else if( iter == 3 ) // that's so just for having less lines
{
R_HorizontalFlip( data, size, size );
}
}

View file

@ -332,7 +332,7 @@ public:
// This will perform swapbuffers, so it is NOT an approppriate way to // This will perform swapbuffers, so it is NOT an approppriate way to
// generate image files that happen during gameplay, as for savegame // generate image files that happen during gameplay, as for savegame
// markers. Use WriteRender() instead. // markers. Use WriteRender() instead.
virtual void TakeScreenshot( int width, int height, const char* fileName, int samples, struct renderView_s* ref ) = 0; virtual void TakeScreenshot( int width, int height, const char* fileName, int samples, struct renderView_s* ref, int exten ) = 0;
// the render output can be cropped down to a subset of the real screen, as // the render output can be cropped down to a subset of the real screen, as
// for save-game reviews and split-screen multiplayer. Users of the renderer // for save-game reviews and split-screen multiplayer. Users of the renderer

View file

@ -237,6 +237,10 @@ idCVar r_shadowMapPolygonOffset( "r_shadowMapPolygonOffset", "3000", CVAR_RENDER
idCVar r_shadowMapOccluderFacing( "r_shadowMapOccluderFacing", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = front faces, 1 = back faces, 2 = twosided" ); idCVar r_shadowMapOccluderFacing( "r_shadowMapOccluderFacing", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = front faces, 1 = back faces, 2 = twosided" );
// RB end // RB end
const char* fileExten[3] = { "tga", "png", "jpg" };
const char* envDirection[6] = { "_nx", "_py", "_ny", "_pz", "_nz", "_px" };
const char* skyDirection[6] = { "_forward", "_back", "_left", "_right", "_up", "_down" };
/* /*
======================== ========================
@ -1223,21 +1227,40 @@ If ref == NULL, common->UpdateScreen will be used
================== ==================
*/ */
// RB: changed .tga to .png // RB: changed .tga to .png
void idRenderSystemLocal::TakeScreenshot( int width, int height, const char* fileName, int blends, renderView_t* ref ) void idRenderSystemLocal::TakeScreenshot( int width, int height, const char* fileName, int blends, renderView_t* ref, int exten )
{ {
byte* buffer; byte* buffer;
int i, j; int i, j, c, temp;
idStr finalFileName;
finalFileName.Format( "%s.%s", fileName, fileExten[exten] );
takingScreenshot = true; takingScreenshot = true;
int pix = width * height; int pix = width * height;
const int bufferSize = pix * 3 + 18;
if( exten == PNG )
{
buffer = ( byte* )R_StaticAlloc( pix * 3 ); buffer = ( byte* )R_StaticAlloc( pix * 3 );
}
else if( exten == TGA )
{
buffer = ( byte* )R_StaticAlloc( bufferSize );
memset( buffer, 0, bufferSize );
}
if( blends <= 1 ) if( blends <= 1 )
{
if( exten == PNG )
{ {
R_ReadTiledPixels( width, height, buffer, ref ); R_ReadTiledPixels( width, height, buffer, ref );
} }
else if( exten == TGA )
{
R_ReadTiledPixels( width, height, buffer + 18, ref );
}
}
else else
{ {
unsigned short* shortBuffer = ( unsigned short* )R_StaticAlloc( pix * 2 * 3 ); unsigned short* shortBuffer = ( unsigned short* )R_StaticAlloc( pix * 2 * 3 );
@ -1247,26 +1270,71 @@ void idRenderSystemLocal::TakeScreenshot( int width, int height, const char* fil
r_jitter.SetBool( true ); r_jitter.SetBool( true );
for( i = 0 ; i < blends ; i++ ) for( i = 0 ; i < blends ; i++ )
{
if( exten == PNG )
{ {
R_ReadTiledPixels( width, height, buffer, ref ); R_ReadTiledPixels( width, height, buffer, ref );
}
else if( exten == TGA )
{
R_ReadTiledPixels( width, height, buffer + 18, ref );
}
for( j = 0 ; j < pix * 3 ; j++ ) for( j = 0 ; j < pix * 3 ; j++ )
{
if( exten == PNG )
{ {
shortBuffer[j] += buffer[j]; shortBuffer[j] += buffer[j];
} }
else if( exten == TGA )
{
shortBuffer[j] += buffer[18 + j];
}
}
} }
// divide back to bytes // divide back to bytes
for( i = 0 ; i < pix * 3 ; i++ ) for( i = 0 ; i < pix * 3 ; i++ )
{
if( exten == PNG )
{ {
buffer[i] = shortBuffer[i] / blends; buffer[i] = shortBuffer[i] / blends;
} }
else if( exten == TGA )
{
buffer[18 + i] = shortBuffer[i] / blends;
}
}
R_StaticFree( shortBuffer ); R_StaticFree( shortBuffer );
r_jitter.SetBool( false ); r_jitter.SetBool( false );
} }
if( exten == PNG )
{
R_WritePNG( finalFileName, buffer, 3, width, height, false );
}
else
{
// fill in the header (this is vertically flipped, which qglReadPixels emits)
buffer[2] = 2; // uncompressed type
buffer[12] = width & 255;
buffer[13] = width >> 8;
buffer[14] = height & 255;
buffer[15] = height >> 8;
buffer[16] = 24; // pixel size
R_WritePNG( fileName, buffer, 3, width, height, false ); // swap rgb to bgr
c = 18 + width * height * 3;
for( i = 18 ; i < c ; i += 3 )
{
temp = buffer[i];
buffer[i] = buffer[i + 2];
buffer[i + 2] = temp;
}
fileSystem->WriteFile( finalFileName, buffer, c );
}
R_StaticFree( buffer ); R_StaticFree( buffer );
@ -1317,7 +1385,7 @@ void R_ScreenshotFilename( int& lastNumber, const char* base, idStr& fileName )
time( &aclock ); time( &aclock );
struct tm* t = localtime( &aclock ); struct tm* t = localtime( &aclock );
sprintf( fileName, "%s%s-%04d%02d%02d-%02d%02d%02d-%03d.png", base, "rbdoom-3-bfg", sprintf( fileName, "%s%s-%04d%02d%02d-%02d%02d%02d-%03d", base, "rbdoom-3-bfg",
1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, lastNumber ); 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, lastNumber );
#endif #endif
// RB end // RB end
@ -1397,7 +1465,7 @@ void R_ScreenShot_f( const idCmdArgs& args )
// put the console away // put the console away
console->Close(); console->Close();
tr.TakeScreenshot( width, height, checkname, blends, NULL ); tr.TakeScreenshot( width, height, checkname, blends, NULL, PNG );
common->Printf( "Wrote %s\n", checkname.c_str() ); common->Printf( "Wrote %s\n", checkname.c_str() );
} }
@ -1444,6 +1512,137 @@ void R_StencilShot()
fileSystem->WriteFile( "screenshots/stencilShot.tga", buffer.Ptr(), c, "fs_savepath" ); fileSystem->WriteFile( "screenshots/stencilShot.tga", buffer.Ptr(), c, "fs_savepath" );
} }
/*
==================
R_EnvShot_f
envshot <basename>
Saves out env/<basename>_ft.tga, etc
==================
*/
void R_EnvShot_f( const idCmdArgs& args )
{
idStr fullname;
const char* baseName;
int i;
idMat3 axis[7], oldAxis;
renderView_t ref;
viewDef_t primary;
int blends;
const char* extension;
int size;
int res_w, res_h, old_fov_x, old_fov_y;
res_w = renderSystem->GetWidth();
res_h = renderSystem->GetHeight();
if( args.Argc() != 2 && args.Argc() != 3 && args.Argc() != 4 )
{
common->Printf( "USAGE: envshot <basename> [size] [blends]\n" );
return;
}
baseName = args.Argv( 1 );
blends = 1;
if( args.Argc() == 4 )
{
size = atoi( args.Argv( 2 ) );
blends = atoi( args.Argv( 3 ) );
}
else if( args.Argc() == 3 )
{
size = atoi( args.Argv( 2 ) );
blends = 1;
}
else
{
size = 256;
blends = 1;
}
if( !tr.primaryView )
{
common->Printf( "No primary view.\n" );
return;
}
primary = *tr.primaryView;
memset( &axis, 0, sizeof( axis ) );
axis[0][0][0] = 1; // this one gets ignored as it always come out wrong.
axis[0][1][2] = 1; // and so we repeat this axis as the last one.
axis[0][2][1] = 1;
axis[1][0][0] = -1;
axis[1][1][2] = -1;
axis[1][2][1] = 1;
axis[2][0][1] = 1;
axis[2][1][0] = -1;
axis[2][2][2] = -1;
axis[3][0][1] = -1;
axis[3][1][0] = -1;
axis[3][2][2] = 1;
axis[4][0][2] = 1;
axis[4][1][0] = -1;
axis[4][2][1] = 1;
axis[5][0][2] = -1;
axis[5][1][0] = 1;
axis[5][2][1] = 1;
axis[6][0][0] = 1; // this is the repetition of the first axis
axis[6][1][2] = 1;
axis[6][2][1] = 1;
// let's get the game window to a "size" resolution
if( ( res_w != size ) || ( res_h != size ) )
{
cvarSystem->SetCVarInteger( "r_windowWidth", size );
cvarSystem->SetCVarInteger( "r_windowHeight", size );
R_SetNewMode( false ); // the same as "vid_restart"
} // FIXME that's a hack!!
for( i = 0 ; i < 7 ; i++ )
{
ref = primary.renderView;
if( i == 0 )
{
// so we return to that axis and fov after the fact.
oldAxis = ref.viewaxis;
old_fov_x = ref.fov_x;
old_fov_y = ref.fov_y;
//this is part of the hack
extension = "_wrong";
}
else
{
// this keeps being part of the hack
extension = envDirection[ i - 1 ]; //yes, indeed, this is totally part of the hack!
}
ref.fov_x = ref.fov_y = 90;
ref.viewaxis = axis[i];
fullname.Format( "env/%s%s", baseName, extension );
tr.TakeScreenshot( size, size, fullname, blends, &ref, TGA );
}
// restore the original resolution, axis and fov
ref.viewaxis = oldAxis;
ref.fov_x = old_fov_x;
ref.fov_y = old_fov_y;
cvarSystem->SetCVarInteger( "r_windowWidth", res_w );
cvarSystem->SetCVarInteger( "r_windowHeight", res_h );
R_SetNewMode( false ); // the same as "vid_restart"
common->Printf( "Wrote a env set with the name %s\n", baseName );
}
//============================================================================ //============================================================================
@ -1536,9 +1735,6 @@ void R_MakeAmbientMap_f( const idCmdArgs& args )
renderView_t ref; renderView_t ref;
viewDef_t primary; viewDef_t primary;
int downSample; int downSample;
const char* extensions[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga",
"_pz.tga", "_nz.tga"
};
int outSize; int outSize;
byte* buffers[6]; byte* buffers[6];
int width = 0, height = 0; int width = 0, height = 0;
@ -1588,7 +1784,7 @@ void R_MakeAmbientMap_f( const idCmdArgs& args )
// read all of the images // read all of the images
for( i = 0 ; i < 6 ; i++ ) for( i = 0 ; i < 6 ; i++ )
{ {
sprintf( fullname, "env/%s%s", baseName, extensions[i] ); fullname.Format( "env/%s%s.%s", baseName, envDirection[i], fileExten[TGA] );
common->Printf( "loading %s\n", fullname.c_str() ); common->Printf( "loading %s\n", fullname.c_str() );
const bool captureToImage = false; const bool captureToImage = false;
common->UpdateScreen( captureToImage ); common->UpdateScreen( captureToImage );
@ -1663,11 +1859,11 @@ void R_MakeAmbientMap_f( const idCmdArgs& args )
if( map == 0 ) if( map == 0 )
{ {
sprintf( fullname, "env/%s_amb%s", baseName, extensions[i] ); fullname.Format( "env/%s_amb%s.%s", baseName, envDirection[i], fileExten[TGA] );
} }
else else
{ {
sprintf( fullname, "env/%s_spec%s", baseName, extensions[i] ); fullname.Format( "env/%s_spec%s.%s", baseName, envDirection[i], fileExten[TGA] );
} }
common->Printf( "writing %s\n", fullname.c_str() ); common->Printf( "writing %s\n", fullname.c_str() );
const bool captureToImage = false; const bool captureToImage = false;
@ -1685,6 +1881,115 @@ void R_MakeAmbientMap_f( const idCmdArgs& args )
} }
} }
void R_TransformCubemap( const char* orgDirection[6], const char* orgDir, const char* destDirection[6], const char* destDir, const char* baseName )
{
idStr fullname;
int i;
bool errorInOriginalImages = false;
int outSize;
byte* buffers[6];
int width = 0, height = 0;
for( i = 0 ; i < 6 ; i++ )
{
// read every image images
fullname.Format( "%s/%s%s.%s", orgDir, baseName, orgDirection[i], fileExten [TGA] );
common->Printf( "loading %s\n", fullname.c_str() );
const bool captureToImage = false;
common->UpdateScreen( captureToImage );
R_LoadImage( fullname, &buffers[i], &width, &height, NULL, true );
//check if the buffer is troublesome
if( !buffers[i] )
{
common->Printf( "failed.\n" );
errorInOriginalImages = true;
}
else if( width != height )
{
common->Printf( "wrong size pal!\n\n\nget your shit together and set the size according to your images!\n\n\ninept programmers are inept!\n" );
errorInOriginalImages = true; // yeah, but don't just choke on a joke!
}
else
{
errorInOriginalImages = false;
}
if( errorInOriginalImages )
{
errorInOriginalImages = false;
for( i-- ; i >= 0 ; i-- )
{
Mem_Free( buffers[i] ); // clean up every buffer from this stage down
}
return;
}
// apply rotations and flips
R_ApplyCubeMapTransforms( i, buffers[i], width );
//save the images with the appropiate skybox naming convention
fullname.Format( "%s/%s/%s%s.%s", destDir, baseName, baseName, destDirection[i], fileExten [TGA] );
common->Printf( "writing %s\n", fullname.c_str() );
common->UpdateScreen( false );
R_WriteTGA( fullname, buffers[i], width, width );
}
for( i = 0 ; i < 6 ; i++ )
{
if( buffers[i] )
{
Mem_Free( buffers[i] );
}
}
}
/*
==================
R_TransformEnvToSkybox_f
R_TransformEnvToSkybox_f <basename>
transforms env textures (of the type px, py, pz, nx, ny, nz)
to skybox textures ( forward, back, left, right, up, down)
==================
*/
void R_TransformEnvToSkybox_f( const idCmdArgs& args )
{
if( args.Argc() != 2 )
{
common->Printf( "USAGE: envToSky <basename>\n" );
return;
}
R_TransformCubemap( envDirection, "env", skyDirection, "skybox", args.Argv( 1 ) );
}
/*
==================
R_TransformSkyboxToEnv_f
R_TransformSkyboxToEnv_f <basename>
transforms skybox textures ( forward, back, left, right, up, down)
to env textures (of the type px, py, pz, nx, ny, nz)
==================
*/
void R_TransformSkyboxToEnv_f( const idCmdArgs& args )
{
if( args.Argc() != 2 )
{
common->Printf( "USAGE: skyToEnv <basename>\n" );
return;
}
R_TransformCubemap( skyDirection, "skybox", envDirection, "env", args.Argv( 1 ) );
}
//============================================================================ //============================================================================
@ -2039,7 +2344,10 @@ void R_InitCommands()
cmdSystem->AddCommand( "listGuis", R_ListGuis_f, CMD_FL_RENDERER, "lists guis" ); cmdSystem->AddCommand( "listGuis", R_ListGuis_f, CMD_FL_RENDERER, "lists guis" );
cmdSystem->AddCommand( "touchGui", R_TouchGui_f, CMD_FL_RENDERER, "touches a gui" ); cmdSystem->AddCommand( "touchGui", R_TouchGui_f, CMD_FL_RENDERER, "touches a gui" );
cmdSystem->AddCommand( "screenshot", R_ScreenShot_f, CMD_FL_RENDERER, "takes a screenshot" ); cmdSystem->AddCommand( "screenshot", R_ScreenShot_f, CMD_FL_RENDERER, "takes a screenshot" );
cmdSystem->AddCommand( "envshot", R_EnvShot_f, CMD_FL_RENDERER, "takes an environment shot" );
cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "makes an ambient map" ); cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "makes an ambient map" );
cmdSystem->AddCommand( "envToSky", R_TransformEnvToSkybox_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "transforms environment textures to sky box textures" );
cmdSystem->AddCommand( "skyToEnv", R_TransformSkyboxToEnv_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "transforms sky box textures to environment textures" );
cmdSystem->AddCommand( "gfxInfo", GfxInfo_f, CMD_FL_RENDERER, "show graphics info" ); cmdSystem->AddCommand( "gfxInfo", GfxInfo_f, CMD_FL_RENDERER, "show graphics info" );
cmdSystem->AddCommand( "modulateLights", R_ModulateLights_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "modifies shader parms on all lights" ); cmdSystem->AddCommand( "modulateLights", R_ModulateLights_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "modifies shader parms on all lights" );
cmdSystem->AddCommand( "testImage", R_TestImage_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given image centered on screen", idCmdSystem::ArgCompletion_ImageName ); cmdSystem->AddCommand( "testImage", R_TestImage_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "displays the given image centered on screen", idCmdSystem::ArgCompletion_ImageName );

View file

@ -814,7 +814,7 @@ public:
virtual const emptyCommand_t* SwapCommandBuffers_FinishCommandBuffers(); virtual const emptyCommand_t* SwapCommandBuffers_FinishCommandBuffers();
virtual void RenderCommandBuffers( const emptyCommand_t* commandBuffers ); virtual void RenderCommandBuffers( const emptyCommand_t* commandBuffers );
virtual void TakeScreenshot( int width, int height, const char* fileName, int downSample, renderView_t* ref ); virtual void TakeScreenshot( int width, int height, const char* fileName, int downSample, renderView_t* ref, int exten );
virtual void CropRenderSize( int width, int height ); virtual void CropRenderSize( int width, int height );
virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false ); virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false );
virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha ); virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha );