Wednesday, June 29, 2011

Forcing fullscreen in Linux for apps that don't support it properly

Following situation: You have an application or game in Linux that you want to run in fullscreen, but the app doesn't support it or not with the flexibility you want.

Simple Case

In the simple case you will have the problem with an application that allows window resize, if that's the case, the solution is a simple:

wmctrl -r ":ACTIVE:" -b toggle,fullscreen

Which will put the currently focused window into fullscreen, i.e. maximize it and get rid of the window borders and title.

Complicated Case

There are of course also applications that don't do window resize properly or not at all, for those the solution is a bit more complicated. First thing we have to do is get rid of the window borders on move the window to 0,0. As the Gnome panel doesn't allow that, just removing the decorations, which can be done with wmctrl, isn't enough, we have to set override redirect, which will take the window out of the window managers hand and thus allow us to position it above the Gnome panel at the top/left of the screen. So how do we do that? A bit of Python and Gtk (raw X11 would of course do as will, but Gtk makes things a little easier):

#! /usr/bin/python
from gtk.gdk import *
import gtk.gdk
import time
import sys

if len(sys.argv) == 2:
w = window_foreign_new(int(sys.argv[1], 16))
else:
w = window_foreign_new((get_default_root_window().property_get("_NET_ACTIVE_WINDOW")[2][0]))

w.set_keep_above(True) # to raise it over the panel
w.set_decorations(0)
w.set_override_redirect(True)
window_process_all_updates()
gtk.gdk.flush()
w.move(0, 0)
gtk.gdk.flush()

This script will either take the currently focused window or a window given on the command line and put it in override redirect mode, as well as position it at 0,0. There is also a keep_above() in there so that the panel won't end up behind the Gnome panel.

The script isn't pretty, bug free or finished, it's actually kind of a mess. The flush() stuff is trying to work around the image move() command getting ignored, but doesn't really fix it. And I am not sure why the set_decorations(0) is needed in addition when doing a set_override_redirect(True). But whatever, it kind of works and if it doesn't just run it twice. Once run the currently focused window should be hanging at the top/left of your screen.

Switching the resolution

A window at the top/left screen is of course by itself not very attractive, so the next step is to switch the resolution, that can either be done manually via the XRandr GUI tools or via shell with something like:

xrandr --output DFP2 --mode "640x480"

Exact commands will of course vary from system to system. The fun part is that this also allows multi-monitor setups:

xrandr \
--output DFP2 \
--mode "640x480" \
--panning "640x480+1280+0/0x0+0+0" \
--output CRT1 \
--mode "1280x1024" \
--panning "1280x1024+0+0/0x0+0+0"

This would put the right monitor into 640x480, while keeping the left monitor at its native resolution, thus you can browse the web while playing an old game in Dosbox or whatever.

Other solutions and remaining issues

Another solution to the fullscreen problem is to run a separate Xserver for the game with the right resolution and without a window manager, this allows clean switching between game and desktop, but doesn't allow multi monitor use.

Mouse/keyboard grab is another problem that might be worth some further exploration, some games depend on it, so it might be worthwhile to force it, while other don't let you ungrab the mouse without exiting the game. I haven't really looked into either, but at least for the more popular things like Dosbox, there is generally a keyboard combination to break it (Ctrl-F10). Another problem with grab is that it is often to tight, i.e. commands like Volume Up/Down will get eaten by the app and not make it to the window manager which is quite annoying.

It might also be worth to cleanup the above script into a proper wrapper that can be used around the game executable to make the whole process of override redirect and resolution switch fully automatic. Integration into the window manager would also be nice, to make it a more standard part of the Linux desktop experience, not an dirty hack.

Saturday, June 25, 2011

Review: Descent 3 (PC)

Descent 3 was developed by Outrage Entertainment and released in 1999. The game follows the same base gameplay that the previous two games in the series did. The player is in control of a small spacecraft that is used to navigate through underground mines, caves and similar structures. Descent allows full six degrees of freedom controls in those environments, thus flying through a hole in the roof or diving through a hole in the ground are very common occasions.

The graphics in Descent 3 stay relatively close to those of the predecessor games, but thanks to Direct3D or OpenGL now allow much higher resolutions and texture filtering. Even so the polygon count is higher however the graphics are largely unspectacular and can look rather block in spots, the one exception being the light effects. The game now as a nice little glow effect around light sources and missiles and laser fire, as in the previous games, continue to light up the environment. Thus firing a missile through a dark cave will give a nice illumination of the cave as the missile flies along. The game also allows the player to fire flares or use headlights on his spaceship to light up dark caves. While all those effects might technically not be all that impressive by today's standards, I haven't really seen any game that really replicated them this well either.

On the control side Descent 3 offers a wide variety of configuration options and allows to map essentially every of the six axis it needs to either a button or joystick axis, thus is works quite fine even with modern day gamepads. An auto-leveling function is available when one doesn't have enough controls available to control the roll of the ship comfortably and while this function works for most part quite fine, I found it a little odd that it often leaves one off by a few degrees, instead of given a perfect horizontal level orientation. Another odd thing with the controls are some of the key mappings, unlike the main vehicle functions, which are completely configurable, some auxiliary functions are not and mapped to weird key combinations. Saving is mapped to Alt-F2 and viewing the log messages is mapped to Alt-F8 and releasing the guide bot is mapped to F4, what makes this weird is that those are all functions one regularly uses in the game, essentially the only function for which one needs the keyboard, so having them mapping to key-combination is rather uncomfortable. Viewing the log messages with Shift-F8 furthermore doesn't pause the game, so it can get really awkward when one gets surprised by an enemy while reading the log.

The control scheme I used for ship control was left-stick for horizontal-strafe and forward/backward, right stick for pitch and yaw and LB/RB for vertical-strafe. I mapped roll to dpad left/right, but didn't use that much in actual gameplay.

The game provides the player with three types of weapons, a gun for firing lasers and other small projectiles, a missile launcher and the ability to drop mines. Upgrades to those weapons are spread throughout the levels or dropped by killed enemies. I found the mines, from which there are even different types, to be rather useless throughout the single player campaign, one acquires them to rarely and the fighting is to hectically to really allow strategic placement of them, they seem to be build for multiplayer use. Same is true for some of the missile types, which while extremely powerful, are so rare that one never really has the change to use them in a good spot. Furthermore the game is rather bad when it comes to weapon, whenever the current weapon runs out of ammunition, the most powerful one will be selected, the problem is that this often results in weapons getting selected that should be reserved for special purposes and fired by accident. Thus one not only wasted a special weapon, but often even dies as result, as their damage radius is to large for them to be used in normal combat.

Aside from the combat mechanics, a central part of Descent is the guide bot. This little bot, whose beeping noises are reminiscent of R2-D2's in Star Wars, is a fundamental helper in guiding the player through the complicated levels. It keeps track of the next mission objective and will show the player the way to the target. It will also light the way by shooting flares into walls and occasionally shoot one into the players windshield by accident. When the players ship catches fire he will also act as fire extinguisher and put the fire out. The guide bot adds a great amount of personality to the game, as it is a small little dependable helper, that helps you through his actions, not by dialog and seeing it flying around the ship trying to get the player to follow him is jut cute. It's implementation has a few small issues, sometimes it will get left behind and not find the way back to the player on his own and in large open areas he seems to fly around a bit randomly and untargeted, marking it hard to follow him, but especially in the more tighter parts of a level the bot is a great orientation help and does this job in a much more interesting and charming way then the anonymous navigation lines and arrows used in modern games.

The enemies in Descent 3 are yet again a whole bunch of industrial robots that have gone aggressive due to a virus, there is a wide variety of enemies, with unique looks and weapons. However where the game falls flat is in how it uses those enemies, far to often it just pushes the player against an overly large number of enemies, making the combat chaotic and random. Frequently one simply gets overpowered by enemies and dies before even realizing what was going on. The enemies also all act with the same six degrees of freedom as the player does, this sadly removes the opportunity of a tactical approaching to exploit the enemies weak spots, instead most of the time one just circle strafes a lot and fires whatever weapons one has left. This is also true for the few boss enemies in the game, which really don't seem to allow any kind of tactical approach other then just shooting a lot at it. Enemies also have a noticeably lack of hit feedback, so it is often not clear if one is even doing any damage.

The way the game handles death and respawn is rather interesting, similar to Bioshock's Vita Chambers, the game will reset the player when he dies, but won't reset the rest of game world. The players collected weapons will however remain at his position of death and have to be required. While this removes a lot of the frustration one might have in the game, it removes any challenge, especially when it comes to boss fights, one simply fires what one has, dies, respawn and fires again. This makes the fights tedious and uninteresting. Furthermore one sometimes loses all the weapons in the process, as fighting the boss doesn't leave time to recollect the lost weapons and the next level might trigger before one has managed to do so. However I only ran into that issue once in the game. On normal levels the guide bot has the ability to search for the lost items so that they can be recollected even when one doesn't remember where one lost them.

As far as story and setting go, Descent 3 is a weird mix. Intro and outro cutscenes, while technically primitive, are quite well done and have a bigger emotional impact then one would expect from this type of game. However they don't really factor into the gameplay itself. There are some rare voice communications that inform the player of the mission goals, but it is so rare and limited to the start of a level, that at the end of it, one regularly forgets why one is even there. The mission briefings at the start of a mission don't really help much either. Essentially without the guide bot remembering what one has to do next, one could easily get completely lost. The setting of the game have however a good amount of variety, one isn't limited to caves and mines, one also goes flying through subway stations, invades factories and goes flying on the surfaces of Venus and Mercury, but again, the story just enough to turn all of that into a larger connected experience. It all feels a little random and is rather hard to follow. The game also throws in a few puzzle sequences here and there which feel a bit out of place, after all flying in a spaceship isn't the best place to push switches.

Overall I am rather split on Descent 3, while I still love the core six-degree-of-freedom gameplay, the guide bot and the creative enemy design, the game build around it just feels rough and unbalanced. Some of the boss enemies, especially the last one, essentially felt completely impossible to beat in any sane manner and beating them by abusing the respawn mechanics didn't felt very satisfactory either. Regular enemies don't far much better, to often one is just overpowered by them with no real way to fight back. Tactical fighting almost never works and it all becomes a hectic circle strafe fest that isn't much fun. The game also features a few points where enemies can endlessly respawn, which seem to serve no other purpose then annoy and frustrate the player and especially late in the game those things can become a huge problem those spots are combined with time consuming switch puzzles one has to do while being attacked by enemies. Often even without proper hints of what one needs to do. Especially later in the game it became just more frustration then it was fun.

Technical notes: Playing the game in Wine in Linux didn't work for me. First stopping point was the video-tab in the setup dialog that freezes. This could be worked around with a regedit hack. Once past that the graphics themselves worked fine and where fluid, the sound however was completely broken. I ended up playing the game in Vista. To map the Xbox360 gamepad triggers to missiles and laser shots I had to use XPadder, as the game didn't allow doing that with its internal configuration.