#include "glutGameMode.h"
#include "glutint.h"
#include "glutState.h"
#include <GL/glut.h>
#include <String.h>
#include <stdio.h>
#include <stdlib.h>
GlutGameMode::GlutGameMode()
:
fActive(false),
fDisplayChanged(false),
fWidth(-1),
fHeight(-1),
fPixelDepth(-1),
fRefreshRate(-1),
fModesList(NULL),
fModesCount(0),
fGameModeWorkspace(-1),
fGameModeWindow(0),
fPreviousWindow(0)
{
}
GlutGameMode::~GlutGameMode()
{
free(fModesList);
}
status_t
GlutGameMode::Set(const char* modeString)
{
const char* templates[] = {
"%1$ix%2$i:%3$i@%4$i",
"%1$ix%2$i:%3$i",
"%1$ix%2$i@%4$i",
"%1$ix%2$i",
":%3$i@%4$i",
":%3$i",
"@%4$i",
NULL
};
for (int i=0; templates[i]; i++) {
int expectedArgs = 0;
const char *p = templates[i];
while (*p) {
if (*p++ == '%')
expectedArgs++;
}
fWidth = fHeight = fPixelDepth = fRefreshRate = -1;
if (sscanf(modeString, templates[i],
&fWidth, &fHeight, &fPixelDepth, &fRefreshRate) == expectedArgs) {
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) {
fGameModeWorkspace = current_workspace();
screen.GetMode(fGameModeWorkspace, &fOriginalMode);
}
status_t status = screen.SetMode(fGameModeWorkspace, mode, false);
if (status != B_OK)
return status;
screen.GetMode(fGameModeWorkspace, &fCurrentMode);
if (!fGameModeWindow) {
fPreviousWindow = glutGetWindow();
fGameModeWindow = glutCreateWindow("glutGameMode");
if (!fGameModeWindow)
return Leave();
} else
glutSetWindow(fGameModeWindow);
BDirectWindow *directWindow
= dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
if (directWindow == NULL)
return B_ERROR;
BString name;
name << "Game Mode " << fCurrentMode.virtual_width
<< "x" << fCurrentMode.virtual_height
<< ":" << _GetModePixelDepth(&fCurrentMode)
<< "@" << _GetModeRefreshRate(&fCurrentMode);
directWindow->Lock();
directWindow->SetTitle(name.String());
directWindow->SetFullScreen(true);
directWindow->Unlock();
fDisplayChanged = true;
fActive = true;
return B_OK;
}
status_t
GlutGameMode::Leave()
{
if (!fActive)
return B_OK;
if (fGameModeWorkspace < 0)
return B_ERROR;
if (fGameModeWindow) {
glutDestroyWindow(fGameModeWindow);
fGameModeWindow = 0;
if (fPreviousWindow)
glutSetWindow(fPreviousWindow);
}
if (_CompareModes(&fOriginalMode, &fCurrentMode)) {
BScreen screen;
screen.SetMode(fGameModeWorkspace, &fOriginalMode, true);
}
fActive = false;
return B_OK;
}
display_mode*
GlutGameMode::_FindMatchingMode()
{
if (fWidth == -1 && fHeight == -1 && fPixelDepth == -1
&& fRefreshRate == -1)
return NULL;
if (!fModesList) {
BScreen screen;
if (screen.GetModeList(&fModesList, &fModesCount) == B_OK) {
qsort(fModesList, fModesCount, sizeof(display_mode), _CompareModes);
} else {
fModesList = NULL;
fModesCount = 0;
}
}
if (!fModesList)
return NULL;
float bestRefreshDiff = 999999;
int bestMode = -1;
for (uint32 i =0; i < fModesCount; i++) {
printf("[%" B_PRId32 "]: %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)) {
if (refreshDiff < bestRefreshDiff) {
bestRefreshDiff = refreshDiff;
bestMode = i;
}
continue;
}
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)
{
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 mode2->virtual_width - mode1->virtual_width;
if (mode1->virtual_height != mode2->virtual_height)
return mode2->virtual_height - mode1->virtual_height;
if (mode1->space != mode2->space)
return _GetModePixelDepth(mode2) - _GetModePixelDepth(mode1);
return _GetModeRefreshRate(mode2) - _GetModeRefreshRate(mode1);
}
void APIENTRY
glutGameModeString(const char* string)
{
gState.gameMode.Set(string);
}
int APIENTRY
glutEnterGameMode(void)
{
return gState.gameMode.Enter() == B_OK;
}
void APIENTRY
glutLeaveGameMode(void)
{
gState.gameMode.Leave();
}
int APIENTRY
glutGameModeGet(GLenum pname)
{
switch( pname ) {
case GLUT_GAME_MODE_ACTIVE:
return gState.gameMode.IsActive();
case GLUT_GAME_MODE_POSSIBLE:
return gState.gameMode.IsPossible();
case GLUT_GAME_MODE_WIDTH:
return gState.gameMode.Width();
case GLUT_GAME_MODE_HEIGHT:
return gState.gameMode.Height();
case GLUT_GAME_MODE_PIXEL_DEPTH:
return gState.gameMode.PixelDepth();
case GLUT_GAME_MODE_REFRESH_RATE:
return gState.gameMode.RefreshRate();
case GLUT_GAME_MODE_DISPLAY_CHANGED:
return gState.gameMode.HasDisplayChanged();
default:
__glutWarning( "Unknown gamemode get: %d", pname );
return -1;
}
}
void APIENTRY
glutForceJoystickFunc(void)
{
}