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:
Philippe Houdoin
2010-08-03 17:34:37 +00:00
parent 92f5c6a2f7
commit bbd5dd572d
3 changed files with 295 additions and 35 deletions
+257 -29
View File
@@ -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;
}
+37 -4
View File
@@ -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;
};
+1 -2
View File
@@ -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;
}
};