DPI and orthographic camera

Hi! I’m using a standard orthographic camera. I have code that adjusts the zoom based on the window size, and everything works perfectly when High DPI is disabled in the project settings. However, when I enable it, the zoom is calculated incorrectly on devices with high DPI. I’ve tried many different approaches, but I still haven’t found a solution

local CAMERA_URL = "/operator"
local DISP_W, DISP_H = 1080, 1920
local VIS_W, VIS_H = 0, 0
local CAM_X, CAM_Y = 540, 960

local camera = { near = -1, far = 1, zoom = 1 }
local state = { width = DISP_W, height = DISP_H, window_width = DISP_W, window_height = DISP_H }


local function get_fixed_fit_projection(cam, st)
	cam.zoom = math.min(st.window_width / st.width, st.window_height / st.height) 
	go.set(CAMERA_URL.."#camera", "orthographic_zoom", cam.zoom)
	local pw, ph = st.window_width / cam.zoom, st.window_height / cam.zoom
	local left, bottom = -(pw - st.width) / 2, -(ph - st.height) / 2
	return vmath.matrix4_orthographic(left, left + pw, bottom, bottom + ph, cam.near, cam.far)
end

local function update_projection()
	state.window_width, state.window_height = window.get_size()
	local inv = vmath.inv(get_fixed_fit_projection(camera, state))
	local btm = inv * vmath.vector4(-1, -1, 0, 1)
	local top = inv * vmath.vector4(1, 1, 0, 1)
	btm, top = btm / btm.w, top / top.w
	VIS_W, VIS_H = top.x - btm.x - CAM_X, top.y - btm.y - CAM_Y
	print("Visible width:", VIS_W, "Visible height:", VIS_H)
end

local function window_event_listener(self, event)
	if event == window.WINDOW_EVENT_RESIZED then update_projection() end
end

function init(self)
	window.set_listener(window_event_listener)
	update_projection()
end

I think you need to factor in the display scale in your calculation. There is currently no API for you to get display scale, but keep an eye on this PR: Added new window API functions by britzl · Pull Request #10252 · defold/defold · GitHub

In the meantime you can try to calculate it by comparing the width and height set in game project with the actual ratio reported by window.get_size():

function init(self)
    local w = sys.get_config_number("display.width")
    local h = sys.get_config_number("display.height")
    local ww, wh = window.get_size()
    local ratio = math.max(ww/w, wh/h)
    print(ratio)
end
2 Likes

Thanks! I’m essentially using the same thing in this section of code, but I still don’t really understand how I can replace dpi with this, because besides that I’m still counting the visible area

Also a simple ratio calculation can hardly help, if we have displays with different dpi but the same size, the ratio calculation will be the same, because window.get_size() returns the size without taking into account the dpi

	cam.zoom = math.min(st.window_width / st.width, st.window_height / st.height) 
	go.set(CAMERA_URL.."#camera", "orthographic_zoom", cam.zoom)

Ok, you’ll have to wait for the PR to be merged. Once it is merged there will be a window.get_display_scale() to get the display scale factor.

2 Likes