Skip to content

Commit 6771201

Browse files
committed
more device init. rework, tool/icon/uiprim import
This depends on e4d1bb2a or later in arcan, but adds support for letting the hmd- driver chose the hmd projection instead of forcing our own. Also should be down to one or two minor things left with device mapping/initialization rework. Bring in some of the UI primitives work from durden, particularly tool loading, popups, icons and buttongrid.
1 parent 367f6e9 commit 6771201

18 files changed

+1294
-1015
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Added model property to blocking autolayouter
99
* Added model methods for cycling stereoscopic mapping
1010
* Reworked device detection and screen mapping
11+
* Child-spawning changed from 'on register' to 'first frame'
1112
* API path for switching appl
1213
* Calibration toggle (/hmd/toggle\_calibration)
1314
* Added IPC control & monitoring, use with socat or arcan-cfgfs mount

README.md

+21-13
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ looks like this:
5555
oversample_h = 1.0,
5656
distortion_model = "basic",
5757
display_rotate = 'cw90',
58+
override_projection = false,
5859
width = 2560,
5960
height = 1440,
60-
map_hint = MAP_FLIP,
61+
map_hint = MAP_FLIP,
6162
hmdarg = "ohmd_index=0",
6263
bindings = [
6364
["F1"] = "mouse=selected"
@@ -74,26 +75,34 @@ display = 'pattern' : This checks for a display EDID matching the lua pattern
7475
presented by the string rather than going for the first one available. If this
7576
is set, setup won't progress until the correct display has been found.
7677

78+
display\_id = 'number' : If present, this ignores the display-pattern above
79+
and just picks whatever that happens to appear as a specific display number,
80+
where 0 will always be the first, and so on.
81+
7782
display\_rotate = cw90 | ccw90 | 180 | cw90ccw90 : This specifies the base
7883
orientation of the display.
7984

8085
distortion\_model = basic, none : Using the universal distortion shader from the
8186
OpenHMD project or disable barrel distortion altogether.
8287

83-
headless = true | false : This mode does not expect to be mapped to a display
84-
but rather outputs to whatever arcan happens to pick based on the video platform
85-
in use. This is mainly for windowed like modes.
88+
override\_projection = false | true : If set to true, this will use a normal
89+
perspective projection matrix, ignoring whatever was provided by the vr device
90+
91+
no\_combiner = false | true : This removes / disables the combiner surface,
92+
effectively making the rendering monoscopic only via the preview window.
93+
94+
headless = false | true : This will ignore mapping the head/rotation tracking
95+
to the output cameras, causing them to be locked in place.
8696

8797
There are some special built-in profiles:
8898

8999
* 'desktop' : 3D desktop only, no vr devices or stereoscopic rendering
90-
* 'basic' : Just draw to the default display and treat it as the VR display
91-
* 'simulated' : 'Headless' operation: stereo with distortion and no combiner stage
100+
* 'client' : Used as a client in another desktop system
92101

93-
'Basic' is useful if you are trying to run arcan as a normal client with an
94-
outer display server like Xorg or on OS X. It draws as a normal window and
95-
you get to use whatever controls the display server provides to move it to
96-
the HMD display.
102+
Client is intended to be used with arcan builds that act as a client inside
103+
another desktop system and not as a display server itself, that would be 'lwa'
104+
(where arcan+safespaces is used as a client to a normal arcan desktop), 'sdl'
105+
or 'sdl2'.
97106

98107
## Configuration
99108

@@ -356,14 +365,13 @@ Milestone 1:
356365
- [ ] Launch targets
357366
- [x] Xarcan
358367
- [x] Wayland-simple (toplevel/fullscreen only)
359-
- [ ] Xwayland
360-
- [ ] full xdg-toplevel
368+
- [ ] Wayland-composited (xdg-popups, subsurfaces, xwayland)
361369

362370
- [ ] Tools
363371
- [ ] Basic 'listview' popup
364372
- [x] Console
365373
- [ ] Button-grid / Streamdeck
366-
- [x] Socket- control IPC
374+
- [x] Socket- control IPC
367375

368376
Milestone 2:
369377

safespaces/config.lua

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ return {
1111
curve = 0.9,
1212
layer_falloff = 0.9,
1313
animation_speed = 30,
14+
preview_w = 2560,
15+
preview_h = 1440,
1416
prefix = "",
1517

1618
-- composition rt- set to -1.0 to invert
@@ -21,13 +23,17 @@ return {
2123

2224
-- external control
2325
control_path = "control",
26+
allow_ipc = true,
2427

2528
-- Special application settings
2629
terminal_font = "hack.ttf",
27-
terminal_font_sz = 28,
30+
terminal_font_sz = 18,
2831
terminal_opacity = 1,
2932

33+
-- icon set to be used
34+
icon_set = "default",
35+
3036
-- Input Controls
3137
meta_1 = "LMETA", -- "COMPOSE" or META on some platforms
32-
meta_2 = "RMETA"
38+
meta_2 = "SYSREQ"
3339
};

safespaces/devices/basic.lua

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
return {
55
width = VRESW,
66
height = VRESH,
7-
headless = true,
87
oversample_w = 1.0,
98
oversample_h = 1.0,
109
hmdarg = "ohmd_index=0",

safespaces/devices/desktop.lua

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
return {
55
headless = true,
66
disable_vrbridge = true,
7+
no_combiner = true,
78
bindings = {
89
}
910
};

safespaces/devices/simulated.lua

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
return {
22
distortion_model = "basic",
33
headless = true,
4+
disable_vrbridge = true,
45
oversample_w = 1.0,
56
oversample_h = 1.0,
67
width = VRESW,

safespaces/icon.lua

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
-- icon loading, caching and resolution management
2+
--
3+
-- eventually this should be generalizable to a uiprim/ script
4+
-- as manual icon handling, covering all the bases for different
5+
-- displays, optimizing for caching, atlas-slicing etc. is quite
6+
-- hairy.
7+
--
8+
-- For now, we just do the minimal placeholder stuff needed to
9+
-- refactor the icon/font label parts of durden, then see what
10+
-- happens from there. The support sheet used for picking/binding
11+
-- should also be moved from the icons widget to here.
12+
--
13+
-- In that direction, there are three classes of icons - labels
14+
-- textual and client defined. The first one need to be loaded
15+
-- and kept.
16+
--
17+
-- The second needs rasterization against the target display.
18+
--
19+
-- The third needs caching.
20+
--
21+
local setname = gconfig_get("icon_set");
22+
23+
-- it is almost always useful having a circle primitive to
24+
-- build with, both for generating single colored round icons
25+
-- or to use as a mask together with resample_image
26+
icon_unit_circle = build_shader(
27+
nil,
28+
[[
29+
uniform float radius;
30+
uniform vec3 color;
31+
varying vec2 texco;
32+
33+
void main()
34+
{
35+
float vis = length(texco * 2.0 - vec2(1.0)) - radius;
36+
float step = fwidth(vis);
37+
vis = smoothstep(step, -step, vis);
38+
gl_FragColor = vec4(color.rgb, vis);
39+
}
40+
]],
41+
"iconmgr_circle"
42+
);
43+
44+
icon_colorize = build_shader(
45+
nil,
46+
[[
47+
uniform vec3 color;
48+
uniform sampler2D map_tu0;
49+
varying vec2 texco;
50+
51+
void main()
52+
{
53+
vec4 col = texture2D(map_tu0, texco);
54+
float intens = max(max(col.r, col.g), col.b);
55+
gl_FragColor = vec4(color * intens, col.a);
56+
}
57+
]],
58+
"iconmgr_colorize"
59+
);
60+
61+
shader_uniform(icon_unit_circle, "radius", "f", 0.5);
62+
local function synthesize_icon(w, shader)
63+
local icon = alloc_surface(w, w);
64+
if not valid_vid(icon) then
65+
return;
66+
end
67+
resample_image(icon, shader, w, w);
68+
return icon;
69+
end
70+
71+
function icon_synthesize_src(name, w, shader, argtbl)
72+
local fn = string.format("icons/%s/%s", setname, name);
73+
local img = load_image(fn);
74+
if not valid_vid(img) then
75+
return;
76+
end
77+
for k,v in pairs(argtbl) do
78+
shader_uniform(shader, k, unpack(v));
79+
end
80+
resample_image(img, shader, w, w);
81+
return img;
82+
end
83+
84+
function icon_synthesize(w, shader, argtbl)
85+
for k,v in pairs(argtbl) do
86+
shader_uniform(shader, k, unpack(v));
87+
end
88+
return synthesize_icon(w, shader);
89+
end
90+
91+
-- The nametable mainly contains the active caches of vids based
92+
-- on a base width. Normally icons are square, though it is not
93+
-- a given.
94+
--
95+
-- For icons where we don't need to scale but can use a function
96+
-- to generate the icon in question, the generate function is
97+
-- provided.
98+
local nametable = {
99+
};
100+
101+
-- take a vsym that passed validation from suppl_valid_vsym and
102+
-- return a vid that can be used for an image_sharestorage into
103+
-- a caller controlled allocation, as well as a possible shader
104+
-- identifier. An open question is if we should allow SDFs. The
105+
-- problem comes with shader used for highlights etc.
106+
function icon_lookup(vsym, px_w)
107+
if not nametable[vsym] then
108+
vsym = "placeholder";
109+
end
110+
local ent = nametable[vsym];
111+
112+
-- do we have a direct match since before?
113+
if ent.widths[px_w] then
114+
return ent.widths[px_w];
115+
end
116+
117+
-- can we build one with it?
118+
if ent.generate then
119+
local res = ent.generate(px_w);
120+
if valid_vid(res) then
121+
ent.widths[px_w] = res;
122+
return res;
123+
end
124+
end
125+
126+
-- find one with the least error
127+
local errv = px_w;
128+
local closest = 0;
129+
130+
for k,v in pairs(ent) do
131+
if type(k) == "number" then
132+
local dist = math.abs(px_w - k);
133+
if dist < errv then
134+
errv = dist;
135+
closest = k;
136+
end
137+
end
138+
end
139+
140+
-- apparently wasn't one for this specific size, fallback generator(s)?
141+
if errv > 0 and ent.generator then
142+
ent.widths[px_w] = ent.generator(px_w);
143+
end
144+
145+
-- no solution at all? return placeholder, this shouldn't infinitely
146+
-- recurse as we always override placeholder with our own definition that
147+
-- has a synthesis option
148+
if closest == 0 then
149+
return icon_lookup("placeholder", px_w);
150+
end
151+
152+
-- do we need to load or generate?
153+
local vid = ent.widths[closest];
154+
if not ent.widths[closest] then
155+
if type(ent[closest]) == "string" then
156+
local fn = string.format("icons/%s/%s", setname, ent[closest]);
157+
ent.widths[closest] = load_image(fn);
158+
159+
-- or provide some visual indicator that the icon reference was bad
160+
if (not valid_vid(ent.widths[closest])) then
161+
ent.widths[closest] = icon_lookup("placeholder", px_w);
162+
end
163+
164+
elseif type(ent[closest]) == "function" then
165+
ent.widths[closest] = ent[closest]();
166+
else
167+
-- missing handler / malformed
168+
warning("icon_synth:bad_type=" .. type(ent[closest]));
169+
end
170+
vid = ent.widths[closest];
171+
end
172+
173+
-- or really panic so we don't return a broken vid
174+
return valid_vid(vid) and vid or WORLDID;
175+
end
176+
177+
-- use a unicode symbol reference (or nametable override)
178+
-- to get an iconic or rastered representation matching the
179+
-- intended display. The display is needed as the rendertarget
180+
-- attachment for the datastore, as that covers the density.
181+
local last_u8;
182+
function icon_lookup_u8(u8, display_rt)
183+
if valid_vid(last_u8) then
184+
delete_image(last_u8);
185+
end
186+
187+
local rt = set_context_attachment(display_rt);
188+
last_u8 = render_text({"\\f,0", u8});
189+
set_context_attachment(rt);
190+
if not valid_vid(last_u8) then
191+
return icon_lookup("placeholder", 32);
192+
end
193+
return last_u8;
194+
end
195+
196+
function icon_known(vsym)
197+
return vsym ~= nil and #vsym > 0 and nametable[vsym] ~= nil;
198+
end
199+
200+
-- the enforcement on location isn't strict here, traversal
201+
-- protection is implemented on a much lower level so this is fine
202+
nametable = system_load(string.format("icons/%s.lua", setname))();
203+
204+
-- make sure we have some standard names
205+
if not nametable.destroy then
206+
nametable.destroy = {
207+
generate = function(w)
208+
return icon_synthesize(w, icon_unit_circle, {color = {"fff", 1.0, 0.1, 0.15}});
209+
end
210+
};
211+
end
212+
213+
-- make sure we always have these
214+
if not nametable.minimize then
215+
nametable.minimize = {
216+
generate = function(w)
217+
return icon_synthesize(w, icon_unit_circle, {color = {"fff", 0.94, 0.7, 0.01}});
218+
end,
219+
widths = {}
220+
};
221+
end
222+
223+
if not nametable.maximize then
224+
nametable.maximize = {
225+
generate = function(w)
226+
return icon_synthesize(w, icon_unit_circle, {color = {"fff", 0.1, 0.6, 0.1}});
227+
end,
228+
widths = {}
229+
};
230+
end
231+
232+
-- reserve this one for ourselves so we always have a valid fallback
233+
nametable.placeholder = {
234+
generate =
235+
function(w)
236+
return icon_synthesize(w, icon_unit_circle, {color = {"fff", 1.0, 1.0, 1.0}});
237+
end
238+
};
239+
240+
-- and safeguard so we have the width cache table
241+
for _, v in pairs(nametable) do
242+
if not v.widths then
243+
v.widths = {};
244+
end
245+
end

0 commit comments

Comments
 (0)