{"name":"Arma 3: Pixel Grid System","title":"Arma 3: Pixel Grid System","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Pixel_Grid_System","revid":339206,"updated":"2023-04-28T12:38:09Z","aliases":["Arma 3 Pixel Grid System","Pixel Grid System"],"markdown":"Arma 3 v1.60\n\n> [!NOTE]\n> When working with Pixel Grid System the following macros might be of use:\n>\n> - `#include \"\\a3\\3DEN\\UI\\macros.inc\"`\n> - `#include \"\\a3\\3DEN\\UI\\macroexecs.inc\"`\n\nReal Virtuality offers the ability to configure and draw HUD and UI elements, through the use of engine supported control types and configuration parameters.\nHUDs can be designed and implemented to show information relevant to the game, offer the ability to create unique interactive systems, along with some elements capable of being drawn in 3D space, to apply towards spatial or even diegetic UI opportunities.\nUI classes are configured using control types defined in engine.\nThese control types include Text, Images, Combo-boxes, List-boxes, Check-boxes, etc. Control types can be configured with their individual parameters, while being positioned and scaled using the following:\n\n**x** - Horizontal position\n**y** - Vertical position\n**w** - Width\n**h** - Height\n\nThese dictate the position in screenspace coordinates that a control should be; however placing a control in the top-left corner of the screen isn't as easy as setting the control to 0,0.\n\nWhen RV was first developed, it was during a time where 4:3 monitors were the norm.\nOur screen-space coordinate system was then based on this concept, with the origin being the top-left corner of a 4:3 screen, with the entire screen inheriting a 4:3 ratio as default.\nHowever, this meant that upon the introduction of different aspect ratios, with the common being 16:9 for 1080p, the origin now existed part way into the screen.\nNot only this, but as resolutions increase, the size of the UI also needs to scale, as it is not ideal for the same \"percentage\" of the screen to be taken up by the UI at higher resolutions as it is at lower ones.\nThis meant that we had to introduce new script commands, which find the top-left corner origin at any resolution and aspect ratio, safeZoneX and safeZoneY.\nObviously, this also meant that the screen width and height changed, so subsequent commands were added for that also, safeZoneW and safeZoneH.\n\nThe main downside of this system is that UI elements are drawn in arbitrary \"percentage\" values of screen space. For example, at 1080p / 16:9 / Interface Size \"Normal\", the following is true:\n\n```\nsafeZoneX = -0.452381\nsafeZoneY = -0.214286\nsafeZoneW = 1.90476\nsafeZoneH = 1.42857\n```\n\nThis is a downside because it means we turn the number of pixels on the screen into a percentage of available space to utilize.\nAs an example, if we centralise a square in the centre of the screen, we would position it at (0.5,0.5), which never changes, and adjust for the width and height of the square itself.\nThe width and height of the square would be specified as some number, like 0.15 or even an evaluation of some formulated grid system ((safeZoneX + safeZoneW) / desiredMaxGridSize).\nThe problem here is that this number is not in pixels, it is in a percentage.\nThis means the control could be drawn in between two pixels on the screen, which means the engine needs to then \"guess\" which pixel it should draw it in; often being not what the designer wanted.\nThis leads to strange offsets across all controls on the screen, that can lead to crooked positioning, blurry text, perceived artefacts, and generally results in an unprofessional portrayal of the game and visual experience.\n\n### Pixel Accuracy\n\nIn order to offer a potential solution to this problem, we have created some new script commands which offer the infrastructure to start building UI in pixel space.\nThe two main script commands are pixelW and pixelH, which return an accurate size for one pixel width and height, based on the current resolution.\nIt is therefore possible to use these commands to draw in exact pixels.\nTo draw a single dot in the center of the screen, you could configure it like this:\n\n```cpp\nclass RscText\n{\n    x = 0.5;\n    y = 0.5;\n    w = \"pixelW\"; // one pixel width\n    h = \"pixelH\"; // one pixel height\n};\n```\n\nHowever, configuring UI using nothing but precise pixels would be very clumsy, and we also need a way to scale our UI up with resolution, in order to maintain visual screen space.\nTo achieve this, we added the Pixel Grid System.\n\nThe Pixel Grid System uses two base config parameters to determine what pixel grid size should be used:\n**uiScaleMaxGrids**: an integer, which is used to divide the current screen height resolution.\n\n```sqf\ngetNumber (configFile >> \"uiScaleMaxGrids\")\n```\n\n**uiScaleFactor**: the resulting use of uiScaleMaxGrids is then used to find an appropriate grid size, using the closest multiple of uiScaleFactor when factoring in the screen resolution and interface size.\n\n```sqf\ngetNumber (configFile >> \"uiScaleFactor\")\n```\n\nThe following three commands offer different variants of the pixelGrid:\n\n- pixelGridBase - returns grid size based on screen resolution.\n- pixelGridNoUIScale - returns grid size based on screen resolution and configs\n- pixelGrid - returns grid size based on screen resolution, interface size and configs\n\nBy combining the pixelW and pixelH commands with pixelGrid, it is possible to configure displays that will scale correctly with resolutions and interface sizes.\nTo configure a centralized rectangle of 12x6 grids, the following can be used:\n\n```cpp\nclass RscText\n{\n    x = \"0.5 - pixelW * pixelGrid * 6\";    // centre minus half width\n    y = \"0.5 - pixelH * pixelGrid * 3\";    // centre minus half height\n    w = \"pixelW * pixelGrid * 12\";        // 12 Grid Width\n    h = \"pixelH * pixelGrid * 6\";        // 6 Grid Height\n};\n```\n\n> [!IMPORTANT]\n> It is very important to remember that in order to maintain pixel accuracy, developers must only multiply grid sizes which result in a whole number of pixels.\n> To ensure this, it is best to multiply grids by `n / uiScaleFactor`.\n\n### Pixel Configuration and Anchoring\n\nIn order to make life a little easier, macro definitions can be used in place of the script commands for general management of UI construction and configuration.\nThe obvious benefit of being able to quickly mass adjust scale consistency to differentiate UI design templates and for greater config readability.\n\n```cpp\n// pixel grids macros\n#define UI_GRID_W (pixelW * pixelGrid)    // one grid width\n#define UI_GRID_H (pixelH * pixelGrid)    // one grid height\n#define UI_GUTTER_W (pixelW * 2)        // gutter width  of 2 pixels\n#define UI_GUTTER_H (pixelH * 2)        // gutter height of 2 pixels\n\n// sizes for our control\n#define BOX_W (UI_GRID_W * 12) // control is 12 grids wide\n#define BOX_H (UI_GRID_H * 5)  // control is 5 grids high\n\n// create a box in the top right corner, with gutter spacing from the screen edge\nclass RscText\n{\n    x = safeZoneX + safeZoneW - (BOX_W + UI_GUTTER_W);    // right side of screen minus box width and gutter\n    y = safeZoneY + UI_GUTTER_H;                        // top of screen plus gutter\n    w = BOX_W;                                            // width of control\n    h = BOX_H;                                            // height of control\n};\n```\n\nIt is also important to know that as resolution changes, the number of available grids may fluctuate:\n\n```cpp\nuiScaleMaxGrids = 64;\nuiScaleFactor = 4;\n```\n\n**1080p**\n\n```\n1080 / uiScaleMaxGrids = 16.875 (pixelGrid rounds to 16)\n1080 / 16 = 67.5 available grids\n```\n\n**1440p**\n\n```\n1440 / uiScaleMaxGrids = 22.5 (pixelGrid rounds to 24)\n1440 / 24 = 60 available grids\n```\n\n**With this in mind, it is always best to try and configure UI by anchoring to SafeZones based values**.","sections":[{"heading":null,"level":1,"markdown":"Arma 3 v1.60\n\n> [!NOTE]\n> When working with Pixel Grid System the following macros might be of use:\n>\n> - `#include \"\\a3\\3DEN\\UI\\macros.inc\"`\n> - `#include \"\\a3\\3DEN\\UI\\macroexecs.inc\"`\n\nReal Virtuality offers the ability to configure and draw HUD and UI elements, through the use of engine supported control types and configuration parameters.\nHUDs can be designed and implemented to show information relevant to the game, offer the ability to create unique interactive systems, along with some elements capable of being drawn in 3D space, to apply towards spatial or even diegetic UI opportunities.\nUI classes are configured using control types defined in engine.\nThese control types include Text, Images, Combo-boxes, List-boxes, Check-boxes, etc. Control types can be configured with their individual parameters, while being positioned and scaled using the following:\n\n**x** - Horizontal position\n**y** - Vertical position\n**w** - Width\n**h** - Height\n\nThese dictate the position in screenspace coordinates that a control should be; however placing a control in the top-left corner of the screen isn't as easy as setting the control to 0,0.\n\nWhen RV was first developed, it was during a time where 4:3 monitors were the norm.\nOur screen-space coordinate system was then based on this concept, with the origin being the top-left corner of a 4:3 screen, with the entire screen inheriting a 4:3 ratio as default.\nHowever, this meant that upon the introduction of different aspect ratios, with the common being 16:9 for 1080p, the origin now existed part way into the screen.\nNot only this, but as resolutions increase, the size of the UI also needs to scale, as it is not ideal for the same \"percentage\" of the screen to be taken up by the UI at higher resolutions as it is at lower ones.\nThis meant that we had to introduce new script commands, which find the top-left corner origin at any resolution and aspect ratio, safeZoneX and safeZoneY.\nObviously, this also meant that the screen width and height changed, so subsequent commands were added for that also, safeZoneW and safeZoneH.\n\nThe main downside of this system is that UI elements are drawn in arbitrary \"percentage\" values of screen space. For example, at 1080p / 16:9 / Interface Size \"Normal\", the following is true:\n\n```\nsafeZoneX = -0.452381\nsafeZoneY = -0.214286\nsafeZoneW = 1.90476\nsafeZoneH = 1.42857\n```\n\nThis is a downside because it means we turn the number of pixels on the screen into a percentage of available space to utilize.\nAs an example, if we centralise a square in the centre of the screen, we would position it at (0.5,0.5), which never changes, and adjust for the width and height of the square itself.\nThe width and height of the square would be specified as some number, like 0.15 or even an evaluation of some formulated grid system ((safeZoneX + safeZoneW) / desiredMaxGridSize).\nThe problem here is that this number is not in pixels, it is in a percentage.\nThis means the control could be drawn in between two pixels on the screen, which means the engine needs to then \"guess\" which pixel it should draw it in; often being not what the designer wanted.\nThis leads to strange offsets across all controls on the screen, that can lead to crooked positioning, blurry text, perceived artefacts, and generally results in an unprofessional portrayal of the game and visual experience."},{"heading":"Pixel Accuracy","level":3,"markdown":"In order to offer a potential solution to this problem, we have created some new script commands which offer the infrastructure to start building UI in pixel space.\nThe two main script commands are pixelW and pixelH, which return an accurate size for one pixel width and height, based on the current resolution.\nIt is therefore possible to use these commands to draw in exact pixels.\nTo draw a single dot in the center of the screen, you could configure it like this:\n\n```cpp\nclass RscText\n{\n    x = 0.5;\n    y = 0.5;\n    w = \"pixelW\"; // one pixel width\n    h = \"pixelH\"; // one pixel height\n};\n```\n\nHowever, configuring UI using nothing but precise pixels would be very clumsy, and we also need a way to scale our UI up with resolution, in order to maintain visual screen space.\nTo achieve this, we added the Pixel Grid System.\n\nThe Pixel Grid System uses two base config parameters to determine what pixel grid size should be used:\n**uiScaleMaxGrids**: an integer, which is used to divide the current screen height resolution.\n\n```sqf\ngetNumber (configFile >> \"uiScaleMaxGrids\")\n```\n\n**uiScaleFactor**: the resulting use of uiScaleMaxGrids is then used to find an appropriate grid size, using the closest multiple of uiScaleFactor when factoring in the screen resolution and interface size.\n\n```sqf\ngetNumber (configFile >> \"uiScaleFactor\")\n```\n\nThe following three commands offer different variants of the pixelGrid:\n\n- pixelGridBase - returns grid size based on screen resolution.\n- pixelGridNoUIScale - returns grid size based on screen resolution and configs\n- pixelGrid - returns grid size based on screen resolution, interface size and configs\n\nBy combining the pixelW and pixelH commands with pixelGrid, it is possible to configure displays that will scale correctly with resolutions and interface sizes.\nTo configure a centralized rectangle of 12x6 grids, the following can be used:\n\n```cpp\nclass RscText\n{\n    x = \"0.5 - pixelW * pixelGrid * 6\";    // centre minus half width\n    y = \"0.5 - pixelH * pixelGrid * 3\";    // centre minus half height\n    w = \"pixelW * pixelGrid * 12\";        // 12 Grid Width\n    h = \"pixelH * pixelGrid * 6\";        // 6 Grid Height\n};\n```\n\n> [!IMPORTANT]\n> It is very important to remember that in order to maintain pixel accuracy, developers must only multiply grid sizes which result in a whole number of pixels.\n> To ensure this, it is best to multiply grids by `n / uiScaleFactor`."},{"heading":"Pixel Configuration and Anchoring","level":3,"markdown":"In order to make life a little easier, macro definitions can be used in place of the script commands for general management of UI construction and configuration.\nThe obvious benefit of being able to quickly mass adjust scale consistency to differentiate UI design templates and for greater config readability.\n\n```cpp\n// pixel grids macros\n#define UI_GRID_W (pixelW * pixelGrid)    // one grid width\n#define UI_GRID_H (pixelH * pixelGrid)    // one grid height\n#define UI_GUTTER_W (pixelW * 2)        // gutter width  of 2 pixels\n#define UI_GUTTER_H (pixelH * 2)        // gutter height of 2 pixels\n\n// sizes for our control\n#define BOX_W (UI_GRID_W * 12) // control is 12 grids wide\n#define BOX_H (UI_GRID_H * 5)  // control is 5 grids high\n\n// create a box in the top right corner, with gutter spacing from the screen edge\nclass RscText\n{\n    x = safeZoneX + safeZoneW - (BOX_W + UI_GUTTER_W);    // right side of screen minus box width and gutter\n    y = safeZoneY + UI_GUTTER_H;                        // top of screen plus gutter\n    w = BOX_W;                                            // width of control\n    h = BOX_H;                                            // height of control\n};\n```\n\nIt is also important to know that as resolution changes, the number of available grids may fluctuate:\n\n```cpp\nuiScaleMaxGrids = 64;\nuiScaleFactor = 4;\n```\n\n**1080p**\n\n```\n1080 / uiScaleMaxGrids = 16.875 (pixelGrid rounds to 16)\n1080 / 16 = 67.5 available grids\n```\n\n**1440p**\n\n```\n1440 / uiScaleMaxGrids = 22.5 (pixelGrid rounds to 24)\n1440 / 24 = 60 available grids\n```\n\n**With this in mind, it is always best to try and configure UI by anchoring to SafeZones based values**."}],"categories":["GUI Topics","Introduced with Arma 3 version 1.60"],"groups":["GUI"]}