knowing the aspect ratio of users monitor - aspect-ratio

as a webpage developer i would like to know if there is any way i can know the aspect ratio of users monitor(those who are using a PC or a Mac). i want to forward different pages(in terms of their page layout) to different users based on their screen size and aspect ratio. is this possible ?

Why not retrieve their desktop size and find the ratio yourself?
var ratio = screen.width / screen.height;
if (ratio == (4/3)) {
// 4:3 ratio
} else if (ratio == (3/2)) {
// 3:2
} else if (ration == (16/9)) {
// 16:9
} /* etc. */

Related

Magnification Below 125% Default Win API (Between 101 - 124%)

I am looking into the windows magnification api and I have been playing around with it, but I have a problem with the magnification defaults, Windows only allows you to increment in 25%'s at the lowest. Is it possible for me to increase this perhaps 1-5% at a time? Perhaps increase by one percent with the mouse scroll in and out?
Windows Lowest 25% Default][1]
Thanks in advance for your assistance.
int xDlg = (int)((float)GetSystemMetrics(SM_CXSCREEN) * (1.0 - (1.0 / magnificationFactor)) / 2.0);
int yDlg = (int)((float)GetSystemMetrics(SM_CYSCREEN) * (1.0 - (1.0 / magnificationFactor)) / 2.0);
BOOL successSet = MagSetFullscreenTransform(magnificationFactor, xDlg, yDlg);
if (successSet)
{
BOOL fInputTransformEnabled;
RECT rcInputTransformSource;
RECT rcInputTransformDest;
if (MagGetInputTransform(&fInputTransformEnabled, &rcInputTransformSource, &rcInputTransformDest))
{
if (fInputTransformEnabled)
{
SetInputTransform(hwndDlg, fInputTransformEnabled);
}
}
}
successSet == false; when it isn't 1.1 anything lower fails and I realised 1.1 = 125% zoom.
There is no such limit in the magnification API. The limitations you see on-screen were chosen by the UI developer.
Both MagSetFullscreenTransform and MagSetWindowTransform take float input arguments. There are no restrictions as far as the magnification factor resolution goes, as long as it is at least 1.0f and no larger than the upper bound.

Isometric Collision - 'Diamond' shape detection

My project uses an isometric perspective for the time being I am showing the co-ordinates in grid-format above them for debugging. However, when it comes to collision/grid-locking of the player, I have an issue.
Due to the nature of sprite drawing, my maths is creating some issues with the 'triangular' corner empty areas of the textures. I think that the issue is something like below (blue is what I think is the way my tiles are being detected, whereas the red is how they ideally should be detected for accurate roaming movement on the tiles:
As you can see, the boolean that checks the tile I am stood on (which takes the pixel central to the player's feet, the player will later be a car and take a pixel based on the direction of movement) is returning false and denying movement in several scenarios, as well as letting the player move in some places that shouldn't be allowed.
I think that it's because the cutoff areas of each texture are (I think) being considered part of the grid area, so when the player is in one of these corner areas it is not truly checking the correct tile, and so returning the wrong results.
The code I'm using for creating the grid is this:
int VisualComponent::TileConversion(Tile* tileToConvert, bool xOrY)
{
int X = (tileToConvert->x - tileToConvert->y) * 64; //change 64 to TILE_WIDTH_HALF
int Y = (tileToConvert->x + tileToConvert->y) * 25;
/*int X = (tileToConvert->x * 128 / 2) + (tileToConvert->y * 128 / 2) + 100;
int Y = (tileToConvert->y * 50 / 2) - (tileToConvert->x * 50 / 2) + 100;*/
if (xOrY)
{
return X;
}
else
{
return Y;
}
}
and the code for checking the player's movement is:
bool Clsentity::CheckMovementTile(int xpos, int ypos, ClsMapData* mapData) //check if the movement will end on a legitimate road tile UNOPTIMISED AS RUNS EVERY FRAME FOR EVERY TILE
{
int x = xpos + 7; //get the center bottom pixel as this is more suitable than the first on an iso grid (more realistic 'foot' placement)
int y = ypos + 45;
int mapX = (x / 64 + y / 25) / 2; //64 is TILE-WIDTH HALF and 25 is TILE HEIGHT
int mapY = (y / 25 - (x / 64)) / 2;
for (int i = 0; i < mapData->tilesList.size(); i++) //for each tile of the map
{
if (mapData->tilesList[i]->x == mapX && mapData->tilesList[i]->y == mapY) //if there is an existing tile that will be entered
{
if (mapData->tilesList[i]->movementTile)
{
HAPI->DebugText(std::to_string(mapX) + " is the x and the y is " + std::to_string(mapY));
return true;
}
}
}
return false;
}​
I'm a little stuck on progression until having this fixed in the game loop aspect of things. If anyone thinks they either know the issue from this or might be able to help it'd be great and I would appreciate it. For reference also, my tile textures are 128x64 pixels and the math behind drawing them to screen treats them as 128x50 (to cleanly link together).
Rather than writing specific routines for rendering and click mapping, seriously consider thinking of these as two views on the data, which can be transformed in terms of matrix transformations of a coordinate space. You can have two coordinate spaces - one is a nice rectangular grid that you use for positioning and logic. The other is the isometric view that you use for display and input.
If you're not familiar with linear algebra, it'll take a little bit to wrap your head around it, but once you do, it makes everything trivial.
So, how does that work? Your isometric view is merely a rotation of a bog standard grid view, right? Well, close. Isometric view also changes the dimensions if you're starting with a square grid. Anyhow: can we just do a simple coordinate transformation?
Logical coordinate system -> display system (e.g. for rendering)
Texture point => Rotate 45 degrees => Scale by sqrt(2) because a 45 degree rotation changes the dimension of the block by sqrt(1 * 1 + 1 * 1)
Display system -> logical coordinate system (e.g. for mapping clicks into logical space)
Click point => descale by sqrt(2) to unsquish => unrotate by 45 degrees
Why?
If you can do coordinate transformations, then you'd be dealing with a pretty bog-standard rectangular grid for everything else you write, which will make your any other logic MUCH simpler. Your calculations there won't involve computing angles or slopes. E.g. now your "can I move 'down'" logic is much simpler.
Let's say you have 64 x 64 tiles, for simplicity. Now transforming a screen space click to a logical tile is simply:
(int, int) whichTile(clickX, clickY) {
logicalX, logicalY = transform(clickX, clickY)
return (logicalX / 64, logicalY / 64)
}
You can do checks like see if x0,y0 and x1,y1 are on the same tile, in the logical space by someting as simple as:
bool isSameTile(x0, y0, x1, y1) {
return floor(x0/64) == floor(x1/64) && floor(y0/64) == floor(y1/64)
}
Everything gets much simpler once you define the transforms and work in the logical space.
http://en.wikipedia.org/wiki/Rotation_matrix
http://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation
http://www.alcove-games.com/advanced-tutorials/isometric-tile-picking/
If you don't want to deal with some matrix library, you can do the equivalent math pretty straightforwardly, but if you separate concerns of logic management from display / input through these transformations, I suspect you'll have a much easier time of it.

How to correctly manage positions of objects for application compatible with iPhone, iPad iPod different resolutions

I'm developing game and I have general question about managing all positions of hundreds of objects.Previously it was a lot easier because there was only one point which was universal for iPhone 3, iPhone 4 iPod touche etc. Now there are different aspect ratios and different resolutions.
I want my game to be compatible with all major devices which are:
iPhone5, iPhone5s, iPhone5c 1136 x 640 ~16:9
iPod 5Gen 1136 x 640 ~16:9
iPhone4, iPhone4s 960 × 640 3:2
iPod 4Gen 960 × 640 3:2
iPad 3Gen, iPad 4Gen, iPad Air 2048 × 1536 4:3
iPad Mini Second Gen 2048 × 1536 4:3
iPad2 1024 × 768 4:3
iPad Mini First Gen 1024 × 768 4:3
First of all I want to correctly identify these Devices. Currently I'm doing this
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) to differentiate ipad and
if ((screenHeight==568) && (uiscale==2.0f)) {
// it is iphone5
}
to find iphone5. With same approach I'm going to identify different iPads. is it correct way? Now about coordinates currently I have positions calculation block in init of each scene. I'm trying to have relative coordinates to screen size, for example posY=winSize.height*0.5f; not to hard code each coordinate. I want to have some shared instance where will be defined once what kind of device is running application, what is screen size etc. and all such calculations will took place for example mainMenuPlayButtonX=winSize.height*0.5f; or gameScenePauseButtonX=winSize.height*0.5f; and etc. will it be correct? Please share what to do.
There are (at least) two major problems with different screen geometries.
Art sized for a particular geometry will usually not work out properly when you try to use it in different one (e.g. landscape for portrait, 4:3 vs. 16:9, etc.).
The positions of items on the screens move around and may not always look good.
Let's do the first one first (this is from this post):
Artwork Sizing
I have made several Apps for iOS and have "the aspect ratio problem" problem with graphics for buttons and backgrounds when going between iPhone and iPad, which have different aspect ratios. Throw orientation into the mix as well.
I use Gimp, Inkscape, Spine, Cocos2d-x, and lots of other tools for reference.
As far as I know, the general options for "different screen geometry" issues are (if there are others, let me know):
Different graphics for each geometry.
Scaling the graphics proportionally for the geometry.
Same graphics for all, scale proportionally based on one dimension
and then place graphics on screen using percentages for fixed stuff.
Option 1 means extra work...not acceptable for a hobbyist or indie (like me) developer.
Option 2 usually looks like junk. Frustration and sadness usually ensue.
Option 3 is the option I use most often. I find that occasionally I have to add small changes (read: hacks) based on the device or geometry. In the case of iOS, it is not too bad, because there are only two geometries to deal with. In the case of Android, where there are lots of different tablet geometries, you could cut it down by working with ranges of geometries and picking a fixed orientation for your application.
At the end of the day, proportional scaling by a single dimension (height or width) has gotten me the most bang for the buck.
I usually make the graphics a little "bigger" than I will need so I only have to scale down. This consumes a bit more memory, but I re-use a lot, use sprite sheets, etc. There is a definite tradeoff with managing every bit of memory (which you have to do in a large AAA rated game) and what you can get away with in a small independent application. I am not encouraging sloppiness or memory mismanagement; I'm encouraging balancing the resources against the developmental needs of simplicity...making the same graphics for different situations burns a lot of daylight.
UI Element Positions
This is specifically for items like menu buttons, fire buttons, joysticks, etc. In general, I create a table which contains the scale and position in percentage of screen size for the nominal screen proportion. When each element is created, it looks up its nominal information in the table and uses it.
Then I create a few copies of this for other major geometries and change the pointer to the table at runtime. So I may have a 4:3 "portrait" table, a 19:16 "landscape" table, etc. During development I tweak the "other tables" as needed. I usually only need to create a few of these.
** This is an example of this approach: **
DeviceGeometry.h
#ifndef __MultiDimension__DeviceGeometry__
#define __MultiDimension__DeviceGeometry__
#include "cocos2d.h"
using namespace cocos2d;
class DeviceGeometry
{
public:
DeviceGeometry();
virtual ~DeviceGeometry();
typedef enum
{
SG_1024_768 = 0,
SG_16_9,
SG_MAX
} SCREEN_GEOMETRY_T;
typedef enum
{
SE_JOYSTICK = 0,
SE_LEFT_FIRE_1,
SE_LEFT_FIRE_2,
SE_EXIT,
SE_MAX
} SCREEN_ELEMENTS_T;
typedef struct
{
// You can include any other pieces of information
// here as well to fine tune the placement or
// use of the element.
SCREEN_ELEMENTS_T element;
CCPoint position;
float scale;
} SCREEN_ELEMENT_DATA_T;
// Call this when you need to change to a different
// geometry.
void Init(SCREEN_GEOMETRY_T geometry);
CCPoint GetPosition(SCREEN_ELEMENTS_T element);
float GetScale(SCREEN_ELEMENTS_T element);
protected:
private:
SCREEN_ELEMENT_DATA_T* _elements;
};
#endif /* defined(__MultiDimension__DeviceGeometry__) */
DeviceGeometry.cpp
#include "DeviceGeometry.h"
DeviceGeometry::SCREEN_ELEMENT_DATA_T _elements_1024_768[DeviceGeometry::SE_MAX] =
{
{ DeviceGeometry::SE_JOYSTICK, ccp(0.8f, 0.1f), 1.0f },
{ DeviceGeometry::SE_LEFT_FIRE_1, ccp(0.2f, 0.075f), 1.0f },
{ DeviceGeometry::SE_LEFT_FIRE_2, ccp(0.2f, 0.15f), 1.0f },
{ DeviceGeometry::SE_EXIT, ccp(0.1f, 0.9f), 1.0f },
};
DeviceGeometry::SCREEN_ELEMENT_DATA_T _elements_16_9[DeviceGeometry::SE_MAX] =
{
{ DeviceGeometry::SE_JOYSTICK, ccp(0.9f, 0.1f), 1.0f },
{ DeviceGeometry::SE_LEFT_FIRE_1, ccp(0.15f, 0.075f), 1.0f },
{ DeviceGeometry::SE_LEFT_FIRE_2, ccp(0.15f, 0.15f), 1.0f },
{ DeviceGeometry::SE_EXIT, ccp(0.125f, 0.925f), 1.0f },
};
DeviceGeometry::DeviceGeometry()
{
_elements = _elements_1024_768;
}
DeviceGeometry::~DeviceGeometry()
{
}
void DeviceGeometry::Init(SCREEN_GEOMETRY_T geometry)
{
switch(geometry)
{
case SG_1024_768:
_elements = _elements_1024_768;
break;
case SG_16_9:
_elements = _elements_16_9;
break;
default:
assert(false);
break;
}
}
CCPoint DeviceGeometry::GetPosition(SCREEN_ELEMENTS_T element)
{
// Sanity checks.
assert(element < SE_MAX);
assert(_elements[element].element == element);
if(_elements[element].element == element)
{
CCPoint& pt = _elements[element].position;
CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
return ccp(pt.x * scrSize.width, pt.y * scrSize.height);
}
return ccp(0,0);
}
float DeviceGeometry::GetScale(SCREEN_ELEMENTS_T element)
{
// Sanity checks.
assert(element < SE_MAX);
assert(_elements[element].element == element);
if(_elements[element].element == element)
{
return _elements[element].scale;
}
return 1.0;
}
Game Element Positions
This is for the position of all the major game elements themselves...spaceships, meteors, asteroids, etc. For this, I use a Viewport approach. This is a bit more complicated. See this post for details.
Was this helpful?
Are you aware that Retina and non-Retina devices use the same coordinate system (points, not pixels)? So you truly only have 3 different screen sizes to support: iPhone, iPhone widescreen and iPad.
Furthermore you can design the iPhone version as if it were running on iPhone widescreen, just make sure you don't display crucial information or user interface elements at the borders where they might be cut off. Alternatively you can decide for individual elements to position them relative to the current device's screen border, which would move them further apart on widescreen but will keep them at the border on regular iPhone screens.

Calculate QGraphicsTextItem font size based on scale

I have QGraphicsTextItem objects on a QGraphicsScene. The user can scale the QGraphicsTextItem objects by dragging the corners. (I am using a custom "transformation editor" to do this.) The user can also change the size of the QGraphicsTextItem by changing the font size from a property panel. What I would like to do is unify these so that when the user scales the object by dragging the corner with the mouse, behind the scenes it actually is calculating "What size font is necessary to make the resulting object fit the target size and keep the scale factor at 1.0?"
What I am doing now is letting the object scale as normal using QGraphicsItem::mouseMoveEvent and then triggering a FinalizeMapScale method in QGraphicsItem::mouseReleaseEvent once the mouse scale is complete. This method should then change the font to the appropriate size and set the scale back to 1.0.
I have a solution that appears to be working, but I'm not crazy about it. I'm relatively new to both Qt and C++, so would appreciate any comments or corrections.
Is there a better way to architect this whole thing?
Are there Qt methods that already do this?
Is my method on the right track but has some Qt or C++ errors?
Feel free to comment on my answer below on submit your own preferred solution. Thanks!
[EDIT] As requested in comment, here is the basics of the scaling code. We actually went a different direction with this, so this code (and the code below) is no longer being used. This code is in the mouseMoveEvent method, having previously set a "scaling_" flag to true in mousePressEvent if the mouse was clicked in the bottom-right "hot spot". Note that this code is in a decorator QGraphicsItem that holds a pointer to the target it is scaling. This abstraction was necessary for our project, but is probably overkill for most uses.
void TransformDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
...
if (scaling_) {
QGraphicsItem *target_item = target_->AsQGraphicsItem();
target_item->setTransformOriginPoint(0.0, 0.0);
QPointF origin_scene = mapToScene(target_item->transformOriginPoint());
QPointF scale_position_scene = mapToScene(event->pos());
qreal unscaled_width = target_item->boundingRect().width();
qreal scale_x = (scale_position_scene.x() - origin_scene.x()) / unscaled_width;
if (scale_x * unscaled_width < kMinimumSize) {
scale_x = kMinimumSize / unscaled_width;
}
target_item->setScale(scale_x);
} else {
QGraphicsObject::mouseMoveEvent(event);
}
}
Please no holy wars about the loop-with-exit construct. We're comfortable with it.
void MapTextElement::FinalizeMapScale() {
// scene_document_width is the width of the text document as it appears in
// the scene after scaling. After we are finished with this method, we want
// the document to be as close as possible to this width with a scale of 1.0.
qreal scene_document_width = document()->size().width() * scale();
QString text = toPlainText();
// Once the difference between scene_document_width and the calculated width
// is below this value, we accept the new font size.
const qreal acceptable_delta = 1.0;
// If the difference between scene_document_width and the calculated width is
// more than this value, we guess at the new font size by calculating a new
// scale factor. Once it is beneath this value, we creep up (or down) by tiny
// increments. Without this, we would sometimes incur long "back and forth"
// loops when using the scale factor.
const qreal creep_delta = 8.0;
const qreal creep_increment = 0.1;
QScopedPointer<QTextDocument> test_document(document()->clone());
QFont new_font = this->font();
qreal delta = 0.0;
// To prevent infinite loops, we store the font size values that we try.
// Because of the unpredictable (at least to me) relationship between font
// point size and rendering size, this was the only way I could get it to
// work reliably.
QList<qreal> attempted_font_sizes;
while (true) {
test_document->setDefaultFont(new_font);
delta = scene_document_width - test_document->size().width();
if (std::abs(delta) <= acceptable_delta ||
attempted_font_sizes.contains(new_font.pointSizeF())) {
break;
}
attempted_font_sizes.append(new_font.pointSizeF());
qreal new_font_size = 0.0;
if (std::abs(delta) <= creep_delta) {
new_font_size = delta > 0.0 ? new_font.pointSizeF() + creep_increment
: new_font.pointSizeF() - creep_increment;
} else {
new_font_size = new_font.pointSizeF()
* scene_document_width
/ test_document->size().width();
}
new_font.setPointSizeF(new_font_size);
}
this->setFont(new_font);
this->setScale(1.0);
}
Another way to look at the problem is: Qt has scaled the font, what is the effective font size (as it appears to the user, not the font size set in the text item) that I need to display to the user as their choice of new font size? This is just an alternative, you still need a calculation similar to yours.
I have a similar problem. I have a text item that I want to be unit size (one pixel size) like my other unit graphic items (and then the user can scale them.) What font (setPointSize) needs to be set? (Also what setTextWidth and what setDocumentMargin?) The advantage of this design is that you don't need to treat the scaling of text items different than the scaling of any other shape of graphics item. (But I don't have it working yet.)
Also, a user interface issue: if the user changes the font size, does the item change size? Or does it stay the same size and the text wrap differently, leaving more or less blank space at the end of the text? When the user appends new text, does the font size change so all the text fits in the size of the shape, or does the shape size grow to accommodate more text? In other words, is it more like a flowchart app (where the shape size is fixed and the font shrinks), or like a word processor app (where the font size is constant and the shape (number of pages) grows?

Aspect ratios - how to go about them? (D3D viewport setup)

Allright - seems my question was as cloudy as my head. Lets try again.
I have 3 properties while configuring viewports for a D3D device:
- The resolution the device is running in (full-screen).
- The physical aspect ratio of the monitor (as fraction and float:1, so for ex. 4:3 & 1.33).
- The aspect ratio of the source resolution (source resolution itself is kind of moot and tells us little more than the aspect ratio the rendering wants and the kind of resolution that would be ideal to run in).
Then we run into this:
// -- figure out aspect ratio adjusted VPs --
m_nativeVP.Width = xRes;
m_nativeVP.Height = yRes;
m_nativeVP.X = 0;
m_nativeVP.Y = 0;
m_nativeVP.MaxZ = 1.f;
m_nativeVP.MinZ = 0.f;
FIX_ME // this does not cover all bases -- fix!
uint xResAdj, yResAdj;
if (g_displayAspectRatio.Get() < g_renderAspectRatio.Get())
{
xResAdj = xRes;
yResAdj = (uint) ((float) xRes / g_renderAspectRatio.Get());
}
else if (g_displayAspectRatio.Get() > g_renderAspectRatio.Get())
{
xResAdj = (uint) ((float) yRes * g_renderAspectRatio.Get());
yResAdj = yRes;
}
else // ==
{
xResAdj = xRes;
yResAdj = yRes;
}
m_fullVP.Width = xResAdj;
m_fullVP.Height = yResAdj;
m_fullVP.X = (xRes - xResAdj) >> 1;
m_fullVP.Y = (yRes - yResAdj) >> 1;
m_fullVP.MaxZ = 1.f;
m_fullVP.MinZ = 0.f;
Now as long as g_displayAspectRatio equals the ratio of xRes/yRes (= adapted from device resolution), all is well and this code will do what's expected of it. But as soon as those 2 values are no longer related (for example, someone runs a 4:3 resolution on a 16:10 screen, hardware-stretched) another step is required to compensate, and I've got trouble figuring out how exactly.
(and p.s I use C-style casts on atomic types, live with it :-) )
I'm assuming what you want to achieve is a "square" projection, e.g. when you draw a circle you want it to look like a circle rather than an ellipse.
The only thing you should play with is your projection (camera) aspect ratio. In normal cases, monitors keep pixels square and all you have to do is set your camera aspect ratio equal to your viewport's aspect ratio:
viewport_aspect_ratio = viewport_res_x / viewport_res_y;
camera_aspect_ratio = viewport_aspect_ratio;
In the stretched case you describe (4:3 image stretched on a 16:10 screen for example), pixels are not square anymore and you have to take that into account in your camera aspect ratio:
stretch_factor_x = screen_size_x / viewport_res_x;
stretch_factor_y = screen_size_y / viewport_res_y;
pixel_aspect_ratio = stretch_factor_x / stretch_factor_y;
viewport_aspect_ratio = viewport_res_x / viewport_res_y;
camera_aspect_ratio = viewport_aspect_ratio * pixel_aspect_ratio;
Where screen_size_x and screen_size_y are multiples of the real size of the monitor (e.g. 16:10).
However, you should simply assume square pixels (unless you have a specific reason no to), as the monitor may report incorrect physical size informations to the system, or no informations at all. Also monitors don't always stretch, mine for example keeps 1:1 pixels aspect ratio and adds black borders for lower resolutions.
Edit
If you want to adjust your viewport to some aspect ratio and fit it on an arbitrary resolution then you could do like that :
viewport_aspect_ratio = 16.0 / 10.0; // The aspect ratio you want your viewport to have
screen_aspect_ratio = screen_res_x / screen_res_y;
if (viewport_aspect_ratio > screen_aspect_ratio) {
// Viewport is wider than screen, fit on X
viewport_res_x = screen_res_x;
viewport_res_y = viewport_res_x / viewport_aspect_ratio;
} else {
// Screen is wider than viewport, fit on Y
viewport_res_y = screen_res_y;
viewport_res_x = viewport_res_y * viewport_aspect_ratio;
}
camera_aspect_ratio = viewport_res_x / viewport_res_y;