display caps

Blitz3D Forums/Blitz3D Programming/display caps

_33(Posted 2007) [#1]
Has anyone looked into ways to get the display capabilities from Windows or Direct X?

I'm talking about, say maximum color depth, maximum X and Y resolution, display aspect ratio?

If it was possible to have this information, the it would be easy to offer screen resolutions with proper aspect ratio to the user.

If anyone looked into this, I'm interested on the findings.

So far, I found this:
http://msdn2.microsoft.com/en-us/library/ms793908.aspx
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/ddraw7/directdraw7/ddref_76t3.asp

DDVIDEOPORTCAPS

The DDVIDEOPORTCAPS structure describes the capabilities and alignment restrictions of a hardware video port.

typedef struct _DDVIDEOPORTCAPS {
DWORD dwSize;
DWORD dwFlags;
DWORD dwMaxWidth;
DWORD dwMaxVBIWidth;
DWORD dwMaxHeight;
DWORD dwVideoPortID;
DWORD dwCaps;
DWORD dwFX;
DWORD dwNumAutoFlipSurfaces;
DWORD dwAlignVideoPortBoundary;
DWORD dwAlignVideoPortPrescaleWidth;
DWORD dwAlignVideoPortCropBoundary;
DWORD dwAlignVideoPortCropWidth;
DWORD dwPreshrinkXStep;
DWORD dwPreshrinkYStep;
DWORD dwNumVBIAutoFlipSurfaces;
DWORD dwNumPreferredAutoflip;
WORD wNumFilterTapsX;
WORD wNumFilterTapsY;
} DDVIDEOPORTCAPS;

Can't seem to find a way to use this in Blitz3D as it requires to use ddraw.lib, which I don't think it is possible to use directly from a Blitz3D app.

Cheers.


DGuy(Posted 2007) [#2]
Would either:

EnumDisplaySettings()
:

"The EnumDisplaySettings function retrieves information about one of the graphics modes for a display device. To retrieve information for all the graphics modes of a display device, make a series of calls to this function."


- Or -


IDirectDraw7::EnumDisplayModes() (sorry, no link):

"The IDirectDraw7::EnumDisplayModes method enumerates all the display modes that the hardware exposes through the DirectDraw object that are compatible with a provided surface description."

Give you the info you need ?


_33(Posted 2007) [#3]
Basically, I wish to know for example:
- Will the video display accept, say, 1600x1200 ?
- What is the video display's aspect ratio ? 5:4, 4:3, 16:9

When I say video display, I don't mean the graphics card, but the screen.

I think DDVIDEOPORTCAPS in Direct Draw is exactly what I was looking for. Just that I have no clue how to write DECLS for a system DLL (or any DLL).

If EnumDisplayModes enumerates the video display modes that it is capable of displaying, then THAT is what I need.


_33(Posted 2007) [#4]
Say I wanted to do a DECLS with this EnumDisplaySettings(), what would it look like? I'm just guessing:

user32.DECLS
.lib "user32.dll" 

api_EnumDisplaySettings% (lpszDeviceName%, iModeNum%, lpDevMode*) : "EnumDisplaySettingsA" 


I'd probably supply GfxDriverName$ to lpszDeviceName, sequentially loop iModeNum, and retrieve the info from lpDevMode...(?)


Gabriel(Posted 2007) [#5]
According to Microsoft, the most reliable way to retrieve the monitor's aspect ratio is to get the desktop resolution and calculate the aspect ratio of that. This, of course, presupposes that the user is using the ideal resolution, which they may well not be. Personally, I would take the *highest* resolution that comes back with EnumDisplaySettings and calculate the aspect ratio of that as I think it's less likely that the monitor's top resolution is a non-native aspect ratio than that the user has set a desktop resolution with a non-native aspect ratio.

I mean I kinda suspect a lot of people with 1280x1024 monitors will have set 1024x768 as their desktop resolution, if only because anything about 1024 is slow in games and thy don't want to have the monitor switching every time they play a game. I could be wrong.


_33(Posted 2007) [#6]
If only I could define a proper type and retrieve lpDevMode into that... I've got the VB type but I can't transcribe that into blitz code. http://vbnet.mvps.org/index.html?code/enums/enumdisplay.htm
Public Type DEVMODE
   dmDeviceName      As String * CCDEVICENAME
   dmSpecVersion     As Integer
   dmDriverVersion   As Integer
   dmSize            As Integer
   dmDriverExtra     As Integer
   dmFields          As Long
   dmOrientation     As Integer
   dmPaperSize       As Integer
   dmPaperLength     As Integer
   dmPaperWidth      As Integer
   dmScale           As Integer
   dmCopies          As Integer
   dmDefaultSource   As Integer
   dmPrintQuality    As Integer
   dmColor           As Integer
   dmDuplex          As Integer
   dmYResolution     As Integer
   dmTTOption        As Integer
   dmCollate         As Integer
   dmFormName        As String * CCFORMNAME
   dmUnusedPadding   As Integer
   dmBitsPerPel      As Integer
   dmPelsWidth       As Long
   dmPelsHeight      As Long
   dmDisplayFlags    As Long
   dmDisplayFrequency As Long
End Type


These two (dmPelsWidth, dmPelsHeight) are the resolution.

So, what I came up with, is a way to scan through the bank that I end up reading in devmode:
devmode% = CreateBank (1000)

rc% = api_EnumDisplaySettings (0, 1, devmode%)
Print rc
Print "Device Name :" + get_string_from_bank$(devmode)
WaitKey()


Function get_string_from_bank$(bank%, offset% = 0)
   a$ = ""
   eol% = False
   While eol = False
      char% = PeekByte(bank, offset)
      If char = 0 Then
         eol = True
      Else
         a$ = a$ + Chr$(char)
         offset = offset + 1
      EndIf
   Wend
   Return a$
End Function

It's just a starting point.


DGuy(Posted 2007) [#7]
I understand this is just first draft code, but a couple of points to keep in mind (from MSDN, bolding mine):

When you call EnumDisplaySettings with iModeNum set to zero, the operating system initializes and caches information about the display device. When you call EnumDisplaySettings with iModeNum set to a non-zero value, the function returns the information that was cached the last time the function was called with iModeNum set to zero.

and

Before calling EnumDisplaySettings, set the dmSize member to sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size, in bytes, of the additional space available to receive private driver data.



_33(Posted 2007) [#8]
Thanks DGuy, I'll look into this tomorrow. I didn't look properly, the 2 strings in the DEVMODE make 32 bytes each, so this is a fixed value. I tought they were variable in length, that is why I was checking for nulls in my string function. Resolutions are easy to catch, but I'm not sure if these are what I wanted in the first place, since EnumDisplaySettings is giving resolution sup to 2048x1536, which my monitor clearly can't display, at any refresh rate. But I have to look into the flags to see if something indicates that it's out of the monitor's range.

Graphics 1024,768,32,2
devmode% = CreateBank (200)
mode% = 0
rc% = 1
modes_in_page% = 0
While rc
   rc% = api_EnumDisplaySettings (0, mode%, devmode%)
   BitsPerPel% = PeekShort (devmode, 104)
   PelsWidth% = PeekInt (devmode, 108)
   PelsHeight% = PeekInt (devmode, 112)
   DisplayFrequency% = PeekShort (devmode, 120)
   If BitsPerPel >= 4 And DisplayFrequency > 1 Then
      Select BitsPerPel
         Case 4  :    bppType$ = "16 Color   "
         Case 8  :    bppType$ = "256 Color  "
         Case 16 :    bppType$ = "High Color "
         Case 24, 32: bppType$ = "True Color "
         Default :    bppType$ = ""
      End Select
      Write bppType$
      Write Str$(PelsWidth) + "x" + Str$(PelsHeight) + " "
      Write Str$(DisplayFrequency) + "hz"
      Print ""
   EndIf
   mode = mode + 1
Wend
WaitKey()
End


I'll try to apply what MS recommends. Thanks for the find.


DGuy(Posted 2007) [#9]
But I have to look into the flags to see if something indicates that it's out of the monitor's range.

Take a look at ChangeDisplaySettings. Particularly the CDS_TEST (tests if the requested graphics mode could be set) flag. May be what you need ...


_33(Posted 2007) [#10]
Keen eye DGuy, I'll see if I can try this out. I still have to check EnumDisplaySettingsEx, but this seems pretty much exactly what I could use to have proper result.

Since I'm quite positive that Blitz3D is 60hz only, I think it's going to be quitre easy to actually pass through the valid modes. Here's the test code for 60hz and 16M colors only:

Graphics 1024,768,32,2
devmode% = CreateBank (200)
mode% = 0
rc% = 1
modes_in_page% = 0
entries_per_line% = 0
While rc
   PokeShort(devmode,36, 200)
   rc% = api_EnumDisplaySettings (0, mode%, devmode%)
   BitsPerPel% = PeekShort (devmode, 104)
   PelsWidth% = PeekInt (devmode, 108)
   PelsHeight% = PeekInt (devmode, 112)
   DisplayFrequency% = PeekShort (devmode, 120)
   If BitsPerPel >= 4 And DisplayFrequency > 1 Then
      Select BitsPerPel
         Case 4  :    bppType$ = "16  "
         Case 8  :    bppType$ = "256 "
         Case 16 :    bppType$ = "65K "
         Case 24, 32: bppType$ = "16M "
         Default :    bppType$ = ""
      End Select
      If DisplayFrequency = 60 And bpptype$ = "16M " Then
         entry$ = LSet$(Str$(mode),4) + bppType$ + Str$(PelsWidth) + "x" + Str$(PelsHeight) + " " + Str$(DisplayFrequency) + "hz"
         Write LSet$(entry$, 25)
         entries_per_line = entries_per_line + 1 : If entries_per_line = 5 Then entries_per_line = 0 : Print ""
      EndIf
   EndIf
   mode = mode + 1
Wend
WaitKey()
End

It looks pretty much like what you get when you do this sort of thing, which only uses Blitz3D commands:
Function Init_gfxmodes(no_16bit% = True)
   term\gfxmodes = 0
   For mode_id% = 1 To CountGfxModes3D()
      If (no_16bit = True And GfxModeDepth(mode_id) = 32) or no_16bit = False Then
         term\gfxmodes = term\gfxmodes + 1
         term\gfx[term\gfxmodes]\mode   = mode_id
         term\gfx[term\gfxmodes]\width  = GfxModeWidth(mode_id)
         term\gfx[term\gfxmodes]\height = GfxModeHeight(mode_id)
         term\gfx[term\gfxmodes]\depth  = GfxModeDepth(mode_id)
      EndIf
   Next
End Function



_33(Posted 2007) [#11]
Here's the user32.DECLS:
api_ChangeDisplaySettings% (lpDevMode*, dwflags%) :"ChangeDisplaySettingsA"
api_EnumDisplaySettings% (lpszDeviceName%, iModeNum%, lpDevMode*) : "EnumDisplaySettingsA"


And here's the previous code with CDS_TEST used on ChangeDisplaySettings. All resolutions with an asterisk should be the compatible ones. But it makes no sense as they all appear to be compatible! I may have coded this wrong?
Graphics 1024,768,32,2
devmode% = CreateBank (200)
mode% = 0
rc% = 1
modes_in_page% = 0
entries_per_line% = 0
While rc
   PokeShort(devmode,36, 200)
   rc% = api_EnumDisplaySettings (0, mode%, devmode%)
   BitsPerPel% = PeekShort (devmode, 104)
   PelsWidth% = PeekInt (devmode, 108)
   PelsHeight% = PeekInt (devmode, 112)
   DisplayFrequency% = PeekShort (devmode, 120)
   If BitsPerPel >= 4 And DisplayFrequency > 1 Then
      Select BitsPerPel
         Case 4  :    bppType$ = "16  "
         Case 8  :    bppType$ = "256 "
         Case 16 :    bppType$ = "65K "
         Case 24, 32: bppType$ = "16M "
         Default :    bppType$ = ""
      End Select
      If DisplayFrequency = 60 And bpptype$ = "16M " Then
         If api_ChangeDisplaySettings(devmode, 2) = 0 Then compatible$ = "*" Else compatible$ = " "
         entry$ = LSet$(Str$(mode),4) + bppType$ + compatible$ + Str$(PelsWidth) + "x" + Str$(PelsHeight) + " " + Str$(DisplayFrequency) + "hz"
         Write LSet$(entry$, 25)
         entries_per_line = entries_per_line + 1 : If entries_per_line = 5 Then entries_per_line = 0 : Print ""
      EndIf
   EndIf
   mode = mode + 1
Wend
WaitKey()
End


This doesn't seem to be what I wanted in the first place. I suspect this doesn't test for monitor compatibility, but more for graphics adapter compatibility.

Also I'm trying to call DirectDraw from Blitz3D and am wondering if a DECLS like this would make proper calls to what I need:
ddraw.DECLS
.lib "ddraw.dll" 

api_DirectDrawCreateEx(lpGUID*, lplpDD*, iid%, pUnkOuter*) : "DirectDrawCreateEx"
api_EnumVideoCallback(lpDDVideoPortCaps*, lpContext*) : "EnumVideoCallback"

http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/ddraw7/directdraw7/ddref_0zp3.asp

or maybe I should use DirectDrawEnumerate:
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/ddraw7/directdraw7/ddref_2yif.asp

It's hard to make sense out of all this! Are all the DirectDraw functions accessible only through what MSDN calls Interfaces?
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/ddraw7/directdraw7/ddref_3647.asp
* IDDVideoPortContainer
* IDirectDraw7
* IDirectDrawClipper
* IDirectDrawColorControl
* IDirectDrawGammaControl
* IDirectDrawPalette
* IDirectDrawSurface7
* IDirectDrawVideoPort