display caps
Blitz3D Forums/Blitz3D Programming/display caps
| ||
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. |
| ||
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 ? |
| ||
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. |
| ||
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...(?) |
| ||
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. |
| ||
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.htmPublic 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. |
| ||
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. |
| ||
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. |
| ||
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 ... |
| ||
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 |
| ||
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 |