# CrystalSpace for OS/2

The OS/2 port of CrystalSpace has a number of specific features that should be mentioned, so that you can better understand sourcecode and/or make modifications, if you need them (if you do, you should make them available to the public, as stated by LGPL).

## DIVE

The current implementation requires DIVE, so the application is compiled as a PM application. This is done by default (bin/os2link.cmd creates automatically a .def file). If you want to compile the application as a console application, you have to link it with the $(DO.LINK.CONSOLE.EXE) macro (have a look at apps/csregsvr/csregsvr.mak).

Other thing you should keep in mind is that DIVE library (libDIVE.cpp) uses a couple of resources, so you should not forget to link the resources to your application. Resources can be found in libDIVE.rc; this is added to linker dependencies for PM programs in CSDIVE driver makefile, so you also don't need to worry about it (but is still useful to know :-)

There is one not too pleasant feature related to DIVE (or to acceleration hardware specifics?). If DIVE image should be rescaled (i.e. the scale ratio is not 1:1) DIVE is almost TWICE (!) slower if DIVE window (the client rectangle, not the window border) is not on a two-aligned bound (at least such an effect I've got on my Matrox Mystique). If you get low frame rates, try moving the window by one pixel left/right.

To fix this if you use WINDOWX/WINDOWY keywords in cryst.cfg file or -pos x command-line switch, the computed X value will be rounded to nearest divisor of 2. However, if you manually move the window it can fall on a odd bound and you'll get twice lower frame rates.

You can use WINDOWWIDTH and WINDOWHEIGHT keywords in cryst.cfg file to define start window width and height (client window width and height, not counting borders and titlebar). If you won't define it, the DIVE window will be rescaled to the maximum possible integer factor such that window won't be larger than screen. For example, a 320x200 window in 1152x864 resolution will be automatically rescaled at startup to 960x600.

### DIVE features

Here is a short list of implementation features related to DIVE:

- DIVE contexts can be created with following pixel formats:
  - FOURCC_LUT8
  - FOURCC_R565
  - FOURCC_R664
  - FOURCC_R555
  - FOURCC_BGR4
  If you use `DEPTH=8` in CrystalSpace configuration file, or use `-depth 8` command-line parameter, CrystalSpace will start with FOURCC_LUT8 pixel format, regardless of what PM screen depth you have. If you use `DEPTH=16` config option or `-depth 16` parameter, the format will be choosed as follows:
  - If you selected 32-bit mode, and current screen depth is 32 bits current pixel format is used. *SEE NOTE BELOW*
  - If screen pixel depth is FOURCC_R565, FOURCC_R664, FOURCC_R555, that pixel format is used.
  - If you use -depth 15 or DEPTH=15 parameters, FOURCC_R555 pixel format will be used.
  - Otherwise the list of DIVE supported pixel formats is scanned. The most wanted mode is R5-G6-B5 mode, if it is not available R6-G6-B4 mode is choosen, if it is not available, R5-G5-B5 mode is choosen. If no 16- or 15-bit mode is available, code falls back to 256-color mode.
  NOTE: Due to a bug (or a misimplemented feature, to say so) in OS/2 DIVE library, you can't use 32-bit modes with the stock DIVE.DLL library. You have to patch it first so that it won't reject BGR4 pixel format when creating image buffers.

  WARNING: This is a Bad Fix {tm} however I didn't had other choice. It works for me with Matrox Mystique and Matrox Millenium ][ video cards, but I don't guarantee it will work for you.

  Go to \MMOS2\DLL. Take the DIVE.DLL library. Unpack it, if it is packed (lxlite /x dive.dll). Now find the following sequence of bytes inside it: `83 C2 08 41 83 F9 [10]` This sequence happens only once in my DIVE.DLL; I hope this is true for your DIVE.DLL as well. Now change the "10" that I took into square brackets with "16". That's all.

  Note that you will likely get wrong results if your current pixel format is NOT low-endian 32-bit (i.e. BGR4). That's not my fault.

- DIVE windows can be rescaled to arbitrary sizes. Rescaling is done automatically by DIVE, as well as color conversion. Note that if EnDIVE is available, you better use the same pixel format as your PM does, since most cards (my Matrox Mystique, for example) supports in hardware EITHER color conversion OR rescaling, but not both (although I can be wrong here, but that was my impression).
- Although DIVE does not (transparently) allow blitting only a portion of backbuffer to screen, there is still a solution. The key is to call each time DiveSetupBlitter with same parameters as usual, but clipping first all rectangles returned by GpiQueryRegionRects against the rectangle you want to update. Look in libDIVE.cpp (diveWindow::SetupBlitter) for more details.

  Although docs states that DiveSetupBlitter is a longplay operation, I think if you should update only a small part of screen it is still faster to use it (for example, CSWS mostly needs to update only the portion of screen around mouse cursor). DiveSetupBlitter is not called multiple times if update region does not change, so if you always call Graphics2D::Print with a constant argument (or NULL for entire area), it won't be called more often than in the 'classic' situation.

- There is an 'almost full-screen DIVE' mode of operation available. To activate/deactivate it you can press Alt+Home (like in DOS windows :-). In this mode window is resized so that window borders and window title will fall outside of physical screen, and DIVE window occupies entire screen. The bad side is that you get not too high frame rates in this mode (for example, on Matrox Mystique a window 320x200x256 rescaled to 1152x864x64K can be updated only about 15 times per second).
- The system menu on CrystalSpace window is replaced by a more application-specific menu. There are some useful options there (also available through hot-keys, for example Ctrl+Alt+1 rescales window to 1:1 scale, Ctrl+Alt+2 to 2:1 and so on). The menu definition is contained in libDIVE.rc. If you need some additional entries, you can add them directly to resource file.

# Mouse/keyboard

I was too lazy to intercept system event queue, so code generates all CrystalSpace events from events that are passed to DIVE window. As a consequence, there are some (minor) flaws:

- If you press a mouse button inside CrystalSpace window, then move the mouse outside the window and release button, CrystalSpace won't receive the 'mouse button released' event, since OS/2 passes mouse events to a window only if mouse is over that window. Theoretically this can be fixed by capturing mouse when any mouse button is pressed and releasing mouse when all mouse buttons will be released. I didn't have time to do it, and anyway it is not so important I think.
- If you press a key inside the window, then activate another window and release it, the same happens as with mouse buttons. Keyboard events are passed by OS/2 only to active windows. To avoid this, the default 'focus change' handler in csSystemDriver class calls Keyboard->Reset and Mouse->Reset if focus goes away. Keyboard::Reset clears all 'Key pressed' flags and emmits corresponding 'csevKeyUp' events. Mouse::Reset clears all 'button down' flags and emmits corresponding events too.

By default Crystal Space Windowing System will use builtin OS/2 mouse pointers whenever possible (there are three cursors that do not have their counterparts in OS/2 and will be emulated in software). This behaviour can be controlled by

      SYS_MOUSE_CURSOR = {yes|no}

parameter in config file. If set to "yes", system mouse pointers will be used when available; if set to "no", mouse pointers will be drawn by CrystalSpace as 2D sprites. This is slower but more precise. Theoretically csGraphics2D::SetMousePointer can be implemented to construct a OS/2 pointer from "native" CrystalSpace textures, but I was too lazy for this.

# Misterious crashes

If you just compiled WALKTEST or MAZED or some other executable (or even CSREGSVR), run it and get misterious exits or crashes during startup, it could be caused by the following problem:

I had a precompiled version of the JPEG and PNG dynamic libraries that were compiled with -Zcrtdll. And compiled Crystal Space with -Zsys, i.e. without EMX C runtime DLLs. For some reason this combination doesn't work until C/C++ compilers and company are resident in memory (if you're using "set GCCLOAD"). So you should either recompile everything with -Zsys, or recompile everything with -Zcrtdll, or do a "emxload -q" before running such executables.

# Contributors

For the moment, there is only one contributor :-) If you have any problems/questions related to OS/2 port, mail them to me:

e-mail:

You also may want to check the PGCC for OS/2 home page, which I'm maintaining. You also may want to use PGCC for CrystalSpace since it better optimizes for Pentium and alike than regular GCC.