-
Notifications
You must be signed in to change notification settings - Fork 1
/
DynResManager.lua
313 lines (245 loc) · 12.2 KB
/
DynResManager.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
local public = {} -- This form of module uses only locals,
-- as described in http://blog.anscamobile.com/2011/09/a-better-approach-to-external-modules/
-- ================================================================================================
-- DynResManager - a tool for handling dynamic resolution images.
-- ------------- the images are loaded by means of DynResManager:loadImage local function.
--
-- written by Michael Magrilov, [email protected]
-- 08.09.2011
--
-- ================================================================================================
-- Version 2.0
-- Changes:
-- 1) New functions for getting screen boundaries and screen size
-- 2) "base" forceLoadRes value added as a synonim to "low"
-- ================================================================================================
---------------------------------------
-- Constants for scalng --
---------------------------------------
local constHiResPicScale = 2.0 -- in this case Hi-res images must be twice as big as lo-res ones
local constHiResSuffix = "@2x" -- Low: "pic.png"; High: "[email protected]"
-- a note: in this version there can be only 1 dot in image name (names like abc.def.jpg are not allowed)
local constHiResThreshold = 1.49 -- Hi-res pic will be loaded if the app is "magnified" by this or greater value;
-- if width in config.lua is 320 and threshhold is 1.8, then hi-res is loaded starting from device width = 320 * 1.8 = 576
-- if width in config.lua is 320 and threshhold is 1.5, then hi-res is loaded starting from device width = 320 * 1.5 = 480
-- (I assume that scale in config.lua = "letterbox" or "zoomeven" and device proportions are "taller"
-- than those of the application);
-- because of scale rounding error it's better to take 1.79 instead of 1.8 and 1.49 instead of 1.5
-- If you need more than two resolution levels,
-- it's possible to turn constHiResPicScale, constHiResSuffix and constHiResThreshold into tables
-- (of course, this requires also changes in local functions)
---------------------------------------------------------------
local function haveToLoadHiRes() -- Here we decide if we have to load hi-res or lo-res images
---------------------------------------------------------------
local deviceScaleX = 1.0 / display.contentScaleX -- App width on the device screen (pix) / app width set in config.lua
local deviceScaleY = 1.0 / display.contentScaleY -- App height on the device screen (pix) / app height set in config.lua
if deviceScaleX >= constHiResThreshold or deviceScaleY >= constHiResThreshold then
return true
else
return false
end
end -- haveToLoadHiRes
public.haveToLoadHiRes = haveToLoadHiRes
---------------------------------------------------------------
local function loadImage(imageFileName, forceLoadRes) -- The main method; optional parm forceLoadRes = "high" / "low" ("base") or empty
---------------------------------------------------------------
local imageFileName = tostring(imageFileName) or false
if imageFileName == "" then return nil end
local forceLoadRes = string.lower(tostring(forceLoadRes)) or false
if forceLoadRes ~= "high" and forceLoadRes ~= "low" and forceLoadRes ~= "base" then forceLoadRes = "" end
if forceLoadRes == "base" then forceLoadRes = "low" end
local hiResImageFileName
local tempImage = nil
-- 1) Load a low-res (base) image if we don't have to load hi-res
if (not haveToLoadHiRes() and forceLoadRes ~= "high") or forceLoadRes == "low" then
tempImage = display.newImage (imageFileName)
tempImage.x = 0
tempImage.y = 0
return tempImage
end
-- 3) Loading a HiRes image - first build its name, then load, if not OK, load base image
hiResImageFileName = string.gsub(imageFileName, "%.", constHiResSuffix..".") -- abc.jpg --> [email protected]
tempImage = display.newImage (hiResImageFileName)
-- 4) If we failed to load a hi-res image, load a lo-res;
if tempImage == nil then
tempImage = display.newImage (imageFileName)
tempImage.x = 0
tempImage.y = 0
return tempImage
end
-- 4) Scaling; if a hi-res image was loaded, its xScale and yScale will not be equal to 1;
-- take it into account if you want to scale the image again!
tempImage.xScale = tempImage.xScale / constHiResPicScale
tempImage.yScale = tempImage.yScale / constHiResPicScale
tempImage.x = 0
tempImage.y = 0
return tempImage
end -- loadImage
public.loadImage = loadImage
---------------------------------------------------------------------------------
-- "Get" public to access constants used by DynResManager
---------------------------------------------------------------------------------
-----------------------------------------
local function getHiResPicScale()
-----------------------------------------
return constHiResPicScale
end
public.getHiResPicScale = getHiResPicScale
---------------------------------------
local function getHiResSuffix()
---------------------------------------
return constHiResSuffix
end
public.getHiResSuffix = getHiResSuffix
------------------------------------------
local function getHiResThreshold()
------------------------------------------
return constHiResThreshold
end
public.getHiResThreshold = getHiResThreshold
---------------------------------------------------------------------------------
-- Some useful public functions ( screen X/Y range and screen size)
---------------------------------------------------------------------------------
------------------------------------------------------
local function minVisibleY()
------------------------------------------------------
return display.screenOriginY
end
public.minVisibleY = minVisibleY
------------------------------------------------------
local function maxVisibleY(scaleMode, yAlign) -- default: "letterbox", "center"
------------------------------------------------------
-- in "letterbox" or "zoomeven" scaling modes works only with yAlign = "bottom" or "center" (default);
-- doesn't work for yAlign = "top" (we can't get the height of the bottom margin)
-- this is true also for screenHeight... functions
local scaleMode = string.lower(tostring(scaleMode)) or ""
if scaleMode ~= "none" and scaleMode ~= "zoomeven" and scaleMode ~= "zoomstretch" then scaleMode = "letterbox" end
local yAlign = string.lower(tostring(yAlign)) or ""
if yAlign ~= "bottom" then yAlign = "center" end
if scaleMode == "zoomstretch" then
return display.viewableContentHeight
end
if scaleMode == "zoomeven" then
return display.viewableContentHeight + display.screenOriginY
end
if scaleMode == "none" or scaleMode == "letterbox" then
if yAlign == "center" then
return display.viewableContentHeight - display.screenOriginY
else
return display.viewableContentHeight
end
end
end
public.maxVisibleY = maxVisibleY
------------------------------------------------------
local function minVisibleX()
------------------------------------------------------
return display.screenOriginX
end
public.minVisibleX = minVisibleX
------------------------------------------------------
local function maxVisibleX(scaleMode, xAlign) -- default: "letterbox", "center"
------------------------------------------------------
-- in "letterbox" or "zoomeven" scaling modes works only with xAlign = "right" or "center" (default);
-- doesn't work for xAlign = "left" (we can't get the width of the right margin)
-- this is true also for screenWidth... functions
local scaleMode = string.lower(tostring(scaleMode)) or ""
if scaleMode ~= "none" and scaleMode ~= "zoomeven" and scaleMode ~= "zoomstretch" then scaleMode = "letterbox" end
local xAlign = string.lower(tostring(xAlign)) or ""
if xAlign ~= "right" then xAlign = "center" end
if scaleMode == "zoomstretch" then
return display.viewableContentWidth
end
if scaleMode == "zoomeven" then
return display.viewableContentWidth + display.screenOriginX
end
if scaleMode == "none" or scaleMode == "letterbox" then
if xAlign == "center" then
return display.viewableContentWidth - display.screenOriginX
else
return display.viewableContentWidth
end
end
end
public.maxVisibleX = maxVisibleX
------------------------------------------------------
local function screenHeightAppPix(scaleMode, yAlign) -- default: "letterbox", "center"
------------------------------------------------------
local scaleMode = string.lower(tostring(scaleMode)) or ""
if scaleMode ~= "none" and scaleMode ~= "zoomeven" and scaleMode ~= "zoomstretch" then scaleMode = "letterbox" end
return ( maxVisibleY(scaleMode, yAlign) - minVisibleY(scaleMode) ) -- not "+ 1" because "min" corresponds to 0
end
public.screenHeightAppPix = screenHeightAppPix
------------------------------------------------------
local function screenHeightPhysPix(scaleMode, yAlign) -- default: "letterbox", "center"
------------------------------------------------------
-- screen height in "physical pixels"
-- I use "0.51" for rounding instead of 0.5 because screenOriginX & screenOriginY are rounded to a half pixel accuracy;
-- still, the function can give one pixel error for "zoomeven" scaling mode
return math.floor(screenHeightAppPix(scaleMode, yAlign) / display.contentScaleY + 0.51)
end
public.screenHeightPhysPix = screenHeightPhysPix
------------------------------------------------------
local function screenWidthAppPix(scaleMode, xAlign) -- default: "letterbox", "center"
------------------------------------------------------
local scaleMode = string.lower(tostring(scaleMode)) or ""
if scaleMode ~= "none" and scaleMode ~= "zoomeven" and scaleMode ~= "zoomstretch" then scaleMode = "letterbox" end
return ( maxVisibleX(scaleMode, xAlign) - minVisibleX(scaleMode) ) -- not "+ 1" because "min" corresponds to 0
end
public.screenWidthAppPix = screenWidthAppPix
------------------------------------------------------
local function screenWidthPhysPix(scaleMode, xAlign) -- default: "letterbox", "center"
------------------------------------------------------
-- screen width in "physical pixels"
-- I use "0.51" for rounding instead of 0.5 because screenOriginX & screenOriginY are rounded to a half pixel accuracy;
-- still, the function can give one pixel error for "zoomeven" scaling mode
return math.floor(screenWidthAppPix(scaleMode, xAlign) / display.contentScaleX + 0.51)
end
public.screenWidthPhysPix = screenWidthPhysPix
-------
---------------------------------------------------------------
-- A function for rendering text with a font size set dynamically according to device resolution.
---------------------------------------------------------------
local function displayText(text, x, y, font, size, refPoint )
---------------------------------------------------------------
local text = text or "xxx"
local x = x or 0
local y = y or 0
local font = font or native.systemFont
local size = size or 12
local refPoint = refPoint or ""
local sizeAtRealResolution
local tempText
local W0, H0
sizeAtRealResolution = size / display.contentScaleY
tempText = display.newText(text, 0, 0, font, sizeAtRealResolution )
refPoint = string.lower(refPoint)
if refPoint == "center" then
tempText:setReferencePoint( display.CenterReferencePoint )
elseif refPoint == "topleft" then
tempText:setReferencePoint( display.TopLeftReferencePoint )
elseif refPoint == "topcenter" then
tempText:setReferencePoint( display.TopCenterReferencePoint )
elseif refPoint == "topright" then
tempText:setReferencePoint( display.TopRightReferencePoint )
elseif refPoint == "centerright" then
tempText:setReferencePoint( display.CenterRightReferencePoint )
elseif refPoint == "bottomright" then
tempText:setReferencePoint( display.BottomRightReferencePoint )
elseif refPoint == "bottomcenter" then
tempText:setReferencePoint( display.BottomCenterReferencePoint )
elseif refPoint == "bottomleft" then
tempText:setReferencePoint( display.BottomLeftReferencePoint )
elseif refPoint == "centerleft" then
tempText:setReferencePoint( display.CenterLeftReferencePoint )
else
tempText:setReferencePoint( display.TopLeftReferencePoint ) -- default
end
tempText.yScale = tempText.yScale * display.contentScaleY
tempText.xScale = tempText.xScale * display.contentScaleX
tempText.x = x
tempText.y = y
return tempText
end -- displayText
public.displayText = displayText
return public