Implement Anti-Aliasing (#518)

Armin Burgmeier 2010-12-29 15:19:46 +01:00
parent a9162e6358
commit f814708a9c
19 changed files with 818 additions and 130 deletions

View File

@ -152,6 +152,7 @@ IDS_CTL_ACTIVE=Aktivieren
IDS_CTL_ALL=Alle
IDS_CTL_AMPLITUDE=Amplitude:
IDS_CTL_ANIMALS=Tiere
IDS_CTL_ANTIALIASING=Antialiasing:
IDS_CTL_AUTHOR=Autor: %s
IDS_CTL_AUTOEDITSCAN=Bearbeitete Objekte im Hintergrund aktualisieren
IDS_CTL_AUTOMATICUPDATES=automatische Updates aktivieren
@ -743,6 +744,7 @@ IDS_MNU_VIEWPORT=Sichtfenster
IDS_MSG_ACTIVE=Aktiver
IDS_MSG_ALLOWSYOUTOJOINADIFFERENT=Erlaubt die Auswahl eines anderen Teams.
IDS_MSG_ALLPLAYERDATA=Sollen die aktuellen Werte für alle Spieler übernommen werden?
IDS_MSG_ANTIALIASING_DESC=FSAA (MultiSampling)-Level einstellen
IDS_MSG_ANUPDATETOVERSIONISAVAILA=Ein neues Update ist verfügbar. Soll das Update heruntergeladen und installiert werden?
IDS_MSG_BACKTOPLAYERDLG=Zurück zur Spielerauswahl.
IDS_MSG_BLITOFFSET=Blit offset
@ -1324,4 +1326,4 @@ IDS_NET_CLIENT_IGNORE_DESC=%s ignorieren. Du kannst Nachrichten von diesem Clien
IDS_NET_CLIENT_IGNORE=Ignorieren
IDS_NET_CLIENT_UNIGNORE=Nicht mehr ignorieren
IDS_MSG_HIGHRESLANDSCAPE=Hochauflösende Landschaft
IDS_MSG_HIGHRESLANDSCAPE_DESC=Experimenteller Effekt für hochauflösende Texturen auf der Landschaft.
IDS_MSG_HIGHRESLANDSCAPE_DESC=Experimenteller Effekt für hochauflösende Texturen auf der Landschaft.

View File

@ -152,6 +152,7 @@ IDS_CTL_ACTIVE=Active
IDS_CTL_ALL=All
IDS_CTL_AMPLITUDE=Amplitude:
IDS_CTL_ANIMALS=Animals
IDS_CTL_ANTIALIASING=Antialiasing:
IDS_CTL_AUTHOR=Author: %s
IDS_CTL_AUTOEDITSCAN=Background update edited objects
IDS_CTL_AUTOMATICUPDATES=Enable automatic updates
@ -742,6 +743,7 @@ IDS_MNU_VIEWPORT=Viewport
IDS_MSG_ACTIVE=Active
IDS_MSG_ALLOWSYOUTOJOINADIFFERENT=Allows you to join a different team.
IDS_MSG_ALLPLAYERDATA=Use current values for all players?
IDS_MSG_ANTIALIASING_DESC=Set FSAA (MultiSampling) level
IDS_MSG_ANUPDATETOVERSIONISAVAILA=A new update is available. Do you want to download and install this update?
IDS_MSG_BACKTOPLAYERDLG=Back to player selection.
IDS_MSG_BLITOFFSET=Blit offset
@ -1323,4 +1325,4 @@ IDS_NET_CLIENT_IGNORE_DESC=Ignores %s. You will not be able to see messages from
IDS_NET_CLIENT_IGNORE=Ignore
IDS_NET_CLIENT_UNIGNORE=Unignore
IDS_MSG_HIGHRESLANDSCAPE=High resolution landscape
IDS_MSG_HIGHRESLANDSCAPE_DESC=Experimental effect for high resolution textures on the landscape.
IDS_MSG_HIGHRESLANDSCAPE_DESC=Experimental effect for high resolution textures on the landscape.

View File

@ -149,6 +149,7 @@ LRESULT APIENTRY FullScreenWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
case SIZE_RESTORED:
case SIZE_MAXIMIZED:
::Application.OnResolutionChanged(LOWORD(lParam), HIWORD(lParam));
::SetWindowPos(Application.pWindow->hRenderWindow, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOZORDER);
break;
}
break;

View File

@ -136,6 +136,7 @@ void C4ConfigGraphics::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt(EnableShaders, "Shader", 0 ,false, true));
pComp->Value(mkNamingAdapt(NoOffscreenBlits, "NoOffscreenBlits", 1 ));
pComp->Value(mkNamingAdapt(ClipManuallyE, "ClipManuallyE", 1 ));
pComp->Value(mkNamingAdapt(MultiSampling, "MultiSampling", 4 ));
}
void C4ConfigSound::CompileFunc(StdCompiler *pComp)

View File

@ -135,6 +135,7 @@ public:
int32_t EnableShaders; // enable pixel shaders on engines that support them
int32_t ClipManuallyE; // do manual clipping in the easy cases
int32_t NoOffscreenBlits; // if set, all blits to non-primary-surfaces are emulated
int32_t MultiSampling; // multisampling samples
void CompileFunc(StdCompiler *pComp);
};

View File

@ -837,6 +837,28 @@ C4StartupOptionsDlg::C4StartupOptionsDlg() : C4StartupDlg(LoadResStrNoAmp("IDS_D
pGroupOptions->SetColors(C4StartupEditBorderColor, C4StartupFontClr);
pSheetGraphics->AddElement(pGroupOptions);
C4GUI::ComponentAligner caGroupOptions(pGroupOptions->GetClientRect(), iIndentX1, iIndentY2, true);
// multisampling
C4GUI::ComponentAligner msBox(caGroupOptions.GetFromTop(C4GUI::ComboBox::GetDefaultHeight()), 0, 0, false);
w=20; q=12; pUseFont->GetTextExtent(LoadResStr("IDS_CTL_ANTIALIASING"), w,q, true);
pGroupOptions->AddElement(new C4GUI::Label(LoadResStr("IDS_CTL_ANTIALIASING"), msBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent), ALeft, C4StartupFontClr, pUseFont, false, false));
pUseFont->GetTextExtent("Off", w, q, true);
C4GUI::ComboBox *pGfxMSCombo = new C4GUI::ComboBox(msBox.GetFromLeft(w+40,C4GUI::ComboBox::GetDefaultHeight()));
pGfxMSCombo->SetToolTip(LoadResStr("IDS_MSG_ANTIALIASING_DESC"));
pGfxMSCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnGfxMSComboFill, &C4StartupOptionsDlg::OnGfxMSComboSelChange));
pGfxMSCombo->SetColors(C4StartupFontClr, C4StartupEditBGColor, C4StartupEditBorderColor);
pGfxMSCombo->SetFont(pUseFont);
pGfxMSCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
// Pre-Select current setting
StdStrBuf Current;
if(Config.Graphics.MultiSampling) Current.Format("%dx", Config.Graphics.MultiSampling);
else Current.Copy("Off");
pGfxMSCombo->SetText(Current.getData());
// Set control read only if multisampling is not available
std::vector<int> multisamples;
Application.pWindow->EnumerateMultiSamples(multisamples);
pGfxMSCombo->SetReadOnly(multisamples.empty());
pGroupOptions->AddElement(pGfxMSCombo);
// --subgroup effects
C4GUI::GroupBox *pGroupEffects = new C4GUI::GroupBox(caSheetGraphics.GetGridCell(1,2,2,3));
pGroupEffects->SetTitle(LoadResStrNoAmp("IDS_CTL_SMOKE"));
@ -1038,6 +1060,64 @@ void C4StartupOptionsDlg::OnGfxEngineCheck(C4GUI::Element *pCheckBox)
LoadGfxTroubleshoot();
}
void C4StartupOptionsDlg::OnGfxMSComboFill(C4GUI::ComboBox_FillCB *pFiller)
{
// clear all old entries first to allow a clean refill
pFiller->ClearEntries();
pFiller->AddEntry("Off", 0);
std::vector<int> multisamples;
Application.pWindow->EnumerateMultiSamples(multisamples);
std::sort(multisamples.begin(), multisamples.end());
for(unsigned int i = 0; i < multisamples.size(); ++i)
{
StdStrBuf text;
text.Format("%dx", multisamples[i]);
pFiller->AddEntry(text.getData(), multisamples[i]);
}
}
bool C4StartupOptionsDlg::OnGfxMSComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
{
if(pTexMgr) pTexMgr->IntLock();
#ifdef USE_GL
lpDDraw->InvalidateDeviceObjects();
// Note: This assumes there is only one GL context (the main context). This
// is true in fullscreen mode, and since the startup dlg is only shown in
// fullscreen mode we are safe this way.
if(pGL) pGL->pMainCtx->Clear();
#endif
#ifdef USE_DIRECTX
// It should also be possible to clear+reinit DDraw also for GL, however,
// if ReInit() does _not_ create a new window on X11 then all rendering
// stops until the Window is being moved again (or tasked-out and back in
// in fullscreen mode). This does not happen when only reinitializing the
// GL context instead of whole DDraw so that's why we do this currently.
if(pD3D) lpDDraw->Clear();
#endif
int32_t PrevMultiSampling = Config.Graphics.MultiSampling;
Config.Graphics.MultiSampling = idNewSelection;
bool success = Application.pWindow->ReInit(&Application);
#ifdef USE_GL
if(pGL) pGL->pMainCtx->Init(Application.pWindow, &Application);
lpDDraw->RestoreDeviceObjects();
#endif
#ifdef USE_DIRECTX
// Note: Editor is hardcoded to false at this point... I guess that's OK
// because C4StartupOptionsDlg is never shown in editor mode anyway.
if(pD3D) lpDDraw->Init(pApp, false, false, Config.Graphics.ResX, Config.Graphics.ResY, Config.Graphics.BitDepth, Config.Graphics.Monitor);
#endif
if(pTexMgr) pTexMgr->IntUnlock();
if(!success) Config.Graphics.MultiSampling = PrevMultiSampling;
return !success;
}
void C4StartupOptionsDlg::OnGfxResComboFill(C4GUI::ComboBox_FillCB *pFiller)
{
// clear all old entries first to allow a clean refill

View File

@ -130,6 +130,8 @@ private:
{ SaveGfxTroubleshoot(); } // immediate save and test
void OnGfxResComboFill(C4GUI::ComboBox_FillCB *pFiller);
bool OnGfxResComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection);
void OnGfxMSComboFill(C4GUI::ComboBox_FillCB *pFiller);
bool OnGfxMSComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection);
bool TryNewResolution(int32_t iResX, int32_t iResY);
void OnGfxClrDepthCheck(C4GUI::Element *pCheckBox);
StdStrBuf GetGfxResString(int32_t iResX, int32_t iResY); // convert resolution to string to be displayed in resolution choice combobox

View File

@ -70,7 +70,7 @@ void CStdD3D::Default()
void CStdD3D::Clear()
{
NoPrimaryClipper();
if (pTexMgr) pTexMgr->IntUnlock();
//if (pTexMgr) pTexMgr->IntUnlock(); // cannot do this here or we can't preserve textures across GL reinitialization as required when changing multisampling
if (lpDevice)
{
EndScene();

View File

@ -83,7 +83,7 @@ CStdGL::~CStdGL()
void CStdGL::Clear()
{
NoPrimaryClipper();
if (pTexMgr) pTexMgr->IntUnlock();
//if (pTexMgr) pTexMgr->IntUnlock(); // cannot do this here or we can't preserve textures across GL reinitialization as required when changing multisampling
InvalidateDeviceObjects();
NoPrimaryClipper();
RenderTarget = NULL;
@ -109,6 +109,7 @@ bool CStdGL::UpdateClipper()
int iHgt=Min(iClipY2, RenderTarget->Hgt-1)-iClipY1+1;
int iX=iClipX1; if (iX<0) { iWdt+=iX; iX=0; }
int iY=iClipY1; if (iY<0) { iHgt+=iY; iY=0; }
if (iWdt<=0 || iHgt<=0)
{
ClipAll=true;
@ -2013,9 +2014,10 @@ void CStdGL::TaskOut()
{
// deactivate
// backup textures
#ifdef _WIN32
if (pTexMgr && !Editor) pTexMgr->IntLock();
if (pCurrCtx) pCurrCtx->Deselect();
#ifdef _WIN32
if (!Editor && !Config.Graphics.Windowed)
{
::ChangeDisplaySettings(NULL, 0);
@ -2028,10 +2030,10 @@ void CStdGL::TaskIn()
{
// restore gl
//if (!DeviceReady()) MainCtx.Init(pWindow, pApp);
#ifdef _WIN32
// restore textures
if (pTexMgr && !Editor) pTexMgr->IntUnlock();
#ifdef _WIN32
if (!Editor && !Config.Graphics.Windowed)
{
Application.SetVideoMode(Config.Graphics.ResX, Config.Graphics.ResY, Config.Graphics.BitDepth, Config.Graphics.Monitor, !Config.Graphics.Windowed);

View File

@ -41,11 +41,14 @@ public:
~CStdGLCtx() { Clear(); }; // dtor
void Clear(); // clear objects
#ifdef _WIN32
bool Init(CStdWindow * pWindow, CStdApp *pApp, HWND hWindow=NULL);
bool Init(CStdWindow * pWindow, CStdApp *pApp, HWND hWindow = NULL);
std::vector<int> EnumerateMultiSamples() const;
#else
bool Init(CStdWindow * pWindow, CStdApp *pApp);
#endif
#ifdef USE_COCOA
/*NSOpenGLContext*/void* GetNativeCtx();
#endif
@ -63,6 +66,7 @@ protected:
HGLRC hrc; // rendering context
HWND hWindow; // used if pWindow==NULL
HDC hDC; // device context handle
static bool InitGlew(HINSTANCE hInst);
#elif defined(USE_X11)
/*GLXContext*/void * ctx;
#elif defined(USE_COCOA)
@ -150,6 +154,7 @@ protected:
friend class CStdGLCtx;
friend class C4StartupOptionsDlg;
friend class C4FullScreen;
friend class CStdWindow;
};
// Global access pointer

View File

@ -44,6 +44,208 @@ void CStdGLCtx::SelectCommon()
}
#ifdef _WIN32
#include <GL/wglew.h>
// Enumerate available pixel formats. Choose the best pixel format in
// terms of color and depth buffer bits and then return all formats with
// different multisampling settings. If there are more then one, then choose
// the one with highest depth buffer size and lowest stencil and auxiliary
// buffer sizes since we don't use them in Clonk.
static std::vector<int> EnumeratePixelFormats(HDC hdc)
{
std::vector<int> result;
if(!wglGetPixelFormatAttribivARB) return result;
int n_formats;
int attributes = WGL_NUMBER_PIXEL_FORMATS_ARB;
if(!wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, &attributes, &n_formats)) return result;
for(int i = 1; i < n_formats+1; ++i)
{
int new_attributes[] = { WGL_DRAW_TO_WINDOW_ARB, WGL_SUPPORT_OPENGL_ARB, WGL_DOUBLE_BUFFER_ARB, WGL_COLOR_BITS_ARB, WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB, WGL_AUX_BUFFERS_ARB, WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB };
const unsigned int nnew_attributes = sizeof(new_attributes)/sizeof(int);
int new_results[nnew_attributes];
if(!wglGetPixelFormatAttribivARB(hdc, i, 0, nnew_attributes, new_attributes, new_results)) continue;
if(!new_results[0] || !new_results[1] || !new_results[2]) continue;
if(new_results[3] < 16 || new_results[4] < 16) continue; // require at least 16 bits per pixel in color and depth
// For no MS we do find a pixel format with depth 32 on my (ck's) computer,
// however, when choosing it then texturing does not work anymore. I am not
// exactly sure what the cause of that is, so let's not choose that one for now.
if(new_results[4] > 24) continue;
// Multisampling with just one sample is equivalent to no-multisampling,
// so don't include that in the result.
if(new_results[7] == 1 && new_results[8] == 1)
continue;
if(result.empty())
{
result.push_back(i);
}
else
{
int old_attributes[] = { WGL_COLOR_BITS_ARB };
const unsigned int nold_attributes = sizeof(old_attributes)/sizeof(int);
int old_results[nold_attributes];
if(!wglGetPixelFormatAttribivARB(hdc, result[0], 0, nold_attributes, old_attributes, old_results)) continue;
if(new_results[3] > old_results[0])
{
result.clear();
result.push_back(i);
}
else if(new_results[3] == old_results[0])
{
unsigned int j;
for(j = 0; j < result.size(); ++j)
{
int equiv_attributes[] = { WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB, WGL_AUX_BUFFERS_ARB, WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB };
const unsigned int nequiv_attributes = sizeof(equiv_attributes)/sizeof(int);
int equiv_results[nequiv_attributes];
if(!wglGetPixelFormatAttribivARB(hdc, result[j], 0, nequiv_attributes, equiv_attributes, equiv_results)) continue;
if(new_results[7] == equiv_results[3] && new_results[8] == equiv_results[4])
{
if(new_results[4] > equiv_results[0] || (new_results[4] == equiv_results[0] && (new_results[5] < equiv_results[1] || (new_results[5] == equiv_results[1] && new_results[6] < equiv_results[2]))))
result[j] = i;
break;
}
}
if(j == result.size()) result.push_back(i);
}
}
}
return result;
}
static int GetPixelFormatForMS(HDC hDC, unsigned int samples)
{
std::vector<int> vec = EnumeratePixelFormats(hDC);
for(unsigned int i = 0; i < vec.size(); ++i)
{
int attributes[] = { WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB };
const unsigned int n_attributes = 2;
int results[2];
if(!wglGetPixelFormatAttribivARB(hDC, vec[i], 0, n_attributes, attributes, results)) continue;
if( (samples == 0 && results[0] == 0) ||
(samples > 0 && results[0] == 1 && results[1] == samples))
{
return vec[i];
}
}
return 0;
}
// Initialize GLEW. We need to choose a pixel format for this, however we need
// GLEW initialized to enumerate pixel formats. So this creates a temporary
// window with a default pixel format, initializes glew and removes that temp
// window again. Then we can enumerate pixel formats and choose a proper one
// for the main window in CStdGLCtx::Init.
bool CStdGLCtx::InitGlew(HINSTANCE hInst)
{
static bool glewInitialized = false;
if(glewInitialized) return true;
/*WNDCLASSEXW WndClass = {0};
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style = CS_DBLCLKS;
WndClass.lpfnWndProc = DefWindowProcW;
WndClass.hInstance = pApp->hInstance;
WndClass.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
WndClass.lpszClassName = L"C4OCTest";
WndClass.hIcon = NULL;
WndClass.hIconSm = NULL;
if(!RegisterClassExW(&WndClass)) return !!pGL->Error(" gl: Error registered class for temp wnd");
*/
// Create window
HWND hWnd = CreateWindowExW (
0,
L"STATIC", //C4FullScreenClassName,
NULL, //L"C4OCTest", //ADDL(C4ENGINENAME),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,0,0,
NULL,NULL,hInst,NULL);
if(!hWnd)
{
pGL->Error(" gl: Failed to create temporary window to choose pixel format");
}
else
{
HDC dc = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
// pixel format
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1 ;
pfd.dwFlags = PFD_DOUBLEBUFFER | /*(pGL->fFullscreen ? PFD_SWAP_EXCHANGE : 0) |*/
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW ;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = pGL->iClrDpt;
pfd.cDepthBits = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
int temp_fmt = ChoosePixelFormat(dc, &pfd);
if(!temp_fmt)
{
pGL->Error(" gl: Error choosing temp pixel format");
}
else if(!SetPixelFormat(dc, temp_fmt, &pfd))
{
pGL->Error(" gl: Error setting temp pixel format");
}
else
{
HGLRC hrc = wglCreateContext(dc);
if(!hrc)
{
pGL->Error(" gl: Error creating temp context");
}
else
{
if(!wglMakeCurrent(dc, hrc))
{
pGL->Error(" gl: Error making temp context current");
}
else
{
// init extensions
GLenum err = glewInit();
if(err != GLEW_OK)
{
// Problem: glewInit failed, something is seriously wrong.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
else
{
glewInitialized = true;
}
wglMakeCurrent(NULL, NULL);
}
wglDeleteContext(hrc);
}
}
ReleaseDC(hWnd, dc);
DestroyWindow(hWnd);
}
return glewInitialized;
}
CStdGLCtx::CStdGLCtx(): pWindow(0), hrc(0), hDC(0), cx(0), cy(0) { }
void CStdGLCtx::Clear()
@ -55,7 +257,7 @@ void CStdGLCtx::Clear()
}
if (hDC)
{
ReleaseDC(pWindow ? pWindow->hWindow : hWindow, hDC);
ReleaseDC(pWindow ? pWindow->hRenderWindow : hWindow, hDC);
hDC=0;
}
pWindow = 0; cx = cy = 0; hWindow = NULL;
@ -66,58 +268,111 @@ bool CStdGLCtx::Init(CStdWindow * pWindow, CStdApp *pApp, HWND hWindow)
// safety
if (!pGL) return false;
// Initialize GLEW so that we can choose a pixel format later
if(!InitGlew(pApp->hInstance)) return false;
// store window
this->pWindow = pWindow;
// default HWND
if (pWindow) hWindow = pWindow->hWindow; else this->hWindow = hWindow;
if (pWindow)
hWindow = pWindow->hRenderWindow;
else
this->hWindow = hWindow;
// get DC
hDC=GetDC(hWindow);
if (!hDC) return !!pGL->Error(" gl: Error getting DC");
PIXELFORMATDESCRIPTOR &rPfd = pApp->GetPFD();
if (!pGL->iPixelFormat)
hDC = GetDC(hWindow);
if(!hDC)
{
// pixel format
memset(&rPfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ;
rPfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
rPfd.nVersion = 1 ;
rPfd.dwFlags = PFD_DOUBLEBUFFER | /*(pGL->fFullscreen ? PFD_SWAP_EXCHANGE : 0) |*/
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW ;
rPfd.iPixelType = PFD_TYPE_RGBA;
rPfd.cColorBits = pGL->iClrDpt;
rPfd.cDepthBits = 0;
rPfd.iLayerType = PFD_MAIN_PLANE;
pGL->iPixelFormat = ChoosePixelFormat(hDC, &rPfd);
if (!pGL->iPixelFormat) return !!pGL->Error(" gl: Error getting pixel format");
pGL->Error(" gl: Error getting DC");
}
if (!SetPixelFormat (hDC, pGL->iPixelFormat, &rPfd)) pGL->Error(" gl: Error setting pixel format");
// create context
hrc = wglCreateContext(hDC); if (!hrc) return !!pGL->Error(" gl: Error creating gl context");
//if (this != &pGL->MainCtx) wglCopyContext(pGL->MainCtx.hrc, hrc, GL_ALL_ATTRIB_BITS);
// share textures
wglMakeCurrent(NULL, NULL); pGL->pCurrCtx=NULL;
if (this != pGL->pMainCtx)
else
{
if (!wglShareLists(pGL->pMainCtx->hrc, hrc)) pGL->Error(" gl: Textures for secondary context not available");
return true;
// Choose a good pixel format.
int pixel_format;
if((pixel_format = GetPixelFormatForMS(hDC, Config.Graphics.MultiSampling)) == 0)
if((pixel_format = GetPixelFormatForMS(hDC, 0)) != 0)
Config.Graphics.MultiSampling = 0;
if(!pixel_format)
{
pGL->Error(" gl: Error choosing pixel format");
}
else
{
PIXELFORMATDESCRIPTOR pfd;
if(!DescribePixelFormat(hDC, pixel_format, sizeof(pfd), &pfd))
{
pGL->Error(" gl: Error describing chosen pixel format");
}
else if(!SetPixelFormat(hDC, pixel_format, &pfd))
{
pGL->Error(" gl: Error setting chosen pixel format");
}
else
{
// create context
hrc = wglCreateContext(hDC);
if(!hrc)
{
pGL->Error(" gl: Error creating gl context");
}
else
{
//if (this != &pGL->MainCtx) wglCopyContext(pGL->MainCtx.hrc, hrc, GL_ALL_ATTRIB_BITS);
// share textures
bool success = false;
wglMakeCurrent(NULL, NULL); pGL->pCurrCtx=NULL;
if (this != pGL->pMainCtx)
{
if(!wglShareLists(pGL->pMainCtx->hrc, hrc))
pGL->Error(" gl: Textures for secondary context not available");
else
success = true;
}
else
{
// select main context
if (!Select())
pGL->Error(" gl: Unable to select context");
else
success = true;
}
if(success)
{
pGL->iPixelFormat = pixel_format;
PIXELFORMATDESCRIPTOR &rPfd = pApp->GetPFD();
rPfd = pfd;
return true;
}
}
wglDeleteContext(hrc); hrc = NULL;
}
}
ReleaseDC(hWindow, hDC); hDC = NULL;
}
// select
if (!Select()) return !!pGL->Error(" gl: Unable to select context");
return false;
}
// init extensions
GLenum err = glewInit();
if (GLEW_OK != err)
std::vector<int> CStdGLCtx::EnumerateMultiSamples() const
{
std::vector<int> result;
std::vector<int> vec = EnumeratePixelFormats(hDC);
for(unsigned int i = 0; i < vec.size(); ++i)
{
// Problem: glewInit failed, something is seriously wrong.
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
int attributes[] = { WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB };
const unsigned int n_attributes = 2;
int results[2];
if(!wglGetPixelFormatAttribivARB(hDC, vec[i], 0, n_attributes, attributes, results)) continue;
if(results[0] == 1) result.push_back(results[1]);
}
// success
return true;
return result;
}
bool CStdGLCtx::Select(bool verbose)
@ -210,7 +465,7 @@ bool CStdGLCtx::Init(CStdWindow * pWindow, CStdApp *)
this->pWindow = pWindow;
// Create Context with sharing (if this is the main context, our ctx will be 0, so no sharing)
// try direct rendering first
ctx = glXCreateContext(pWindow->dpy, (XVisualInfo*)pWindow->Info, pGL->pMainCtx ? (GLXContext)pGL->pMainCtx->ctx : 0, True);
ctx = glXCreateContext(pWindow->dpy, (XVisualInfo*)pWindow->Info, (pGL->pMainCtx != this) ? (GLXContext)pGL->pMainCtx->ctx : 0, True);
// without, rendering will be unacceptable slow, but that's better than nothing at all
if (!ctx)
ctx = glXCreateContext(pWindow->dpy, (XVisualInfo*)pWindow->Info, pGL->pMainCtx ? (GLXContext)pGL->pMainCtx->ctx : 0, False);

View File

@ -46,7 +46,13 @@ CStdWindow* CStdGtkWindow::Init(WindowKind windowKind, CStdApp * pApp, const cha
Active = true;
dpy = pApp->dpy;
if (!FindInfo()) return 0;
if(!FindInfo(Config.Graphics.MultiSampling, &Info))
{
// Disable multisampling if we don't find a visual which
// supports the currently configured setting.
if(!FindInfo(0, &Info)) return NULL;
Config.Graphics.MultiSampling = 0;
}
assert(!window);
@ -130,6 +136,14 @@ CStdWindow* CStdGtkWindow::Init(WindowKind windowKind, CStdApp * pApp, const cha
return this;
}
bool CStdGtkWindow::ReInit(CStdApp* pApp)
{
// TODO: Recreate the window with a newly chosen visual
// Probably we don't need this, since there is no way to change
// MultiSampling when no window is open.
return false;
}
void CStdGtkWindow::Clear()
{
if (window != NULL)
@ -148,7 +162,7 @@ void CStdGtkWindow::Clear()
// We must free it here since we do not call CStdWindow::Clear()
if (Info)
{
XFree(Info);
delete static_cast<XVisualInfo*>(Info);
Info = 0;
}
}

View File

@ -35,6 +35,7 @@ public:
using CStdWindow::Init;
virtual CStdWindow * Init(WindowKind windowKind, CStdApp * pApp, const char * Title, CStdWindow * pParent = 0, bool HideCursor = true);
virtual bool ReInit(CStdApp* pApp);
GtkWidget* window;
protected:

View File

@ -58,8 +58,20 @@ CStdWindow * CStdWindow::Init(CStdApp * pApp, const char * Title, CStdWindow * p
return this;
}
bool CStdWindow::ReInit(CStdApp* pApp)
{
// TODO: How do we enable multisampling with SDL?
// Maybe re-call SDL_SetVideoMode?
return false;
}
void CStdWindow::Clear() {}
void CStdWindow::EnumerateMultiSamples(std::vector<int>& samples) const
{
// TODO: Enumerate multi samples
}
bool CStdWindow::StorePosition(const char *, const char *, bool) { return true; }
bool CStdWindow::RestorePosition(const char *, const char *, bool) { return true; }

View File

@ -1581,7 +1581,20 @@ void CTexMgr::IntLock()
for (std::list<CTexRef *>::iterator i=Textures.begin(); j--; ++i)
{
CTexRef *pRef = *i;
if (pRef->Lock() && !pRef->texLock.pBits) pRef->fIntLock = true;
if (pRef->Lock() && pRef->texLock.pBits)
{
pRef->fIntLock = true;
#ifdef USE_GL
// Release the underlying texture with GL and recreate
// it on unlock, so that the texture survives
// context recreation.
if(pGL)
{
glDeleteTextures(1, &pRef->texName);
pRef->texName = 0;
}
#endif
}
}
}

View File

@ -95,8 +95,17 @@ CStdWindow * CStdWindow::Init(CStdApp * pApp)
C4FullScreenClassName,
ADDL(C4ENGINENAME),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,0,0,
CW_USEDEFAULT,CW_USEDEFAULT, Config.Graphics.ResX, Config.Graphics.ResY,
NULL,NULL,pApp->hInstance,NULL);
if(!hWindow) return NULL;
RECT rc;
GetClientRect(hWindow, &rc);
hRenderWindow = CreateWindowExW(0, L"STATIC", NULL, WS_CHILD,
0, 0, rc.right - rc.left, rc.bottom - rc.top,
hWindow, NULL, pApp->hInstance, NULL);
if(!hRenderWindow) { DestroyWindow(hWindow); return NULL; }
ShowWindow(hRenderWindow, SW_SHOW);
#ifndef USE_CONSOLE
// Show & focus
@ -107,10 +116,34 @@ CStdWindow * CStdWindow::Init(CStdApp * pApp)
return this;
}
bool CStdWindow::ReInit(CStdApp* pApp)
{
// We don't need to change anything with the window for any
// configuration option changes on Windows.
// However, re-create the render window so that another pixel format can
// be chosen for it. The pixel format is chosen in CStdGLCtx::Init.
RECT rc;
GetClientRect(hWindow, &rc);
HWND hNewRenderWindow = CreateWindowExW(0, L"STATIC", NULL, WS_CHILD,
0, 0, rc.right - rc.left, rc.bottom - rc.top,
hWindow, NULL, pApp->hInstance, NULL);
if(!hNewRenderWindow) return false;
ShowWindow(hNewRenderWindow, SW_SHOW);
DestroyWindow(hRenderWindow);
hRenderWindow = hNewRenderWindow;
return true;
}
void CStdWindow::Clear()
{
// Destroy window
if (hRenderWindow) DestroyWindow(hRenderWindow);
if (hWindow) DestroyWindow(hWindow);
hRenderWindow = NULL;
hWindow = NULL;
}
@ -147,6 +180,10 @@ void CStdWindow::SetSize(unsigned int cx, unsigned int cy)
cx = rect.right - rect.left;
cy = rect.bottom - rect.top;
::SetWindowPos(hWindow, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOZORDER);
// Also resize child window
GetClientRect(hWindow, &rect);
::SetWindowPos(hRenderWindow, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOZORDER);
}
}
@ -157,6 +194,18 @@ void CStdWindow::FlashWindow()
::FlashWindow(hWindow, FLASHW_ALL | FLASHW_TIMERNOFG);
}
void CStdWindow::EnumerateMultiSamples(std::vector<int>& samples) const
{
#ifdef USE_GL
if(pGL && pGL->pMainCtx)
samples = pGL->pMainCtx->EnumerateMultiSamples();
#endif
#ifdef USE_DIRECTX
// TODO: Enumerate multi samples
#endif
}
/* CStdTimerProc */
int CStdMultimediaTimerProc::iTimePeriod = 0;
@ -520,4 +569,4 @@ bool EraseItemSafe(const char *szFilename)
bool IsGermanSystem()
{
return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_GERMAN;
}
}

View File

@ -307,6 +307,17 @@ public:
#ifndef _WIN32
virtual CStdWindow * Init(WindowKind windowKind, CStdApp * pApp, const char * Title, CStdWindow * pParent = 0, bool HideCursor = true);
#endif
// Reinitialize the window with updated configuration settings.
// Keep window kind, title and size as they are. Currently the only point
// at which it makes sense for this function to be called is when the
// multisampling configuration option changes, since, for the change to
// take effect, we need to choose another visual or pixel format, respectively.
virtual bool ReInit(CStdApp* pApp);
// Creates a list of available samples for multisampling
virtual void EnumerateMultiSamples(std::vector<int>& samples) const;
bool StorePosition(const char *szWindowName, const char *szSubKey, bool fStoreSize = true);
bool RestorePosition(const char *szWindowName, const char *szSubKey, bool fHidden = false);
bool GetSize(RECT * pRect);
@ -317,12 +328,13 @@ public:
#ifdef _WIN32
public:
HWND hWindow;
HWND hRenderWindow;
protected:
bool RegisterWindowClass(HINSTANCE hInst);
virtual bool Win32DialogMessageHandling(MSG * msg) { return false; };
#elif defined(USE_X11)
protected:
bool FindInfo();
bool FindInfo(unsigned int samples, void** info);
unsigned long wnd;
unsigned long renderwnd;
@ -556,6 +568,7 @@ protected:
bool ReadStdInCommand();
friend class CStdGL;
friend class CStdGLCtx;
friend class CStdWindow;
friend class CStdGtkWindow;
};

View File

@ -363,6 +363,7 @@ void CStdApp::HandleXMessage()
case ConfigureNotify:
if (pWindow && event.xany.window == pWindow->wnd)
{
XResizeWindow(dpy, pWindow->renderwnd, event.xconfigure.width, event.xconfigure.height);
OnResolutionChanged(event.xconfigure.width, event.xconfigure.height);
}
break;

View File

@ -49,6 +49,177 @@
#include "StdXPrivate.h"
// Some helper functions for choosing a proper visual
#ifdef USE_GL
// Returns which XVisual attribute for two given attributes is greater.
static int CompareVisualAttribute(Display* dpy, XVisualInfo* first, XVisualInfo* second, int attrib)
{
int first_value, second_value;
glXGetConfig(dpy, first, attrib, &first_value);
glXGetConfig(dpy, second, attrib, &second_value);
if(first_value != second_value) return first_value > second_value ? 1 : -1;
return 0;
}
// Given two X visuals, check which one is superior, according to
// the following rule: Double buffering is preferred over single
// buffering, then highest color buffer is preferred. If both are equal
// then the buffers are considered equal (return value 0).
static int CompareVisual(Display* dpy, XVisualInfo* first, XVisualInfo* second)
{
int result = CompareVisualAttribute(dpy, first, second, GLX_DOUBLEBUFFER);
if(result != 0) return result;
result = CompareVisualAttribute(dpy, first, second, GLX_BUFFER_SIZE);
return result;
}
// Compare otherwise equivalent visuals. If the function above
// considered two visuals to be equivalent then this function can
// be used to decide which one to use. We prefer visuals with high depth
// beffer size and low accumulation and stencil buffer sizes since the latter
// two are not used in Clonk.
static int CompareEquivalentVisual(Display* dpy, XVisualInfo* first, XVisualInfo* second)
{
int result = CompareVisualAttribute(dpy, first, second, GLX_DEPTH_SIZE);
if(result != 0) return result;
result = CompareVisualAttribute(dpy, first, second, GLX_STENCIL_SIZE);
if(result != 0) return -result;
result = CompareVisualAttribute(dpy, first, second, GLX_ACCUM_RED_SIZE);
if(result != 0) return -result;
result = CompareVisualAttribute(dpy, first, second, GLX_ACCUM_GREEN_SIZE);
if(result != 0) return -result;
result = CompareVisualAttribute(dpy, first, second, GLX_ACCUM_BLUE_SIZE);
if(result != 0) return -result;
result = CompareVisualAttribute(dpy, first, second, GLX_ACCUM_ALPHA_SIZE);
return -result;
}
// This function generates a list of acceptable visuals. The most
// superiour visual as defined by CompareVisual is chosen. If there
// are two or more visuals which compare equal with CompareVisual then
// we add all of them to the output list as long as their multi
// sampling properties differ. If they do not differ then we use
// CompareEquivalentVisual to decide which one to put into the output
// list.
static std::vector<XVisualInfo> EnumerateVisuals(Display* dpy)
{
XVisualInfo templateInfo;
templateInfo.screen = DefaultScreen(dpy);
long vinfo_mask = VisualScreenMask;
int nitems;
XVisualInfo* infos = XGetVisualInfo(dpy, vinfo_mask, &templateInfo, &nitems);
std::vector<XVisualInfo> selected_infos;
for(int i = 0; i < nitems; ++i)
{
// Require minimum depth and color buffer
if(infos[i].depth < 8 || infos[i].bits_per_rgb < 4) continue;
// Require it to be an RGBA visual
int value;
glXGetConfig(dpy, &infos[i], GLX_RGBA, &value);
if(!value) continue;
// Require GL rendering to be supported (probably always true...)
glXGetConfig(dpy, &infos[i], GLX_USE_GL, &value);
if(!value) continue;
// Multisampling with only 1 sample gives the same result as
// no multisampling at all, so simply ignore these visuals.
int second_value;
glXGetConfig(dpy, &infos[i], GLX_SAMPLE_BUFFERS_ARB, &value);
glXGetConfig(dpy, &infos[i], GLX_SAMPLES_ARB, &second_value);
if(value == 1 && second_value == 1) continue;
// This visual is acceptable in principle. Use it if
// we don't have any other.
if(selected_infos.empty())
{
selected_infos.push_back(infos[i]);
}
// Otherwise, check which one is superior. Note that all selected
// visuals have same buffering and RGBA sizes.
else
{
unsigned int j;
switch(CompareVisual(dpy, &infos[i], &selected_infos[0]))
{
case 1:
// The new visual is superior.
selected_infos.clear();
selected_infos.push_back(infos[i]);
break;
case -1:
// The old visual is superior.
break;
case 0:
// The visuals are equal. OK, so check whether there is an otherwise equivalent
// visual (read: same multisampling properties) but with different depth, stencil or
// auxiliary buffer sizes. If so, replace it, otherwise add the new one.
for(j = 0; j < selected_infos.size(); ++j)
{
if(CompareVisualAttribute(dpy, &infos[i], &selected_infos[j], GLX_SAMPLE_BUFFERS_ARB) != 0) continue;
if(CompareVisualAttribute(dpy, &infos[i], &selected_infos[j], GLX_SAMPLES_ARB) != 0) continue;
// The new visual has the same multi sampling properties then the current one.
// Use CompareEquivalentVisual() to decide
switch(CompareEquivalentVisual(dpy, &infos[i], &selected_infos[j]))
{
case 1:
// The current info is more suitable
selected_infos[j] = infos[i];
break;
case -1:
// The existing info is more suitable;
break;
case 0:
// No decision. Keep the existing one, but we could as well take
// the new one since we don't know what the difference between the two is.
break;
}
// Break the for loop. There is only one visual
// with the same multi sampling properties.
break;
}
// If we did not find a visual with the same multisampling in the for loop
// then add this visual to the result list
if(j == selected_infos.size())
selected_infos.push_back(infos[i]);
break;
}
}
}
XFree(infos);
return selected_infos;
}
#endif // USE_GL
static Window CreateRenderWindow(Display* dpy, Window parent, XVisualInfo* info)
{
XWindowAttributes parent_attr;
if(!XGetWindowAttributes(dpy, parent, &parent_attr)) return NULL;
XSetWindowAttributes attr;
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), info->visual, AllocNone);
unsigned long attrmask = CWBackPixel | CWBorderPixel | CWColormap;
return XCreateWindow(dpy, parent, 0, 0, parent_attr.width, parent_attr.height, 0,
info->depth, InputOutput, info->visual, attrmask, &attr);
}
/* CStdWindow */
CStdWindow::CStdWindow ():
@ -69,9 +240,15 @@ CStdWindow * CStdWindow::Init(CStdWindow::WindowKind windowKind, CStdApp * pApp,
Active = true;
dpy = pApp->dpy;
if (!FindInfo() ) return 0;
// Try to get a multisampling visual
if(!FindInfo(Config.Graphics.MultiSampling, &Info))
{
// Disable multisampling if we don't find a visual which
// supports the currently configured setting.
if(!FindInfo(0, &Info)) return NULL;
Config.Graphics.MultiSampling = 0;
}
// Various properties
XSetWindowAttributes attr;
attr.border_pixel = 0;
attr.background_pixel = 0;
@ -86,8 +263,8 @@ CStdWindow * CStdWindow::Init(CStdWindow::WindowKind windowKind, CStdApp * pApp,
PointerMotionMask |
ButtonPressMask |
ButtonReleaseMask;
attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), ((XVisualInfo*)Info)->visual, AllocNone);
unsigned long attrmask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
unsigned long attrmask = CWBackPixel | CWBorderPixel | CWEventMask;
Pixmap bitmap = 0;
if (HideCursor)
{
@ -116,8 +293,9 @@ CStdWindow * CStdWindow::Init(CStdWindow::WindowKind windowKind, CStdApp * pApp,
}
wnd = XCreateWindow(dpy, DefaultRootWindow(dpy),
0, 0, Config.Graphics.ResX, Config.Graphics.ResY, 0, ((XVisualInfo*)Info)->depth, InputOutput, ((XVisualInfo*)Info)->visual,
attrmask, &attr);
0, 0, Config.Graphics.ResX, Config.Graphics.ResY, 0, CopyFromParent, InputOutput, CopyFromParent,
attrmask, &attr);
if (attr.cursor)
XFreeCursor(dpy, attr.cursor);
if (bitmap)
@ -125,26 +303,19 @@ CStdWindow * CStdWindow::Init(CStdWindow::WindowKind windowKind, CStdApp * pApp,
if (!wnd)
{
Log("Error creating window.");
return 0;
return NULL;
}
// Update the XWindow->CStdWindow-Map
CStdAppPrivate::SetWindow(wnd, this);
if (!pApp->Priv->xic && pApp->Priv->xim)
if (pApp->Priv->xim && !pApp->Priv->xic)
{
pApp->Priv->xic = XCreateIC(pApp->Priv->xim,
XNClientWindow, wnd,
XNFocusWindow, wnd,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNResourceName, C4ENGINENAME,
XNResourceClass, C4ENGINENAME,
NULL);
if (!pApp->Priv->xic)
{
Log("Failed to create input context.");
XCloseIM(pApp->Priv->xim);
pApp->Priv->xim=0;
}
else
XNClientWindow, wnd,
XNFocusWindow, wnd,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNResourceName, C4ENGINENAME,
XNResourceClass, C4ENGINENAME,
NULL);
if(pApp->Priv->xic)
{
long ic_event_mask;
if (XGetICValues(pApp->Priv->xic, XNFilterEvents, &ic_event_mask, NULL) == NULL)
@ -152,45 +323,109 @@ CStdWindow * CStdWindow::Init(CStdWindow::WindowKind windowKind, CStdApp * pApp,
XSelectInput(dpy, wnd, attr.event_mask);
XSetICFocus(pApp->Priv->xic);
}
else
{
Log("Failed to create input context.");
XCloseIM(pApp->Priv->xim);
pApp->Priv->xim=0;
}
}
#if 0
// Set _NET_WM_STATE
if(n_net_wm_state_atoms)
{
XChangeProperty(dpy, wnd_info.wnd, XInternAtom(dpy, "_NET_WM_STATE", False), XInternAtom(dpy, "ATOM", False), 32, PropModeReplace, reinterpret_cast<unsigned char*>(net_wm_state_atoms), n_net_wm_state_atoms);
}
#endif
// We want notification of closerequests and be killed if we hang
Atom WMProtocols[2];
const char * WMProtocolnames[] = { "WM_DELETE_WINDOW", "_NET_WM_PING" };
XInternAtoms(dpy, const_cast<char **>(WMProtocolnames), 2, false, WMProtocols);
XSetWMProtocols(dpy, wnd, WMProtocols, 2);
// Let the window manager know our pid so it can kill us
Atom PID = XInternAtom(pApp->dpy, "_NET_WM_PID", false);
Atom PID = XInternAtom(dpy, "_NET_WM_PID", false);
int32_t pid = getpid();
if (PID != None) XChangeProperty(pApp->dpy, wnd, PID, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<const unsigned char*>(&pid), 1);
if (PID != None) XChangeProperty(dpy, wnd, PID, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<const unsigned char*>(&pid), 1);
// State and Icon
XWMHints * wm_hint = XAllocWMHints();
wm_hint->input = 1;
wm_hint->flags = StateHint | InputHint | IconPixmapHint | IconMaskHint;
wm_hint->initial_state = NormalState;
XWMHints* wm_hints = XAllocWMHints();
wm_hints->input = 1;
wm_hints->flags = StateHint | InputHint | IconPixmapHint | IconMaskHint;
wm_hints->initial_state = NormalState;
// Trust XpmCreatePixmapFromData to not modify the xpm...
XpmCreatePixmapFromData (dpy, wnd, const_cast<char **>(c4x_xpm), &wm_hint->icon_pixmap, &wm_hint->icon_mask, 0);
XpmCreatePixmapFromData (dpy, wnd, const_cast<char **>(c4x_xpm), &wm_hints->icon_pixmap, &wm_hints->icon_mask, 0);
// Window class
XClassHint * class_hint = XAllocClassHint();
class_hint->res_name = const_cast<char *>(C4ENGINENAME);
class_hint->res_class = const_cast<char *>(C4ENGINENAME);
Xutf8SetWMProperties(dpy, wnd, const_cast<char*>(Title), const_cast<char*>(Title), pApp->Priv->argv, pApp->Priv->argc, 0, wm_hint, class_hint);
Xutf8SetWMProperties(dpy, wnd, const_cast<char*>(Title), const_cast<char*>(Title), pApp->Priv->argv, pApp->Priv->argc, 0, wm_hints, class_hint);
XFree(class_hint);
Hints = wm_hints;
// Set "parent". Clonk does not use "real" parent windows, but multiple toplevel windows.
if (pParent) XSetTransientForHint(dpy, wnd, pParent->wnd);
// Show window
XMapWindow (dpy, wnd);
// Update XWindow<->StdWindow map
CStdAppPrivate::SetWindow(wnd, this);
// Create the subwindow which we render into
renderwnd = CreateRenderWindow(dpy, wnd, static_cast<XVisualInfo*>(Info));
if(!renderwnd)
{
XDestroyWindow(dpy, wnd); wnd = NULL;
Log("Error creating render window.");
return NULL;
}
// Clean up
// The pixmap has to stay as long as the window exists, so it does not hurt to never free it.
//XFreePixmap(dpy,xwmh->icon_pixmap);
//XFreePixmap(dpy,xwmh->icon_mask);
Hints = wm_hint;
XFree(class_hint);
// Render into whole window
renderwnd = wnd;
// Show window
XMapWindow (dpy, renderwnd);
XMapWindow (dpy, wnd);
return this;
}
bool CStdWindow::ReInit(CStdApp* pApp)
{
// Can only re-init if we have been initialized already
if(!wnd) return false;
// Check whether multisampling settings was changed. If not then we
// don't need to ReInit anything.
#ifdef USE_GL
int value;
glXGetConfig(dpy, static_cast<XVisualInfo*>(Info), GLX_SAMPLES_ARB, &value);
if(value == Config.Graphics.MultiSampling) return true;
#else
return true;
#endif
// Check whether we have a visual with the requested number of samples
void* new_info;
if(!FindInfo(Config.Graphics.MultiSampling, &new_info)) return false;
Window new_window = CreateRenderWindow(dpy, wnd, static_cast<XVisualInfo*>(new_info));
if(!new_window)
{
delete static_cast<XVisualInfo*>(new_info);
return false;
}
delete static_cast<XVisualInfo*>(Info);
Info = new_info;
// Replace existing render window with new one
XUnmapWindow(dpy, renderwnd);
XMapWindow(dpy, new_window);
XDestroyWindow(dpy, renderwnd);
renderwnd = new_window;
return true;
}
void CStdWindow::Clear()
{
// Destroy window
@ -198,58 +433,57 @@ void CStdWindow::Clear()
{
CStdAppPrivate::SetWindow(wnd, 0);
XUnmapWindow(dpy, wnd);
XDestroyWindow(dpy, renderwnd);
XDestroyWindow(dpy, wnd);
if (Info) XFree (Info);
if (Hints) XFree(Hints);
Hints = NULL;
// Might be necessary when the last window is closed
XFlush(dpy);
}
wnd = renderwnd = 0;
if (Info) delete static_cast<XVisualInfo*>(Info);
Info = NULL;
}
bool CStdWindow::FindInfo()
bool CStdWindow::FindInfo(unsigned int samples, void** info)
{
#ifdef USE_GL
// get an appropriate visual
// attributes for a single buffered visual in RGBA format with at least 4 bits per color
static int attrListSgl[] = { GLX_RGBA,
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 8,
None
};
// attributes for a double buffered visual in RGBA format with at least 4 bits per color
static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_DEPTH_SIZE, 8,
None
};
// doublebuffered is the best
Info = glXChooseVisual(dpy, DefaultScreen(dpy), attrListDbl);
if (!Info)
std::vector<XVisualInfo> infos = EnumerateVisuals(dpy);
for(unsigned int i = 0; i < infos.size(); ++i)
{
Log(" gl: no doublebuffered visual.");
// a singlebuffered is probably better than the default
Info = glXChooseVisual(dpy, DefaultScreen(dpy), attrListSgl);
}
#endif // USE_GL
if (!Info)
{
Log(" gl: no singlebuffered visual, either.");
// just try to get the default
XVisualInfo vitmpl; int blub;
vitmpl.visual = DefaultVisual(dpy, DefaultScreen(dpy));
vitmpl.visualid = XVisualIDFromVisual(vitmpl.visual);
Info = XGetVisualInfo(dpy, VisualIDMask, &vitmpl, &blub);
}
if (!Info)
{
Log(" gl: no visual at all.");
return false;
}
int v_buffers, v_samples;
glXGetConfig(dpy, &infos[i], GLX_SAMPLE_BUFFERS_ARB, &v_buffers);
glXGetConfig(dpy, &infos[i], GLX_SAMPLES_ARB, &v_samples);
return true;
if((samples == 0 && v_buffers == 0) ||
(samples > 0 && v_buffers == 1 && v_samples == samples))
{
*info = new XVisualInfo(infos[i]);
return true;
}
}
#else
// TODO: Do we need to handle this case?
#endif // USE_GL
return false;
}
void CStdWindow::EnumerateMultiSamples(std::vector<int>& samples) const
{
#ifdef USE_GL
std::vector<XVisualInfo> infos = EnumerateVisuals(dpy);
for(unsigned int i = 0; i < infos.size(); ++i)
{
int v_buffers, v_samples;
glXGetConfig(dpy, &infos[i], GLX_SAMPLE_BUFFERS_ARB, &v_buffers);
glXGetConfig(dpy, &infos[i], GLX_SAMPLES_ARB, &v_samples);
if(v_buffers == 1) samples.push_back(v_samples);
}
#endif
}
bool CStdWindow::StorePosition(const char *, const char *, bool) { return true; }