Wie ermittle ich alle möglichen Bildschirmauflösungen?

Previous topic - Next topic

Quentin

Bei einigen Spielen kann es sinnvoll sein, wenn man seinen "Kunden" die Wahl lässt, in welchen Bildschirmauflösungen sie/er das Spiel spielen will. GLBasic bietet zur Zeit hier noch keine Hilfestellung. Man kann zwar mit dem Befehl SETSCREEN diverse Auflösungen einstellen, kann sich dabei aber nicht wirklich sicher sein, daß diese auch auf allen möglichen Computern laufen.

Abhilfe schafft hier das Einbinden einer Funktion der Window-API, die die möglichen Auflösungen der Grafikkarte zurückliefert. Das folgende Beispielprogramm demonstriert die Verwendung dieser Funktion.

An dieser Stelle nochmal "special thanks to Gernot" für die Hilfe beim Aufruf der Funktion

Herzstück ist die Funktion GetScreenModes(), die auf zwei Arten aufgerufen werden kann.

GetScreenModes(0)    
--> liefert alle Auflösungen zurück, die von der Grafikkarte unterstützt werden. Hierbei können sich einzelne Auflösungen häufig wiederholen, da viele Auflösungen mit unterschiedlicher Farbtiefe und Bildwiederholfrequenz möglich sind (je nach Grafikkarte). Farbtiefe und Frequenz spielen für GLBasic noch keine Rolle, da sie mit den Standardbefehlen z.B. SETSCREEN nicht beeinflusst werden können (aber was nicht ist, kann ja noch kommen)

GetScreenModes(1)
--> liefert alle möglichen Auflösungen zurück, wobei doppelte Einträge bezüglich der Auflösung aus der Liste entfernt werden.

Code (glbasic) Select
// --------------------------------- //
// Project: ScreenModes
// Start: Thursday, July 05, 2007
// IDE Version: 4.237

// diese Struktur wird immer benötigt, wenn man die Funktion GetScreenModes() nutzen will
TYPE tScreenMode
  width
  height
  bits
  frequency
ENDTYPE
GLOBAL ScreenMode[] AS tScreenMode
GLOBAL scrmode AS tScreenMode


// Testprogramm Teil 1
LOADFONT "arial.bmp", 0     // <-- hier bitte eigenen Font einsetzen !!!!!!
GETFONTSIZE fontx, fonty
GetScreenModes(0)
PRINT "Alle möglichen Auflösungen:", 0, 0
y = 2 * fonty
FOREACH scrmode IN ScreenMode[]
  PRINT scrmode.width + " x " + scrmode.height + " Farbtiefe: "+scrmode.bits+" Bits " + "Frequenz: "+scrmode.frequency, 0, y
  INC y, fonty
NEXT
SHOWSCREEN
KEYWAIT

// Testprogramm Teil 2
GetScreenModes(1)
PRINT "Auflösungen ohne Doppelnennungen:", 0, 0
y = 2 * fonty
FOREACH scrmode IN ScreenMode[]
  PRINT scrmode.width + " x " + scrmode.height, 0, y
  INC y, fonty
NEXT
SHOWSCREEN
KEYWAIT

// Testprogramm Teil 3
LOCAL maxres = BOUNDS(ScreenMode[], 0) - 1
SETSCREEN ScreenMode[maxres].width, ScreenMode[maxres].height, 1
PRINT "Das ist die höchstmögliche Auflösung im Vollbildmodus", 0, 0
y = 2 * fonty
FOREACH scrmode IN ScreenMode[]
  PRINT scrmode.width + " x " + scrmode.height, 0, y
  INC y, fonty
NEXT
SHOWSCREEN
KEYWAIT

END

FUNCTION WeNeedOne:
ENDFUNCTION

// In __GLBASIC__ namespace, outside of functions make a pointer to a function
INLINE
    DECLARE_ALIAS(    user32_EnumDisplaySettings, "user32.dll", \
                    "EnumDisplaySettingsA", (const char*, unsigned int, void*), \
                    int);
ENDINLINE

FUNCTION EnumDisplaySettings: disp$, num

    LOCAL retcode

    INLINE
        struct DEVMODE {
              char dmDeviceName[32];
              short dmSpecVersion;
              short dmDriverVersion;
              short dmSize;
              short dmDriverExtra;
              long  dmFields;
              short dmOrientation;
              short dmPaperSize;
              short dmPaperLength;
              short dmPaperWidth;
              short dmScale;
              short dmCopies;
              short dmDefaultSource;
              short dmPrintQuality;
              short dmColor;
              short dmDuplex;
              short dmYResolution;
              short dmTTOption;
              short dmCollate;
              char dmFormName[32];
              short dmUnusedPadding;
              long dmBitsPerPel;
              long dmPelsWidth;
              long dmPelsHeight;
              long dmDisplayFlags;
              long dmDisplayFrequency;
        };
        DEVMODE devmode;
        devmode.dmSize = sizeof(DEVMODE);
        // if disp$ = "", pass NULL instead!
        if (user32_EnumDisplaySettings(LEN(disp_Str) ? disp_Str.c_str() : NULL, num, &devmode))
        {
        scrmode.width = devmode.dmPelsWidth;
        scrmode.height = devmode.dmPelsHeight;
        scrmode.bits = devmode.dmBitsPerPel;
        scrmode.frequency = devmode.dmDisplayFrequency;
        retcode = 1;
        }
        else
        {
        retcode = 0;
        }
    ENDINLINE

    RETURN retcode

ENDFUNCTION


// ------------------------------------------------------------- //
// -=#  SCREENMODES  #=-
// ------------------------------------------------------------- //
FUNCTION GetScreenModes: restrict

  LOCAL found = TRUE
  LOCAL mode = 0
  LOCAL notsorted = TRUE
  LOCAL count, i
  LOCAL swapmode AS tScreenMode

  // alle möglichen Auflösungen ermitteln. Wenn die Funktion als
  // Wiederholfrequenz eine "0" oder eine "1" zurückliefert, kann
  // Windows nicht genau feststellen, um welche Frequenz es sich handelt.
  // Sicherheitshalber bleibt dieser Modus dann unberücksichtigt.
  WHILE found
    IF EnumDisplaySettings("", mode)
      IF scrmode.frequency > 1
        DIMPUSH ScreenMode[], scrmode
      ENDIF
    ELSE
      found = FALSE
    ENDIF
    INC mode, 1
  WEND

  // Liste sortieren nach der Auflösung
  // Ein einfacher Bubble-Sort ist hier schnell genug
  count = BOUNDS(ScreenMode[], 0)
  WHILE notsorted
    notsorted = FALSE
    FOR i = 0 TO count - 2
      IF ScreenMode[i].width > ScreenMode[i+1].width AND _
         ScreenMode[i].height > ScreenMode[i+1].height
        swapmode = ScreenMode[i]
        ScreenMode[i] = ScreenMode[i+1]
        ScreenMode[i+1] = swapmode
        notsorted = TRUE
      ENDIF
    NEXT
  WEND
 
  // wenn gewünscht, werden alle doppelten Einträge entfernt
  IF restrict = 1
    swapmode.width = 0
    swapmode.height = 0
    FOREACH scrmode IN ScreenMode[]
      IF scrmode.width = swapmode.width AND scrmode.height = swapmode.height
        DELETE scrmode
      ENDIF
      swapmode = scrmode
    NEXT  
  ENDIF
 
ENDFUNCTION // SCREENMODES
Um diese Funktionalität in den eigenen Programmen zu nutzen, einfach das Coding in das eigene einbinden und die Testblöcke löschen.
Wer es gebrauchen kann, viel Spaß damit.

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Quentin

lol

Jawull!

Vorschlag Schranzor:
Du schreibst das Teil um, daß man statt dem TYPE DIM verwendet ;) dann ist das was für jeden Geschmack.

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Quentin

mir ist grad noch etwas aufgefallen.

Funktion EnumDisplaySettings (bzw. EnumDisplaySettingsA) liefert nur die Modi zurück, die auch vom angeschlossenen Monitor unterstützt werden. Versuchhalber habe ich einmal Funktion EnumDisplaySettingsEx (bzw. EnumDisplaySettingsExA) eingebaut, die wirklich alle Modi zurückgibt, die von der Grafikkarte unterstützt werden.

Bin mir jetzt nicht sicher, ob man das wirklich auf die Menschheit loslassen sollte. Zwar reizvoll, aber mit der ersten Variante wäre man wohl eher auf der sichern Seite.

Meinungen dazu?

Kitty Hello