Experimental GLUT Game Mode support.
Still several issues with non-32bits color spaces. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37878 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -14,72 +14,300 @@
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void APIENTRY
|
||||
glutGameModeString(const char *string)
|
||||
// GlutGameMode class
|
||||
|
||||
GlutGameMode::GlutGameMode()
|
||||
:
|
||||
fActive(false),
|
||||
fDisplayChanged(false),
|
||||
fWidth(-1),
|
||||
fHeight(-1),
|
||||
fPixelDepth(-1),
|
||||
fRefreshRate(-1),
|
||||
fModesList(NULL),
|
||||
fModesCount(0),
|
||||
fGameModeWorkspace(-1)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
GlutGameMode::~GlutGameMode()
|
||||
{
|
||||
free(fModesList);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GlutGameMode::Set(const char* modeString)
|
||||
{
|
||||
// String format: [WxH][:Bpp][@Hz]
|
||||
|
||||
const char* templates[] = {
|
||||
"%1$ix%2$i:%3$i@%4$i", // WxH:Bpp@Hz
|
||||
"%1$ix%2$i:%3$i", // WxH:Bpp
|
||||
"%1$ix%2$i@%4$i", // WxH@Hz
|
||||
"%1$ix%2$i", // WxH
|
||||
":%3$i@%4$i", // :Bpp@Hz
|
||||
":%3$i", // :Bpp
|
||||
"@%4$i", // @Hz
|
||||
NULL
|
||||
};
|
||||
|
||||
// Find matching string format template, if any
|
||||
for (int i=0; templates[i]; i++) {
|
||||
// count expected arguments in this template
|
||||
int expectedArgs = 0;
|
||||
const char *p = templates[i];
|
||||
while (*p) {
|
||||
if (*p++ == '%')
|
||||
expectedArgs++;
|
||||
}
|
||||
|
||||
// printf("Trying %s pattern\n", templates[i]);
|
||||
|
||||
fWidth = fHeight = fPixelDepth = fRefreshRate = -1;
|
||||
|
||||
if (sscanf(modeString, templates[i],
|
||||
&fWidth, &fHeight, &fPixelDepth, &fRefreshRate) == expectedArgs) {
|
||||
// printf("match!\n");
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GlutGameMode::IsPossible()
|
||||
{
|
||||
display_mode* mode = _FindMatchingMode();
|
||||
return mode != NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GlutGameMode::Enter()
|
||||
{
|
||||
display_mode* mode = _FindMatchingMode();
|
||||
if (!mode)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BScreen screen;
|
||||
if (!fActive) {
|
||||
// First enter: remember this workspace original mode...
|
||||
fGameModeWorkspace = current_workspace();
|
||||
screen.GetMode(fGameModeWorkspace, &fOriginalMode);
|
||||
}
|
||||
|
||||
// Don't make it new default mode for this workspace...
|
||||
status_t status = screen.SetMode(fGameModeWorkspace, mode, false);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// Retrieve the new active display mode, which could be
|
||||
// a sligth different than the one we asked for...
|
||||
screen.GetMode(fGameModeWorkspace, &fCurrentMode);
|
||||
|
||||
// create a new window in full screen
|
||||
glutCreateWindow("glutGameMode");
|
||||
BDirectWindow *directWindow
|
||||
= dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
|
||||
if (directWindow == NULL)
|
||||
// Hum?!
|
||||
return B_ERROR;
|
||||
|
||||
directWindow->SetFullScreen(true);
|
||||
|
||||
fDisplayChanged = true;
|
||||
fActive = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GlutGameMode::Leave()
|
||||
{
|
||||
if (!fActive)
|
||||
return B_OK;
|
||||
|
||||
if (fGameModeWorkspace < 0)
|
||||
return B_ERROR;
|
||||
|
||||
if (_CompareModes(&fOriginalMode, &fCurrentMode)) {
|
||||
// Restore original display mode
|
||||
BScreen screen;
|
||||
// Make restored mode the default one,
|
||||
// as it was before entering game mode...
|
||||
screen.SetMode(fGameModeWorkspace, &fOriginalMode, true);
|
||||
}
|
||||
|
||||
fActive = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
display_mode*
|
||||
GlutGameMode::_FindMatchingMode()
|
||||
{
|
||||
if (fWidth == -1 && fHeight == -1 && fPixelDepth == -1
|
||||
&& fRefreshRate == -1)
|
||||
// nothing to match!
|
||||
return NULL;
|
||||
|
||||
if (!fModesList) {
|
||||
// Lazy retrieval of supported modes...
|
||||
BScreen screen;
|
||||
if (screen.GetModeList(&fModesList, &fModesCount) == B_OK) {
|
||||
// sort modes
|
||||
qsort(fModesList, fModesCount, sizeof(display_mode), _CompareModes);
|
||||
} else {
|
||||
// bad luck, no modes can be retrieved!
|
||||
fModesList = NULL;
|
||||
fModesCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fModesList)
|
||||
return NULL;
|
||||
|
||||
float bestRefreshDiff = 999999;
|
||||
int bestMode = -1;
|
||||
for (uint32 i =0; i < fModesCount; i++) {
|
||||
|
||||
printf("[%ld]: %d x %d, %d Bpp, %d Hz\n", i,
|
||||
fModesList[i].virtual_width, fModesList[i].virtual_height,
|
||||
_GetModePixelDepth(&fModesList[i]),
|
||||
_GetModeRefreshRate(&fModesList[i]));
|
||||
|
||||
if (fWidth > 0 && fModesList[i].virtual_width != fWidth)
|
||||
continue;
|
||||
|
||||
if (fHeight > 0 && fModesList[i].virtual_height != fHeight)
|
||||
continue;
|
||||
|
||||
if (fPixelDepth > 0
|
||||
&& _GetModePixelDepth(&fModesList[i]) != fPixelDepth)
|
||||
continue;
|
||||
|
||||
float refreshDiff = fabs(_GetModeRefreshRate(&fModesList[i])
|
||||
- fRefreshRate);
|
||||
if (fRefreshRate > 0 && (refreshDiff > 0.006 * fRefreshRate)) {
|
||||
// not exactly the same, but maybe the best similar mode so far?
|
||||
if (refreshDiff < bestRefreshDiff) {
|
||||
bestRefreshDiff = refreshDiff;
|
||||
bestMode = i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hey, this one match everything!
|
||||
return &fModesList[i];
|
||||
}
|
||||
|
||||
if (bestMode == -1)
|
||||
return NULL;
|
||||
|
||||
return &fModesList[bestMode];
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
GlutGameMode::_GetModePixelDepth(const display_mode* mode)
|
||||
{
|
||||
switch (mode->space) {
|
||||
case B_RGB32: return 32;
|
||||
case B_RGB24: return 24;
|
||||
case B_RGB16: return 16;
|
||||
case B_RGB15: return 15;
|
||||
case B_CMAP8: return 8;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
GlutGameMode::_GetModeRefreshRate(const display_mode* mode)
|
||||
{
|
||||
// we have to be catious as refresh rate cannot be controlled directly,
|
||||
// so it suffers under rounding errors and hardware restrictions
|
||||
return rint(10 * float(mode->timing.pixel_clock * 1000)
|
||||
/ float(mode->timing.h_total * mode->timing.v_total)) / 10.0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
GlutGameMode::_CompareModes(const void* _mode1, const void* _mode2)
|
||||
{
|
||||
display_mode *mode1 = (display_mode *)_mode1;
|
||||
display_mode *mode2 = (display_mode *)_mode2;
|
||||
|
||||
if (mode1->virtual_width != mode2->virtual_width)
|
||||
return mode1->virtual_width - mode2->virtual_width;
|
||||
|
||||
if (mode1->virtual_height != mode2->virtual_height)
|
||||
return mode1->virtual_height - mode2->virtual_height;
|
||||
|
||||
if (mode1->space != mode2->space)
|
||||
return _GetModePixelDepth(mode1) - _GetModePixelDepth(mode2);
|
||||
|
||||
return _GetModeRefreshRate(mode1) - _GetModeRefreshRate(mode2);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark GLUT game mode API
|
||||
|
||||
void APIENTRY
|
||||
glutGameModeString(const char* string)
|
||||
{
|
||||
gState.gameMode.Set(string);
|
||||
}
|
||||
|
||||
|
||||
int APIENTRY
|
||||
glutEnterGameMode(void)
|
||||
{
|
||||
// TODO
|
||||
return 0;
|
||||
return gState.gameMode.Enter() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void APIENTRY
|
||||
glutLeaveGameMode(void)
|
||||
{
|
||||
// TODO
|
||||
gState.gameMode.Leave();
|
||||
}
|
||||
|
||||
|
||||
int APIENTRY
|
||||
glutGameModeGet(GLenum pname)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch( pname ) {
|
||||
case GLUT_GAME_MODE_ACTIVE:
|
||||
ret = gState.gameMode != NULL;
|
||||
break;
|
||||
return gState.gameMode.IsActive();
|
||||
|
||||
case GLUT_GAME_MODE_POSSIBLE:
|
||||
// TODO
|
||||
break;
|
||||
return gState.gameMode.IsPossible();
|
||||
|
||||
case GLUT_GAME_MODE_WIDTH:
|
||||
if (gState.gameMode)
|
||||
ret = gState.gameMode->width;
|
||||
break;
|
||||
return gState.gameMode.Width();
|
||||
|
||||
case GLUT_GAME_MODE_HEIGHT:
|
||||
if (gState.gameMode)
|
||||
ret = gState.gameMode->height;
|
||||
break;
|
||||
return gState.gameMode.Height();
|
||||
|
||||
case GLUT_GAME_MODE_PIXEL_DEPTH:
|
||||
if (gState.gameMode)
|
||||
ret = gState.gameMode->pixelDepth;
|
||||
break;
|
||||
return gState.gameMode.PixelDepth();
|
||||
|
||||
case GLUT_GAME_MODE_REFRESH_RATE:
|
||||
if (gState.gameMode)
|
||||
ret = gState.gameMode->refreshRate;
|
||||
break;
|
||||
return gState.gameMode.RefreshRate();
|
||||
|
||||
case GLUT_GAME_MODE_DISPLAY_CHANGED:
|
||||
// TODO
|
||||
break;
|
||||
return gState.gameMode.HasDisplayChanged();
|
||||
|
||||
default:
|
||||
__glutWarning( "Unknown gamemode get: %d", pname );
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <GL/glut.h>
|
||||
#include <Screen.h>
|
||||
|
||||
|
||||
/*! All information needed for game mode and
|
||||
@@ -14,8 +15,40 @@
|
||||
*/
|
||||
class GlutGameMode {
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
int pixelDepth;
|
||||
int refreshRate;
|
||||
GlutGameMode();
|
||||
virtual ~GlutGameMode();
|
||||
|
||||
status_t Set(const char* modeString);
|
||||
|
||||
status_t Enter();
|
||||
status_t Leave();
|
||||
|
||||
bool IsActive() const { return fActive; }
|
||||
bool IsPossible();
|
||||
bool HasDisplayChanged() const { return fDisplayChanged; }
|
||||
|
||||
int Width() const { return fWidth; }
|
||||
int Height() const { return fHeight; }
|
||||
int PixelDepth() const { return fPixelDepth; }
|
||||
int RefreshRate() const { return fRefreshRate; }
|
||||
|
||||
private:
|
||||
display_mode* _FindMatchingMode();
|
||||
|
||||
static int _CompareModes(const void* mode1, const void* mode2);
|
||||
static int _GetModeRefreshRate(const display_mode* mode);
|
||||
static int _GetModePixelDepth(const display_mode* mode);
|
||||
|
||||
bool fActive;
|
||||
bool fDisplayChanged;
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
int fPixelDepth;
|
||||
int fRefreshRate;
|
||||
display_mode* fModesList;
|
||||
uint32 fModesCount;
|
||||
display_mode fOriginalMode;
|
||||
int fGameModeWorkspace;
|
||||
display_mode fCurrentMode;
|
||||
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ struct GlutState {
|
||||
int modifierKeys; // only valid during keyboard callback
|
||||
int keyRepeatMode; // global repeat
|
||||
|
||||
GlutGameMode* gameMode;
|
||||
GlutGameMode gameMode;
|
||||
|
||||
bool debug; // call glGetError
|
||||
bool quitAll; // quit
|
||||
@@ -67,7 +67,6 @@ struct GlutState {
|
||||
menuStatus = 0;
|
||||
modifierKeys = ~0;
|
||||
keyRepeatMode = GLUT_KEY_REPEAT_DEFAULT;
|
||||
gameMode = NULL;
|
||||
debug = quitAll = false;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user