Difference between revisions of "API-Truecolor"

Jump to navigation Jump to search
4,475 bytes added ,  15:17, 25 October 2018
m
Text replacement - "</source>" to "</syntaxhighlight>"
(Created reference documentation for truecolor API)
 
m (Text replacement - "</source>" to "</syntaxhighlight>")
 
(17 intermediate revisions by 3 users not shown)
Line 20: Line 20:
*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 '''''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 ''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 ''should'' do so by calling convertScreenRect from copyRectToScreen when conversion is necessary, 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.
*Backends supporting color order conversion with limited hardware ''should'' override convertScreenRect with platform-optimized code, but are not required to.


== Truecolor API initialization protocol ==
== Truecolor API initialization protocol ==
Line 27: Line 26:
'''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.
'''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.


#Determine/obtain desired pixel format
#Init with desired pixel format
#*If your engine can only produce graphics in one RGB color format, use Graphics::PixelFormat::createFormat{the desired 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 might say Graphics::PixelFormat requestedFormat = Graphics::PixelFormat::createFormatRGB555();
#**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 OSystem::getSupportedFormats and use the first value in the returned Common::List.
#*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...
#*If your engine can support more than one RGB mode, but not all of them...
#*#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.
#*#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.
#*#Use the return value from Graphics::findCompatibleFormat(OSystem::getSupportedFormats(),{your format list}
#*#call initGraphics with this list of formats as the fourth parameter
#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();
#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.
#*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.
#*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: [[Image:QuuxGradientRGB565.png]]
<syntaxhighlight lang="cpp">
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;
}
</syntaxhighlight>


=== Backend initialization protocol ===
=== Backend initialization protocol ===
Line 43: Line 163:
#*If format is NULL, use Graphics::PixelFormat::createFormatCLUT8()
#*If format is NULL, use Graphics::PixelFormat::createFormatCLUT8()
#*If requested screen format is supported, attempt to set screen up with it.  
#*If requested screen format is supported, attempt to set screen up with it.  
#**If setup is unsuccessful, fall back to 256 color mode and set the value that getScreenFormat returns to Graphics::PixelFormat::createFormatCLUT8().
#**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 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 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.
#*If requested screen format is not supported, continue running in 256 color mode.


== Complete API function reference ==
== Complete API reference ==
=== New functions ===
=== New functions ===
==== OSystem ====
==== OSystem ====
Line 59: Line 180:
**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 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.
**Backends which support fast conversion ''should'' put larger colorspaces before smaller color spaces, but are not required to.
*virtual bool OSystem::convertScreenRect(byte *dstbuf, const byte *srcbuf, int dstpitch, int srcpitch, int w, int h, Graphics::PixelFormat hwFmt)
**Blits a rect from screen format known by the game to the hardware format known by the backend.
**This '''''must''''' return false if the blit fails (due to unsupported format conversion).
**This '''''must''''' return true if the blit succeeds.
**This ''should'' be overridden by backends where helpful, but is not required to be.


==== Graphics::PixelFormat ====
==== Graphics::PixelFormat ====
*inline Graphics::PixelFormat Graphics::findCompatibleFormat(Common::List<Graphics::PixelFormat> backend, Common::List<Graphics::PixelFormat> frontend)
*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.
**Returns the first entry on the backend list that also occurs in the frontend list, or CLUT8 if there is no matching format.
*static inline Graphics::PixelFormat Graphics::PixelFormat::createFormat{format}(void)
*inline Graphics::PixelFormat (void)
**creates a PixelFormat and initializes it to the specified format. A list of formats provided follows:
**creates an uninitialized PixelFormat.
***createFormatCLUT8() // 256 color paletted
*inline Graphics::PixelFormat(byte BytesPerPixel, byte RBits, byte GBits, byte BBits, byte ABits, byte RShift, byte GShift, byte BShift, byte AShift)
***createFormatRGBA4444()
**creates an initialized PixelFormat.
***createFormatARGB4444()
**[_]Bits is the width in bits of the relevant channel
***createFormatABGR4444()
***RBits = red bits, GBits = green bits, BBits = blue bits, ABits = alpha bits.
***createFormatBGRA4444()
**[_]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.
***createFormatRGB555()
***In RGB565, RShift is 11, GShift is 5, and BShift is 0.
***createFormatBGR555()
***In RGBA4444, RShift is 12, GShift is 8, BShift is 4, and AShift is 0.
***createFormatXRGB1555()
*static inline Graphics::PixelFormat Graphics::PixelFormat::createFormatCLUT8(void)
***createFormatXBGR1555()
**creates a PixelFormat set to indicate 256 color paletted mode
***createFormatRGB565()
**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.
***createFormatBGR565()
***Which would be accomplished normally via Graphics::PixelFormat(1,8,8,8,8,0,0,0,0);
***createFormatRGB888() // this mode, and those below it, are not yet supported by Scalers or the GUI
**Because this methods are static, it can be called without creating a pixel format first
***createFormatBGR888()
***For instance, if (format == NULL) newFormat = Graphics::PixelFormat::createFormatCLUT8();
***createFormatRGBA8888()
***createFormatARGB8888()
***createFormatABGR8888()
***createFormatBGRA8888()
**XRGB1555 and XBGR1555 ''should'' only be used when the backend has to handle the alpha, but may be used in other circumstances.
**These methods are provided for convenience, and are each equivalent to initializing a Graphics::PixelFormat with the bytedepth, component losses, and component shifts of the format described.
***For instance, calling Graphics::PixelFormat::createFormatCLUT8() is equivalent to calling Graphics::PixelFormat(1,8,8,8,8,0,0,0,0)
**Because these methods are static, they can be called without creating a pixel format first
***For instance, Graphics::PixelFormat format = Graphics::PixelFormat::createFormatRGB555();


==== Miscellaneous ====
==== Miscellaneous ====
*bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, int w, int h, Graphics::PixelFormat dstFmt, Graphics::PixelFormat srcFmt)
*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
**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 false if the blit fails (due to unsupported format conversion)
Line 102: Line 209:
=== Modified functions ===
=== Modified functions ===
====engine====
====engine====
*void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format = NULL)
*void initGraphics(int width, int height, bool defaultTo1xScaler, const Graphics::PixelFormat *format)
**Can now take a format parameter, which is a pointer to a requested pixelformat, and defaults to NULL
**Now takes a format parameter, which is a pointer to a requested pixelformat
**Uses 256 color mode if format is NULL
**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 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====
====OSystem====
Line 112: Line 224:
**Uses 256 color mode if format is NULL
**Uses 256 color mode if format is NULL
*OSystem::TransactionError OSystem::endGFXTransaction(void)
*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.
**'''''Must''''' now return kTransactionFormatNotSupported if the backend fails in an attempt to initialize to a new pixel format during a GFX transaction.


====CursorMan====
====CursorMan====
Line 123: Line 235:
*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())
*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.
**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.
TrustedUser
2,147

edits

Navigation menu