/******************************************************************************
|
|
@file Shell/PVRShell.cpp
|
@copyright Copyright (c) Imagination Technologies Limited.
|
@brief Makes programming for 3D APIs easier by wrapping surface
|
initialization, Texture allocation and other functions for use by a demo.
|
|
******************************************************************************/
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <math.h>
|
|
#include "PVRShell.h"
|
#include "PVRShellOS.h"
|
#include "PVRShellAPI.h"
|
#include "PVRShellImpl.h"
|
|
/*! This file simply defines a version string. It can be commented out. */
|
#include "sdkver.h"
|
#ifndef PVRSDK_VERSION
|
#define PVRSDK_VERSION "n.nn.nn.nnnn"
|
#endif
|
|
/*! Define to automatically stop the app after x frames. If negative, run forever. */
|
#ifndef PVRSHELL_QUIT_AFTER_FRAME
|
#define PVRSHELL_QUIT_AFTER_FRAME -1
|
#endif
|
|
/*! Define to automatically stop the app after x amount of seconds. If negative, run forever. */
|
#ifndef PVRSHELL_QUIT_AFTER_TIME
|
#define PVRSHELL_QUIT_AFTER_TIME -1
|
#endif
|
|
/*! Define for the screen shot file name. */
|
#define PVRSHELL_SCREENSHOT_NAME "PVRShell"
|
|
#if defined(_WIN32)
|
#define snprintf _snprintf
|
#endif
|
|
// No Doxygen for CPP files, due to documentation duplication
|
/// @cond NO_DOXYGEN
|
|
// Define DISABLE_SWIPE_MAPPING to disable the PVRShell's simple mapping of swipes to key commands.
|
//#define DISABLE_SWIPE_MAPPING 1
|
/*****************************************************************************
|
** Prototypes
|
*****************************************************************************/
|
static bool StringCopy(char *&pszStr, const char * const pszSrc);
|
|
/****************************************************************************
|
** Class: PVRShell
|
****************************************************************************/
|
|
/*!***********************************************************************
|
@brief Constructor
|
*************************************************************************/
|
PVRShell::PVRShell()
|
{
|
m_pShellInit = NULL;
|
m_pShellData = new PVRShellData;
|
|
m_pShellData->nShellPosX=0;
|
m_pShellData->nShellPosY=0;
|
|
m_pShellData->bFullScreen = false; // note this may be overridden by some OS versions of PVRShell
|
|
m_pShellData->nAASamples= 0;
|
m_pShellData->nColorBPP = 0;
|
m_pShellData->nDepthBPP = 0;
|
|
m_pShellData->nDieAfterFrames = PVRSHELL_QUIT_AFTER_FRAME;
|
m_pShellData->fDieAfterTime = PVRSHELL_QUIT_AFTER_TIME;
|
|
m_pShellData->bNeedPbuffer = false;
|
m_pShellData->bNeedPixmap = false;
|
m_pShellData->bNeedPixmapDisableCopy = false;
|
m_pShellData->bNeedZbuffer = true;
|
m_pShellData->bLockableBackBuffer = false;
|
m_pShellData->bSoftwareRender = false;
|
m_pShellData->bNeedStencilBuffer = false;
|
|
m_pShellData->bNeedAlphaFormatPre = false;
|
m_pShellData->bUsingPowerSaving = true;
|
m_pShellData->bOutputInfo = false;
|
m_pShellData->bNoShellSwapBuffer = false;
|
|
m_pShellData->pszAppName = 0;
|
m_pShellData->pszExitMessage = 0;
|
|
m_pShellData->nSwapInterval = 1;
|
m_pShellData->nInitRepeats = 0;
|
|
m_pShellData->nCaptureFrameStart = -1;
|
m_pShellData->nCaptureFrameStop = -1;
|
m_pShellData->nCaptureFrameScale = 1;
|
|
m_pShellData->nPriority = 2;
|
|
m_pShellData->bForceFrameTime = false;
|
m_pShellData->nFrameTime = 33;
|
|
// Internal Data
|
m_pShellData->bShellPosWasDefault = true;
|
m_pShellData->nShellCurFrameNum = 0;
|
#ifdef PVRSHELL_FPS_OUTPUT
|
m_pShellData->bOutputFPS = false;
|
#endif
|
m_pShellData->bDiscardFrameColor=false;
|
m_pShellData->bDiscardFrameDepth=true;
|
m_pShellData->bDiscardFrameStencil=true;
|
}
|
|
/*!***********************************************************************
|
@brief Destructor
|
*************************************************************************/
|
PVRShell::~PVRShell()
|
{
|
delete m_pShellData;
|
m_pShellData = NULL;
|
}
|
|
// Allow user to set preferences from within InitApplication
|
|
/*!***********************************************************************
|
@brief This function is used to pass preferences to the PVRShell.
|
If used, this function must be called from InitApplication().
|
@param[in] prefName Name of preference to set to value
|
@param[in] value Value
|
@return true for success
|
*************************************************************************/
|
|
bool PVRShell::PVRShellSet(const prefNameBoolEnum prefName, const bool value)
|
{
|
switch(prefName)
|
{
|
case prefFullScreen:
|
m_pShellData->bFullScreen = value;
|
return true;
|
|
case prefPBufferContext:
|
m_pShellData->bNeedPbuffer = value;
|
return true;
|
|
case prefPixmapContext:
|
m_pShellData->bNeedPixmap = value;
|
return true;
|
|
case prefPixmapDisableCopy:
|
m_pShellData->bNeedPixmapDisableCopy = value;
|
return true;
|
|
case prefZbufferContext:
|
m_pShellData->bNeedZbuffer = value;
|
return true;
|
|
case prefLockableBackBuffer:
|
m_pShellData->bLockableBackBuffer = value;
|
return true;
|
|
case prefSoftwareRendering:
|
m_pShellData->bSoftwareRender = value;
|
return true;
|
|
case prefStencilBufferContext:
|
m_pShellData->bNeedStencilBuffer = value;
|
return true;
|
|
case prefAlphaFormatPre:
|
m_pShellData->bNeedAlphaFormatPre = value;
|
return true;
|
|
case prefPowerSaving:
|
m_pShellData->bUsingPowerSaving = value;
|
return true;
|
|
case prefOutputInfo:
|
m_pShellData->bOutputInfo = value;
|
return true;
|
|
case prefNoShellSwapBuffer:
|
m_pShellData->bNoShellSwapBuffer = value;
|
return true;
|
|
case prefForceFrameTime:
|
m_pShellData->bForceFrameTime = value;
|
return true;
|
|
#ifdef PVRSHELL_FPS_OUTPUT
|
case prefOutputFPS:
|
m_pShellData->bOutputFPS = value;
|
return true;
|
#endif
|
|
case prefDiscardColor:
|
m_pShellData->bDiscardFrameColor = value;
|
return true;
|
case prefDiscardDepth:
|
m_pShellData->bDiscardFrameDepth = value;
|
return true;
|
case prefDiscardStencil:
|
m_pShellData->bDiscardFrameStencil = value;
|
return true;
|
default:
|
return m_pShellInit->OsSet(prefName, value);
|
}
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to get parameters from the PVRShell.
|
It can be called from anywhere in the program.
|
@param[in] prefName Name of preference to set to value
|
@return The requested value.
|
*************************************************************************/
|
|
bool PVRShell::PVRShellGet(const prefNameBoolEnum prefName) const
|
{
|
switch(prefName)
|
{
|
case prefFullScreen: return m_pShellData->bFullScreen;
|
case prefIsRotated: return (m_pShellData->nShellDimY > m_pShellData->nShellDimX);
|
case prefPBufferContext: return m_pShellData->bNeedPbuffer;
|
case prefPixmapContext: return m_pShellData->bNeedPixmap;
|
case prefPixmapDisableCopy: return m_pShellData->bNeedPixmapDisableCopy;
|
case prefZbufferContext: return m_pShellData->bNeedZbuffer;
|
case prefLockableBackBuffer: return m_pShellData->bLockableBackBuffer;
|
case prefSoftwareRendering: return m_pShellData->bSoftwareRender;
|
case prefNoShellSwapBuffer: return m_pShellData->bNoShellSwapBuffer;
|
case prefStencilBufferContext: return m_pShellData->bNeedStencilBuffer;
|
case prefAlphaFormatPre: return m_pShellData->bNeedAlphaFormatPre;
|
case prefPowerSaving: return m_pShellData->bUsingPowerSaving;
|
case prefOutputInfo: return m_pShellData->bOutputInfo;
|
case prefForceFrameTime: return m_pShellData->bForceFrameTime;
|
#ifdef PVRSHELL_FPS_OUTPUT
|
case prefOutputFPS: return m_pShellData->bOutputFPS;
|
#endif
|
case prefDiscardColor: return m_pShellData->bDiscardFrameColor;
|
case prefDiscardDepth: return m_pShellData->bDiscardFrameDepth;
|
case prefDiscardStencil: return m_pShellData->bDiscardFrameStencil;
|
default: return false;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to pass preferences to the PVRShell.
|
If used, this function must be called from InitApplication().
|
@param[in] prefName Name of preference to set to value
|
@param[in] value Value
|
@return true for success
|
*************************************************************************/
|
|
bool PVRShell::PVRShellSet(const prefNameFloatEnum prefName, const float value)
|
{
|
switch(prefName)
|
{
|
case prefQuitAfterTime:
|
m_pShellData->fDieAfterTime = value;
|
return true;
|
|
default:
|
break;
|
}
|
return false;
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to get parameters from the PVRShell.
|
It can be called from anywhere in the program.
|
@param[in] prefName Name of preference to set to value
|
@return The requested value.
|
*************************************************************************/
|
float PVRShell::PVRShellGet(const prefNameFloatEnum prefName) const
|
{
|
switch(prefName)
|
{
|
case prefQuitAfterTime: return m_pShellData->fDieAfterTime;
|
default: return -1;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to pass preferences to the PVRShell.
|
If used, this function must be called from InitApplication().
|
@param[in] prefName Name of preference to set to value
|
@param[in] value Value
|
@return true for success
|
*************************************************************************/
|
bool PVRShell::PVRShellSet(const prefNameIntEnum prefName, const int value)
|
{
|
switch(prefName)
|
{
|
case prefWidth:
|
if(value > 0)
|
{
|
m_pShellData->nShellDimX = value;
|
return true;
|
}
|
return false;
|
|
case prefHeight:
|
if(value > 0)
|
{
|
m_pShellData->nShellDimY = value;
|
return true;
|
}
|
return false;
|
|
case prefPositionX:
|
m_pShellData->bShellPosWasDefault = false;
|
m_pShellData->nShellPosX = value;
|
return true;
|
|
case prefPositionY:
|
m_pShellData->bShellPosWasDefault = false;
|
m_pShellData->nShellPosY = value;
|
return true;
|
|
case prefQuitAfterFrame:
|
m_pShellData->nDieAfterFrames = value;
|
return true;
|
|
case prefInitRepeats:
|
m_pShellData->nInitRepeats = value;
|
return true;
|
|
case prefAASamples:
|
if(value >= 0)
|
{
|
m_pShellData->nAASamples = value;
|
return true;
|
}
|
return false;
|
|
case prefColorBPP:
|
if(value >= 0)
|
{
|
m_pShellData->nColorBPP = value;
|
return true;
|
}
|
return false;
|
|
case prefDepthBPP:
|
if(value >= 0)
|
{
|
m_pShellData->nDepthBPP = value;
|
return true;
|
}
|
return false;
|
|
case prefRotateKeys:
|
{
|
switch((PVRShellKeyRotate)value)
|
{
|
case PVRShellKeyRotateNone:
|
m_pShellInit->m_eKeyMapUP = PVRShellKeyNameUP;
|
m_pShellInit->m_eKeyMapLEFT = PVRShellKeyNameLEFT;
|
m_pShellInit->m_eKeyMapDOWN = PVRShellKeyNameDOWN;
|
m_pShellInit->m_eKeyMapRIGHT = PVRShellKeyNameRIGHT;
|
break;
|
case PVRShellKeyRotate90:
|
m_pShellInit->m_eKeyMapUP = PVRShellKeyNameLEFT;
|
m_pShellInit->m_eKeyMapLEFT = PVRShellKeyNameDOWN;
|
m_pShellInit->m_eKeyMapDOWN = PVRShellKeyNameRIGHT;
|
m_pShellInit->m_eKeyMapRIGHT = PVRShellKeyNameUP;
|
break;
|
case PVRShellKeyRotate180:
|
m_pShellInit->m_eKeyMapUP = PVRShellKeyNameDOWN;
|
m_pShellInit->m_eKeyMapLEFT = PVRShellKeyNameRIGHT;
|
m_pShellInit->m_eKeyMapDOWN = PVRShellKeyNameUP;
|
m_pShellInit->m_eKeyMapRIGHT = PVRShellKeyNameLEFT;
|
break;
|
case PVRShellKeyRotate270:
|
m_pShellInit->m_eKeyMapUP = PVRShellKeyNameRIGHT;
|
m_pShellInit->m_eKeyMapLEFT = PVRShellKeyNameUP;
|
m_pShellInit->m_eKeyMapDOWN = PVRShellKeyNameLEFT;
|
m_pShellInit->m_eKeyMapRIGHT = PVRShellKeyNameDOWN;
|
break;
|
default:
|
return false;
|
}
|
}
|
return true;
|
case prefCaptureFrameStart:
|
m_pShellData->nCaptureFrameStart = value;
|
return true;
|
case prefCaptureFrameStop:
|
m_pShellData->nCaptureFrameStop = value;
|
return true;
|
case prefCaptureFrameScale:
|
m_pShellData->nCaptureFrameScale = value;
|
return true;
|
case prefFrameTimeValue:
|
m_pShellData->nFrameTime = value;
|
return true;
|
default:
|
{
|
if(m_pShellInit->ApiSet(prefName, value))
|
return true;
|
|
return m_pShellInit->OsSet(prefName, value);
|
}
|
}
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to get parameters from the PVRShell.
|
It can be called from anywhere in the program.
|
@param[in] prefName Name of preference to set to value
|
@return The requested value.
|
*************************************************************************/
|
int PVRShell::PVRShellGet(const prefNameIntEnum prefName) const
|
{
|
switch(prefName)
|
{
|
case prefWidth: return m_pShellData->nShellDimX;
|
case prefHeight: return m_pShellData->nShellDimY;
|
case prefPositionX: return m_pShellData->nShellPosX;
|
case prefPositionY: return m_pShellData->nShellPosY;
|
case prefQuitAfterFrame: return m_pShellData->nDieAfterFrames;
|
case prefSwapInterval: return m_pShellData->nSwapInterval;
|
case prefInitRepeats: return m_pShellData->nInitRepeats;
|
case prefAASamples: return m_pShellData->nAASamples;
|
case prefCommandLineOptNum: return m_pShellInit->m_CommandLine.m_nOptLen;
|
case prefColorBPP: return m_pShellData->nColorBPP;
|
case prefDepthBPP: return m_pShellData->nDepthBPP;
|
case prefCaptureFrameStart: return m_pShellData->nCaptureFrameStart;
|
case prefCaptureFrameStop: return m_pShellData->nCaptureFrameStop;
|
case prefCaptureFrameScale: return m_pShellData->nCaptureFrameScale;
|
case prefFrameTimeValue: return m_pShellData->nFrameTime;
|
case prefPriority: return m_pShellData->nPriority;
|
default:
|
{
|
int n;
|
|
if(m_pShellInit->ApiGet(prefName, &n))
|
return n;
|
if(m_pShellInit->OsGet(prefName, &n))
|
return n;
|
return -1;
|
}
|
}
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to pass preferences to the PVRShell.
|
If used, this function must be called from InitApplication().
|
@param[in] prefName Name of preference to set to value
|
@param[in] value Value
|
@return true for success
|
*************************************************************************/
|
bool PVRShell::PVRShellSet(const prefNamePtrEnum prefName, const void * const ptrValue)
|
{
|
PVRSHELL_UNREFERENCED_PARAMETER(prefName);
|
PVRSHELL_UNREFERENCED_PARAMETER(ptrValue);
|
return false;
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to get parameters from the PVRShell.
|
It can be called from anywhere in the program.
|
@param[in] prefName Name of preference to set to value
|
@return The requested value.
|
*************************************************************************/
|
void *PVRShell::PVRShellGet(const prefNamePtrEnum prefName) const
|
{
|
switch(prefName)
|
{
|
case prefNativeWindowType: return m_pShellInit->OsGetNativeWindowType();
|
case prefPointerLocation:
|
if (m_pShellInit->m_bTouching)
|
return m_pShellInit->m_vec2PointerLocation;
|
break;
|
default:
|
{
|
void *p;
|
|
if(m_pShellInit->ApiGet(prefName, &p))
|
return p;
|
if(m_pShellInit->OsGet(prefName, &p))
|
return p;
|
}
|
}
|
return NULL;
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to pass preferences to the PVRShell.
|
If used, this function must be called from InitApplication().
|
@param[in] prefName Name of preference to set to value
|
@param[in] value Value
|
@return true for success
|
*************************************************************************/
|
bool PVRShell::PVRShellSet(const prefNameConstPtrEnum prefName, const void * const ptrValue)
|
{
|
switch(prefName)
|
{
|
case prefAppName:
|
StringCopy(m_pShellData->pszAppName, (char*)ptrValue);
|
return true;
|
case prefExitMessage:
|
StringCopy(m_pShellData->pszExitMessage, (char*)ptrValue);
|
PVRShellOutputDebug("Exit message has been set to: \"%s\".\n", ptrValue);
|
return true;
|
default:
|
break;
|
}
|
return false;
|
}
|
|
/*!***********************************************************************
|
@brief This function is used to get parameters from the PVRShell.
|
It can be called from anywhere in the program.
|
@param[in] prefName Name of preference to set to value
|
@return The requested value.
|
*************************************************************************/
|
const void *PVRShell::PVRShellGet(const prefNameConstPtrEnum prefName) const
|
{
|
switch(prefName)
|
{
|
case prefAppName:
|
return m_pShellData->pszAppName;
|
case prefExitMessage:
|
return m_pShellData->pszExitMessage;
|
case prefReadPath:
|
return m_pShellInit->GetReadPath();
|
case prefWritePath:
|
return m_pShellInit->GetWritePath();
|
case prefCommandLine:
|
return m_pShellInit->m_CommandLine.m_psOrig;
|
case prefCommandLineOpts:
|
return m_pShellInit->m_CommandLine.m_pOpt;
|
case prefVersion:
|
return PVRSDK_VERSION;
|
default:
|
return 0;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief It will be stored as 24-bit per pixel, 8-bit per chanel RGB.
|
The memory should be freed with free() when no longer needed.
|
@param[in] Width size of image to capture (relative to 0,0)
|
@param[in] Height size of image to capture (relative to 0,0)
|
@param[out] pLines receives a pointer to an area of memory containing the screen buffer.
|
@return true for success
|
*************************************************************************/
|
bool PVRShell::PVRShellScreenCaptureBuffer(const int Width, const int Height, unsigned char **pLines)
|
{
|
/* Allocate memory for line */
|
*pLines=(unsigned char *)calloc(Width*Height*3, sizeof(unsigned char));
|
if (!(*pLines)) return false;
|
|
return m_pShellInit->ApiScreenCaptureBuffer(Width, Height, *pLines);
|
}
|
|
/*!***********************************************************************
|
@brief Writes out the image data to a BMP file with basename fname.
|
@details The file written will be fname suffixed with a number to make the file unique.
|
For example, if fname is "abc", this function will attempt
|
to save to "abc0000.bmp"; if that file already exists, it
|
will try "abc0001.bmp", repeating until a new filename is
|
found. The final filename used is returned in ofname.
|
@param[in] fname base of file to save screen to
|
@param[in] Width size of image to capture (relative to 0,0)
|
@param[in] Height size of image to capture (relative to 0,0)
|
@param[in] pLines image data to write out (24bpp, 8-bit per channel RGB)
|
@param[in] ui32PixelReplicate expand pixels through replication (1 = no scale)
|
@param[out] ofname If non-NULL, receives the filename actually used
|
@return true for success
|
*************************************************************************/
|
int PVRShell::PVRShellScreenSave(
|
const char * const fname,
|
const int Width,
|
const int Height,
|
const unsigned char * const pLines,
|
const unsigned int ui32PixelReplicate,
|
char * const ofname)
|
{
|
char *pszFileName;
|
|
/*
|
Choose a filename
|
*/
|
{
|
FILE *file = 0;
|
const char *pszWritePath;
|
int nScreenshotCount;
|
|
pszWritePath = (const char*)PVRShellGet(prefWritePath);
|
|
size_t nFileNameSize = strlen(pszWritePath) + 200;
|
pszFileName = (char*)malloc(nFileNameSize);
|
|
/* Look for the first file name that doesn't already exist */
|
for(nScreenshotCount = 0; nScreenshotCount < 10000; ++nScreenshotCount)
|
{
|
snprintf(pszFileName, nFileNameSize, "%s%s%04d.bmp", pszWritePath, fname, nScreenshotCount);
|
|
file = fopen(pszFileName,"r");
|
if(!file)
|
break;
|
fclose(file);
|
}
|
|
/* If all files already exist, replace the first one */
|
if (nScreenshotCount==10000)
|
{
|
snprintf(pszFileName, nFileNameSize, "%s%s0000.bmp", pszWritePath, fname);
|
PVRShellOutputDebug("PVRShell: *WARNING* : Overwriting %s\n", pszFileName);
|
}
|
|
if(ofname) // requested the output file name
|
{
|
strcpy(ofname, pszFileName);
|
}
|
}
|
|
const int err = PVRShellWriteBMPFile(pszFileName, Width, Height, pLines, ui32PixelReplicate);
|
FREE(pszFileName);
|
if (err)
|
{
|
return 10*err+1;
|
}
|
else
|
{
|
// No problem occurred
|
return 0;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Swaps the bytes in pBytes from little to big endian (or vice versa)
|
@param[in] pBytes The bytes to swap
|
@param[in] i32ByteNo The number of bytes to swap
|
*************************************************************************/
|
inline void PVRShellByteSwap(unsigned char* pBytes, int i32ByteNo)
|
{
|
int i = 0, j = i32ByteNo - 1;
|
|
while(i < j)
|
{
|
unsigned char cTmp = pBytes[i];
|
pBytes[i] = pBytes[j];
|
pBytes[j] = cTmp;
|
|
++i;
|
--j;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Writes out the image data to a BMP file with name fname.
|
@param[in] pszFilename file to save screen to
|
@param[in] ui32Width the width of the data
|
@param[in] ui32Height the height of the data
|
@param[in] pImageData image data to write out (24bpp, 8-bit per channel RGB)
|
@return 0 on success
|
*************************************************************************/
|
int PVRShell::PVRShellWriteBMPFile(
|
const char * const pszFilename,
|
const unsigned int ui32Width,
|
const unsigned int ui32Height,
|
const void * const pImageData,
|
const unsigned int ui32PixelReplicate)
|
{
|
#define ByteSwap(x) PVRShellByteSwap((unsigned char*) &x, sizeof(x))
|
|
const int i32BMPHeaderSize = 14; /* The size of a BMP header */
|
const int i32BMPInfoSize = 40; /* The size of a BMP info header */
|
int Result = 1;
|
FILE* fpDumpfile = 0;
|
|
fpDumpfile = fopen(pszFilename, "wb");
|
|
if (fpDumpfile != 0)
|
{
|
const short int word = 0x0001;
|
const char * const byte = (char*) &word;
|
bool bLittleEndian = byte[0] ? true : false;
|
|
unsigned int i32OutBytesPerLine = ui32Width * 3 * ui32PixelReplicate;
|
unsigned int i32OutAlign = 0;
|
|
// round up to a dword boundary
|
if(i32OutBytesPerLine & 3)
|
{
|
i32OutBytesPerLine |= 3;
|
++i32OutBytesPerLine;
|
i32OutAlign = i32OutBytesPerLine - ui32Width * 3 * ui32PixelReplicate;
|
}
|
|
unsigned char *pData = (unsigned char*) pImageData;
|
|
{
|
int ui32RealSize = i32OutBytesPerLine * ui32Height * ui32PixelReplicate;
|
|
// BMP Header
|
unsigned short bfType = 0x4D42;
|
unsigned int bfSize = i32BMPHeaderSize + i32BMPInfoSize + ui32RealSize;
|
unsigned short bfReserved1 = 0;
|
unsigned short bfReserved2 = 0;
|
unsigned int bfOffBits = i32BMPHeaderSize + i32BMPInfoSize;
|
|
// BMP Info Header
|
unsigned int biSize = i32BMPInfoSize;
|
unsigned int biWidth = ui32Width * ui32PixelReplicate;
|
unsigned int biHeight = ui32Height * ui32PixelReplicate;
|
unsigned short biPlanes = 1;
|
unsigned short biBitCount = 24;
|
unsigned int biCompression = 0L;
|
unsigned int biSizeImage = ui32RealSize;
|
unsigned int biXPelsPerMeter = 0;
|
unsigned int biYPelsPerMeter = 0;
|
unsigned int biClrUsed = 0;
|
unsigned int biClrImportant = 0;
|
|
if(!bLittleEndian)
|
{
|
for(unsigned int i = 0; i < ui32Width * ui32Height; ++i)
|
PVRShellByteSwap(pData + (3 * i), 3);
|
|
ByteSwap(bfType);
|
ByteSwap(bfSize);
|
ByteSwap(bfOffBits);
|
ByteSwap(biSize);
|
ByteSwap(biWidth);
|
ByteSwap(biHeight);
|
ByteSwap(biPlanes);
|
ByteSwap(biBitCount);
|
ByteSwap(biCompression);
|
ByteSwap(biSizeImage);
|
}
|
|
// Write Header.
|
fwrite(&bfType , 1, sizeof(bfType) , fpDumpfile);
|
fwrite(&bfSize , 1, sizeof(bfSize) , fpDumpfile);
|
fwrite(&bfReserved1 , 1, sizeof(bfReserved1), fpDumpfile);
|
fwrite(&bfReserved2 , 1, sizeof(bfReserved2), fpDumpfile);
|
fwrite(&bfOffBits , 1, sizeof(bfOffBits) , fpDumpfile);
|
|
// Write info header.
|
fwrite(&biSize , 1, sizeof(biSize) , fpDumpfile);
|
fwrite(&biWidth , 1, sizeof(biWidth) , fpDumpfile);
|
fwrite(&biHeight , 1, sizeof(biHeight) , fpDumpfile);
|
fwrite(&biPlanes , 1, sizeof(biPlanes) , fpDumpfile);
|
fwrite(&biBitCount , 1, sizeof(biBitCount) , fpDumpfile);
|
fwrite(&biCompression , 1, sizeof(biCompression) , fpDumpfile);
|
fwrite(&biSizeImage , 1, sizeof(biSizeImage) , fpDumpfile);
|
fwrite(&biXPelsPerMeter , 1, sizeof(biXPelsPerMeter), fpDumpfile);
|
fwrite(&biYPelsPerMeter , 1, sizeof(biYPelsPerMeter), fpDumpfile);
|
fwrite(&biClrUsed , 1, sizeof(biClrUsed) , fpDumpfile);
|
fwrite(&biClrImportant , 1, sizeof(biClrImportant) , fpDumpfile);
|
}
|
|
// Write image.
|
for(unsigned int nY = 0; nY < ui32Height; ++nY)
|
{
|
const unsigned char * pRow = &pData[3 * ui32Width * nY];
|
for(unsigned int nRepY = 0; nRepY < ui32PixelReplicate; ++nRepY)
|
{
|
for(unsigned int nX = 0; nX < ui32Width; ++nX)
|
{
|
const unsigned char * pPixel = &pRow[3 * nX];
|
for(unsigned int nRepX = 0; nRepX < ui32PixelReplicate; ++nRepX)
|
{
|
fwrite(pPixel, 1, 3, fpDumpfile);
|
}
|
}
|
|
fwrite("\0\0\0\0", i32OutAlign, 1, fpDumpfile);
|
}
|
}
|
|
// Last but not least close the file.
|
fclose(fpDumpfile);
|
|
Result = 0;
|
}
|
else
|
{
|
PVRShellOutputDebug("PVRShell: Failed to open \"%s\" for writing screen dump.\n", pszFilename);
|
}
|
|
return Result;
|
}
|
|
/*!***********************************************************************
|
@brief The number itself should be considered meaningless; an
|
application should use this function to determine how much
|
time has passed between two points (e.g. between each
|
frame).
|
@return A value which increments once per millisecond.
|
*************************************************************************/
|
unsigned long PVRShell::PVRShellGetTime()
|
{
|
if(m_pShellData->bForceFrameTime)
|
{
|
// Return a "time" value based on the current frame number
|
return (unsigned long) m_pShellData->nShellCurFrameNum * m_pShellData->nFrameTime;
|
}
|
else
|
{
|
// Read timer from a platform dependant function
|
return m_pShellInit->OsGetTime();
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Check if a key was pressed. The keys on various devices
|
are mapped to the PVRShell-supported keys (listed in @a PVRShellKeyName) in
|
a platform-dependent manner, since most platforms have different input
|
devices. Check the <a href="modules.html">Modules page</a> for your OS
|
for details on how the enum values map to your device's key code input.
|
@param[in] key Code of the key to test
|
@return true if key was pressed
|
*************************************************************************/
|
bool PVRShell::PVRShellIsKeyPressed(const PVRShellKeyName key)
|
{
|
if(!m_pShellInit)
|
return false;
|
|
return m_pShellInit->DoIsKeyPressed(key);
|
}
|
|
// class PVRShellCommandLine
|
|
/*!***********************************************************************
|
@brief Constructor
|
*************************************************************************/
|
PVRShellCommandLine::PVRShellCommandLine()
|
{
|
memset(this, 0, sizeof(*this));
|
}
|
|
/*!***********************************************************************
|
@brief Destructor
|
*************************************************************************/
|
PVRShellCommandLine::~PVRShellCommandLine()
|
{
|
delete [] m_psOrig;
|
delete [] m_psSplit;
|
FREE(m_pOpt);
|
}
|
|
/*!***********************************************************************
|
@brief Set command-line options to pStr
|
@param[in] pStr Input string
|
*************************************************************************/
|
void PVRShellCommandLine::Set(const char *pStr)
|
{
|
delete [] m_psOrig;
|
m_psOrig = 0;
|
|
if(pStr)
|
{
|
size_t len = strlen(pStr)+1;
|
m_psOrig = new char[len];
|
strcpy(m_psOrig, pStr);
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Prepend command-line options to m_psOrig
|
@param[in] pStr Input string
|
*************************************************************************/
|
void PVRShellCommandLine::Prefix(const char *pStr)
|
{
|
if(!m_psOrig)
|
Set(pStr);
|
else if(!pStr)
|
return;
|
else
|
{
|
char *pstmp = m_psOrig;
|
size_t lenA = strlen(pStr);
|
size_t TotalLen = lenA + 1 + strlen(m_psOrig);
|
|
m_psOrig = new char[TotalLen + 1];
|
|
strcpy(m_psOrig, pStr);
|
m_psOrig[lenA] = ' ';
|
strcpy(m_psOrig + lenA + 1, pstmp);
|
m_psOrig[TotalLen] = '\0';
|
|
delete[] pstmp;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Prepend command-line options to m_psOrig from a file
|
@param[in] pFileName Input string
|
*************************************************************************/
|
bool PVRShellCommandLine::PrefixFromFile(const char *pFileName)
|
{
|
char* nl;
|
FILE *pFile = fopen(pFileName, "rb");
|
|
if(pFile)
|
{
|
// Get the file size
|
fseek(pFile, 0, SEEK_END);
|
long m_Size = ftell(pFile) + 2;
|
fseek(pFile, 0, SEEK_SET);
|
|
char *pFullFile = new char[m_Size];
|
|
if(pFullFile)
|
{
|
size_t offset = 0;
|
while(fgets(pFullFile + offset, (int) (m_Size - offset), pFile))
|
{
|
offset = strlen(pFullFile);
|
|
// Replace new lines with spaces
|
nl = strrchr(pFullFile, '\r');
|
if(nl) *nl = ' ';
|
|
nl = strrchr(pFullFile, '\n');
|
if(nl) *nl = ' ';
|
}
|
|
pFullFile[offset] = '\0';
|
Prefix(pFullFile);
|
|
delete[] pFullFile;
|
fclose(pFile);
|
return true;
|
}
|
|
fclose(pFile);
|
}
|
|
return false;
|
}
|
|
/*!***********************************************************************
|
@brief Parse m_psOrig for command-line options and store them in m_pOpt
|
*************************************************************************/
|
void PVRShellCommandLine::Parse()
|
{
|
size_t len;
|
int nIn, nOut;
|
bool bInQuotes;
|
SCmdLineOpt opt;
|
|
if(!m_psOrig)
|
return;
|
|
// Delete/free up any options we may have parsed recently
|
delete [] m_psSplit;
|
FREE(m_pOpt);
|
|
// Take a copy to be edited
|
len = strlen(m_psOrig) + 1;
|
m_psSplit = new char[len];
|
|
// Break the command line into options
|
bInQuotes = false;
|
opt.pArg = NULL;
|
opt.pVal = NULL;
|
nIn = -1;
|
nOut = 0;
|
|
do
|
{
|
++nIn;
|
if(m_psOrig[nIn] == '"')
|
{
|
bInQuotes = !bInQuotes;
|
}
|
else
|
{
|
if(bInQuotes && m_psOrig[nIn] != 0)
|
{
|
if(!opt.pArg)
|
opt.pArg = &m_psSplit[nOut];
|
|
m_psSplit[nOut++] = m_psOrig[nIn];
|
}
|
else
|
{
|
switch(m_psOrig[nIn])
|
{
|
case '=':
|
m_psSplit[nOut++] = 0;
|
opt.pVal = &m_psSplit[nOut];
|
break;
|
|
case ' ':
|
case '\t':
|
case '\0':
|
m_psSplit[nOut++] = 0;
|
if(opt.pArg || opt.pVal)
|
{
|
// Increase list length if necessary
|
if(m_nOptLen == m_nOptMax)
|
m_nOptMax = m_nOptMax * 2 + 1;
|
SCmdLineOpt* pTmp = (SCmdLineOpt*)realloc(m_pOpt, m_nOptMax * sizeof(*m_pOpt));
|
if(!pTmp)
|
{
|
FREE(m_pOpt);
|
return;
|
}
|
|
m_pOpt = pTmp;
|
|
// Add option to list
|
m_pOpt[m_nOptLen++] = opt;
|
opt.pArg = NULL;
|
opt.pVal = NULL;
|
}
|
break;
|
|
default:
|
if(!opt.pArg)
|
opt.pArg = &m_psSplit[nOut];
|
|
m_psSplit[nOut++] = m_psOrig[nIn];
|
break;
|
}
|
}
|
}
|
} while(m_psOrig[nIn]);
|
}
|
|
/*!***********************************************************************
|
@brief Apply the command-line options to shell
|
@param[in] shell
|
*************************************************************************/
|
void PVRShellCommandLine::Apply(PVRShell &shell)
|
{
|
int i;
|
const char *arg, *val;
|
|
for(i = 0; i < m_nOptLen; ++i)
|
{
|
arg = m_pOpt[i].pArg;
|
val = m_pOpt[i].pVal;
|
|
if(!arg)
|
continue;
|
|
if(val)
|
{
|
if(_stricmp(arg, "-width") == 0)
|
{
|
shell.PVRShellSet(prefWidth, atoi(val));
|
}
|
else if(_stricmp(arg, "-height") == 0)
|
{
|
shell.PVRShellSet(prefHeight, atoi(val));
|
}
|
else if(_stricmp(arg, "-aasamples") == 0)
|
{
|
shell.PVRShellSet(prefAASamples, atoi(val));
|
}
|
else if(_stricmp(arg, "-fullscreen") == 0)
|
{
|
shell.PVRShellSet(prefFullScreen, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-sw") == 0)
|
{
|
shell.PVRShellSet(prefSoftwareRendering, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-quitafterframe") == 0 || _stricmp(arg, "-qaf") == 0)
|
{
|
shell.PVRShellSet(prefQuitAfterFrame, atoi(val));
|
}
|
else if(_stricmp(arg, "-quitaftertime") == 0 || _stricmp(arg, "-qat") == 0)
|
{
|
shell.PVRShellSet(prefQuitAfterTime, (float)atof(val));
|
}
|
else if(_stricmp(arg, "-posx") == 0)
|
{
|
shell.PVRShellSet(prefPositionX, atoi(val));
|
}
|
else if(_stricmp(arg, "-posy") == 0)
|
{
|
shell.PVRShellSet(prefPositionY, atoi(val));
|
}
|
else if(_stricmp(arg, "-vsync") == 0)
|
{
|
shell.PVRShellSet(prefSwapInterval, atoi(val));
|
}
|
else if(_stricmp(arg, "-powersaving") == 0 || _stricmp(arg, "-ps") == 0)
|
{
|
shell.PVRShellSet(prefPowerSaving, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-colourbpp") == 0 || _stricmp(arg, "-colorbpp") == 0 ||_stricmp(arg, "-cbpp") == 0)
|
{
|
shell.PVRShellSet(prefColorBPP, atoi(val));
|
}
|
else if(_stricmp(arg, "-depthbpp") == 0 || _stricmp(arg, "-dbpp") == 0)
|
{
|
shell.PVRShellSet(prefDepthBPP, atoi(val));
|
}
|
else if(_stricmp(arg, "-rotatekeys") == 0)
|
{
|
shell.PVRShellSet(prefRotateKeys, atoi(val));
|
}
|
else if(_stricmp(arg, "-c") == 0)
|
{
|
const char* pDash = strchr(val, '-');
|
|
shell.PVRShellSet(prefCaptureFrameStart, atoi(val));
|
|
if(!pDash)
|
shell.PVRShellSet(prefCaptureFrameStop, atoi(val));
|
else
|
shell.PVRShellSet(prefCaptureFrameStop, atoi(pDash + 1));
|
}
|
else if(_stricmp(arg, "-screenshotscale") == 0)
|
{
|
shell.PVRShellSet(prefCaptureFrameScale, atoi(val));
|
}
|
else if(_stricmp(arg, "-priority") == 0)
|
{
|
shell.PVRShellSet(prefPriority, atoi(val));
|
}
|
else if(_stricmp(arg, "-config") == 0)
|
{
|
shell.PVRShellSet(prefRequestedConfig, atoi(val));
|
}
|
else if(_stricmp(arg, "-display") == 0)
|
{
|
shell.PVRShellSet(prefNativeDisplay, atoi(val));
|
}
|
else if(_stricmp(arg, "-forceframetime") == 0 || _stricmp(arg, "-fft") == 0)
|
{
|
shell.PVRShellSet(prefForceFrameTime, true);
|
shell.PVRShellSet(prefFrameTimeValue, atoi(val));
|
}
|
else if(_stricmp(arg, "-discardframeall") == 0)
|
{
|
shell.PVRShellSet(prefDiscardColor, (atoi(val) != 0));
|
shell.PVRShellSet(prefDiscardDepth, (atoi(val) != 0));
|
shell.PVRShellSet(prefDiscardStencil, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-discardframecolor") == 0 || _stricmp(arg, "-discardframecolour") == 0)
|
{
|
shell.PVRShellSet(prefDiscardColor, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-discardframedepth") == 0)
|
{
|
shell.PVRShellSet(prefDiscardDepth, (atoi(val) != 0));
|
}
|
else if(_stricmp(arg, "-discardframestencil") == 0)
|
{
|
shell.PVRShellSet(prefDiscardStencil, (atoi(val) != 0));
|
}
|
}
|
else
|
{
|
if(_stricmp(arg, "-version") == 0)
|
{
|
shell.PVRShellOutputDebug("Version: \"%s\"\n", shell.PVRShellGet(prefVersion));
|
}
|
#ifdef PVRSHELL_FPS_OUTPUT
|
else if(_stricmp(arg, "-fps") == 0)
|
{
|
shell.PVRShellSet(prefOutputFPS, true);
|
}
|
#endif
|
else if(_stricmp(arg, "-info") == 0)
|
{
|
shell.PVRShellSet(prefOutputInfo, true);
|
}
|
else if(_stricmp(arg, "-forceframetime") == 0 || _stricmp(arg, "-fft") == 0)
|
{
|
shell.PVRShellSet(prefForceFrameTime, true);
|
}
|
}
|
}
|
}
|
|
// @Class PVRShellInit
|
|
/*!***********************************************************************
|
@brief Constructor
|
*************************************************************************/
|
PVRShellInit::PVRShellInit()
|
{
|
memset(this, 0, sizeof(*this));
|
}
|
|
/*!***********************************************************************
|
@brief Destructor
|
*************************************************************************/
|
PVRShellInit::~PVRShellInit()
|
{
|
Deinit();
|
|
delete [] m_pReadPath;
|
m_pReadPath = NULL;
|
|
delete [] m_pWritePath;
|
m_pWritePath = NULL;
|
}
|
|
/*!***********************************************************************
|
@brief PVRShell deinitialisation.
|
@param[in] Shell
|
*************************************************************************/
|
void PVRShellInit::Deinit()
|
{
|
if(m_pShell)
|
{
|
// Is the App currently running?
|
if(m_eState > ePVRShellInitApp && m_eState < ePVRShellExit)
|
{
|
// If so force it to go through the exit procedure
|
if(m_eState < ePVRShellReleaseView)
|
m_eState = ePVRShellReleaseView;
|
|
// Class the App as done
|
gShellDone = true;
|
|
// Run through the exiting states
|
while(Run()){};
|
}
|
|
delete m_pShell;
|
m_pShell = 0;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief PVRShell Initialisation.
|
@Function Init
|
@param[in] Shell
|
@return True on success and false on failure
|
*************************************************************************/
|
bool PVRShellInit::Init()
|
{
|
Deinit();
|
|
m_pShell = NewDemo();
|
|
if(!m_pShell)
|
return false;
|
|
m_pShell->m_pShellInit = this;
|
|
// set default direction key mappings
|
m_eKeyMapDOWN = PVRShellKeyNameDOWN;
|
m_eKeyMapLEFT = PVRShellKeyNameLEFT;
|
m_eKeyMapUP = PVRShellKeyNameUP;
|
m_eKeyMapRIGHT = PVRShellKeyNameRIGHT;
|
nLastKeyPressed = PVRShellKeyNameNull;
|
|
OsInit();
|
|
gShellDone = false;
|
m_eState = ePVRShellInitApp;
|
return true;
|
}
|
|
/*!***********************************************************************
|
@brief Receives the command-line from the application.
|
@param[in] str A string containing the command-line
|
*************************************************************************/
|
void PVRShellInit::CommandLine(const char *str)
|
{
|
m_CommandLine.Set(str);
|
}
|
|
/*!***********************************************************************
|
@brief Receives the command-line from the application.
|
@param[in] argc Number of strings in argv
|
@param[in] argv An array of strings
|
*************************************************************************/
|
void PVRShellInit::CommandLine(int argc, char **argv)
|
{
|
size_t tot, len;
|
char *buf;
|
int i;
|
|
tot = 0;
|
for(i = 0; i < argc; ++i)
|
tot += strlen(argv[i]);
|
|
if(!tot)
|
{
|
CommandLine((char*) "");
|
return;
|
}
|
|
// Add room for spaces and the \0
|
tot += argc;
|
|
buf = new char[tot];
|
tot = 0;
|
for(i = 0; i < argc; ++i)
|
{
|
len = strlen(argv[i]);
|
strncpy(&buf[tot], argv[i], len);
|
tot += len;
|
buf[tot++] = ' ';
|
}
|
buf[tot-1] = 0;
|
|
CommandLine(buf);
|
|
delete [] buf;
|
}
|
|
/*!***********************************************************************
|
@brief Return 'true' if the specific key has been pressed.
|
@param[in] key The key we're querying for
|
*************************************************************************/
|
bool PVRShellInit::DoIsKeyPressed(const PVRShellKeyName key)
|
{
|
if(key == nLastKeyPressed)
|
{
|
nLastKeyPressed = PVRShellKeyNameNull;
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell that a key has been pressed.
|
@param[in] nKey The key that has been pressed
|
*************************************************************************/
|
void PVRShellInit::KeyPressed(PVRShellKeyName nKey)
|
{
|
nLastKeyPressed = nKey;
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell that a touch has began at a location.
|
@param[in] vec2Location The position of a click/touch on the screen when it first touches
|
*************************************************************************/
|
void PVRShellInit::TouchBegan(const float vec2Location[2])
|
{
|
m_bTouching = true;
|
m_vec2PointerLocationStart[0] = m_vec2PointerLocation[0] = vec2Location[0];
|
m_vec2PointerLocationStart[1] = m_vec2PointerLocation[1] = vec2Location[1];
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell that a touch has began at a location.
|
@param[in] vec2Location The position of the pointer/touch pressed on the screen
|
*************************************************************************/
|
void PVRShellInit::TouchMoved(const float vec2Location[2])
|
{
|
if(m_bTouching)
|
{
|
m_vec2PointerLocation[0] = vec2Location[0];
|
m_vec2PointerLocation[1] = vec2Location[1];
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell that the current touch has ended at a location.
|
@param[in] vec2Location The position of the pointer/touch on the screen when it is released
|
*************************************************************************/
|
void PVRShellInit::TouchEnded(const float vec2Location[2])
|
{
|
if(m_bTouching)
|
{
|
m_bTouching = false;
|
m_vec2PointerLocationEnd[0] = m_vec2PointerLocation[0] = vec2Location[0];
|
m_vec2PointerLocationEnd[1] = m_vec2PointerLocation[1] = vec2Location[1];
|
|
#if !defined(DISABLE_SWIPE_MAPPING)
|
float fX = m_vec2PointerLocationEnd[0] - m_vec2PointerLocationStart[0];
|
float fY = m_vec2PointerLocationEnd[1] - m_vec2PointerLocationStart[1];
|
float fTmp = fX * fX + fY * fY;
|
|
if(fTmp > 0.005f)
|
{
|
fTmp = 1.0f / sqrt(fTmp);
|
fY *= fTmp;
|
float fAngle = acos(fY);
|
|
const float pi = 3.1415f;
|
const float pi_half = pi * 0.5f;
|
const float error = 0.25f;
|
|
if(fAngle < error)
|
KeyPressed(m_eKeyMapDOWN);
|
else if(fAngle > (pi - error))
|
KeyPressed(m_eKeyMapUP);
|
else if(fAngle > (pi_half - error) && fAngle < (pi_half + error))
|
KeyPressed((fX < 0) ? m_eKeyMapLEFT : m_eKeyMapRIGHT);
|
}
|
else if(fTmp < 0.09f)
|
{
|
if (m_vec2PointerLocationEnd[0] <= 0.3f) // Left half of the screen
|
KeyPressed(PVRShellKeyNameACTION1);
|
else if (m_vec2PointerLocationEnd[0] >= 0.7f) // Right half of the screen
|
KeyPressed(PVRShellKeyNameACTION2);
|
}
|
#endif
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell where to read external files from
|
@return A path the application is capable of reading from
|
*************************************************************************/
|
const char* PVRShellInit::GetReadPath() const
|
{
|
return m_pReadPath;
|
}
|
|
/*!***********************************************************************
|
@brief Used by the OS-specific code to tell the Shell where to write to
|
@return A path the applications is capable of writing to
|
*************************************************************************/
|
const char* PVRShellInit::GetWritePath() const
|
{
|
return m_pWritePath;
|
}
|
|
/*!****************************************************************************
|
@brief Sets the default app name (to be displayed by the OS)
|
@param[in] str The application name
|
*******************************************************************************/
|
void PVRShellInit::SetAppName(const char * const str)
|
{
|
const char *pName = strrchr(str, PVRSHELL_DIR_SYM);
|
|
if(pName)
|
{
|
++pName;
|
}
|
else
|
{
|
pName = str;
|
}
|
m_pShell->PVRShellSet(prefAppName, pName);
|
}
|
|
/*!***********************************************************************
|
@brief Set the path to where the application expects to read from.
|
@param[in] str The read path
|
*************************************************************************/
|
void PVRShellInit::SetReadPath(const char * const str)
|
{
|
m_pReadPath = new char[strlen(str)+1];
|
|
if(m_pReadPath)
|
{
|
strcpy(m_pReadPath, str);
|
char* lastSlash = strrchr(m_pReadPath, PVRSHELL_DIR_SYM);
|
|
if(lastSlash)
|
lastSlash[1] = 0;
|
}
|
}
|
|
/*!***********************************************************************
|
@brief Set the path to where the application expects to write to.
|
@param[in] str The write path
|
*************************************************************************/
|
void PVRShellInit::SetWritePath(const char * const str)
|
{
|
m_pWritePath = new char[strlen(str)+1];
|
|
if(m_pWritePath)
|
{
|
strcpy(m_pWritePath, str);
|
char* lastSlash = strrchr(m_pWritePath, PVRSHELL_DIR_SYM);
|
|
if(lastSlash)
|
lastSlash[1] = 0;
|
}
|
}
|
|
#ifdef PVRSHELL_FPS_OUTPUT
|
/*****************************************************************************
|
@fn FpsUpdate
|
@brief Calculates a value for frames-per-second (FPS).
|
@details This is only compiled in to the application if PVRSHELL_FPS_OUTPUT is defined.
|
*****************************************************************************/
|
void PVRShellInit::FpsUpdate()
|
{
|
unsigned int ui32TimeDelta, ui32Time;
|
|
ui32Time = m_pShell->PVRShellGetTime();
|
++m_i32FpsFrameCnt;
|
ui32TimeDelta = ui32Time - m_i32FpsTimePrev;
|
|
if(ui32TimeDelta >= 1000)
|
{
|
float fFPS = 1000.0f * (float) m_i32FpsFrameCnt / (float) ui32TimeDelta;
|
|
m_pShell->PVRShellOutputDebug("PVRShell: frame %d, FPS %.1f.\n",
|
m_pShell->m_pShellData->nShellCurFrameNum, fFPS);
|
|
m_i32FpsFrameCnt = 0;
|
m_i32FpsTimePrev = ui32Time;
|
}
|
}
|
#endif
|
|
/*****************************************************************************
|
@brief Main message loop / render loop
|
@return false when the app should quit
|
*****************************************************************************/
|
bool PVRShellInit::Run()
|
{
|
static unsigned long StartTime = 0;
|
|
switch(m_eState)
|
{
|
case ePVRShellInitApp:
|
{
|
// Make sure the shell isn't done
|
gShellDone = false;
|
|
// Prepend command-line options from PVRShellCL.txt
|
const char * const pCL = "PVRShellCL.txt";
|
const char *pPath = (const char*) m_pShell->PVRShellGet(prefReadPath);
|
size_t nSize = strlen(pPath) + strlen(pCL) + 1;
|
char *pString = new char[nSize];
|
|
if(pString)
|
{
|
snprintf(pString, nSize, "%s%s", pPath, pCL);
|
|
if(!m_CommandLine.PrefixFromFile(pString))
|
{
|
delete[] pString;
|
pPath = (const char*) m_pShell->PVRShellGet(prefWritePath);
|
nSize = strlen(pPath) + strlen(pCL) + 1;
|
pString = new char[nSize];
|
|
snprintf(pString, nSize, "%s%s", pPath, pCL);
|
|
if(m_CommandLine.PrefixFromFile(pString))
|
m_pShell->PVRShellOutputDebug("Loaded command-line options from %s.\n", pString);
|
}
|
else
|
m_pShell->PVRShellOutputDebug("Loaded command-line options from %s.\n", pString);
|
|
delete[] pString;
|
}
|
|
// Parse the command-line
|
m_CommandLine.Parse();
|
|
#if defined(_DEBUG)
|
m_pShell->PVRShellOutputDebug("PVRShell command line: %d/%d\n", m_CommandLine.m_nOptLen, m_CommandLine.m_nOptMax);
|
for(int i = 0; i < m_CommandLine.m_nOptLen; ++i)
|
{
|
m_pShell->PVRShellOutputDebug("CL %d: \"%s\"\t= \"%s\".\n", i,
|
m_CommandLine.m_pOpt[i].pArg ? m_CommandLine.m_pOpt[i].pArg : "",
|
m_CommandLine.m_pOpt[i].pVal ? m_CommandLine.m_pOpt[i].pVal : "");
|
}
|
#endif
|
// Call InitApplication
|
if(!m_pShell->InitApplication())
|
{
|
m_eState = ePVRShellExit;
|
return true;
|
}
|
|
m_eState = ePVRShellInitInstance;
|
return true;
|
}
|
case ePVRShellInitInstance:
|
{
|
m_CommandLine.Apply(*m_pShell);
|
|
// Output non-api specific data if required
|
OutputInfo();
|
|
// Perform OS initialisation
|
if(!OsInitOS())
|
{
|
m_pShell->PVRShellOutputDebug("InitOS failed!\n");
|
m_eState = ePVRShellQuitApp;
|
return true;
|
}
|
|
// Initialize the 3D API
|
if(!OsDoInitAPI())
|
{
|
m_pShell->PVRShellOutputDebug("InitAPI failed!\n");
|
m_eState = ePVRShellReleaseOS;
|
gShellDone = true;
|
return true;
|
}
|
|
// Output api specific data if required
|
OutputAPIInfo();
|
|
// Initialise the app
|
if(!m_pShell->InitView())
|
{
|
m_pShell->PVRShellOutputDebug("InitView failed!\n");
|
m_eState = ePVRShellReleaseAPI;
|
gShellDone = true;
|
return true;
|
}
|
|
if(StartTime==0)
|
{
|
StartTime = OsGetTime();
|
}
|
|
m_eState = ePVRShellRender;
|
return true;
|
}
|
case ePVRShellRender:
|
{
|
// Main message loop:
|
if(!m_pShell->RenderScene())
|
break;
|
|
ApiRenderComplete();
|
OsRenderComplete();
|
|
#ifdef PVRSHELL_FPS_OUTPUT
|
if(m_pShell->m_pShellData->bOutputFPS)
|
FpsUpdate();
|
#endif
|
int nCurrentFrame = m_pShell->m_pShellData->nShellCurFrameNum;
|
|
if(DoIsKeyPressed(PVRShellKeyNameScreenshot) || (nCurrentFrame >= m_pShell->m_pShellData->nCaptureFrameStart && nCurrentFrame <= m_pShell->m_pShellData->nCaptureFrameStop))
|
{
|
unsigned char *pBuf;
|
const int nWidth = m_pShell->PVRShellGet(prefWidth);
|
const int nHeight = m_pShell->PVRShellGet(prefHeight);
|
if(m_pShell->PVRShellScreenCaptureBuffer(nWidth, nHeight, &pBuf))
|
{
|
if(m_pShell->PVRShellScreenSave(PVRSHELL_SCREENSHOT_NAME, nWidth, nHeight, pBuf, m_pShell->m_pShellData->nCaptureFrameScale) != 0)
|
{
|
m_pShell->PVRShellSet(prefExitMessage, "Screen-shot save failed.\n");
|
}
|
}
|
else
|
{
|
m_pShell->PVRShellSet(prefExitMessage, "Screen capture failed.\n");
|
}
|
FREE(pBuf);
|
}
|
|
if(DoIsKeyPressed(PVRShellKeyNameQUIT))
|
gShellDone = true;
|
|
if(gShellDone)
|
break;
|
|
/* Quit if maximum number of allowed frames is reached */
|
if((m_pShell->m_pShellData->nDieAfterFrames>=0) && (nCurrentFrame >= m_pShell->m_pShellData->nDieAfterFrames))
|
break;
|
|
/* Quit if maximum time is reached */
|
if((m_pShell->m_pShellData->fDieAfterTime>=0.0f) && (((OsGetTime()-StartTime)*0.001f) >= m_pShell->m_pShellData->fDieAfterTime))
|
break;
|
|
m_pShell->m_pShellData->nShellCurFrameNum++;
|
return true;
|
}
|
|
case ePVRShellReleaseView:
|
m_pShell->ReleaseView();
|
|
case ePVRShellReleaseAPI:
|
OsDoReleaseAPI();
|
|
case ePVRShellReleaseOS:
|
OsReleaseOS();
|
|
if(!gShellDone && m_pShell->m_pShellData->nInitRepeats)
|
{
|
--m_pShell->m_pShellData->nInitRepeats;
|
m_eState = ePVRShellInitInstance;
|
return true;
|
}
|
|
m_eState = ePVRShellQuitApp;
|
return true;
|
|
case ePVRShellQuitApp:
|
// Final app tidy-up
|
m_pShell->QuitApplication();
|
m_eState = ePVRShellExit;
|
|
case ePVRShellExit:
|
OsExit();
|
StringCopy(m_pShell->m_pShellData->pszAppName, 0);
|
StringCopy(m_pShell->m_pShellData->pszExitMessage, 0);
|
return false;
|
}
|
|
m_eState = (EPVRShellState)(m_eState + 1);
|
return true;
|
}
|
|
/*!***********************************************************************
|
@brief When prefOutputInfo is set to true this function outputs
|
various pieces of non-API dependent information via
|
PVRShellOutputDebug.
|
*************************************************************************/
|
void PVRShellInit::OutputInfo()
|
{
|
if(m_pShell->PVRShellGet(prefOutputInfo))
|
{
|
m_pShell->PVRShellOutputDebug("\n");
|
m_pShell->PVRShellOutputDebug("App name: %s\n" , m_pShell->PVRShellGet(prefAppName));
|
m_pShell->PVRShellOutputDebug("SDK version: %s\n" , m_pShell->PVRShellGet(prefVersion));
|
m_pShell->PVRShellOutputDebug("\n");
|
m_pShell->PVRShellOutputDebug("Read path: %s\n" , m_pShell->PVRShellGet(prefReadPath));
|
m_pShell->PVRShellOutputDebug("Write path: %s\n" , m_pShell->PVRShellGet(prefWritePath));
|
m_pShell->PVRShellOutputDebug("\n");
|
m_pShell->PVRShellOutputDebug("Command-line: %s\n" , m_pShell->PVRShellGet(prefCommandLine));
|
m_pShell->PVRShellOutputDebug("\n");
|
m_pShell->PVRShellOutputDebug("Power saving: %s\n" , m_pShell->PVRShellGet(prefPowerSaving) ? "On" : "Off");
|
m_pShell->PVRShellOutputDebug("AA Samples requested: %i\n", m_pShell->PVRShellGet(prefAASamples));
|
m_pShell->PVRShellOutputDebug("Fullscreen: %s\n", m_pShell->PVRShellGet(prefFullScreen) ? "Yes" : "No");
|
m_pShell->PVRShellOutputDebug("PBuffer requested: %s\n", m_pShell->PVRShellGet(prefPBufferContext) ? "Yes" : "No");
|
m_pShell->PVRShellOutputDebug("ZBuffer requested: %s\n", m_pShell->PVRShellGet(prefZbufferContext) ? "Yes" : "No");
|
m_pShell->PVRShellOutputDebug("Stencil buffer requested: %s\n", m_pShell->PVRShellGet(prefStencilBufferContext) ? "Yes" : "No");
|
|
if(m_pShell->PVRShellGet(prefColorBPP) > 0)
|
m_pShell->PVRShellOutputDebug("Colour buffer size requested: %i\n", m_pShell->PVRShellGet(prefColorBPP));
|
if(m_pShell->PVRShellGet(prefDepthBPP) > 0)
|
m_pShell->PVRShellOutputDebug("Depth buffer size requested: %i\n", m_pShell->PVRShellGet(prefDepthBPP));
|
|
m_pShell->PVRShellOutputDebug("Software rendering requested: %s\n", m_pShell->PVRShellGet(prefSoftwareRendering) ? "Yes" : "No");
|
m_pShell->PVRShellOutputDebug("Swap Interval requested: %i\n", m_pShell->PVRShellGet(prefSwapInterval));
|
|
if(m_pShell->PVRShellGet(prefInitRepeats) > 0)
|
m_pShell->PVRShellOutputDebug("No of Init repeats: %i\n", m_pShell->PVRShellGet(prefInitRepeats));
|
|
if(m_pShell->PVRShellGet(prefQuitAfterFrame) != -1)
|
m_pShell->PVRShellOutputDebug("Quit after frame: %i\n", m_pShell->PVRShellGet(prefQuitAfterFrame));
|
|
if(m_pShell->PVRShellGet(prefQuitAfterTime) != -1.0f)
|
m_pShell->PVRShellOutputDebug("Quit after time: %f\n", m_pShell->PVRShellGet(prefQuitAfterTime));
|
}
|
}
|
|
/****************************************************************************
|
** Local code
|
****************************************************************************/
|
/*!***********************************************************************
|
@brief This function copies pszSrc into pszStr.
|
@param[out] pszStr The string to copy pszSrc into
|
@param[in] pszSrc The source string to copy
|
*************************************************************************/
|
static bool StringCopy(char *&pszStr, const char * const pszSrc)
|
{
|
size_t len;
|
|
FREE(pszStr);
|
|
if(!pszSrc)
|
return true;
|
|
len = strlen(pszSrc)+1;
|
pszStr = (char*)malloc(len);
|
if(!pszStr)
|
return false;
|
|
strcpy(pszStr, pszSrc);
|
return true;
|
}
|
|
/// @endcond
|
//NO_DOXYGEN
|
|
/*****************************************************************************
|
End of file (PVRShell.cpp)
|
*****************************************************************************/
|