Archived

This topic is now archived and is closed to further replies.

Lightrocker

Getting aspect ratio of a monitor

Recommended Posts

Is it possible to retrieve the aspect ration of a monitor? I need this to project scenes and graphical user interfaces correctly to the screen, because there are some computers, which got a widescreen monitor. Dividing resolution width by height can result in wrong values (e.g. for 1280x1024 -> 5:4 and not 4:3). So I need a way to get the correct aspect ratio of the monitor. Thanks!

Share this post


Link to post
Share on other sites
1280/1024 == 5/4 == 1.25
1024/768 == 4/3 == 1.3333

else, the user has to specify it (means if the screen is native for 1280x1024 but runs at 1024x768, then the whole image would be deformed anyways)




If that''s not the help you''re after then you''re going to have to explain the problem better than what you have. - joanusdmentia

davepermen.net

Share this post


Link to post
Share on other sites
The aspect ration, which is set in a projection matrix, should not depend on the resolution but the real monitor. If there is a 4:3 monitor, then I want to set 4:3 also for non-4:3 resolutions like 1280x1024. And if there is a widescreen monitor, then I want to set its real aspect ratio and not the one of the user-defined resolution.

Is it possible? I did not find a method to get it.

Share this post


Link to post
Share on other sites
If you use a projection matrix built with a correct aspect ratio in mind and you don''t do any direct blitting of pixels, then you won''t have a problem. For 3d graphics, this is a non issue.

If you have a 2D interface or view images, things get weird.

Share this post


Link to post
Share on other sites
quote:
Original post by GameCat
If you use a projection matrix built with a correct aspect ratio in mind and you don''t do any direct blitting of pixels, then you won''t have a problem. For 3d graphics, this is a non issue.

It''s not a non-issue in the case the original poster was concerned about - widescreen monitors. The vast majority of users have standard 4:3 monitors but there are widescreen monitors out there with a 16:9 aspect ratio and also monitors that can be rotated to give a portrait display with a 3:4 aspect ratio. Monitors with non-standard aspect ratios may well have non-square pixels in many video modes so you can''t automatically calculate the correct aspect ratio based on the screen resolution (that doesn''t work in the inexplicably popular 1280x1024 screen mode on a standard monitor for example). As far as I know all displays are one of 4:3, 16:9 or 3:4 and 3:4 displays can always (I believe) be rotated to a standard 4:3 mode so the easiest thing to do is probably to let the user specify the aspect ratio of their monitor as either 4:3 or 16:9 and use that regardless of the resolution.

Share this post


Link to post
Share on other sites
mattnewport is right. I have no problems with displaying two-dimensional images or interfaces, if I have got the correct aspect ratio. I hoped, that there is a Windows API function, which returns the dimension or the aspect ratio of the monitor. GetDeviceCaps is not doing so.
So a user definition seems to be the only way, but I found out that my desktop TFT monitor has got a 5:4 aspect ratio while my CRT and my laptop TFT are 4:3 ones. Does anybody know, if there are some other monitors than 16:9, too?

Share this post


Link to post
Share on other sites
Out of curiosity, how did you verify that GetDeviceCaps does not work? I am asking since (years ago) I wrote an app where I wanted stuff to appear the same size on screen as the dimensions specified and I used it - seemed to work with the limited tests I did. Thus I simply cut/paste the code in my gl app thinking it would.

I did notice that ASPECTX/ASPECTY returns a small integer and probably is rounded off so I chose to use HORZSIZE/VERTSIZE (since they were in mm) and did my calculations off there.

I was assuming that (if the user has the proper monitor type in Display Properties) that everything would work fine.

Guess I should get off my lazy butt and haul this computer in the other room and try it on my widescreen DLT with that DVI connector aching to be used. Then I''ll know for sure.

Share this post


Link to post
Share on other sites
One thing I would suggest is to just use the desktop resolution that the user is normally running off. I know that''s not really what you want to do, but think about it this way.... If the user is running a res that gives a 4:3 aspect ratio, then that is what the user is comfortable with, and most likely is the proper ratio for his/her monitor.. If the user has a widescreen, then the ratio will most likely represent that..

Share this post


Link to post
Share on other sites
@JotDot:

GetDeviceCaps() using HORZSIZE/VERTSIZE results in 4:3 for resolutions like 640x480, 800x600, 1024x768... and 5:4 for 1280x1024 and not real monitor aspect ratio. I already tried that.

@mrhodes:

The GUI of Windows is working another way than I want for my games, in which the GUI should be arranged the same way for the same monitor in every possible resolution. In Windows there fits more information into the screen the higher the resolution is. I only want a higher quality for a higher resolution.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You ship with your software a square piece of plastic that people can put on their monitor.

At install you ask them to change some knobs until the piece fit the screen.

done.

LeGreg

Share this post


Link to post
Share on other sites
You people make things so complicated .
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);
float aspectRatio = (float)width/(float)height;

Share this post


Link to post
Share on other sites
Well, I thought widescreen monitors had more pixels horizontal resolution so it would work out. The few ones I''ve seen (very expensive older sgi TFT displays), did have square pixels, but I can''t say I''ve kept up. Those monitors had some funky Number 9 gfx-cards though, I don''t even know if modern cards support proper 16:9 resolutions.

FWIW, I can rotate my monitor and the windows gdi graphics stays correct. I don''t know if it works with games, it''s a pretty useless feature really. If the rotated display gets reported as 768x1024, then things should work out correctly in your projection matrix. Since things do seem to work correctly, I assume that is the case.

And really, if people use 1280x1024 on an 4:3 monitor, what can you do? They''ll have to live with stretched graphics. If they run their desktop in that res, they''re probably used to that look anyway. As a side note, I installed a brand new LCD for my parents today which was 1280x1024 but with correct aspect ratio (i.e the physical dimensions of the actual display area was 337x270mm). So don''t assume that everyone with 1280x1024 has non square pixels.

The really hard part is finding out what the best resolution setting is for that particular display. For example, games often select the highest possible refresh rate for a given resolution. This is generally bad for LCDs, since thay usually have so-so repsonse times and look best at 60Hz. The only thing that seems to work decently is to assume the desktop display mode is sane and use that.

Share this post


Link to post
Share on other sites
GameCat : "And really, if people use 1280x1024 on an 4:3 monitor, what can you do?"

I'd agree with that. As far as I know, Windows itself for example doesn't try to do anything different for non 4:3 compliant resolutions. Indeed, I've just tried 1600x900 which is of course 16:9 ratio, and the Windows were a bit squashed, because I'm using a 4:3 monitor.

I doubt you can programatically get the aspect ratio of the monitor, so the simplest solution I can think of would be to take from console games, which give the user the option of 4:3 or 16:9. You probably don't need to bother with 5:3 or anything else, since the physical aspect ratios of any monitor is going to be either 16:9 or 4:3 and nothing else. Someone might disagree on that... feel free![EDIT]Don't bother I'll do it myself! 1280x1024 LCD monitors actually have 5:4 physical aspect ratios to match their resolution. I guess you could give the user the option to give their aspect ratio manually, in addition to or instead of, being able to select 16:9/4:3.[/EDIT]

If a user selects 16:9, and a widescreen resolution such as 1600x900, or 4:3 with a res such as 1600x1200, everything works out correct. If they mix and match, for example selecting 4:3 and 1600x900, you can use it as a 1200x900 screen by ignoring each side. In this example, it would be 200 pixels off each side. A similar thing can done when you have 16:9 meets 1280x960 you just use 1280x960 of the screen. You simply use 1280x720 of the pixels, not using the top and bottom rows of 120 pixels.

Ro_Akira

[edited by - Ro_Akira on April 25, 2004 8:08:18 PM]

[edited by - Ro_Akira on April 25, 2004 8:09:13 PM]

[edited by - Ro_Akira on April 25, 2004 8:32:39 PM]

[edited by - Ro_Akira on April 25, 2004 8:33:26 PM]

Share this post


Link to post
Share on other sites
Ro_Akira> the whole point of detecting the aspect ratio is to prevent the user from selecting a resolution that will appear squashed on its screen? O_o

why not use that to generate the projection matrix from the fov? you let the user choose whatever resolution he wants, but you only change the aspect ratio internally, the user doesn''t even know about it.

with this, even rendering in 800*600 on a 16/9 screen (if the screen can handle it of course, as it will result in hugely squashed pixels) will produce non-squashed images

I thought that was why the OP wanted to get the monitor dimensions?

Share this post


Link to post
Share on other sites
> I doubt you can programatically get the aspect ratio of the monitor
Look up.

quote:
You probably don''t need to bother with 5:3 or anything else, since the physical aspect ratios of any monitor is going to be either 16:9 or 4:3 and nothing else. Someone might disagree on that... feel free!

:rolleyes: You''ve never heard of 16:10 monitors for DTP, or 5:3 widescreen laptops? My LCD screen is 5:4. I''ve seen some funky Sun boxes that have still other ratios.

quote:
1280 seems to be usually matched with something other than 960, which saddens me greatly (especially that some (all?!) 4:3 LCD monitors have native 1280x(non-960) resolutions) . It used to anger me greatly, but I''ve learned to live with it

LOL!

Share this post


Link to post
Share on other sites
hey,

This may seem a little bit simple, but shouldn''t it be the perogative of the user to select a good display mode. Widescreen monitors support strange resolutions (in my limited experience), and good graphics drivers should allow the system to access those.

If the user has their desktop at 1600x900 or whatnot, both directx and GL should accept that this mode is available, and ley the user run in this resolution. I''d personally calculate the aspect ratio from the mode the user picks. If someone''s running a widescreen monitor at 1280x1024, then they''re gonna have to put up with windows'' aspect ratios of squishing everything. I personally, would just assume square pixels and calculate the aspect ratio off the render window size. After all, that''s all most games do to my knowledge.

//end rant

CJM

Share this post


Link to post
Share on other sites
Jan - I was also thinking VESA's DDC EDID.

Problem is getting into VESA from 32 bit mode. It works in 16 bit - I tested that in debug. XP doesn't really like 32 bit apps going down to 16 bit.

So I quickly threw together some code that *might* work. Apparently windows grabs the EDID on boot and saves it in the registry. Here is a quick attempt at fetching it:

// Note: The code was made in the wee hours of the night. Thus it is sloppy code (ie: I noticed a bit late some routines use TCHAR etc and I don't). It also assumes a single monitor.

Give it a shot and let me know if it works. Hey.. if you like it - clean up the code and repost


#include <windows.h>

// GetMonitorSize() returns the size of the monitor in centimeters. A value of (0,0) is returned if unable.


SIZE GetMonitorSize(void)
{
HKEY hkDisplay;
SIZE size;
bool found=false;

size.cx=size.cy=0;

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Enum\\Display",0,KEY_READ,&hkDisplay)==ERROR_SUCCESS) {

int ddEnum;
DISPLAY_DEVICE dd;

for (dd.cb=sizeof dd,ddEnum=0; !found && EnumDisplayDevices(NULL,ddEnum,&dd,0); ++ddEnum) {
// dd.DeviceString holds the name of the adapter


if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
DISPLAY_DEVICE mon;

mon.cb=sizeof mon;
if (EnumDisplayDevices(dd.DeviceName,0,&mon,0)) {
// mon.DeviceString holds the name of the monitor


char buff[_MAX_PATH];
DWORD BuffLen=sizeof buff;

int DispSubKeyEnum=0;
do {
BuffLen=sizeof buff;
if (RegEnumKeyEx(hkDisplay,DispSubKeyEnum++,buff,&BuffLen,NULL,NULL,NULL,NULL)!=ERROR_SUCCESS) break;

HKEY hkClass;
if (RegOpenKeyEx(hkDisplay,buff,0,KEY_READ,&hkClass)!=ERROR_SUCCESS) break;

int dvEnum=0;
do {
BYTE DeviceID[_MAX_PATH];
BuffLen=sizeof buff;
if (RegEnumKeyEx(hkClass,dvEnum++,buff,&BuffLen,NULL,NULL,NULL,NULL)!=ERROR_SUCCESS) break;

HKEY hkDev;
DWORD hkType;
if (RegOpenKeyEx(hkClass,buff,0,KEY_READ,&hkDev)==ERROR_SUCCESS) {

DWORD DevLen=sizeof DeviceID;
RegQueryValueEx(hkDev,"HardwareID",NULL,&hkType,DeviceID,&DevLen);

if (hkType==REG_MULTI_SZ || hkType==REG_SZ) {

BYTE * p=DeviceID+strlen((char *)DeviceID);
p[0]='\\'; ++p;
DevLen=sizeof(DeviceID)-DevLen-1;

if (RegQueryValueEx(hkDev,"Driver",NULL,&hkType,p,&DevLen)==ERROR_SUCCESS) {

if (!strcmp(mon.DeviceID,(char *)DeviceID) && (hkType==REG_MULTI_SZ || hkType==REG_SZ)) {

HKEY hkDevParams;
if (RegOpenKeyEx(hkDev,"Device Parameters",0,KEY_READ,&hkDevParams)==ERROR_SUCCESS) {

BYTE edid[256];
DWORD len=sizeof edid;
if (RegQueryValueEx(hkDevParams,"EDID",NULL,&hkType,edid,&len)==ERROR_SUCCESS) {

size.cx=edid[21];
size.cy=edid[22];
found=true;

}
RegCloseKey(hkDevParams);
}
}
}
}
RegCloseKey(hkDev);
}
} while(!found);
RegCloseKey(hkClass);
} while(!found);
}
}
}
RegCloseKey(hkDisplay);
}

return size;
}


There. I'm off to bed.

ps: Who was the genius that thought of a status code with a name of ERROR_SUCCESS anyways?

[Edit by superpig: if you're going to paste code so large that it has me, at 1280x1024, scroll the page sideways, then please use [ source ] tags rather than [ code ] tags. Thanks! ]

[edited by - Superpig on April 26, 2004 4:44:00 AM]

Share this post


Link to post
Share on other sites
Superpig - You''re too fast

I couldn''t remember if it was source or code. I thought one wouldn''t work and I would simply edit if I was wrong. I was wondering why I didn''t get the nice box. Checking the source on another thread I realized it but you''re too fast on the draw

Share this post


Link to post
Share on other sites
Nice find, that's much nicer than mucking around with V86 + the VESA calls But mother mary, 13 nested blocks - ouch
Here's a cleaned-up version - only 5 levels


// useful for determining aspect ratio. not called by detect().

// if we fail, outputs are unchanged (assumed initialized to defaults)

int get_monitor_size(int& width_cm, int& height_cm)
{
DISPLAY_DEVICE adapter = { sizeof(DISPLAY_DEVICE) };
DISPLAY_DEVICE monitor = { sizeof(DISPLAY_DEVICE) };
// need to be distinct (EnumDisplayDevices requirement)


LONG err;
char key_name[256];
DWORD key_name_len;
DWORD key_type;

bool found = false;


// make sure EnumDisplayDevices is available (as pEnumDisplayDevicesA)

TRY(import_EnumDisplayDevices());

HKEY hkDisplay;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\Display", 0, KEY_READ, &hkDisplay) != 0)
return -1;

// we only look at the first monitor of the first display adapter

// attached to the desktop, assumed to be the primary monitor.


// for each display adapter

for(int adapter_idx = 0; !found; adapter_idx++)
{
// get display adapter

if(!pEnumDisplayDevicesA(0, adapter_idx, &adapter, 0))
break;
if(!(adapter.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
continue;

// get its associated monitor;

// will search for its DeviceID in the registry

if(!pEnumDisplayDevicesA(adapter.DeviceName, 0, &monitor, 0))
continue;

// for each class in registry

for(int class_idx = 0; !found; class_idx++)
{
// open next key

HKEY hkClass;
key_name_len = sizeof(key_name);
if(RegEnumKeyEx(hkDisplay, class_idx, key_name, &key_name_len, 0, 0, 0, 0) != 0)
break;
if(RegOpenKeyEx(hkDisplay, key_name, 0, KEY_READ, &hkClass) != 0)
break;

// for each device in registry

for(int dev_idx = 0; !found; dev_idx++)
{
// open next key

HKEY hkDev;
key_name_len = sizeof(key_name);
if(RegEnumKeyEx(hkClass, dev_idx, key_name, &key_name_len, 0, 0, 0, 0) != 0)
break;
if(RegOpenKeyEx(hkClass, key_name, 0, KEY_READ, &hkDev) != 0)
break;

// build dev_id: (%s\\%s, HardwareID, Driver)

// example: "Monitor\NEC6604\{4D36E96E-E325-11CE-BFC1-08002BE10318}\0001"

// will compare this against monitor.DeviceID

char dev_id[256];
DWORD dev_id_len = sizeof(dev_id);
err = RegQueryValueEx(hkDev, "HardwareID", 0, &key_type, (BYTE*)dev_id, &dev_id_len);
if(err != 0 || (key_type != REG_MULTI_SZ && key_type != REG_SZ))
goto skip_dev;
char* p = (char*)dev_id + strlen((const char*)dev_id);
*p++ = '\\';
dev_id_len = sizeof(dev_id) - dev_id_len;
err = RegQueryValueEx(hkDev, "Driver", 0, &key_type, (BYTE*)p, &dev_id_len);
if(err != 0 || (key_type != REG_MULTI_SZ && key_type != REG_SZ))
goto skip_dev;

// this (hkDev) is not the monitor you're looking for..

if(strcmp(monitor.DeviceID, (const char*)dev_id) != 0)
goto skip_dev;

HKEY hkDevParams;
if(RegOpenKeyEx(hkDev, "Device Parameters", 0, KEY_READ, &hkDevParams) != 0)
goto skip_dev;

// read EDID

BYTE edid[256];
DWORD edid_len = sizeof(edid);
if(RegQueryValueEx(hkDevParams, "EDID", 0, &key_type, edid, &edid_len) == 0)
{
width_cm = edid[21];
height_cm = edid[22];
found = true;
// break out of all loops; all keys will be closed

}

RegCloseKey(hkDevParams);

skip_dev:
RegCloseKey(hkDev);
}

RegCloseKey(hkClass);
}
}

RegCloseKey(hkDisplay);

return found? 0 : -1;
}


// edit: -code +source

[edited by - Jan Wassenberg on April 27, 2004 12:45:38 PM]

Share this post


Link to post
Share on other sites
Am I the only one who thinks those code boxes suck?

and for the record, I have a 16x10 aspect ratio monitor (Sony GDM-FW900)

-=[ Megahertz ]=-

Share this post


Link to post
Share on other sites