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.)

August 18, 2009

Radical changes required?

Filed under: Planning — Upthorn @ 2:16 am

I’m at a sticking point in designing the keymapper API, or planning/progressing on the similar tasks, which stems from the complexity of the existing code.

I wonder if it might be faster, easier, and better overall to redesign some parts of the keymapper from scratch, so I can focus on building something clean and simple, instead of trying to figure out what parts of the existing structure can be cut out without compromising the function of its design.

Up until this point, I’ve been working under the assumption that the prior student’s design is fundamentally sound, and it is only the details of implementation that needed reworking, but if that is not the case, then the approach I’ve been taking will require more time and effort to be successful than a complete redesign of the component would.

I’m going to consider, over the course of the next day, how I would do this if I had to implement it from scratch, and see if I can find a simpler method than the one that was used.

August 17, 2009

Over the wire and through the woods.

Filed under: Planning — Upthorn @ 2:14 pm

I’ve just been informed by LordHoto that the 1900UTC August 17th line is not, in fact, a deadline for students, but the end of their obligation to perform, and I can continue up until the 24th, to submit code which may be evaluated.

So, I’ll be continuing to work on the API in the hopes of doing just that.

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 13, 2009

slow going

Filed under: Uncategorized — Upthorn @ 10:01 am

As anyone who’s been following the commit logs can tell, I’m having a lot of difficulty keeping up a good pace of work on the keymapper. The reason for this is that, unlike with my prior project, nearly all the progress I make on this task comes at the expense of code that someone else wrote before, and because I did not get a lot of time to look over it before I started working (which is mostly my own fault), I don’t really understand how it all works together well enough to be certain that the code I’m replacing it with will be better.

As a result, I’m being very hesitant about any changes I make because I always want to be certain I understand what the existing code is doing (and how) before I destroy it to make room for my own.

However, I am still working on the keymapper improvements, and I have no intent of giving up before I’ve finished them, no matter how long I have to keep working on this past the end of this year’s GSoC.

August 11, 2009

Keymapper API proposal for engine to define actions

Filed under: Planning — Upthorn @ 2:22 am

Note: I’m staying up late to get this proposal written before the deadline my mentor has given, so my words in this post might not make a lot of sense.

It seems to me that the problem with the currently implemented approach is that the Action structure is too complicated to require engine authors to create and initialize a full structure for every single action that they wish to be mapped to a key. Additionally, it requires engine authors to give each individual action a universally unique 4 character ID, so that actions and their keymappings can be saved to the config without any other game that ScummVM can run ever overwriting it with a different key. However, some of the more complicated features of the Action structure may be necessary for some games to fully function in a reduced-key environment.

Because of these factors, it seems to me that there are two steps which should be taken to make the keymapper work better for engine authors:

  1. The Common::Action structure needs to be closely examined, and unnecessary components removed.
  2. One or more constructors should be provided to allow for easy mass production of more common types of Actions, especially ones that simply need to map one key press to some other button.

I fear that this API proposal is grossly insufficient, because the task of properly implementing modifiers in the keymapper has been much more interesting and less straightforward than I expected, and has left me with very little time before to properly examine the other aspects of the keymapper component before now.

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.

August 4, 2009

Back in the saddle

Filed under: Planning — Upthorn @ 2:25 pm

Alright, I’m finally back from vacation, and well rested, and shaking off my cold, so it’s time to get back to work on this.

From this point, I’m actually going to be working on the keymapper, so I’m making this blog post to organize my thoughts into a plan of action.

  1. Become familiar with the current working of the keymapper.
  2. Create a standardized framework for backends to describe keys and define keymaps.
  3. Make a stack for keymaps to be pushed onto and popped from as needed.
  4. Make use of the framework to allow the keymapper to automatically generate keymaps.
  5. Figure out some way to make the keymaps easily userconfigurable.

This is only the most general of outlines at the moment, I expect to add subtasks, and rearrange the task list as I become more familiar with the keymapper as it currently exists.

Note: I wrote this post on July 30, but somehow wordpress never published it, thankfully it was saved to drafts, at least.

July 21, 2009

Still alive

Filed under: Uncategorized — Upthorn @ 10:21 am

I’m still alive. Also still on vacation. I haven’t yet had an opportunity to discuss keymappers with Sev, but have not forgotten about my obligations. However, my schedule of having fun with people I haven’t seen in years is very demanding, and takes priority because of the limited window of opportunity. I hope to be back to working full swing on the project next Wednesday.

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.

July 6, 2009

Updated API reference

Filed under: Uncategorized — Upthorn @ 4:31 am

Note: the following is copied from the source of the wiki reference article I just wrote for it.

Contents

//

Introduction

This page is meant as a reference for developers implementing the Truecolor API in their engine and backend modules. This page will provide a complete spec of API requirements and suggestions, as well as a protocol for engines and backends to follow during setup.

NOTE: This API was designed with backwards-compatibility for 8-bit Graphics only engines in mind. If your engine only uses 256 color graphics, you should not have to change anything, so long as the engine’s ENABLE_RGB_COLOR setting matches the backend’s during compilation, so that functions link properly.

Truecolor API specifications

Engine specifications

  • Engines capable of some, but not all RGB formats must use Graphics::findCompatibleFormat with OSystem::getSupportedFormats() as the first parameter, and the engine’s supported format list as the second parameter.
  • Lists of formats supported by the engine must be in descending order of preference. That is, the first value is the most wanted, and the last value id the least wanted.
  • Engines capable of any RGB format must use the first item in the backend’s getSupportedFormats() list to generate graphics.
  • Engines with static graphical resources should use the backend’s preferred format, and convert resources upon loading, but are not required to.
  • Engines which do not require the backend to handle alpha should not use XRBG1555 or XBGR1555 modes, but may do so.

Backend specifications

  • When no format has been requested, or no game is running, the return value of getScreenFormat must equal that of Graphics::PixelFormat::createFormatCLUT8().
  • If a requested format can not be set up, the backend must revert to 256 color mode (that is, Graphics::PixelFormat::createFormatCLUT8()).
  • Backends must not change the return value of getScreenFormat outside of initBackend, initSize, or endGFXTransaction.
  • Backends must be able to display 256 color cursors even when the screen format is set differently.
  • Backends supporting GFX transactions must return kTransactionFormatNotSupported from endGFXTransaction when screen format change fails.
  • Backends must place the highest color mode that is supported by the backend and the hardware at the beginning of the list returned by getSupportedFormats.
  • Backends should support graphics in RGB(A) color order, even if their hardware uses a different color order, but are not required to.
  • Backends supporting color order conversion with limited hardware may use Graphics::crossBlit, but are strongly recommended to use platform-optimized code.

Truecolor API initialization protocol

Engine initialization protocol

NOTE: This API was designed with backwards-compatibility for 8-bit Graphics only engines in mind. If your engine does not make use of per-pixel RGB color graphics, you should not have to change anything, so long as ENABLE_RGB_COLOR is set in configuration during compilation, so that functions link properly.

  1. Init with desired pixel format
    • If your engine can only produce graphics in one RGB color format, initialize a Graphics::PixelFormat to the desired format, and call initGraphics with a pointer to that format as the fourth parameter.
      • For instance, if your engine can only produce graphics in RGB555, you would say Graphics::PixelFormat myFormat(2, 3, 3, 3, 8, 10, 5, 0, 0);
    • If your engine can easily support any RGB mode (for instance if it converts from YUV), call initGraphics with NULL for the fourth parameter.
    • If your engine can support more than one RGB mode, but not all of them…
      1. Produce a Common::List of Graphics::PixelFormat objects describing the supported formats. This list must be in order of descending preference, so that the most desired format is first, and the least desired is last.
      2. call initGraphics with this list of formats as the fourth parameter
  2. Check the return value of OSystem::getScreenFormat() to see if setup of your desired format was successful. If setup was not successful, it will return Graphics::PixelFormat::createFormatCLUT8();
    • If the setup was not successful, and your engine cannot run in 256 colors, display an error and return.
    • Otherwise, initialize your engine to use the pixel format that getScreenFormat returned, and run normally.

Example

Here is an example of a simple engine that uses the best color depth available to display and color-cycle this gradient:

GradientRGB565

Common::Error QuuxEngine::run() {
	Graphics::PixelFormat ourFormat;

	// Request the backend to initialize a 640 x 480 surface with the best available format.
	initGraphics(640, 480, true, NULL);

	// If our engine could only handle one format, we would specify it here instead of asking the backend:
	// 	// RGB555
	// 	ourFormat(2, 3, 3, 3, 8, 10, 5, 0,  0);
	// 	initGraphics(640, 480, true, &ourFormat);

	// If our engine could handle only a few formats, this would look quite different:
	//  	Common::List<Graphics::PixelFormat> ourFormatList;
	//
	// 	// RGB555
	// 	ourFormat(2, 3, 3, 3, 8, 10, 5, 0,  0); 
	// 	ourFormatList.push_back(ourFormat);

	//
	// 	// XRGB1555
	// 	ourFormat(2, 3, 3, 3, 7, 10, 5, 0, 15); 
	// 	ourFormatList.push_back(ourFormat);
	// 	
	// 	// Use the best format which is compatible between our engine and the backend

	// 	initGraphics(640, 480, true, ourFormatList);

	// Get the format the system was able to provide
	// in case it cannot support that format at our requested resolution
	ourFormat = _system->getScreenFormat();

 	byte *offscreenBuffer = (byte *)malloc(640 * 480 * ourFormat.bytesPerPixel);

 	if (ourFormat.bytesPerPixel == 1) {
		// Initialize palette to simulate RGB332

		// If our engine had no 256 color mode support, we would error out here:
		//  	return Common::kUnsupportedColorMode;

		byte palette[1024];
		memset(&palette,0,1024);

		byte *dst = palette;
		for (byte r = 0; r < 8; r++) {

			for (byte g = 0; g < 8; g++) {

				for (byte b = 0; b < 4; b++) {

					dst[0] = r << 5;
					dst[1] = g << 5;

					dst[2] = b << 6;
					dst[3] = 0;

					dst += 4;
				}
			}
		}

		_system->setPalette(palette,0,256);
	}

	uint32 t = 0;

	// Create a mask to limit the color from exceeding the bitdepth
	// The result is equivalent to:
	// 	uint32 mask = 0;
	// 	for (int i = ourFormat.bytesPerPixel; i > 0; i--) {
	// 		mask <<= 8;
	// 		mask |= 0xFF;
	// 	}
	uint32 mask = (1 << (ourFormat.bytesPerPixel << 3)) - 1;

	// Repeat this until the event manager tells us to stop
	while (!shouldQuit()) {

		// Keep t from exceeding the number of bits in each pixel.
		// I think this is faster than "t %= (ourFormat.bytesPerPixel * 8);" would be.
		t &= (ourFormat.bytesPerPixel << 3) - 1;

		// Draw the actual gradient
		for (int16 y = 0; y < 480; y++) {

			uint8 *dst = offscreenBuffer + (y * 640 * ourFormat.bytesPerPixel);

			for (int16 x = 0; x < 640; x++) {

				uint32 color = (x * y) & mask;
				color = (color << t) | (color >> ((ourFormat.bytesPerPixel << 3) - t));

				// Currently we have to jump through hoops to write variable-length data in an endian-safe manner.
				// In a real-life implementation, it would probably be better to have an if/else-if tree or
				// a switch to determine the correct WRITE_UINT* function to use in the current bitdepth.
				// Though, something like this might end up being necessary for 24-bit pixels, anyway.

#ifdef SCUMM_BIG_ENDIAN
				for (int i = 0; i < ourFormat.bytesPerPixel; i++) {

					dst[ourFormat.bytesPerPixel - i] = color & 0xFF;

					color >>= 8;
				}
				dst += ourFormat.bytesPerPixel;

#else
				for (int i = ourFormat.bytesPerPixel; i > 0; i--) {

					*dst++ = color & 0xFF;
					color >>= 8;

				}
#endif
			}
		}
		// Copy our gradient to the screen. The pitch of our image is the width * the number of bytes per pixel.
		_system->copyRectToScreen(offscreenBuffer, 640 * ourFormat.bytesPerPixel, 0, 0, 640, 480);

		// Tell the system to update the screen.
		_system->updateScreen();

		// Get new events from the event manager so the window doesn't appear non-responsive.
		parseEvents();

		// Wait a semi-arbitrary length in order to animate fluidly, but not insanely fast
		_system->delayMillis(66);

		// Increment our time variable, which doubles as our bit-shift counter.
		t++;
	}
	return Common::kNoError;
}

Backend initialization protocol

  1. During first initialization, set the value that getScreenFormat returns to Graphics::PixelFormat::createFormatCLUT8()
  2. When initSize is called, attempt to set screen format with the PixelFormat pointed to by the format parameter
    • If format is NULL, use Graphics::PixelFormat::createFormatCLUT8()
    • If requested screen format is supported, attempt to set screen up with it.
      • If setup is unsuccessful, fall back to previous color mode and set the value that getScreenFormat returns accordingly.
        • Note: During game initialization, this must always result in a fall-back to 256 color mode with getScreenFormat returning a value equivalent to Graphics::PixelFormat::createFormatCLUT8. This may only have any other result if the same game has already run an initSize with a different format, and is trying to switch formats during runtime.
      • If setup is successful, update the value that getScreenFormat returns to the value that was requested.
        • If format is supported by backend but not directly in hardware, ensure that graphics are converted in copyRectToScreen
    • If requested screen format is not supported, continue running in 256 color mode.

Complete API reference

New functions

OSystem

  • Graphics::PixelFormat OSystem::getScreenFormat(void)
    • Returns the pixel format currently accepted for graphics from the engine.
  • Common::List<Graphics::PixelFormat> OSystem::getSupportedFormats(void)
    • Returns a list of all the pixel formats the backend can accept graphics in.
    • The first item in this list must be the highest color graphics mode supported by the backend which is directly supported by the hardware.
    • The remainder of the list must be in order of descending preference, such that the last item in the list is the one that the backend functions worst in.
    • Backends which do not support fast conversion must put all modes directly supported in hardware, (and CLUT8), before modes that will require conversion during copyRectToScreen.
    • Backends which support fast conversion should put larger colorspaces before smaller color spaces, but are not required to.

Graphics::PixelFormat

  • inline 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.
  • inline Graphics::PixelFormat (void)
    • creates an uninitialized PixelFormat.
  • inline Graphics::PixelFormat(byte BytesPerPixel, byte RBits, byte GBits, byte BBits, byte ABits, byte RShift, byte GShift, byte BShift, byte AShift)
    • creates an initialized PixelFormat.
    • [_]Bits is the width in bits of the relevant channel
      • RBits = red bits, GBits = green bits, BBits = blue bits, ABits = alpha bits.
    • [_]Shift is the number (starting from 0) of the least significant bit in the relevant channel, which is equal to the bitshift required to make a channel.
      • In RGB565, RShift is 11, GShift is 5, and BShift is 0.
      • In RGBA4444, RShift is 12, GShift is 8, BShift is 4, and AShift is 0.
  • static inline Graphics::PixelFormat Graphics::PixelFormat::createFormatCLUT8(void)
    • creates a PixelFormat set to indicate 256 color paletted mode
    • This method is provided for convenience, and is equivalent to initializing a Graphics::PixelFormat with the bytedepth of 1, component losses of 8, and component shifts of 0.
      • Which would be accomplished normally via Graphics::PixelFormat(1,8,8,8,8,0,0,0,0);
    • Because this methods are static, it can be called without creating a pixel format first
      • For instance, if (format == NULL) newFormat = Graphics::PixelFormat::createFormatCLUT8();

Miscellaneous

  • bool Graphics::crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, int w, int h, Graphics::PixelFormat dstFmt, Graphics::PixelFormat srcFmt)
    • blits a rectangle from a “surface” in srcFmt to a “surface” in dstFmt
    • returns false if the blit fails (due to unsupported format conversion)
    • returns true if the blit succeeds
    • can convert the rectangle in place if src and dst are the same, and srcFmt and dstFmt have the same bytedepth

Modified functions

engine

  • void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format)
    • Now takes a format parameter, which is a pointer to a requested pixelformat
    • Uses top item in backend’s getSupportedFormats list if format is NULL
    • Now displays a warning if it recieves OSystem::kTransactionFormatNotSupported in return from endGFXTransaction
    • Now overloaded to simplify initialization for the three engine types:
  • void initGraphics(int width, int height, bool defaultTo1xScaler)
    • A wrapper which sets format as a pointer to Graphics::PixelFormat::createFormatCLUT8();
  • void initGraphics(int width, int height, bool defaultTo1xScaler, const Commmon::List<Graphics::PixelFormat> &formatList)
    • A wrapper which sets format as a pointer to the return value from Graphics::findCompatibleFormat(OSystem::getSupportedFormats(),formatList)

OSystem

  • virtual void OSystem::initSize(uint width, uint height, Graphics::PixelFormat *format = NULL)
    • Can now take a format parameter, which is a pointer to a requested pixelformat, and defaults to NULL
    • Uses 256 color mode if format is NULL
  • OSystem::TransactionError OSystem::endGFXTransaction(void)
    • Must now return kTransactionFormatNotSupported if the backend fails in an attempt to initialize to a new pixel format during a GFX transaction.

CursorMan

  • void Graphics::CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, Graphics::PixelFormat *format)
    • Can now take a format parameter, which is a pointer to a Graphics::PixelFormat describing the pixel format of the cursor graphic, and defaults to NULL.
    • Uses 256 color mode if format is NULL
  • void Graphics::CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, Graphics::PixelFormat *format)
    • Can now take a format parameter, which is a pointer to a Graphics::PixelFormat describing the pixel format of the cursor graphic, and defaults to NULL.
    • Uses 256 color mode if format is NULL
  • Graphics::CursorManager::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8())
    • Can now take a format parameter, which is a Graphics::PixelFormat describing the pixel format of the cursor graphic, and defaults to 256 color mode.

Modified Types

  • enum Common::Error
    • Now includes a kUnsupportedColorMode value, for engines which get unsupported pixel formats after a format change request fails.
  • enum OSystem::TransactionError
    • Now includes a kTransactionFormatNotSupported value, for backends to announce failure to supply game screen with requested pixel format.

July 5, 2009

Taking the left fork

Filed under: Planning — Upthorn @ 2:03 am

Of my initial project (16-bit support), all that remains to be done is to document the API on the wiki. My mentor, Sev has requested of me that I move on to improving the keymapper, which he sees as a much higher priority than scaler and backend support for 24 or 32 bit color formats.

I agree with that assessment, and I can’t really say I was looking forward to upgrading the scalers.

In light of this, I am providing a new planned timeline:

Optimistic:

  • Jul 5th – Jul 6th: Fully document the API in this blog, doxygen, and wiki.
  • Jul 7th – Jul 10th: Midterm evaluation for google, and any finishing touches necessary for the API docs.
  • Jul 11th – Jul 13th: Begin research on the keymapper
  • Jul 14th – Jul 28th: The vacation I mentioned in my application, possibly continue research on the keymapper.
  • Jul 29th –  Aug 5th: Design and implement the requested enhancements.
  • Aug 6th – Aug 17th: Improve scalers, gui, and SDL backend to support 24 and 32 bit pixel formats, if time permits.

Pessimistic:

  • Jul 5th – Jul 11th: Fully document the API in this blog, doxygen, and wiki.
  • Jul 12th – Jul 13th: Last minute midterm evaluation for google, and a round of Q&A to finish the API docs.
  • Jul 14th – Jul 28th: The vacation I mentioned in my application, begin research on the keymapper.
  • Jul 29th –  Aug 17th: Design and implement the requested keymapper enhancements.

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 23, 2009

Status report

Filed under: Uncategorized — Upthorn @ 2:19 pm

What follows is a copy of the status report email I sent the ScummVM GSoC mentors list, as it has been requested that I post it on my blog as well:

Hello Eugene, everyone:
Here is the status report and timeline for my project, as requested:

My project was to develop and implement 16-bit (and optionally 24/32 bit) graphical support for games that made use of it. I was to focus primarily on the later HE Scumm games.

The current status is that:

  • the 16-bit HE Scumm games are all displaying in 16-bit
  • A preliminary API has been designed for games to request specific graphical formats of the backend
  • this API has been implemented in the SDL backend

My currently active tasks are:

  • refining/simplifying the API
  • writing documentation for the API

My future tasks are:

  • Exhaustive testing of the 16-bit scumm engine games, to ensure that there are no 16-bit related display glitches
  • Work necessary in other engines with 16-bit RGB graphics to make use of the finalized API, (as time permits)
  • Upgrading the scalers, gui, and SDL backend to support 24/32 bit pixel formats, if time permits

Here is the timeline so far:

  • May 18th – May 21st: Began work on SDL backend, implementing 16-bit screen surface to test with
  • May 22nd – May 29th: Began work on Scumm engine, implementing 16-bit displays to test 16-bit SDL screen.
  • May 30th – Jun 1st: Travis assumed responsibility for Scumm HE rendering code for 16-bit support. I tested games for display bugs, and fixed a backend bug.
  • Jun 3rd: Max creates SVN branch for me, Kirben and I commited our patches.
  • Jun 4th – Jun 6th: developed hack to allow 8-bit and 16-bit cursors to display properly.
  • Jun 7th – Jun 13th: Discussed API concerns with key ScummVM developers, developed ad-hoc API while awaiting conclusions.
  • Jun 14th – Jun 17th: Documented discussion results and refactored ad-hoc API code to bring it in line with the decisions that were made.
  • Jun 18th – Jun 22rd: Began streamlining and refining the API.

Here is my expected timeline for the future (optimistic):

  • Jun 23rd – Jun 26th: Finalize and document the API.
  • Jun 27th – Jul 13th: Test 16-bit SCUMM HE games for display glitching.
  • Jul 14th – Jul 28th: The vacation I mentioned in my application, possible continued testing of SCUMM HE games.
  • Jul 29th – Jul 31st: Do research of other engines requiring RGB color support.
  • Aug 1st – Aug 7th: Enhance these engines to make use of the API
  • Aug 8th – Aug 17th: Improve scalers, gui, and SDL backend to support 24 and 32 bit pixel formats

Here is my expected timeline for the future (pessimistic):

  • Jun 23rd – Jul 13th: Finalize and document the API.
  • Jul 14th – Jul 28th: The vacation I mentioned in my application, begin testing 16-bit HE Scumm games for graphical glitching
  • Jul 29th – Aug 17th: Continued testing and bugfixing of 16-bit HE Scumm games.

I hope this is sufficient,
Jody Northup

June 17, 2009

Organizing my thoughts

Filed under: Planning — Upthorn @ 12:02 am

So, in an earlier post, I made an outline of the steps in front of me:

Because of how quickly this project has been moving, I’ve managed to lose all track of where I am and where I’m going.

So, in order to collect my thoughts, I’m referring back to that outline, and taking stock of the steps, their completion status, and their relationship to reality:

  1. Modify the Scumm HE engine to display a 16-bit background resource when the freddicove demo is loaded (to test my understanding of the resource format and standard rendering process).
  2. Integrate this functionality into the standard running of the Scumm HE engines. — Kirben did these three.
  3. Add 16-bit support in place for other resource types. — Kirben did these three.
  4. Modify rendering, for 16-bit HE games, such that the 8-bit resources are rendered using the palette->rgb mapping system that the game engine provides. (possibly involves implementing this functionality) — Kirben did these three.
  5. Perform unit tests to ensure that all 16-bit Scumm HE games are rendering properly — Partially done, remainder delayed until completion of API work
  6. Hack the mouse cursor for 16-bit support because  the erroneous display is incredibly annoying.
  7. Reimplement 16-bit cursor support in a less hackish manner because that was ugly.
  8. Discuss with mentor at length to determine ideal API behavior for bit-depth/pixel format negotiation between game engines and backends. — Not just my mentor, but most of the dev community. (Here are the final results.)
  9. Implement hackish proof-of-concept API while awaiting discussion from dev community.
  10. Implement support for this API in SDL backend and Scumm HE engine. (The real one) — This is basically done, although I want to change the behavior of a few things slightly. — (This is the point at which the mouse cursor will be upgraded, because between the in-game mouse cursor and the in-game menu, at least one must be assured to display properly if any meaningful testing is to be done.) — This turned out to be a lie. See steps 6 and 7
  11. Document this API exhaustively. — This may be difficult, and I will have to discuss with Sev about where and how I should do this.
  12. Finish testing 16-bit Scumm HE games. — I think I have all of them but pjgames, now.
  13. See what can be done about engines other than Scumm.
  14. NEW! See about fixing up the gui, SDL backend, and scalers for 24/32 bit color support.

Because of Kirben’s intervention, this whole task has been going much more quickly than even my most optimistic expectations. I imagine that, on my own, I might have finished step 3 by now, but I really am not sure. Certainly I was expecting it to take at least another month to get to this point.

June 14, 2009

How this is going to work

Filed under: Planning — Upthorn @ 5:28 am

After a great deal of discussion on the matter, Eugene has given me a final decision:

The engine is going to specify a Graphics::PixelFormat to the backend.

So here’s how this is going to work:

  • New Methods
    • Graphics::PixelFormat constructor, for convenience of engine developers (details to be determined)
    • OSystem::getBestFormat(void)
      • Returns a Graphics::PixelFormat describing the highest bitdepth supported by the backend (important for YUV games which will want to output in the highest quality)
    • OSystem::initFormat(Graphics::PixelFormat)
      • Set up the color format of the virtual screen in the gfxtransaction, to be applied on endGfxTransaction
    • Graphics::PixelFormat OSystem::getScreenFormat(void)
      • Returns a pixelformat describing the current color mode
    • CursorManager::pushCursorFormat(Graphics::PixelFormat)
      • Pushes a new cursor pixel format onto the stack, and set it in the backend.
    • CursorManager::popCursorFormat(void)
      • Pop a cursor pixel format from the stack, and restore the previous one to the backend.
      • If there is no previous format, the current screen format is used instead.
      • Unlike CursorManager::popCursorPalette, this must be called prior to CursorManager::popCursor
    • CursorManager::replaceCursorFormat(Graphics::PixelFormat)
      • Replace the current cursor pixel format on the stack.
      • If the stack is empty, the format is pushed instead.
      • These methods should be called whenever the equivalent *CursorPalette methods are called, to keep cursor rendering straight across color mode changes.
  • Changed functions/methods
    • initGraphics
      • Takes an optional pointer to a Graphics::PixelFormat struct
      • if pointer is null or not supplied, initializes using CLUT8 (standard 8-bit that everything already uses)
    • OSystem::endGFXTransaction
      • Must apply the color mode setup by initFormat
      • kTransactionPixelFormatNotSupported is included in the return value if color mode setup fails
  • TODO: new and changed class members.

The bitdepth initialization process will be as follows:

  • 8Bit paletted:
    1. Engine calls initGraphics (no changes are required on the engine side)
    2. initGraphics initializes a CLUT8 Graphics::PixelFormat, skips compatibility checking because all backends must support CLUT8 exactly they currently do
    3. initGraphics passes the CLUT8 PixelFormat to OSystem::initFormat
    4. Backend sees that the format matches the one that is currently set up, and ignores that part of the transaction
  • High or true color RGB:
    1. Engine initializes a Graphics::PixelFormat with the color format that the game uses (games which convert from YUV will query OSystem::getBestFormat to decide this)
    2. Engine passes this format to initGraphics
    3. initGraphics passes this format to OSystem::initFormat
    4. Backend sets up virtual screen format to be applied with transaction
    5. Backend attempts to initialize virtual screen with specified format and resolution, falls back to 8-bit and returns kTransactionPixelFormatNotSupported on failure.
    6. initGraphics checks transaction return for kTransactionPixelFormatNotSupported, and warns if encountered.
    7. Engine queries backend (using OSystem::getScreenFormat) to check the current color format
    8. Engine branches based on result:
      • Requested format
        1. Engine runs happily
      • CLUT8
        • If engine supports a 256 color fallback mode
          1. Engine falls back to 256 colors, and runs with only minor complaint
        • If engine does not support a 256 color fallback
          1. Engine displays error message that the system does not support its required format
          2. Engine returns with error (error code TBD).

June 11, 2009

bitdepth/pixelformat pros and cons

Filed under: Planning — Upthorn @ 3:11 am

I have recieved and reviewed the discussion in the bitdepth/pixelformat mailing list thread that I started, and I’m a bit worried by the results:
One vote (Sven) for the old bitformat (8, 555, 565, 888) style of format specification
One vote (Eugene) for the engine requesting only a bitdepth, not a full format
Two votes (Johannes and Max) for the engine requesting a (list of) fully formed Graphics::PixelFormat object(s).
One vote (Myself) for using an enumerated list
Three people (Marcus, Joost, Oystein) contributing useful information about backend concerns, but no recommendations of their own

Nothing resembling a consensus, and very little discussion on the pros and cons of each method.

So, I’m going to list the pros and cons (as I see them) for each format:

  • Old bitformat:
    • Pros:
      • Already defined and implemented
      • Values presented in a very readable and understandable format
      • Requires minimum of sanity checking by backends
      • Requires minimum of sanity checking by engines
    • Cons:
      • Requires extra work for backends wanting to add support for a format not currently defined
      • Requires extra conversions to/from a format that can be understood by video interface
      • Viewed as outdated and “evil” by some menbers of the community
    • Neutral/dependant:
      • Backend responsible for specifying color order
  • Bitdepth only
    • Pros:
      • Already defined
      • Values presented in a very readable and understandable format
      • Minimum of sanity checking necessary for backend
    • Cons
      • Disallows possibility of multiple formats in same bitdepth (ARGB1555/RGB555/RGB565/RGBA444)
      • Requires all engines with higher than 256 color modes to fully understand Graphics::PixelFormat values
      • Requires all engines with higher than 256 color modes to support color format conversions to match backend
      • Requires extra conversions to/from a format that can be understood by video interface
    • Neutral/dependant:
      • Backend entirely responsible for specifying color format
  • Graphics::PixelFormat
    • Pros:
      • Already defined and implemented
      • Allows great flexibility in negotiation of color mode between engine and backend
      • No extra conversions necessary once format is agreed upon
    • Cons:
      • Complicated for engine to produce a list of supported formats
      • Requires backend developers to create and maintain a comprehensive list of supported formats or perform extensive checks to determine compatibility.
      • Requires engine to fully understand and work with Graphics::PixelFormat object
    • Neutral/dependant:
      • Engine is primarily responsible for determining color format.
  • Enum type (colormode and colororder fields)
    • Pros:
      • Allows great flexibility in negotiation of color mode between engine and backend
      • Values presented in a very readable and understandable format
      • Requires minimum of sanity checking by backends
      • Requires minimum of sanity checking by engines
    • Cons:
      • Slightly complicated for engine to produce list of supported formats.
      • Requires extra conversions to/from a format that can be understood by video interface.
    • Neutral/dependant:
      • Engine is primarily responsible for determining color format.
  • Enum type (colormode only)
    • Pros:
      • Values presented in a very readable and understandable format
      • Requires minimum of sanity checking by backends
      • Requires minimum of sanity checking by engines
    • Cons:
      • Requires extra conversions to/from a format that can be understood by video interface.
    • Neutral/dependant:
      • Backend responsible for specifying color order
  • New type (not yet defined)
    • Pros:
      • Can be designed specifically for this task
    • Cons:
      • May require significant effort to implement

Now, if I take Eugene’s recommendation (from IRC) that color order passed from engine to backend is always RGBA, then removing the ability from the engines to specify their own order is actually a plus, as it shields from potential future developer error. But, I don’t know if that idea is universally agreed upon.

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 8, 2009

The barest of skeletons

Filed under: Planning — Upthorn @ 11:59 pm

While no consensus has yet been reached on the concerns regarding the API, I am going ahead and starting work one of the possibilites that has begun to feel fully formed in my head:

This model uses an enum type, (temporarily Graphics::ColorFormat) which is divided into two parts, FormatType and ColorOrder, which are ORed together.

To start with, I am providing ten values for FormatType:

  • kFormat8Bit = 0
  • kFormatRGB555 = 1
  • kFormatARGB1555 = 2
  • kFormatRGB556 = 3
  • kFormatRGB565 = 4
  • kFormatRGB655 = 5
  • kFormatARGB4444 = 6
  • kFormatRGB888 = 7
  • kFormatARGB6666 = 8
  • kFormatARGB8888 = 9

and 31 values for ColorOrder

  • kFormatPalette = 0 << 8
  • kFormatRGB = 1 << 8
  • kFormatRBG = 2 << 8
  • kFormatGRB = 3 << 8
  • kFormatGBR = 4 << 8
  • kFormatBRG = 5 << 8
  • kFormatBGR = 6 << 8
  • kFormatARGB = 7 << 8
  • kFormatBGRA = 30 << 8

For this tentative model,  the optional parameter to Engine::InitGraphics will be a Common::List of formats the game supports. The backend will iterate through this list and test each entry for compatibility, using a pair of switches, as per the following simplified example:

OSystem::TransactionError checkFormatCompatibility(Graphics::ColorFormat format)
{
switch(format & kFormatTypeMask) {
case kFormat8Bit:
case kFormatRGB555:
break;
default:
return kTransactionPixelFormatNotSupported;
}

switch (format & kFormatOrderMask) {
case kFormatRGB:
case kFormatARGB:
return kTransactionSuccess;
default:
return kTransactionPixelFormatNotSupported;
}
}

NOTE FOR DEVELOPERS: I do not really expect this to be an acceptable final implementation, as it is a combination of overkill (who’s ever heard of BAGR6666 color?) and underkill (no YUV support), so, pending further notice do not use information from this post to make any plans or modifications to your engine or your backend. I am only using this as a direction for me to pursue while I await a final decision from full developers.

June 7, 2009

First outlines of an API

Filed under: Planning — Upthorn @ 5:39 pm

After discussing the API a bit with my mentor, Sev, it has been determined that the game engine should initially request a bitdepth/pixelformat of the backend by means of an optional parameter passed to Engine::InitGraphics

There are still a few details that haven’t been determined, like:

  • What happens when the engine requests an unsupported format;
  • Should the parameter be a bitdepth (8, 16, 24, 32) a generic specifier (8, 555, 565, 1555, 888, 8888), a fully formed Graphics::PixelFormat object, or some other format not yet defined;
  • Should any pixelformat conversions be performed if the engine and backend cannot agree on a directly supported format
  • If so, should they be performed by the engine, or by the backend? or should it vary by circumstance?
  • Probably many others that I haven’t considered yet

But, I am beginning to form a mental picture of how this thing will work, and I will, of course, discuss these remaining questions with Sev, and others, at the next opportunity.

Next Page »

Blog at WordPress.com.