Jump to content

  • Log In with Google      Sign In   
  • Create Account

Erik Rufelt

Member Since 17 Apr 2002
Offline Last Active Jun 15 2016 08:30 AM

#5294810 WinAPI + OpenGL: Change window style and/or resolution

Posted by on 03 June 2016 - 10:59 AM

Try updating your graphics drivers if you don't have the newest stable one already..

From your images it seems clear that the OpenGL part stays right where it was in respect to the top-left corner of the window (not the just the client-area).. whereas I guess the top left part that was the border before gets the background-color..

Could be a difference in what theme is used in Windows or if there are any window-helper plugins or something that causes the difference in behavior on different computers..

Try dragging another window on top of the window with the error and see if the OpenGL drawn part is properly updated..

I guess you call PumpMessages from a loop and always do glClear and Swap after that?

You could try only calling DefWindowProc always and skip any viewport and resize handling etc as glClear and Swap don't care about the viewport anyway, and maybe add a Sleep(10) or something in the loop to avoid insane update-rates..




#5294786 WinAPI + OpenGL: Change window style and/or resolution

Posted by on 03 June 2016 - 08:31 AM

I don't get it.. does it not work?  I ran your program and see nothing strange.. maybe a difference between Windows versions or something..

You should post a single-file source code we can run instead of an exe if possible.

 

Anyway, I think your window styles look weird. Especially setting the style when going back to windowed mode.. save the style when you decide to switch to fullscreen and restore it to the saved style when going back to windowed.. removing the fullscreen style bits will break if the windowed mode has any of the same bits set. Many window-styles are combinations of several bits.

Also it looks really complicated, too much code to combine the styles, very difficult to follow exactly what bits will remain in the end.. easy to miss things.

 

I don't get making the window area the same either.. if you want a particular window-area in client-mode then handle that.. but what is the point of a borderless window that doesn't cover the screen?

 

Also getting multiple WM_SIZE shouldn't matter, you could get that anyway if the window is resized, I don't think those messages are supposed to be relied on to send an exact size exactly once or things like that. I'm not sure a resize or especially a style-change is guaranteed to be in any way atomic with respect to the message queue.




#5294545 WinAPI + OpenGL: Change window style and/or resolution

Posted by on 01 June 2016 - 04:43 PM

Show your game loop with PeekMessage as well as the WndProc.




#5294523 WinAPI + OpenGL: Change window style and/or resolution

Posted by on 01 June 2016 - 01:57 PM

An interesting difference: when creating a window I define a style based on the parameters. The return value of SetWindowLongPtr is the previous window style which should be the same as the manually defined style, but it's not. Is that normal?

 

Depends, it can have WS_VISIBLE and others added.. also many styles commonly used when creating a window are actually combinations of several sub-styles.




#5294462 WinAPI + OpenGL: Change window style and/or resolution

Posted by on 01 June 2016 - 07:59 AM

I use this one, has some comments and TODOs that could be double-checked..

It has a check to (supposedly) only go to fullscreen on monitors connected to the primary GPU in case you have more than one, if not that part is unnecessary..

// Get device for monitor
static bool getDeviceForMonitor(const MONITORINFOEX &monitorInfo, LPDISPLAY_DEVICE pOutDevice) {
    DISPLAY_DEVICE displayDevice = {0};
    displayDevice.cb = sizeof(displayDevice);
    
    DWORD dwDevNum = 0;
    BOOL bRet = EnumDisplayDevices(NULL, dwDevNum, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME);
    while(bRet != 0) {
        if(wcscmp(monitorInfo.szDevice, displayDevice.DeviceName) == 0) {
            *pOutDevice = displayDevice;
            
            return true;
        }
        
        ++dwDevNum;
        memset(&displayDevice, 0, sizeof(displayDevice));
        displayDevice.cb = sizeof(displayDevice);
        bRet = EnumDisplayDevices(NULL, dwDevNum, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME);
    }
    
    return false;
}

// Toggle fullscreen
// TODO try SetWindowPlacement instead?
// TODO use maximized WS_POPUP to fill screen instead of manually setting rect?  check methods...
static bool toggleFillscreen(HWND hWnd, bool setFillscreen) {
    bool resultIsFullscreen = setFillscreen;
    
    static LONG_PTR savedWindowStyle = 0;
    static LONG_PTR savedWindowExStyle = 0;
    static RECT savedWindowRect;
    
    if(setFillscreen) {
        resultIsFullscreen = false;
        
        int x = 0;
        int y = 0;
        int w = GetSystemMetrics(SM_CXSCREEN);
        int h = GetSystemMetrics(SM_CYSCREEN);
        
        HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
        HMONITOR hPrimaryMonitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
        if(hMonitor != NULL && hPrimaryMonitor != NULL) {
            BOOL bRet;
            bool switchToFullscreen = false;
            bool gotPrimary = false;
            bool gotTarget = false;
            
            MONITORINFOEX primaryInfo;
            ZeroMemory(&primaryInfo, sizeof(primaryInfo));
            primaryInfo.cbSize = sizeof(primaryInfo);
            bRet = GetMonitorInfo(hPrimaryMonitor, &primaryInfo);
            if(bRet != 0) {
                gotPrimary = true;
            }
            
            MONITORINFOEX monitorInfo;
            ZeroMemory(&monitorInfo, sizeof(monitorInfo));
            monitorInfo.cbSize = sizeof(monitorInfo);
            bRet = GetMonitorInfo(hMonitor, &monitorInfo);
            if(bRet != 0) {
                x = monitorInfo.rcMonitor.left;
                y = monitorInfo.rcMonitor.top;
                w = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
                h = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
                
                gotTarget = true;
            }
            
            if(gotTarget && gotPrimary) {
                if(wcscmp(primaryInfo.szDevice, monitorInfo.szDevice) == 0) {
                    switchToFullscreen = true;
                }
                else {
                    DISPLAY_DEVICE primaryDevice;
                    bool gotPrimaryDevice = getDeviceForMonitor(primaryInfo, &primaryDevice);
                    
                    DISPLAY_DEVICE targetDevice;
                    bool gotTargetDevice = getDeviceForMonitor(monitorInfo, &targetDevice);
                    
                    if(gotPrimaryDevice && gotTargetDevice) {
                        // always false for secondary monitors, even when connected the same GPU as the primary monitor..
                        //bool isPrimaryDevice = ((primaryDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) != 0);

                        // according to docs for EDD_GET_DEVICE_INTERFACE_NAME DeviceID is supposed to contain 'something'.. seems to always be empty
                        //if(wcscmp(primaryDevice.DeviceID, targetDevice.DeviceID) == 0)) {
                        //    switchToFullscreen = true;
                        //}

                        // seems these registry key paths are per physical GPU apart from the last component which is an index
                        // so this should probably match monitors on the same physical GPU
                        for(size_t i = wcslen(primaryDevice.DeviceKey); i > 0; --i) {
                            if(primaryDevice.DeviceKey[i - 1] == L'\\')
                                break;
                            primaryDevice.DeviceKey[i - 1] = 0;
                        }
                        for(size_t i = wcslen(targetDevice.DeviceKey); i > 0; --i) {
                            if(targetDevice.DeviceKey[i - 1] == L'\\')
                                break;
                            targetDevice.DeviceKey[i - 1] = 0;
                        }
                        if(wcscmp(primaryDevice.DeviceKey, targetDevice.DeviceKey) == 0) {
                            switchToFullscreen = true;
                        }

                        // this only compares the name of the graphics card, identical for 2 GPUs of the same type..
                        //if(wcscmp(primaryDevice.DeviceString, targetDevice.DeviceString) == 0) {
                        //    switchToFullscreen = true;
                        //}
                    }
                }
            }

            if(switchToFullscreen) {
                GetWindowRect(hWnd, &savedWindowRect);
                if(GetWindowLongPtr(hWnd, GWL_STYLE) & WS_MAXIMIZE) {
                    savedWindowStyle = SetWindowLongPtr(hWnd, GWL_STYLE, WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED | WS_VISIBLE | WS_MAXIMIZE);
                    savedWindowExStyle = SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);
                }
                else {
                    savedWindowStyle = SetWindowLongPtr(hWnd, GWL_STYLE, WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPED | WS_VISIBLE);
                    savedWindowExStyle = SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);
                }
                SetWindowPos(hWnd, HWND_TOPMOST, x, y, w, h, SWP_FRAMECHANGED | SWP_DRAWFRAME);
                
                resultIsFullscreen = true;
            }
            else
                MessageBeep(MB_OK);
        }
    }
    else {
        SetWindowLongPtr(hWnd, GWL_STYLE, savedWindowStyle | WS_VISIBLE);
        SetWindowLongPtr(hWnd, GWL_EXSTYLE, savedWindowExStyle);
        HWND hWndInsertAfter = HWND_NOTOPMOST;
        if((savedWindowExStyle & WS_EX_TOPMOST) == WS_EX_TOPMOST)
            hWndInsertAfter = HWND_TOPMOST;
        SetWindowPos(
            hWnd,
            hWndInsertAfter,
            savedWindowRect.left,
            savedWindowRect.top,
            savedWindowRect.right-savedWindowRect.left,
            savedWindowRect.bottom-savedWindowRect.top,
            SWP_FRAMECHANGED | SWP_DRAWFRAME
        );
    }
    
    return resultIsFullscreen;
}

And use like this:

(Won't work for more than one window in it's current form as the toggleFillscreen function has statics to save the window placement..)

bool currentFullscreen = false;

...

if(toggleKeyPressed)
  currentFullscreen = toggleFillscreen(hWnd, !currentFullscreen);

EDIT: added a retain topmost style




#5294011 responsiveness of main game loop designs

Posted by on 29 May 2016 - 02:07 AM

In extreme cases you could improve perceived latency by drawing some things after the main game/simulation graphics, like if your game displays a mouse cursor. Even if your normal simulation and rendering was done as usual you could delay your swap/present and draw the cursor with an updated position right before the image is sent to the display, possibly with input data received several ms after the simulation was last updated. You could even buffer a few rendered frames, then go back and draw the cursor on top right before getting the image ready for presentation.

For OpenGL there is https://www.opengl.org/registry/specs/NV/wgl_delay_before_swap.txt to achieve minimal latency.




#5292631 Antialiasing in 3D with Core OpenGL (Windows)

Posted by on 20 May 2016 - 08:05 AM

You should be able to smooth edges with alpha-blended lines or similar after all your regular geometry is drawn (using depth-testing but not depth-writes). I would imagine GL_LINE_SMOOTH could work fine there with depth-testing..

Your question is tagged with OpenGL ES but the title says Windows, do you do OpenGL ES on desktop or regular OpenGL?




#5291579 Screen tearing when using OpenGL on Windows

Posted by on 14 May 2016 - 10:55 AM

VSync is often unreliable in windowed mode. If you create a window filling the entire screen with its client area and nothing obscuring it (WS_POPUP / WS_EX_TOPMOST) the Nvidia driver should switch to exclusive fullscreen mode.

For perfect VSync you actually want pre-rendered frames, so it should not be set to 1, that would break VSync if even a single frame happened to lag behind because of some background process or similar that is out of application control




#5290828 Manually loading OpenGL functions on Windows

Posted by on 09 May 2016 - 10:59 AM

I also use the fallback method to get pointers for the old functions.. I think that's what common extension libraries do as well, though I haven't actually checked..

If including a recent glcorearb.h header without the prototypes-define it won't define the old prototypes either, but will define the function pointer types for the 1.0 functions etc. as well. And with the prototypes-define it will add prototypes for all functions including newer ones.

On Linux all function pointers can be obtained with glXGetProcAddress so there no fallback is required.

If still linking to opengl32.lib one could of course do another fallback, something like mynamespace::glClear = ::glClear instead of GetProcAddress...




#5290766 bezier curve character

Posted by on 09 May 2016 - 02:46 AM

No.




#5290106 how good is rand() ?

Posted by on 04 May 2016 - 12:37 PM

 

"The rand function returns a pseudorandom integer in the range 0 to RAND_MAX (32767). "  so it returns 0 thru 32766, but not 32767, right?

 

Correct.  In modern math notation this type of function works with [0,x)  meaning it includes zero but stops just short of x.  This is also common in many other systems.  Graphics, for example, typically draw segments in the [A,B) form, starting exactly at A and ending the instant before B.

 

 

I tried this in VS2015 and it does return RAND_MAX.. is it not supposed to?

#include <iostream>
int main() {
	for(int i = 0; i < 200000; ++i) {
		int r = rand();
		if(r == RAND_MAX)
			std::cout << "MAX\n";
		else if(r == (RAND_MAX - 1))
			std::cout << "ALMOST\n";
		else if(r == 0)
			std::cout << "ZERO\n";
	}
}



#5290079 how good is rand() ?

Posted by on 04 May 2016 - 10:14 AM

Not too good..

If you Google for its implementation you get a few results. Something like next = (current * A) + B with overflow wrapping around.

 

EDIT: And it does return the value RAND_MAX at times, not just RAND_MAX-1.




#5289282 Lol, IDirectDrawSurface7::Blt changes Aero scheme to Windows 7 Basic

Posted by on 29 April 2016 - 12:26 PM

Not sure if it can be fixed.. OpenGL apps does that sometimes too. I think it's fixed in OpenGL by selecting a pixel-format with the PFD_SUPPORT_COMPOSITION flag. Maybe you can set the pixel-format on the window before creating the DD surface or somehow specify that flag in your caps when you create the primary surface..




#5287807 Window Creation in Win 7

Posted by on 20 April 2016 - 12:21 PM

glClearBufferfv and glClear both clear the buffer.. so glClear will overwrite glClearBufferfv with whatever color is set by glClearColor (defaults to black if glClearColor has never been called).




#5286828 Window Creation in Win 7

Posted by on 14 April 2016 - 02:03 AM

//The docs say the second arg to glClearBufferfv should be GL_DRAW_BUFFERi to clear and if it is GL_NONE then the operation does nothing. GL_NONE = 0, which you use, so try using GL_DRAW_BUFFER0 instead of 0 as the second arg.(incorrect)

Also remember to remove the glClear after your if-statement so that you don't re-clear it to the default clear color again before swap.

You seem to run into many of these weird problems caused by small mistakes in the details. Make it a habit to read the docs for the functions you use if they don't work right away, as well as use the debugger to single-step through the code, which is extremely helpful to solve these problems a hundred times faster than posting on GD.net about them.

I like this site for GL docs: http://docs.gl/

 

Do you use Visual Studio? If you don't use the debugger then start doing so, by default just press F9 on a particular line of code and then F5 to run with the debugger and the debugger will break on that line, where you can single-step with F10 and inspect variables with mouse-over. Faster than ExitProcess and std::cout.






PARTNERS