forked from Mirrors/openclonk
Implement Anti-Aliasing (#518)
parent
a9162e6358
commit
f814708a9c
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in New Issue