diff --git a/Nasal/view.nas b/Nasal/view.nas index 3f65153df..41e05e946 100644 --- a/Nasal/view.nas +++ b/Nasal/view.nas @@ -233,7 +233,7 @@ var manager = { me.current.handler.start(); if (hasmember(me.current.handler, "update")) me._loop_(me.loopid += 1); -# resetFOV(); + screenWidthCompens.update(); }, reset : func { if (hasmember(me.current.handler, "reset")) @@ -652,57 +652,71 @@ var point = { # view.ScreenWidthCompens: optional FOV compensation for wider screens. # It keeps an equivalent of 55° FOV on a 4:3 zone centered on the screen # whichever is the screen width/height ratio. Works only if width >= height. -# -# status: 0=Init, 1=toggle option, 2=waiting for the window size to change. -var defaultFov = nil; -var oldW = 0; -var oldH = 0; -var fovStore = {}; +var screenWidthCompens = { + defaultFov: nil, + oldW: nil, oldH: nil, oldOpt: nil, + assumedW: 4, assumedH: 3, + fovStore: [], + lastViewStatus: {}, + statusNode: nil, # = /sim/current-view/field-of-view-compensation + getStatus: func me.statusNode.getValue(), + setStatus: func(state) me.statusNode.setValue(state), + calcNewFov: func(fov=55, oldW=nil, oldH=nil, w=nil, h=nil) { + if (w == nil) w = getprop("/sim/rendering/camera-group/camera/viewport/width"); + if (h == nil) h = getprop("/sim/rendering/camera-group/camera/viewport/height"); + if (oldW == nil) oldW = me.assumedW; + if (oldH == nil) oldH = me.assumedH; + if (w/h == oldW/oldH or h > w) return fov; + else return math.atan2(w/h, oldW/oldH / math.tan(fov * D2R)) * R2D; + }, + init: func() { + me.defaultFov = getprop("/sim/current-view/config/default-field-of-view-deg"); + me.statusNode = props.globals.getNode("/sim/current-view/field-of-view-compensation", 1); + me.oldW = getprop("/sim/rendering/camera-group/camera/viewport/width"); + me.oldH = getprop("/sim/rendering/camera-group/camera/viewport/height"); -var screenWidthCompens = func(status) { - var opt = getprop("/sim/current-view/field-of-view-compensation"); - if (status == 0) { - defaultFov = getprop("/sim/current-view/config/default-field-of-view-deg"); + setsize(me.fovStore, size(views)); forindex (var i; views) { - var defaultFovNode = views[i].getNode("config/default-field-of-view-deg", 1); - fovStore[i] = defaultFovNode.getValue(); + me.fovStore[i] = views[i].getNode("config/default-field-of-view-deg", 1).getValue() or 55; + me.lastViewStatus[i] = { w:me.assumedW, h:me.assumedH }; } - } elsif (status == 1) { - opt = ! opt; - setprop("/sim/current-view/field-of-view-compensation", opt); - if (! opt) { - forindex (var i; views) { - var defaultFovNode = views[i].getNode("config/default-field-of-view-deg", 1); - defaultFovNode.setValue(fovStore[i]); + me.update(opt:nil, force:1); + }, + toggle: func() me.update(!me.getStatus(), 1), + update: func(opt=nil, force=0) { + if (opt == nil) + opt = me.getStatus(); + else me.setStatus(opt); + var w = getprop("/sim/rendering/camera-group/camera/viewport/width"); + var h = getprop("/sim/rendering/camera-group/camera/viewport/height"); + # Update config/default-field-of-view-deg nodes if state changed: + if (force or me.oldOpt != opt or me.oldW/me.oldH != w/h) { + me.oldW = w; + me.oldH = h; + me.oldOpt = opt; + if (!opt) { + setprop("/sim/current-view/config/default-field-of-view-deg", me.defaultFov); + forindex (var i; views) + views[i].setValue("config/default-field-of-view-deg", me.fovStore[i]); + } else { + setprop("/sim/current-view/config/default-field-of-view-deg", + me.calcNewFov(fov:me.defaultFov, w:w, h:h)); + forindex (var i; views) + views[i].setValue("config/default-field-of-view-deg", + me.calcNewFov(fov:me.fovStore[i], w:w, h:h)); } - var vn = getprop("/sim/current-view/view-number"); - setprop("/sim/current-view/field-of-view", fovStore[vn]); } - } elsif (status == 2 and ! opt) { - return; - } - var w = getprop("/sim/rendering/camera-group/camera/viewport/width"); - var h = getprop("/sim/rendering/camera-group/camera/viewport/height"); - if (! opt) { - setprop("/sim/current-view/config/default-field-of-view-deg", defaultFov); - return; - } - if ( w != oldW or h != oldH or status == 1) { - oldW = w; - oldH = h; - d = 1.28066 * h; # 1.28066 = 4/3 (width/height ratio) / 2 / tan(55°) - newFov = 2 * math.atan2( w / h * h / 2, d) * R2D; - setprop("/sim/current-view/config/default-field-of-view-deg", newFov); - forindex (var i; views) { - var defaultFovNode = views[i].getNode("config/default-field-of-view-deg", 1); - defaultFovNode.setValue(newFov); + # Update this view if necessary: + if (!opt) (w,h) = (me.assumedW,me.assumedH); # back to default FOV + var thisview = me.lastViewStatus[index]; + if (thisview.w/thisview.h != w/h) { + fovProp.setValue(me.calcNewFov(fovProp.getValue(), thisview.w, thisview.h, w, h)) + and + ((thisview.opt,thisview.w,thisview.h) = (opt,w,h)); } - fovProp.setValue(newFov); - } - settimer(func { screenWidthCompens(2); }, 1); -} - + }, +}; _setlistener("/sim/signals/nasal-dir-initialized", func { @@ -715,10 +729,19 @@ _setlistener("/sim/signals/nasal-dir-initialized", func { }, 1); props.globals.initNode("/position/altitude-agl-ft"); # needed by Fly-By View + screenWidthCompens.init(); manager.init(); manager.register("Fly-By View", fly_by_view_handler); manager.register("Model View", model_view_handler); - screenWidthCompens(0); +}); +_setlistener("/sim/signals/reinit", func { + screenWidthCompens.update(opt:nil,force:1); +}); +_setlistener("/sim/startup/xsize", func { + screenWidthCompens.update(); +}); +_setlistener("/sim/startup/ysize", func { + screenWidthCompens.update(); }); diff --git a/gui/dialogs/rendering.xml b/gui/dialogs/rendering.xml index 4e03d6e54..6159f972f 100644 --- a/gui/dialogs/rendering.xml +++ b/gui/dialogs/rendering.xml @@ -214,7 +214,7 @@ sim/current-view/field-of-view-compensation nasal - +