ScummVM RGB color progress blog

August 20, 2009

Hope and change

Filed under: Progress — Upthorn @ 10:06 pm

So, as I suggested in my prior blog post, I’ve been working on totally redesigning the Common::Action and Common::Keymap structures.

I’ve been at work on this for a few days now, but because I’m totally redesigning the way they interact with each other, and interface with the rest of the code at large, I’m not done yet, and the code won’t compile until I finish, so I can’t commit it yet.

So, to show what I’ve been working at, I’m posting what I’ve gotten done here.

So far, all the actual rewritten code has been going into the Action struct and related enums.

enum ActionType {

//Emulate a hardware event in the engine
kSingleKeyPressActionType,
kMultiKeyPressType,
kMouseClickType,
kMouseWheelType,

//Interface directly with the VM
kSaveActionType,
kMenuActionType,
kQuitActionType,
kVirtualKeyboardActionType,
kKeyRemapActionType,
kVolumeUpActionType,
kVolumeDownActionType,

//This is the total number of types currently defined in this enum
kActionTypeMax

};

enum ClickType {

kLeftClickType,
kMiddleClickType,
kRightClickType

};

enum KeyType {

//Direction keys
kDirUpKeyType,
kDirDownKeyType,
kDirLeftKeyType,
kDirRightKeyType,

//Keyboard keys
kTextKeyType, //Letters, numbers, symbols, whitespace
kModifierKeyType, //Ctrl, Alt, Shift

//Gamepad buttons
kFaceButtonKeyType, //A, B, C, X, Y, Z, and the like
kShoulderButtonKeyType, //Separated from FaceButtons because they can be used as pseudo-modifier keys.

//System key types
kPauseKeyType, //Start, Pause, etc..
kMenuKeyType, //Select, Escape, etc…
kSystemActionKeyType, //F1-F12, volume sliders, and so forth

//This is the total number of types currently defined in this enum
kKeyTypeMax

};

struct Action {

char id[ACTION_ID_SIZE];

ActionType type;
KeyType preferredKey;

private:

List<Event> _events;
HardwareKey *_mappedKey;

public:

void mapKey (const HardwareKey *key);

void addKeyPressEvent(KeyCode code, byte modifiers) {

KeyState key = KeyState(code);
key.flags = modifiers;

Event keyPress;
keyPress.type = EVENT_KEYDOWN;
keyPress.kbd = key;

_events.push_back(keyPress);

}

void addMouseClickEvent(ClickType t) {

Event mouseClick;
if (t == kLeftClickType)

mouseClick.type = EVENT_LBUTTONDOWN;

else if (t == kRightClickType)

mouseClick.type = EVENT_RBUTTONDOWN;

else

mouseClick.type = EVENT_MBUTTONDOWN;

_events.push_back(mouseClick);

}

template <ActonType t>;
Action<kSingleKeyPressActionType> (char *i, KeyType k, KeyCode c, byte m) {

memcpy(id,i,ACTION_ID_SIZE);

type = t;
preferredKey = k;

addKeyPressEvent(c,m);

}

Action<kMultiKeyPressType> (char *i, KeyType k, List<KeyCode> cs, byte m) {

memcpy(id,i,ACTION_ID_SIZE);

type = t;
preferredKey = k;

List<KeyCode>::iterator it;
for (it = cs.begin(); it != cs.end(); it++) {

KeyCode c = *it;
addKeyPressEvent(c,m);

}

}

Action<kMouseClickType> (char *i, bool l = true, bool m = false, bool r = false) {

memcpy(id,i,ACTION_ID_SIZE);

type = t;
preferredKey = k;

if (l)

addMouseClickEvent(kLeftClickType);

if (m)

addMouseClickEvent(kMiddleClickType);

if (r)

addMouseClickEvent(kRightClickType);

}

Action<kMouseWheelType> (char *i, bool up = false) {

memcpy(id,i,ACTION_ID_SIZE);

Event evt;
if (up)

evt.type = EVENT_WHEELUP;

else

evt.type = EVENT_WHEELDOWN;

_events.push_back(evt);

}

Action (char *i) {

memcpy(id,i,ACTION_ID_SIZE);
type = t;

}

};

There’s more about how this is going to work which is still in my head, but a lot of initialization stuff that was previously done by Action methods is going to be moved into the Keymap, so there will no longer be any need for an Action to know anything about the set that it is in, except to have a HardwareKey pointer provided to it (and even that will only be so that the Keymap can do effective data-management when an action gets remapped.)

Advertisements

August 16, 2009

Down to the wire

Filed under: Planning,Progress — Upthorn @ 5:17 pm

As I am writing this, the GSoC Coding period ends in just under 19 hours. Shortly after my last blog post, I began to make some headway on the task, and I’ve kept up a reasonable pace since then, and I’ve now got modifiers working in a way that I’m satisfied with, so I’m finally starting on the real meat of the task — the engine<->keymapper interface. Unfortunately, I haven’t managed to take a whole lot of time yet to sit and think about the details of how this is going to work, so I’m going to be flying by the seat of my pants a bit.

I hope to have a more fully-fleshed proposal for an API, and some work on an initial implementation done, before the 19:00 UTC deadline.

Wish me good luck, I will need it.

EDIT:

With 6 and a half hours remaining in the GSoC coding period, and badly in need of sleep, it looks like I won’t be able to get the API proposal finished before the pencils down deadline.

In fact, what I’ve managed to get done towards it is embarassingly small, but I will post it here for posterity, anyway:

How this is going to work:

  • simple method to create simple common actions such as mouse clicks and key presses
    • Autogenerate keypress and mouseclick action IDs and descriptions
      • What is the bare minimum required for an Action structure to be functional?
      • What aspects of an Action can be defaulted or autogenerated in the majority of cases?
        • preferredkey
        • events
        • id?
        • description?
        • Priority??
          • How does priority work? (is 0 the highest priority, or the lowest?)
          • What is the point of having a “parent-child” keymap hierarchy?
  • model Keymapper interface after CursorManager
    • implement a stack for keymaps
      • implement pushKeyMap
        • What input should it take?
          • cursor manager takes the components for a cursor, and handles cursor assembly internally
          • But maybe if there’s a streamlined method for keymap production, the engine could handle that and push the completed map
      • replaceKeyMap
      • popKeyMap
      • Surely there are other distinguishing features to the CursorManager

August 7, 2009

Gaining momentum

Filed under: Progress — Upthorn @ 11:08 am

After a long break from coding (longer than what I’d wanted by half), I’ve started working on properly implementing modifiers for the keymapper, instead of feeding every key in an additional time for each possible combination of modifiers that exists.

I’ve got it halfway working in a temporary way — it only feeds the keys in once, but the remap dialog can recognize modified keys and tell that they are different from unmodified keys (and that ctrl-a is different from shift-a), but events mapped to modified keys aren’t triggering at all for some reason.

The more important thing, though, is that I’m back in the swing of coding and getting work done again. Hopefully I should be back up to full speed in another day or two.

July 14, 2009

Initial project goal completed. Also, vacation.

Filed under: Progress — Upthorn @ 1:37 am

Ahead of even my wildest dreams, I have already completed the initial project goal of a color format API. (see prior blog entry for more information).

I must thank Eugene (sev), Max (fingolfin), Johannes (LordHoto), and Travis (Kirben), for the great amount of support and help they have provided me on this. I would also like to thank Sven (DrMcCoy), Willem (wjp), and Jordi (jvprat) for the interest they have shown and the insight they have provided.

Just in timed for the vacation I have already scheduled, which begins in the morning after I post this, and continues for two weeks. I will still be somewhat active on the next project goal, when I can get a moment away from having fun times with friends, but I do not expect to make regular SVN commits during this time, and it may be slightly longer than one week before my next blog update gets posted.

When I return, I expect to be tackling the issue of keymappers with full force.

June 27, 2009

finalized API function reference:

Filed under: Planning,Progress — Upthorn @ 12:01 am

So here is the skinny on the pixel format request API :

  • static inline Graphics::PixelFormat Graphics::PixelFormat::createFormat*(void)
    • creates a PixelFormat and initializes it to the specified format. A list of formats provided follows:
      • createFormatCLUT8() // 256 color paletted
      • createFormatRGBA4444()
      • createFormatARGB4444()
      • createFormatABGR4444()
      • createFormatBGRA4444()
      • createFormatRGB555() //16bit 555 RGB
      • createFormatBGR555()
      • createFormatXRGB1555() //only use these if you need the backend to handle alpha
      • createFormatXBGR1555() //otherwise use the 555 versions, instead of 1555
      • createFormatRGB565()
      • createFormatBGR565()
      • createFormatRGB888() // when 24 and 32-bit modes are supported
      • createFormatBGR888() // when 24 and 32-bit modes are supported
      • createFormatRGBA8888() // when 24 and 32-bit modes are supported
      • createFormatARGB8888() // when 24 and 32-bit modes are supported
      • createFormatABGR8888() // when 24 and 32-bit modes are supported
      • createFormatBGRA8888() // when 24 and 32-bit modes are supported
    • Because these methods are static, they can be called before the object is defined, E.G.:
      • Graphics::PixelFormat _screenFormat = Graphics::PixelFormat::createFormatRGB555();
  • void initGraphics(int width, int height, bool defaultTo1xScaler, Graphics::PixelFormat *format = NULL)
    • format is a pointer to a Graphics::PixelFormat describing the pixel format requested of the backend.
    • if format is left as NULL, CLUT8 will be used.
  • Common::List<Graphics::PixelFormat> OSystem::getSupportedFormats(void)
    • returns a list of all pixel formats supported by the backend
    • Backends supporting non-paletted color data must support data in native hardware color order, and should support data RGBA color order.
    • All backends are required to support data in CLUT8 (256 color palette) format.
    • The first item in the list (List.begin()) must always be the pixelformat which provides the greatest RGB colorspace that is directly supported by hardware
      • on dreamcast, this would be Graphics::PixelFormat::createFormatRGB565
      • on PSP, this would be Graphics::PixelFormat::createFormatABGR8888 once 32-bit modes are supported by scalers, and Graphics::PixelFormat::createFormatBGR565 until then.
    • The rest of the list shall be ordered by preference of backend
      • If the backend can convert color orders quickly, larger colorspace formats should be first.
      • An ABGR-preferred SDL system with fast conversion would order like this:
        1. createFormatBGR565()
        2. createFormatRGB565()
        3. createFormatXBGR1555()
        4. createFormatXRGB1555()
        5. createFormatBGR555()
        6. createFormatRGB555()
        7. createFormatBGRA4444()
        8. createFormatABGR4444()
        9. createFormatARGB4444()
        10. createFormatRGBA4444()
        11. createFormatCLUT8()
        • That is, larger colorspace first, equivalent colorspaces ordered by hardware support.
      • Whereas a similarly capable system with slower conversion would order like this:
        1. createFormatBGR565()
        2. createFormatXBGR1555()
        3. createFormatBGR555()
        4. createFormatBGRA4444()
        5. createFormatCLUT8()
        6. createFormatRGB565()
        7. createFormatXRGB1555()
        8. createFormatRGB555()
        9. createFormatRGBA4444()
        10. createFormatABGR4444()
        11. createFormatARGB4444()
        • That is, hardware supported RGB formats first, equivalently supported formats ordered by size of colorspace
    • Note: aside from the guarantee that the first item is directly supported in hardware, there is no way for an engine to determine whether or not any given format on the list is hardware supported. This is the reason that list ordering is important: the engine will use the first item in the list that it is compatible with.
  • Graphics::PixelFormat OSystem::getScreenFormat(void)
    • Returns the pixel format the game screen is currently initialized for.
  • virtual void OSystem::initSize(uint width, uint height, Graphics::PixelFormat *format = NULL)
    • initializes the size and pixel format of the game screen.
    • if format is left as NULL, a new Graphics::PixelFormat will be created, and initialized to CLUT8.
    • this is changed from the separate initFormat that was specified when I did not realize GFX transactions were an optional feature.
  • OSystem::TransactionError OSystem::endGFXTransaction(void)
    • backends supporting GFX transactions will return kTransactionFormatNotSupported in the list of transaction errors, when they are unable to initialize the screen with the requested format.
  • Graphics::PixelFormat Graphics::findCompatibleFormat(Common::List<Graphics::PixelFormat> backend, Common::List<Graphics::PixelFormat> frontend)
    • Returns the first entry on the backend list that also occurs in the frontend list, or CLUT8 if there is no matching format.
  • void Graphics::CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, Graphics::PixelFormat *format)
    • format is a pointer to a Graphics::PixelFormat describing the pixel format of the cursor graphic.
    • if format is left as NULL, CLUT8 will be used.
  • void Graphics::CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, Graphics::PixelFormat *format)
    • format is a pointer to a Graphics::PixelFormat describing the pixel format of the cursor graphic.
    • if format is left as NULL, a new Graphics::PixelFormat will be created, and initialized to CLUT8.
  • Graphics::CursorManager::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, Graphics::PixelFormat *format = NULL)
    • format is a pointer to a Graphics::PixelFormat describing the pixel format of the cursor graphic.
    • if format is left as NULL, a new Graphics::PixelFormat will be created, and initialized to CLUT8.

This is how initialization works:

  • Engine side:
    • Case 1: Game runs in 8-bit paletted mode
      1. No changes are necessary.
    • Case 2: Game runs in a specific high/true color format
      1. engine calls initGraphics with that format
      2. engine calls OSystem::getScreenFormat() to check resulting format against requested format
        • Case A: getScreenFormat() returns requested format
          1. engine runs happily
        • Case B: getScreenFormat() returns CLUT8 and engine has an 8-bit fallback mode
          1. engine switches to fallback mode
          2. engine runs in 8-bits
        • Case C: getScreenFormat() returns CLUT8 and engine doesn’t have fallback mode
          1. engine displays error and returns immediately
        • Case D: getScreenFormat() returns a format that is neither CLUT8 nor the requested format
          1. Tester submits bug report to backend maintainer
          2. Backend maintainer ensures that CLUT8 is the only unrequested mode that backend will fallback to.
    • Case 3: Game can support any RGB mode easily
      1. engine calls OSystem::getSupportedFormats()
      2. engine calls initGraphics with the top list item.
      3. engine calls OSystem::getScreenFormat() to ensure that format is usable properly at requested resolution
        • see cases 2A – 2D
    • Case 4: Game can run in a small number of RGB modes
      1. engine calls OSystem::getSupportedFormats() to get list of formats supported by backend
      2. engine produces list of formats game can run in
      3. engine calls Graphics::findCompatibleFormat(backend_list, engine_list)
      4. engine calls initGraphics with return value from findCompatibleFormat
      5. engine calls OSystem::getScreenFormat() to ensure that format is usable properly at requested resolution
        • see cases 2A – 2D
  • Backend side:
    • backend recieves screen’s requested resolution and format from initGraphics
      • Case 1: NULL pointer
        1. backend initializes screen to 8-bit graphics at requested resolution.
      • Case 2: Hardware directly supports format at requested resolution
        1. backend initializes screen to requested format at requested resolution.
      • Case 3: Hardware supports format at requested resolution, in a different color order
        • Case A: Requested format is RGBA or another conversion-supported color order
          1. backend initializes screen to corrected-order format equivalent at requested resolution.
          2. Backend implements pixel conversion on copyRectToScreen, preferably using ASM hand-crafted for speed.
          3. getScreenFormat will “lie” and return the requested format, rather than the hardware-supported equivalent that is actually being used.
        • Case B: Requested format is GABR or similarly nonsensical/unsupported color order
          1. backend initializes screen to 8-bit graphics at requested resolution.
      • Case 4: Hardware does not support format
        • Case A: requested format has alpha component and hardware supports equivalently-aligned format without alpha
          1. Backend initializes screen to alpha-less equivalent format at requested resolution.
          2. Backend implements alpha blending in software.
          3. getScreenFormat will “lie” and return the requested format, rather than the hardware-supported equivalent that is actually being used.
        • Case B: hardware supports higher format, backend can easily up-convert (optional case, to be handled at backend maintainer’s disgression)
          1. backend initializes screen to higher format.
          2. backend implements up-conversion on copyRectToScreen.
          3. getScreenFormat will “lie” and return the requested format, rather than the hardware-supported equivalent that is actually being used.
        • Case C: all other cases
          1. backend initializes screen to 8-bit graphics at requested resolution.
      • Case 5: Hardware supports format but not at requested resolution
        1. backend initializes screen to 8-bit graphics at requested resolution.

June 10, 2009

The vestiges of flesh

Filed under: Progress — Upthorn @ 3:50 am

Well, using the ad-hoc solution I described yesterday, I now have the SDL backend supporting (a very limited set of) pixelformat requests from engine codes.

And I’ve got the Scumm engine module making use of it.

Here’s a “before” and “after” set of the Humongous Interactive Catalog:

catalog_static_555RGB

Catalog, rendered in 555RGB

Catalog, rendered in properly paletted CLUT8

Catalog, rendered in properly paletted CLUT8

Incidentally, because I had never actually tried the interactive catalog before having converted the backend to render in 555RGB, I never realized until taking these screenshots that those perfect circles on the left are actually horribly distorted ellipses, and therefore, even though I knew everything was rendering at half width, I somehow expected a result that looked a bit more like this:

catalog_expected

And just to prove I haven’t broken 16-bit, here’s a screenshot of freddicove running in 16bit (RGB555) color, on the same build of ScummVM

Remember that screenshot back in my first progress update?...

Remember that screenshot back in my first progress update? ...this is what it would look like now.

Of course, this is a ad-hoc, temporary solution. It’s not nearly as dirty a hack as my first modification to make the backend render as 16-bit, but still, I strongly doubt that it will be an acceptable final implementation.

Additionally, in its current state, there is absolutely no error checking or sanitizing, and the mouse cursor code is still using the temporary hack I mentioned three posts ago — not respecting or even checking the backend state at all.

But it’s still a start, and I’m still proud of it.

June 5, 2009

Good news, everyone.

Filed under: Planning,Progress — Upthorn @ 11:02 am

My success in getting the initial 16-bit support into the backend, and getting it to work with resources from freddicove, triggered Kirben into a frenzy of updates to the Scumm engine code. 16-bit HE games seem to be working almost perfectly, now.

During this period, I have been doing some bug hunting in regard to this.

For example, when Kirben first mentioned strange graphical glitchesCoveIntroBroken

occuring in the intro to freddicove, I started msvc debugger and traced the issue to an error in the SDL copyRectToScreen method, that I had failed to correct when changing to 16-bit — when testing for the special case of a rectangle being the full width of the screen, it checked the rectangle’s pitch (or number of bytes from the start of one line to the start of the next), instead of width (or number of pixels from the start of one line to the start of the next) for equality with the screen width, resulting in the case being used when the rectangle being copied was half the screen width, but not when it was full.

CoveIntroFixed

I then corrected this error, and began looking at similar glitches that had been reported in baseball2001, and spyfox3.

During this time, the full versions of Spy Fox 3, Backyard Soccer MLS, Freddi Fish 5: The Case of Coral Cove, and Moonbase Commander arrived from ebay, and I began using those for testing. So far, I have concentrated primarily on Spy Fox 3, as it seemed to have the highest instance of graphical errors.

Long story short: Kirben seems to have fixed all of the known display errors that were internal to the Scumm engine, and I now have cursors displaying in 16-bit, because the work he did fixing hePalettes to work properly in 16-bit was incompatible with the cursors rendering properly in 8-bit mode. (I have screenshots of this, but this post is cluttered as it is, and little, if any, difference is visible from those cursors rendering properly in 8-bit.)

Additionally because of all these rapid developments on the scumm engine, I will begin discussion and work on the API as soon as Sev gets back from his vacation.

May 29, 2009

Minor progress update.

Filed under: Progress — Upthorn @ 7:54 am

If the prior post is to be taken as a checklist, the first item can now be crossed off.

ScummVM displaying a background from freddicove in glorious 16-bit color.

ScummVM displaying a background from freddicove in glorious 16-bit color.

Many thanks to Kirben for the help he provided in locating this resource.

May 24, 2009

Initial progress

Filed under: Progress — Upthorn @ 2:18 am

So, I’ve got the SDL backend set up with a 16 bit game screen, and copyRectToScreen set up to use it instead of the 8bpp one. Currently, for testing purposes, it just assumes that all pixel data passed from the game is 16bit RGB.

So games aren’t exactly playable with this compiled in, at the moment, as I haven’t yet begun modification of the core engine to display in 16bpp, as you can see in this screenshot of the freddicove demo

Freddicove in 16bpp

Freddicove in 16bpp

As you might see there, I still have it rendering the mouse pointer as 8bpp. This is so that I can still have a reasonable idea of what it’s pointing at and use it to find the exit button.

At _sev’s suggestion, I have changed the vCUPhe subengine to display a 16bpp gradient instead of playing humongous entertainment preview movies, in order to test the backend.

Well, it turns out the backend portion is working, fine, as you can see in this

full color 16-bit gradient

full color 16-bit gradient

So, this is the current state of things. I’ll be making another post a little later on with my current roadmap for the rest of the project.

Create a free website or blog at WordPress.com.