Moderators Popular Post IIYAMA Posted June 13, 2019 Moderators Popular Post Share Posted June 13, 2019 [TUT] Scaling DX The reason why I am creating this topic, is because there are a lot of people asking this question: Quote How to display DX for all screen formats? And to be honest there is no best practice for. But here you have my recommendation as guidance for display them the ~s~a~m~e~ for all screen formats. There are two important factors while dealing with screen formats 1. Pixel density Indication: PPI(Pixels Per Inch) and some also use the term DPI(Dots Per Inch) They do not have to be the same while talking about printing stuff. This indication tells us about how many pixels are used per inch. Which more or less tells us how sharp/smooth things like text can be looking. PPI doesn't really play a big role, but to display something nicely you need enough pixels to display it. Else it will be either too small or too crispy. So be careful to not scale things (especially text) too small. 2. Display aspect ratio Wiki The difference between resolution X and resolution Y as a ratio. A list of common ratios: 4:3 5:4 3:2 16:10 16:9 So for example if we take: fHD: 1920x1080 Which has the ratio 16:9 that is calculated like this: 1920 / 16 = 120 120 * 9 = 1080 Scaling without ratio Before I am going to explain any of this, I am going to ask you an important question: Quote Does anybody play his MTA game on a vertical screen? Just like you hold your mobile phone. Like this: (vertical) ▮ Or horizontal? ▅ I assume most people would agree to play MTA horizontal, else you are probably reading a book or document. p.s If you play MTA on a vertical screen, then we developers do not like you at all, sorry. So what does this tell us? You can assume that the X-resolution is never going to be smaller than the Y-resolution. Useful? You will figure it out. Doing the scaling Note: This part is ABOUT SCALING and not positioning. So what we are going to do is: Calculating a scale which can display the same DX on multiple screen formats > without messing with the ratio. Example: A computer runs MTA at a resolution of 1920 x 1080. Lets define that! local devScreenX = 1920 local devScreenY = 1080 If this code is used by a different pc, we also need to know on which resolution it is running: local screenX, screenY = guiGetScreenSize() For the next step we have to look at this screenshot: I have cut out of the wide-screen format a square. Squares have the ratio 1:1, which means that we have removed our ratio difference from this screen resolution. It is very easy to do, as our Y * Y resolution makes exactly that beautiful square! The next thing we have to do is creating our scaling value. This value is required for adjust our resolution values so that they match to every screen format. So to use our ratio 1:1, we use the Y resolution to achieve that: local scaleValue = screenY / devScreenY And as last we can create a rectangle shape that is displayed at the center of every screen format, perfectly! local devScreenX = 1920 local devScreenY = 1080 local screenX, screenY = guiGetScreenSize() local scaleValue = screenY / devScreenY addEventHandler("onClientRender", root, function () -- create a scaled size local sizeX = scaleValue * 300 -- 300px local sizeY = scaleValue * 50 -- 50px -- get the center of the screen local centerX = screenX / 2 local centerY = screenY / 2 -- calculate the starting point of the rectangle local startRectangleX = centerX - (sizeX / 2) local startRectangleY = centerY - (sizeY / 2) dxDrawRectangle ( startRectangleX, startRectangleY, sizeX, sizeY, tocolor ( 255, 255, 255, 255 ) ) end) Lower limit What if we have a resolution of 800x600? And the text is getting too small? Making sure that the pixel density is OK, is very important. So to counter that we have to make sure that the text is not getting too small. Our development Y resolution is 1080 pixels. And we are dealing with an Y resolution 600 pixels. The first thing we are going to look at, is what the scale is going to be at that point. 600 / 1080 = 0.55555555555555555555555555555556 It is not very nice to have your text scaled to 55.5% of the original size, when having low resolution already. But without scaling, the DX stuff might fill up the entire screen and that is just as bad. So what we now need is a limit, in this case a lower limit. scaleValue = math.max(scaleValue, 0.65) The math.max function returns the highest value of all the arguments you put in to it. In this case it contains the: scaleValue: 0.555 And the lower limit of: 0.65 This will make sure that the DX stuff is not getting smaller than 65%. This might make text read able for a 800x600 resolution. Spoiler local devScreenX = 1920 local devScreenY = 1080 local screenX, screenY = guiGetScreenSize() local scaleValue = screenY / devScreenY scaleValue = math.max(scaleValue, 0.65) -- < here add the limit addEventHandler("onClientRender", root, function () -- create a scaled size local sizeX = scaleValue * 300 -- 300px local sizeY = scaleValue * 50 -- 50px -- get the center of the screen local centerX = screenX / 2 local centerY = screenY / 2 -- calculate the starting point of the rectangle local startRectangleX = centerX - (sizeX / 2) local startRectangleY = centerY - (sizeY / 2) dxDrawRectangle ( startRectangleX, startRectangleY, sizeX, sizeY, tocolor ( 255, 255, 255, 255 ) ) end) Positioning Do you want to place your dx-effects at a specific place on your screen? See the following useful function: https://wiki.multitheftauto.com/wiki/GetScreenStartPositionFromBox 11 4 Link to comment
koragg Posted June 15, 2019 Share Posted June 15, 2019 Nice trick for the scale on :~ty resolutions Also here's a similar topic which @Halemade and I expanded with another method as well: 1 Link to comment
Moderators IIYAMA Posted June 15, 2019 Author Moderators Share Posted June 15, 2019 7 hours ago, koragg said: Nice trick for the scale on :~ty resolutions Also here's a similar topic which @Halemade and I expanded with another method as well: Cold you explain to me, for which user interfaces/layout that method works well? I can understand that in case of text+box or gridlayout you want to give it a bit more space, but for a button would you use the X axis as well or rather the scaling method? (Both from that topic) 1 Link to comment
koragg Posted June 16, 2019 Share Posted June 16, 2019 14 hours ago, IIYAMA said: Cold you explain to me, for which user interfaces/layout that method works well? I can understand that in case of text+box or gridlayout you want to give it a bit more space, but for a button would you use the X axis as well or rather the scaling method? (Both from that topic) I haven't really made DX buttons so can't say for sure. My buttons and menus at my server are the default MTA ones (non-DX). I used my method to scale all DX rectangles & texts on the screen and it works quite well with those. 2 Link to comment
Scripting Moderators ds1-e Posted June 29, 2019 Scripting Moderators Share Posted June 29, 2019 (edited) Thanks for scaling part. Seems like it worked. Quote Note: This part is ABOUT SCALING and not positioning. I would like to see positioning tut also. I'm confused because, I've readed lots of tutorial, but still i can't get it to work. This thing is correct? -- left screen side --x = coords -- from left to half of screen -- half of screen --x = screenX/2 -- to center elements -- right screen side --x = screenX - coords -- from right side Edited June 29, 2019 by DNL291 removed big quote Link to comment
Moderators IIYAMA Posted June 29, 2019 Author Moderators Share Posted June 29, 2019 9 hours ago, majqq said: Thanks for scaling part. Seems like it worked. I would like to see positioning tut also. I'm confused because, I've readed lots of tutorial, but still i can't get it to work. This thing is correct? -- left screen side --x = coords -- from left to half of screen -- half of screen --x = screenX/2 -- to center elements -- right screen side --x = screenX - coords -- from right side Yes those are correct. If you have trouble with them. Then you could think of building utility stuff. local devScreenX = 1920 local devScreenY = 1080 local screenX, screenY = guiGetScreenSize() local scaleValue = screenY / devScreenY scaleValue = math.max(scaleValue, 0.65) function getScreenStartPositionFromBox (width, height, offsetX, offsetY, startIndicationX, startIndicationY) local startX = offsetX local startY = offsetY if startIndicationX == "right" then startX = screenX - (width + offsetX) elseif startIndicationX == "center" then startX = screenX / 2 - width / 2 + offsetX end if startIndicationY == "bottom" then startY = screenY - (height + offsetY) elseif startIndicationY == "center" then startY = screenY / 2 - height / 2 + offsetY end return startX, startY end just for the `could` float width, float height, float offsetX, float offsetY [, string startIndicationX, string startIndicationY ] print(getScreenStartPositionFromBox(400, 400, 100, 0, "right", "center")) print(getScreenStartPositionFromBox(400, 400, 0, 0, "center", "center")) print(getScreenStartPositionFromBox(400, 400, 0, 100, "center", "top")) print(getScreenStartPositionFromBox(400, 400, 100, 100, "left", "top")) print(getScreenStartPositionFromBox(400, 400, 100, 100, "right", "top")) 1 Link to comment
Scripting Moderators ds1-e Posted June 30, 2019 Scripting Moderators Share Posted June 30, 2019 (edited) Honestly, i don't understand why this is happening. My res: 1280x960, second res: 1280x1024, i don't know why button pos is incorrect. On other resolutions same. 1. 2. Code: local centerX = screenX/2 local centerY = screenY/2 -- function scaleSize(size, devY) if not size or not devY then outputChatBox("scaleSize: Missing arguments.") return end if size and devY then local scaleValue = screenY/devY scaleValue = math.max(scaleValue, 0.85) local scaledSize = scaleValue * size return scaledSize end end -- function getScreenStartPositionFromBox(width, height, offsetX, offsetY, startIndicationX, startIndicationY) local startX = offsetX local startY = offsetY if startIndicationX == "right" then startX = screenX - (width + offsetX) elseif startIndicationX == "center" then startX = screenX / 2 - width / 2 + offsetX end if startIndicationY == "bottom" then startY = screenY - (height + offsetY) elseif startIndicationY == "center" then startY = screenY / 2 - height / 2 + offsetY end return startX, startY end -- local position_gui = {inventory_window = {}, loot_gridlist = {}, loot_button = {}} position_gui.inventory_window[1], position_gui.inventory_window[2] = getScreenStartPositionFromBox(750, 480, 0, 0, "center", "center") position_gui.loot_gridlist[1], position_gui.loot_gridlist[2] = getScreenStartPositionFromBox(350, 385, 15, 60, "left", "top") position_gui.loot_button[1], position_gui.loot_button[2] = getScreenStartPositionFromBox(30, 320, 364, 60, "left", "top") -- local inventory_window = guiCreateWindow(position_gui.inventory_window[1], position_gui.inventory_window[2], scaleSize(750, 960), scaleSize(480, 960), "", false) local inventory_gridlist = guiCreateGridList(position_gui.loot_gridlist[1], position_gui.loot_gridlist[2], scaleSize(350, 960), scaleSize(385, 960), false, inventory_window) local inventory_button = guiCreateButton(position_gui.loot_button[1], position_gui.loot_button[2], scaleSize(30, 960), scaleSize(320, 960), "->", false, inventory_window) Edited June 30, 2019 by majqq Link to comment
Moderators IIYAMA Posted June 30, 2019 Author Moderators Share Posted June 30, 2019 3 hours ago, majqq said: getScreenStartPositionFromBox(350, 385, 15, 60, "left", "top") These are absolute values. Shouldn't you scale some of them as well? 1 Link to comment
Scripting Moderators ds1-e Posted June 30, 2019 Scripting Moderators Share Posted June 30, 2019 (edited) 2 hours ago, IIYAMA said: These are absolute values. Shouldn't you scale some of them as well? You mean width and height? I will try. EDIT: I should do it for everything? Edited June 30, 2019 by majqq 1 Link to comment
Moderators IIYAMA Posted June 30, 2019 Author Moderators Share Posted June 30, 2019 11 minutes ago, majqq said: You mean width and height? I will try. EDIT: I should do it for everything? Including offset, unless you have a custom X axis position in mind which is located at for example 1/4 of the screen. 1 Link to comment
Scripting Moderators ds1-e Posted June 30, 2019 Scripting Moderators Share Posted June 30, 2019 37 minutes ago, IIYAMA said: Including offset, unless you have a custom X axis position in mind which is located at for example 1/4 of the screen. Yes, probably works, i'm very grateful, your tutorial and help solved my biggest nightmare, thanks mate. 1 Link to comment
XaskeL Posted June 30, 2019 Share Posted June 30, 2019 it is very userful! I calculated a little differently, but the result is definitely the same! Thank you for at least someone created a textbook on this topic. 1 Link to comment
Mefisto_PL Posted April 12, 2020 Share Posted April 12, 2020 (edited) I was trying to use this method, but after all this pain i've been through, it still looks different on each resolution, it works perfectly on 800x600. Here is the photo of 1280x1024: https://imgur.com/nYswa5d The text should be in the right corner local devSX = 1920 local devSY = 1080 local sx, sy = guiGetScreenSize() local scaleV = sy / devSY scaleV = math.max(scaleV, 0.65) function statsShow () local text = "Ping: " ..getPlayerPing(localPlayer) .. " | FPS: " .. getElementData(localPlayer, "FPS") local textWidth = dxGetTextWidth(text) local centerX = sx/2 local centerY = sy/2 local textX = centerX - ((scaleV*-840)/2) local textY = centerY - ((scaleV*-830)/2) dxDrawText( text, textX-2, textY, textWidth, sy, tocolor(0, 0, 0, 255), scaleV*2, "arial") dxDrawText( text, textX+2, textY, textWidth, sy, tocolor(0, 0, 0, 255), scaleV*2, "arial") dxDrawText( text, textX, textY-2, textWidth, sy, tocolor(0, 0, 0, 255), scaleV*2, "arial") dxDrawText( text, textX, textY+2, textWidth, sy, tocolor(0, 0, 0, 255), scaleV*2, "arial") dxDrawText( text, textX, textY, textWidth, sy, tocolor(255, 255, 255, 255), scaleV*2, "arial") end addEventHandler("onClientRender", root, statsShow) Edited April 12, 2020 by Mefisto_PL Link to comment
Moderators IIYAMA Posted April 12, 2020 Author Moderators Share Posted April 12, 2020 (edited) 9 hours ago, Mefisto_PL said: The text should be in the right corner This tutorial is about scaling, not about positioning. If you are going to place it in the right + bottom corner, you have to start from that corner, not from the center. textWidth DOES NOT EXIST with the dxDrawText function. This function is making use of a text bounding box, which has a START (x,y) and an END (x,y). In this box you can align the the text: left, right, top, bottom. center(x), center(y). The following bounding box > starts at 0,0 which is the left + top corner and > ends on the right + bottom corner with some offset from the sides. The text is aligned to the right and to the bottom. local offsetFromSides = scaleV * 10 local textEndX = sx - offsetFromSides local textEndY = sy - offsetFromSides dxDrawText( text, 0, 0, textEndX, textEndY, tocolor(255, 255, 255, 255), scaleV*2, "arial", "right", "bottom") Edited April 12, 2020 by IIYAMA 1 Link to comment
DiGiTal Posted November 25, 2020 Share Posted November 25, 2020 p.s If you play MTA on a vertical screen, then we developers do not like you at all, sorry. U killed me xDD Question: -Why the scale works only with Y local scaleValueY = screenY / devScreenY local scaleValueX = screenX / devScreenX Why not like this??? and what About this scale trick?? local sx_, sy_ = guiGetScreenSize() local sx, sy = sx_/1440, sy_/900 dxDrawText("$123456789", 140*sx, 648*sy, 0*sx, 0*sy, tocolor(0,0,0,255), 0.8*sy,"bankgothic") Link to comment
Scripting Moderators ds1-e Posted November 26, 2020 Scripting Moderators Share Posted November 26, 2020 On 25/11/2020 at 22:20, DiGiTal said: -Why the scale works only with Y On 13/06/2019 at 21:21, IIYAMA said: I have cut out of the wide-screen format a square. Squares have the ratio 1:1, which means that we have removed our ratio difference from this screen resolution. It is very easy to do, as our Y * Y resolution makes exactly that beautiful square! On 25/11/2020 at 22:20, DiGiTal said: and what About this scale trick?? This is a trick which i do not recommend. Due of thing mentioned above. Personally i'm using a IIYAMA's way for everything, and it works perfectly. 2 Link to comment
Moderators IIYAMA Posted November 27, 2020 Author Moderators Share Posted November 27, 2020 (edited) On 25/11/2020 at 22:20, DiGiTal said: drawText("$123456789", 140*sx, 648*sy, 0*sx, 0*sy, tocolor(0,0,0,255), 0.8*sy,"bankgothic") Hey DiGiTal Summary: Y axis: Y axis position & compute pixel density(scale) X axis: X axis position drawText("$123456789", 140*sx, 648*sy, 0*sx, 0*sy, tocolor(0,0,0,255), 0.8*sy,"bankgothic") drawText("$123456789", <start position>, <start position>, <end position>, <end position>, tocolor(0,0,0,255), <scale>,"bankgothic") Take a look at your code. There are 3 types of arguments. start position (boundingbox) x y end position (boundingbox) x y scale (text) And an `invisible` one, which is the boundingbox size: boundingbox width = (end position x) - (start position x) boundingbox height = (end position y) - (start position y) You are currently not using the boundingbox. But that is something you could scale as well. When scaling and positioning, there is 1 important thing to keep in mind and that is to look at both of them differently. Because for some cases you want to scale position over the X and Y axis at the same time. X axis is used for the raw position. Y axis is used for the offset. local scaleValueY = sy_/900 local startPositionX = x_ -- right side of the screen local offsetX = scaleValueY * 30 -- calculate an scaled offset value local positionX = startPositionX - offsetX Your code drawText("$123456789", 140*sx, 648*sy, 0*sx, 0*sy, tocolor(0,0,0,255), 0.8*sy,"bankgothic") = drawText("$123456789", <10.2%>, <72%>, <0%>, <0%>, tocolor(0,0,0,255), <80% * 100%>,"bankgothic") I assume this is text placed above the radar. Now how to figure out the difference in methods? The only way is actually to see it for yourself. I made the following changes to reproduce your situation: Argument 2: Scaling the left offset over the Y axis. Argument 3: Starting from bottom to top, to improves `value` readability. (but doesn't change the outcome) Changed the text color to red. local scaleValueY = sy_/900 drawText("$123456789", scaleValueY * 140, sy_ - (scaleValueY * 252), 0, 0, tocolor(255,0,0,255), 0.8 * scaleValueY,"bankgothic") Your development resolution is: 1440 x 900 Check if both of them are aligned properly. If yes, then: Run both of examples at the same time with different resolutions and ratio aspects. Check the X position of both methods and see how those behave. Make some screenshots, which we can discus here. Edited November 27, 2020 by IIYAMA 2 Link to comment
Moderators IIYAMA Posted February 28, 2021 Author Moderators Share Posted February 28, 2021 I have added a useful function to the wiki, for positioning: https://wiki.multitheftauto.com/wiki/GetScreenStartPositionFromBox 1 Link to comment
MohammedX Posted July 14, 2021 Share Posted July 14, 2021 I have a question @IIYAMA do i have to work on resolution of 1920x1080? or on any resolution. cuz i prefer 1280x720 most of it and some people say that u should work on 1920x1080 resolution that is better? maybe my question is stupid....or idk i just asking 1 Link to comment
Scripting Moderators ds1-e Posted July 20, 2021 Scripting Moderators Share Posted July 20, 2021 On 14/07/2021 at 18:02, MohammedX said: I have a question @IIYAMA do i have to work on resolution of 1920x1080? or on any resolution. cuz i prefer 1280x720 most of it and some people say that u should work on 1920x1080 resolution that is better? maybe my question is stupid....or idk i just asking Not really. I am using this method on 1360x768. 1 Link to comment
Moderators IIYAMA Posted July 24, 2021 Author Moderators Share Posted July 24, 2021 On 14/07/2021 at 18:02, MohammedX said: most of it and some people say that u should work on 1920x1080 resolution that is better? You should work with the resolution you have yourself. Since that is the only absolute measure you have when building your interface. If you have your monitor on 1280x720 and you use 1920x1080. You can't calculate width/height exactly with your own pixels. So if you want 100% of the height of your screen and you fill in 720, the output is 720 / 1080 = 0.666666666667 = ~67% height! If you did use 1280x720: 720 / 720 = 1 = 100% height! That is what we want to see. Link to comment
UndR Posted July 24, 2021 Share Posted July 24, 2021 (edited) This method works for me perfect: local scrX, scrY = guiGetScreenSize() local devScreenY = 1024 local scale = math.min(math.max(scrY / devScreenY, 0.65), 2) local parent_w = 600 local parent_h = 360 local parent_x = scrX / 2 - parent_w * scale / 2 local parent_y = scrY /2 - parent_h * scale / 2 addEventHandler("onClientRender", root, function() dxDrawRectangle(parent_x, parent_y, parent_w * scale, parent_h * scale, tocolor(23, 23, 25)) dxDrawCircle(parent_x + (50) * scale, parent_y + (50) * scale, 50 * scale, 0, 360, tocolor(60, 80, 150)) end) Edited July 25, 2021 by UndR 1 Link to comment
Casti Posted July 8 Share Posted July 8 @IIYAMA For the next step we have to look at this screenshot: (404 not found) 1 Link to comment
Moderators IIYAMA Posted July 8 Author Moderators Share Posted July 8 9 hours ago, Casti said: @IIYAMA For the next step we have to look at this screenshot: (404 not found) Thx for preserving the original content! 1 Link to comment
Recommended Posts