OpenGL renderer for Windows

Started by Crimson Wizard, Wed 10/05/2017 23:24:15

Previous topic - Next topic

Crimson Wizard

I finally seem to make OpenGL work in any display mode under Windows:
http://www.mediafire.com/file/9gm6xt1d88xt45k/acwin-3.4.1-opengl.zip
http://www.mediafire.com/file/vh847jgpeqt6wq7/acwin-3.4.1-opengl2.zip
http://www.mediafire.com/file/5qsa7vi6d1ra27e/acwin-3.4.1-opengl3.zip


"OpenGL" should be available in drivers list in winsetup.

I believe understand making scenes in 3D better now... and also learnt that with 3D it is so much easier to do a lot of unnecessary and duplicating operations, with coordinate translations and camera positioning countering each other. Until you change something you do not notice that.


If I can find time, I may try to make it work on Linux too, because Linux port was suffering from lack of hardware-accelerated renderer all those years.

abstauber

Great news! At a first glance, it seems to run just fine.

Gurok

#2
This is really amazing, CW. I'm very impressed. REALLY amazing. Possibly solves a bunch of video card compatibility problems. I want to stress this before I tell you all the weird things I came across.

Some of my notes:
- The very first time I used it, OpenGL blanked the whole screen for a split second even though I chose to run the game windowed. I wasn't able to replicate this afterwards
- When running a 320x200 game, I cannot select my native resolution for full screen (1920x1200). The highest resolution listed is 1920x1080. The native resolution used to be listed at the top as Desktop Resolution. Running in a window and choosing to stretch to fit screen lists 1920x1138, which is the desktop work area. This seems correct though, as it's windowed
- I chose to run in OpenGL at 640x480, full screen. Any time there was a screenshot overlaid (my game uses screenshots a lot), the screenshot appeared vertically squished. In windowed-mode, screenshots were slightly distorted (maybe off by one pixel), but otherwise displayed correctly (aspect ratio was fine)
- Alt+tabbing out of a full-screen OpenGL game leaves me with the game running in a borderless window on my desktop. Alt+tabbing back in restores the borderless window to its full screen glory -- http://i.imgur.com/hzHgjKJ.jpg
- Alt+Enter from OpenGL full screen gives me a blank window (no output). This breaks OpenGL completely. Alt+Enter again will give me a full-screen display of white
    o Note: I'm guessing you just haven't implemented Alt+Enter support for this driver
- In OpenGL windowed or full screen, there is a line of distortion running down the centre of the screen. One of the centre columns is duplicated (seen here on the left of the mouse cursor where there's a double-width line)

- Or here again, with the shape of the "o" and "Y" in the prompt:

- The same is true vertically, see "Load Game":

- In OpenGL full screen, there is a standard Windows cursor visible in the letterbox portion of the screen
- Why is DirectX 5 called Allegro/DX5? Don't Direct3D and DirectX 5 both use Allegro (audio, keyboard, etc.)? I don't want to get into bikeshedding, but the old name was fine by me

Again, I am very much impressed with how well it all works. Please keep going! I would love to help, but it isn't really my area of expertise.
[img]http://7d4iqnx.gif;rWRLUuw.gi

Crimson Wizard

Quote from: Gurok on Thu 11/05/2017 14:32:10
- When running a 320x200 game, I cannot select my native resolution for full screen (1920x1200). The highest resolution listed is 1920x1080. The native resolution used to be listed at the top as Desktop Resolution.

This seem to be a winsetup issue in recent 3.4.1 Beta, also reported here:
http://www.adventuregamestudio.co.uk/forums/index.php?topic=54681.msg636560801#msg636560801

arj0n


Scavenger

I tried it out with one of my games, it worked better than I expected it to! There were a lot of bugs, however.


  • LightLevels don't work at all.
  • Palette colour 0 never works as a walkbehind colour, regardless what the mask says. It is always drawn behind characters.
  • FLCs don't play at all.
  • Changing the palette ends up with weirdly discoloured sprites sometimes, no effect at others: I believe this room fades the palette to white.
  • If additional background frames have a different palette to the main background frame, it doesn't get changed, like so
  • Any colours addressing palette slots is miscoloured, like this text box and this dynamic sprite box (the floor should be purple, I literally just cleared a sprite to that colour)
  • As expected, changing a palette slot's colour doesn't work correctly, but... it did seem to work for some things. It's inconsistent.

Crimson Wizard

#6
Quote from: Scavenger on Mon 15/05/2017 11:04:11
I tried it out with one of my games, it worked better than I expected it to! There were a lot of bugs, however.

8-bit games won't work properly with OpenGL or Direct3D yet; the fact that they run with OpenGL now is a fortunate side effect of another fix.
I believe there may be ways to deal with all those problems, but they are not my priority for the nearest release (unless someone else makes necessary fixes in time).

One thing though, FLC playback is currently broken in general, but that's related to updating AGS to Allegro 4.4.2. I am currently working on the fix.

Crimson Wizard

For the reference, I made this game that displays room with 1-pixel wide boundaries and random straight lines across the screen to test pixel distortion and other similar issues:
https://www.dropbox.com/s/e6pzj2dlk8malsg/test_precisesize.zip?dl=0

Crimson Wizard

#8
Uploaded new version:
http://www.mediafire.com/file/vh847jgpeqt6wq7/acwin-3.4.1-opengl2.zip

What has changed:
- Fixed mode switch; (mode reinitialization was breaking all sprites)
- Fixed pixel distortion, and missing rightmost and topmost pixel rows (OpenGL);
- Restored FLIC playback functionality (at least on Windows for now).

Regarding FLIC, I found out that it runs about double speed compared to software renderer (DD5). I know nothing about how it works, so ignore that for now... but what if its speed relies on speed of rendering too? That would not be easy to fix.

Other known issues:
- Direct3D misses bottom and rightmost pixel rows when rendering is done to texture (as opposed to "Render sprites at screen resolution" mode). I could not yet find the reason of this, but suspect is may have something to do with uneven scaling or floating point number mistakes when texture is stretched to screen (not sure). Curiously, if texture is made double size, this mistake goes away, but that would defeat the purpose of this mode.
- Alt+tabbing from OpenGL fullscreen makes OpenGL window stay. ... I just realized that could be because I do not remove "TOPMOST" window flag. I will look into this again.
- System cursor visible on black borders even in fullscreen mode. That is simply because OpenGL does not have "real" fullscreen mode, but renders on borderless window stretched to whole screen. Frankly IDK how to fix this. I tried ShowCursor(FALSE) on Windows, but that just did not work (that's an old API anyway).
- Something bad with screenshots, as reported by Gurok. Have not looked into that yet.

Snarky

Quote from: Crimson Wizard on Wed 17/05/2017 18:56:33
- System cursor visible on black borders even in fullscreen mode. That is simply because OpenGL does not have "real" fullscreen mode, but renders on borderless window stretched to whole screen. Frankly IDK how to fix this. I tried ShowCursor(FALSE) on Windows, but that just did not work (that's an old API anyway).

Can you avoid the issue by clamping the cursor position to the game region of the screen, like it would be in "real" fullscreen?

tzachs

Quote from: Crimson Wizard on Wed 17/05/2017 18:56:33
- System cursor visible on black borders even in fullscreen mode. That is simply because OpenGL does not have "real" fullscreen mode, but renders on borderless window stretched to whole screen. Frankly IDK how to fix this. I tried ShowCursor(FALSE) on Windows, but that just did not work (that's an old API anyway).

I don't think this is true, actually. OpenGL does not control the window as far as I understand, you control the window yourself (or with a library). You can see in my engine, for example, I use OpenGL on Windows and I support both modes.
As for hiding the cursor, I believe the library I use (OpenTK) just sets an empty bitmap as the cursor.

Crimson Wizard

#11
Quote from: tzachs on Thu 18/05/2017 14:48:37
Quote from: Crimson Wizard on Wed 17/05/2017 18:56:33
- System cursor visible on black borders even in fullscreen mode. That is simply because OpenGL does not have "real" fullscreen mode, but renders on borderless window stretched to whole screen. Frankly IDK how to fix this. I tried ShowCursor(FALSE) on Windows, but that just did not work (that's an old API anyway).

I don't think this is true, actually. OpenGL does not control the window as far as I understand, you control the window yourself

Well, this is what I meant. Probably worded it wrongly. I am creating the window myself, and modifying its style myself too.

Crimson Wizard

Another update:
http://www.mediafire.com/file/5qsa7vi6d1ra27e/acwin-3.4.1-opengl3.zip

- Fixed screenshots not working (probably);
- Hide OpenGL window when tabbing out of fullscreen.


NicolaGs

The issue I reported in the latest beta thread about missing resolutions is fixed ! :)
My first game : I Want Out!

Scorpiorus

I managed to track down that nasty flickering system cursor glitch in OpenGL letterbox modes, where it shows over black borders outside of the viewport area of our fullscreen window.

A short story is that the Allegro version (4.4.2-agspatch) we use with AGS Engine, forces Windows operating system (OS) to draw a system arrow cursor if the mouse cursor position is outside of the window's viewport area defined with the Allegro void set_mouse_range(int x1, int y1, int x2, int y2) function. And that arrow cursor showing is pretty hardcoded inside Allegro internals, I have to say. WinAPI's ::ShowCursor(FALSE) won't help, because it relies on OS' window message handling, and Allegro totally controls it with its own window procedure, simply doing it not the way ShowCursor(FALSE) wants...

At the moment, we pass our letterbox inner area coords into Allegro's set_mouse_range(). If OS' mouse cursor is inside that area, Allegro draws a customizable OS system cursor, which we have defined as show_os_cursor(MOUSE_CURSOR_NONE). But if it's outside, Allegro uses OS' arrow cursor, no matter what...

A quick solution would be to set the Allegro's mouse range to the whole screen/fullscreen-window even in letterbox modes. The player still won't be able to move their game-mouse-cursor over that black area, as it's restricted elsewhere in the engine. The only question remains -- if is it ok with the AGS engine to expand Allegro mouse range to the entire screen/window? I've tested it on Windows OS and it seemed to work fine. But I'm not sure about other ports of the engine... In theory, if it gets pushed back inside game viewport area by some other engine code (who let you out of the box?!), it shouldn't cause any trouble, should it?

And this is the suggested quick fix to consider:
(original source code: ags/Engine/device/mousew32.cpp)
Code: cpp

#include "gfx/graphicsdriver.h"
extern IGraphicsDriver *gfxDriver;

void Mouse::SetGraphicArea()
{
    //Rect dst_r = GameScaling.ScaleRange(play.viewport);
    //mgraphconfine(dst_r.Left, dst_r.Top, dst_r.Right, dst_r.Bottom);

    DisplayMode dm = gfxDriver->GetDisplayMode();
    mgraphconfine(0, 0, dm.Width-1, dm.Height-1); // <-- mgraphconfine() in its turn calls Allegro's set_mouse_range()
}



If the above fix or its variations won't be suitable, then the other methods would involve either directly patching Allegro source codes to replace the hardcoded arrow cursor with no_cursor, or trying to take remote control over its window message loop with void win_set_window(HWND wnd) and/or void win_set_msg_pre_proc(int (*proc)(HWND, UINT, WPARAM, LPARAM, int *retval)) functions, which is also tricky and would add more bulk into the AGS engine source code, because we then may have to copy Allegro window message handling function code over into the engine and mock up our own version of it, fixing the hardcoded cursor but also replicating everything else Allegro does with handling window messages.



To clarify the original issue, the Allegro version we use in AGS, basically does the following:

When we call allegro void set_mouse_range(int x1, int y1, int x2, int y2), it among other things stores the passed constraints in its internal global variables:
(source code: allegro-4.4.2-agspatch/src/win/wmouse.c)
Code: c

static int mouse_minx = 0;            /* mouse range */
static int mouse_miny = 0;
static int mouse_maxx = 319;
static int mouse_maxy = 199;


Next, Allegro tries to repeatedly update its mouse position variables (globals _mouse_x and _mouse_y) asking for a new cursor position values from Windows OS, and checking if the new position is within the bounds set by set_mouse_range, with the following macros/function.
Code: c
#define READ_CURSOR_POS(p)  // p - out param that's passed in to get Windows OS cursor position send back to the macros/function invoker
{                                                   
   GetCursorPos(&p);                                // use WinAPI to retrieve mouse cursor position into a temporary
                                                    
   p.x -= wnd_x;                                    
   p.y -= wnd_y;                                    
                                                    
   if ((p.x < mouse_minx) || (p.x > mouse_maxx) ||  // if mouse cursor position is outside of the area earlier defined with set_mouse_range()... 
       (p.y < mouse_miny) || (p.y > mouse_maxy)) {  
      if (_mouse_on) {                              // then...
         _mouse_on = FALSE;                         // mark the mouse as OUTSIDE; _mouse_on will be used within mouse_set_syscursor()
         wnd_schedule_proc(mouse_set_syscursor);    // queue up a background call into mouse_set_syscursor() via window message procedure
      }                                             
   }                                                
   else {                                           
      if (!_mouse_on) {                             
         _mouse_on = TRUE;                          
         wnd_schedule_proc(mouse_set_syscursor);    
      }                                             
      _mouse_x = p.x;                               
      _mouse_y = p.y;                               
   }                                                
}



Allegro's window message handling procedure to invoke the queued call into mouse_set_syscursor():
(source code: allegro-4.4.2-agspatch/src/win/wwnd.c)
Code: bf

// Window procedure for the Allegro window class.
static LRESULT CALLBACK directx_wnd_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
{
   ....
   if (message == msg_call_proc)
      return ((int (*)(void))wparam) (); // <---this is what really calls mouse_set_syscursor()
                                         // (NOTE: see the "Code:" tag to get the idea of how this works :PpPpPppp)
   if (message == msg_suicide) {
      DestroyWindow(wnd);
      return 0;
   }
   ....
   ....
   ....
   switch (message) {
      case WM_CREATE:
      case WM_DESTROY:
      case WM_SETCURSOR: // <---WinAPI's ShowCursor() works with this message (probably trying to disable it which is useless)
         if (!user_wnd_proc || _mouse_installed) {
            mouse_set_syscursor(); // <---another (direct) call into mouse_set_syscursor()
            return 1;  /* not TRUE */
         }
         break;
      case WM_ACTIVATE: ....
      case WM_TIMER: ....
      case WM_ENTERSIZEMOVE: ....
      case WM_EXITSIZEMOVE: ....
      case WM_MOVE: ....
      case WM_SIZE: ....
      ....
      case WM_INITMENUPOPUP: ....
      case WM_MENUSELECT: ....
      case WM_MENUCHAR : ....
      case WM_CLOSE: ....
   }
   ....
}



And finally, the cause of all the trouble -- mouse_set_syscursor():
(source code: allegro-4.4.2-agspatch/src/win/wmouse.c)
Code: c

// mouse_set_syscursor: [window thread]
// Selects whatever system cursor we should display.
int mouse_set_syscursor(void)
{
   HWND allegro_wnd = win_get_window();
   if ((mouse_dinput_device && _mouse_on) || (gfx_driver && !gfx_driver->windowed)) {
      SetCursor(_win_hcursor);  // <---this is what sets our NO_CURSOR thing when the cursor is inside the letterbox viewport area...
                                // ...because _win_hcursor == NULL, as we ordered with "show_os_cursor(MOUSE_CURSOR_NONE)"

      /* Make sure the cursor is removed by the system. */
      PostMessage(allegro_wnd, WM_MOUSEMOVE, 0, 0);
   }
   else
      SetCursor(LoadCursor(NULL, IDC_ARROW)); // <---the hardcoded ARROW CURSOR when outside! (SetCursor() is a WinAPI function)

   return 0;
}


The _mouse_on==FALSE condition gets us into the ARROW CURSOR branch. And !gfx_driver->windowed can't help us much, since technically we are in windowed mode where our window has no borders and is being stretched all over the screen.

The arrow cursor is only a fraction of a second outside of the inner viewport area before it gets pushed back by the AGS engine code.
Still that time is enough to get it noticed over a black portion of the screen...



Sorry for "a short story"... :p

p.s.
It keeps me amused reading Allegro manuals and source code. Lots of fun ^^
Spoiler

Code: c

int gfx_directx_show_mouse(struct BITMAP *bmp, int x, int y)
{
   if (hcursor) {
      _win_hcursor = hcursor;
   }
   if (_win_hcursor) {
      POINT p;

      SetCursor(_win_hcursor);
      /* Windows is too stupid to actually display the mouse pointer when we
       * change it and waits until it is moved, so we have to generate a fake
       * mouse move to actually show the cursor.
       */
      GetCursorPos(&p);
      SetCursorPos(p.x, p.y);
      return 0;
   }

   return -1;
}

[close]

SMF spam blocked by CleanTalk