Merge remote-tracking branch 'origin/master' into tlj

This commit is contained in:
Bastien Bouclet 2014-12-14 18:11:21 +01:00
commit bba76f503f
81 changed files with 1301 additions and 413 deletions

View File

@ -89,6 +89,7 @@ into one directory. Specifically, you'll need:
* The Movies directory from each CD * The Movies directory from each CD
* A copy of the Escape from Monkey Monkey Island update EXE * A copy of the Escape from Monkey Monkey Island update EXE
You will need a patch specific to the EMI version you're using: You will need a patch specific to the EMI version you're using:
* "EFMI Installer" if you have the Mac version of EMI.
Language | URL Language | URL
---------- |--------------------------------------------------------- ---------- |---------------------------------------------------------
@ -231,12 +232,13 @@ The following settings are currently available in the config-file,
however some of them might not work with your current build. And however some of them might not work with your current build. And
some of them might make ResidualVM crash, or behave in weird ways. some of them might make ResidualVM crash, or behave in weird ways.
Setting | Values | Effect Setting | Values | Effect
-------------- | ----------- | --------------------------------------------------- -------------- | ----------------- | ---------------------------------------------------
show_fps | [true/false] | If true, then ResidualVM will show the current FPS-rate, while you play. show_fps | [true/false] | If true, then ResidualVM will show the current FPS-rate, while you play.
last_set | [set-name] | The set you were last on, ResidualVM will try to continue from there. last_set | [set-name] | The set you were last on, ResidualVM will try to continue from there.
last_save | [save-number] | The save you last saved, ResidualVM will have that selected the next time you try to load a game. last_save | [save-number] | The save you last saved, ResidualVM will have that selected the next time you try to load a game.
use_arb_shaders| [true/false] | If true, and if you are using the OpenGL renderer ResidualVM will use ARB shaders. While fast they may be incompatible with some graphics drivers. use_arb_shaders| [true/false] | If true, and if you are using the OpenGL renderer ResidualVM will use ARB shaders. While fast they may be incompatible with some graphics drivers.
fullscreen_res | [desktop/WWWxHHH] | If set to "desktop" (the default), ResidualVM will use your desktop resolution in fullscreen mode. If set to a resolution such as "640x480" or "1280x720", that resolution will be used.
6. Troubleshooting, Known Bugs, Issues 6. Troubleshooting, Known Bugs, Issues

View File

@ -62,7 +62,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode() {
_bIsDirectory = true; _bIsDirectory = true;
_sPath = ""; _sPath = "";
_pFileLock = 0; _pFileLock = 0;
_nProt = 0; // protection is ignored for the root volume _nProt = 0; // Protection is ignored for the root volume
LEAVE(); LEAVE();
} }
@ -84,7 +84,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_bIsDirectory = false; _bIsDirectory = false;
_bIsValid = false; _bIsValid = false;
// Check whether the node exists and if it is a directory // Check whether the node exists and if it's a directory
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END); struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END);
if (pExd) { if (pExd) {
_nProt = pExd->Protection; _nProt = pExd->Protection;
@ -93,7 +93,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK); _pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
_bIsValid = (_pFileLock != 0); _bIsValid = (_pFileLock != 0);
// Add a trailing slash if it is needed // Add a trailing slash if needed
const char c = _sPath.lastChar(); const char c = _sPath.lastChar();
if (c != '/' && c != ':') if (c != '/' && c != ':')
_sPath += '/'; _sPath += '/';
@ -134,7 +134,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
delete[] n; delete[] n;
} }
_bIsValid = false; _bIsValid = false;
_bIsDirectory = false; _bIsDirectory = false;
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END); struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END);
@ -188,10 +188,10 @@ bool AmigaOSFilesystemNode::exists() const {
bool nodeExists = false; bool nodeExists = false;
// previously we were trying to examine the node in order // Previously we were trying to examine the node in order
// to determine if the node exists or not. // to determine if the node exists or not.
// I don't see the point : once you have been granted a // I don't see the point : once you have been granted a
// lock on it then it means it exists... // lock on it, it means it exists...
// //
// ============================= Old code // ============================= Old code
// BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK); // BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
@ -237,8 +237,8 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
ENTER(); ENTER();
bool ret = false; bool ret = false;
//TODO: honor the hidden flag // TODO: Honor the hidden flag
// There is nothing like a hidden flag under AmigaOS... // There is no such thing as a hidden flag in AmigaOS...
if (!_bIsValid) { if (!_bIsValid) {
debug(6, "Invalid node"); debug(6, "Invalid node");
@ -252,7 +252,7 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
return false; // Empty list return false; // Empty list
} }
if (_pFileLock == 0) { if (isRootNode()) {
debug(6, "Root node"); debug(6, "Root node");
LEAVE(); LEAVE();
myList = listVolumes(); myList = listVolumes();
@ -264,7 +264,7 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE), EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE),
TAG_END); TAG_END);
if (context) { if (context) {
struct ExamineData * pExd = NULL; // NB: no need to free value after usage, all is dealt by the DirContext release struct ExamineData * pExd = NULL; // NB: No need to free the value after usage, everything will be dealt with by the DirContext release
AmigaOSFilesystemNode *entry ; AmigaOSFilesystemNode *entry ;
while ( (pExd = IDOS->ExamineDir(context)) ) { while ( (pExd = IDOS->ExamineDir(context)) ) {
@ -307,21 +307,33 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
AbstractFSNode *AmigaOSFilesystemNode::getParent() const { AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
ENTER(); ENTER();
if (_pFileLock == 0) { if (isRootNode()) {
debug(6, "Root node"); debug(6, "Root node");
LEAVE(); LEAVE();
return new AmigaOSFilesystemNode(*this); return new AmigaOSFilesystemNode(*this);
} }
BPTR pLock = _pFileLock;
if (!_bIsDirectory) {
assert(!pLock);
pLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
assert(pLock);
}
AmigaOSFilesystemNode *node; AmigaOSFilesystemNode *node;
BPTR parentDir = IDOS->ParentDir( _pFileLock ); BPTR parentDir = IDOS->ParentDir( pLock );
if (parentDir) { if (parentDir) {
node = new AmigaOSFilesystemNode(parentDir); node = new AmigaOSFilesystemNode(parentDir);
IDOS->UnLock(parentDir); IDOS->UnLock(parentDir);
} else } else
node = new AmigaOSFilesystemNode(); node = new AmigaOSFilesystemNode();
if (!_bIsDirectory) {
IDOS->UnLock(pLock);
}
LEAVE(); LEAVE();
return node; return node;
@ -332,9 +344,9 @@ bool AmigaOSFilesystemNode::isReadable() const {
return false; return false;
// Regular RWED protection flags are low-active or inverted, thus the negation. // Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is readable whatever the // Moreover, a pseudo root filesystem is readable whatever the
// protection says // protection says.
bool readable = !(_nProt & EXDF_OTR_READ) || _pFileLock == 0; bool readable = !(_nProt & EXDF_OTR_READ) || isRootNode();
return readable; return readable;
} }
@ -344,9 +356,9 @@ bool AmigaOSFilesystemNode::isWritable() const {
return false; return false;
// Regular RWED protection flags are low-active or inverted, thus the negation. // Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is never writable whatever // Moreover, a pseudo root filesystem is never writable whatever
// the protection says (because of the pseudo nature) // the protection says (Because of it's pseudo nature).
bool writable = !(_nProt & EXDF_OTR_WRITE) && _pFileLock !=0; bool writable = !(_nProt & EXDF_OTR_WRITE) && !isRootNode();
return writable; return writable;
} }
@ -371,12 +383,13 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
if (dosList->dol_Type == DLT_VOLUME && if (dosList->dol_Type == DLT_VOLUME &&
dosList->dol_Name) { dosList->dol_Name) {
// Original was // The original line was
// dosList->dol_Name && //if (dosList->dol_Type == DLT_VOLUME &&
// dosList->dol_Task) { //dosList->dol_Name &&
//dosList->dol_Task) {
// which errored using SDK 53.24 with a 'struct dosList' has no member called 'dol_Task' // which errored using SDK 53.24 with a 'struct dosList' has no member called 'dol_Task'
// I removed dol_Task because it's not used anywhere else // I removed dol_Task because it's not used anywhere else
// and it neither brought up further errors nor crashes or regressions. // and it neither brought up further errors nor crashes or regressions
// Copy name to buffer // Copy name to buffer
IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN); IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN);
@ -410,7 +423,7 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
delete[] volName; delete[] volName;
} }
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES); dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
} }
IDOS->UnLockDosList(kLockFlags); IDOS->UnLockDosList(kLockFlags);

View File

@ -62,6 +62,11 @@ protected:
*/ */
virtual AbstractFSList listVolumes() const; virtual AbstractFSList listVolumes() const;
/**
* True if this is the pseudo root filesystem.
*/
bool isRootNode() const { return _bIsValid && _bIsDirectory && _pFileLock == 0; }
public: public:
/** /**
* Creates an AmigaOSFilesystemNode with the root node as path. * Creates an AmigaOSFilesystemNode with the root node as path.
@ -76,19 +81,19 @@ public:
AmigaOSFilesystemNode(const Common::String &p); AmigaOSFilesystemNode(const Common::String &p);
/** /**
* Creates an AmigaOSFilesystemNode given its lock and display name * Creates an AmigaOSFilesystemNode given its lock and display name.
* *
* @param pLock BPTR to the lock. * @param pLock BPTR to the lock.
* @param pDisplayName name to be used for display, in case not supplied the FilePart() of the filename will be used. * @param pDisplayName name to be used for display, in case not supplied the FilePart() of the filename will be used.
* *
* @note This shouldn't even be public as it's only internally, at best it should have been protected if not private * @note This shouldn't even be public as it's only internally, at best it should have been protected if not private.
*/ */
AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0); AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0);
/** /**
* Copy constructor. * Copy constructor.
* *
* @note Needed because it duplicates the file lock * @note Needed because it duplicates the file lock.
*/ */
AmigaOSFilesystemNode(const AmigaOSFilesystemNode &node); AmigaOSFilesystemNode(const AmigaOSFilesystemNode &node);

View File

@ -20,6 +20,8 @@
* *
*/ */
#define FORBIDDEN_SYMBOL_EXCEPTION_putenv
#include "common/scummsys.h" #include "common/scummsys.h"
#if defined(SDL_BACKEND) #if defined(SDL_BACKEND)
@ -42,6 +44,10 @@
#include "graphics/pixelbuffer.h" #include "graphics/pixelbuffer.h"
#include "gui/EventRecorder.h" #include "gui/EventRecorder.h"
#ifdef USE_OPENGL
#include "graphics/opengles2/extensions.h"
#endif
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{0, 0, 0} {0, 0, 0}
}; };
@ -50,18 +56,25 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
: :
SdlGraphicsManager(sdlEventSource), SdlGraphicsManager(sdlEventSource),
_screen(0), _screen(0),
_subScreen(0),
_overlayVisible(false), _overlayVisible(false),
_overlayscreen(0), _overlayscreen(0),
_overlayWidth(0), _overlayHeight(0), _overlayWidth(0), _overlayHeight(0),
_overlayDirty(true), _overlayDirty(true),
_screenChangeCount(0) _screenChangeCount(0),
_lockAspectRatio(true),
_gameRect()
#ifdef USE_OPENGL #ifdef USE_OPENGL
, _opengl(false), _overlayNumTex(0), _overlayTexIds(0) , _opengl(false), _overlayNumTex(0), _overlayTexIds(0)
, _frameBuffer(nullptr)
#endif #endif
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
, _boxShader(nullptr), _boxVerticesVBO(0) , _boxShader(nullptr), _boxVerticesVBO(0)
#endif #endif
{ {
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
_desktopW = vi->current_w;
_desktopH = vi->current_h;
} }
SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() { SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() {
@ -92,7 +105,8 @@ bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) {
return return
(f == OSystem::kFeatureFullscreenMode) || (f == OSystem::kFeatureFullscreenMode) ||
#ifdef USE_OPENGL #ifdef USE_OPENGL
(f == OSystem::kFeatureOpenGL); (f == OSystem::kFeatureOpenGL) ||
(f == OSystem::kFeatureAspectRatioCorrection);
#else #else
false; false;
#endif #endif
@ -103,6 +117,9 @@ void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
case OSystem::kFeatureFullscreenMode: case OSystem::kFeatureFullscreenMode:
_fullscreen = enable; _fullscreen = enable;
break; break;
case OSystem::kFeatureAspectRatioCorrection:
_lockAspectRatio = enable;
break;
default: default:
break; break;
} }
@ -112,6 +129,9 @@ bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
switch (f) { switch (f) {
case OSystem::kFeatureFullscreenMode: case OSystem::kFeatureFullscreenMode:
return _fullscreen; return _fullscreen;
case OSystem::kFeatureAspectRatioCorrection:
return _lockAspectRatio;
break;
default: default:
return false; return false;
} }
@ -172,7 +192,61 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
#endif #endif
_fullscreen = fullscreen; _fullscreen = fullscreen;
ConfMan.registerDefault("fullscreen_res", "desktop");
const Common::String &fsres = ConfMan.get("fullscreen_res");
if (fsres != "desktop") {
uint newW, newH;
int converted = sscanf(fsres.c_str(), "%ux%u", &newW, &newH);
if (converted == 2) {
_desktopW = newW;
_desktopH = newH;
} else {
warning("Could not parse 'fullscreen_res' option: expected WWWxHHH, got %s", fsres.c_str());
}
}
ConfMan.registerDefault("aspect_ratio", true);
_lockAspectRatio = ConfMan.getBool("aspect_ratio");
uint fbW = screenW;
uint fbH = screenH;
_gameRect = Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
#ifdef USE_OPENGL #ifdef USE_OPENGL
bool framebufferSupported = false;
// Use the desktop resolution for fullscreen when possible
if (_fullscreen) {
if (g_engine->hasFeature(Engine::kSupportsArbitraryResolutions)) {
// If the game supports arbitrary resolutions, use the desktop mode as the game mode
screenW = _desktopW;
screenH = _desktopH;
} else if (_opengl) {
// If available, draw to a framebuffer and scale it to the desktop resolution
#ifndef AMIGAOS
// Spawn a 32x32 window off-screen
SDL_putenv(const_cast<char *>("SDL_VIDEO_WINDOW_POS=9000,9000"));
SDL_SetVideoMode(32, 32, 0, SDL_OPENGL);
SDL_putenv(const_cast<char *>("SDL_VIDEO_WINDOW_POS=centered"));
Graphics::initExtensions();
framebufferSupported = Graphics::isExtensionSupported("GL_EXT_framebuffer_object");
if (_fullscreen && framebufferSupported) {
screenW = _desktopW;
screenH = _desktopH;
if (_lockAspectRatio) {
float scale = MIN(_desktopH / float(fbH), _desktopW / float(fbW));
float scaledW = scale * (fbW / float(_desktopW));
float scaledH = scale * (fbH / float(_desktopH));
_gameRect = Math::Rect2d(
Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)),
Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH))
);
}
}
#endif
}
}
if (_opengl) { if (_opengl) {
if (ConfMan.hasKey("antialiasing")) if (ConfMan.hasKey("antialiasing"))
_antialiasing = ConfMan.getInt("antialiasing"); _antialiasing = ConfMan.getInt("antialiasing");
@ -195,6 +269,15 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
sdlflags = SDL_SWSURFACE; sdlflags = SDL_SWSURFACE;
} }
if (_fullscreen && !accel3d) {
screenW = _desktopW;
screenH = _desktopH;
_gameRect = Math::Rect2d(
Math::Vector2d((_desktopW - fbW) / 2, (_desktopH - fbH) / 2),
Math::Vector2d((_desktopW + fbW) / 2, (_desktopH + fbH) / 2)
);
}
if (_fullscreen) if (_fullscreen)
sdlflags |= SDL_FULLSCREEN; sdlflags |= SDL_FULLSCREEN;
@ -281,9 +364,8 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
debug("INFO: GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); debug("INFO: GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION));
// GLEW needs to be initialized to use shaders // GLEW needs to be initialized to use shaders
debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION));
GLenum err = glewInit(); GLenum err = glewInit();
if (err != GLEW_OK) { if (err != GLEW_OK) {
warning("Error: %s", glewGetErrorString(err)); warning("Error: %s", glewGetErrorString(err));
@ -305,6 +387,8 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
_boxShader->enableVertexAttribute("texcoord", _boxVerticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0); _boxShader->enableVertexAttribute("texcoord", _boxVerticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
#endif #endif
Graphics::initExtensions();
} }
#endif #endif
@ -361,6 +445,19 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
_screenFormat = Graphics::PixelFormat(f->BytesPerPixel, 8 - f->Rloss, 8 - f->Gloss, 8 - f->Bloss, 0, _screenFormat = Graphics::PixelFormat(f->BytesPerPixel, 8 - f->Rloss, 8 - f->Gloss, 8 - f->Bloss, 0,
f->Rshift, f->Gshift, f->Bshift, f->Ashift); f->Rshift, f->Gshift, f->Bshift, f->Ashift);
#if defined(USE_OPENGL) && !defined(AMIGAOS)
if (_opengl && _fullscreen
&& !g_engine->hasFeature(Engine::kSupportsArbitraryResolutions)
&& framebufferSupported) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
_frameBuffer = new Graphics::FrameBuffer(fbW, fbH);
_frameBuffer->attach();
}
#endif
if (_fullscreen && !accel3d) {
_subScreen = SDL_CreateRGBSurface(SDL_SWSURFACE, fbW, fbH, bpp, _screen->format->Rmask, _screen->format->Gmask, _screen->format->Bmask, _screen->format->Amask);
return Graphics::PixelBuffer(_screenFormat, (byte *)_subScreen->pixels);
}
return Graphics::PixelBuffer(_screenFormat, (byte *)_screen->pixels); return Graphics::PixelBuffer(_screenFormat, (byte *)_screen->pixels);
} }
@ -472,6 +569,68 @@ void SurfaceSdlGraphicsManager::drawOverlayOpenGL() {
glPopAttrib(); glPopAttrib();
} }
void SurfaceSdlGraphicsManager::drawFramebufferOpenGL() {
// Save current state
glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT);
// prepare view
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 1.0, 1.0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, _desktopW, _desktopH);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
float texcropX = _frameBuffer->getWidth() / float(_frameBuffer->getTexWidth());
float texcropY = _frameBuffer->getHeight() / float(_frameBuffer->getTexHeight());
float offsetX = _gameRect.getTopLeft().getX();
float offsetY = _gameRect.getTopLeft().getY();
float sizeX = _gameRect.getWidth();
float sizeY = _gameRect.getHeight();
glColor4f(1.0, 1.0, 1.0, 1.0);
glBindTexture(GL_TEXTURE_2D, _frameBuffer->getColorTextureName());
glBegin(GL_QUADS);
glTexCoord2f(0, texcropY);
glVertex2f(offsetX, offsetY);
glTexCoord2f(texcropX, texcropY);
glVertex2f(offsetX + sizeX, offsetY);
glTexCoord2f(texcropX, 0.0);
glVertex2f(offsetX + sizeX, offsetY + sizeY);
glTexCoord2f(0.0, 0.0);
glVertex2f(offsetX, offsetY + sizeY);
glEnd();
// Restore previous state
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glPopAttrib();
}
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
void SurfaceSdlGraphicsManager::drawOverlayOpenGLShaders() { void SurfaceSdlGraphicsManager::drawOverlayOpenGLShaders() {
if (!_overlayscreen) if (!_overlayscreen)
@ -501,6 +660,23 @@ void SurfaceSdlGraphicsManager::drawOverlayOpenGLShaders() {
} }
} }
} }
void SurfaceSdlGraphicsManager::drawFramebufferOpenGLShaders() {
glBindTexture(GL_TEXTURE_2D, _frameBuffer->getColorTextureName());
_boxShader->use();
float texcropX = _frameBuffer->getWidth() / float(_frameBuffer->getTexWidth());
float texcropY = _frameBuffer->getHeight() / float(_frameBuffer->getTexHeight());
_boxShader->setUniform("texcrop", Math::Vector2d(texcropX, texcropY));
_boxShader->setUniform("flipY", false);
_boxShader->setUniform("offsetXY", _gameRect.getTopLeft());
_boxShader->setUniform("sizeWH", Math::Vector2d(_gameRect.getWidth(), _gameRect.getHeight()));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
}
#endif #endif
#endif #endif
@ -527,6 +703,17 @@ void SurfaceSdlGraphicsManager::drawOverlay() {
void SurfaceSdlGraphicsManager::updateScreen() { void SurfaceSdlGraphicsManager::updateScreen() {
#ifdef USE_OPENGL #ifdef USE_OPENGL
if (_opengl) { if (_opengl) {
if (_frameBuffer) {
_frameBuffer->detach();
glViewport(0, 0, _screen->w, _screen->h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
#ifndef USE_OPENGL_SHADERS
drawFramebufferOpenGL();
#else
drawFramebufferOpenGLShaders();
#endif
}
if (_overlayVisible) { if (_overlayVisible) {
if (_overlayDirty) { if (_overlayDirty) {
updateOverlayTextures(); updateOverlayTextures();
@ -538,10 +725,21 @@ void SurfaceSdlGraphicsManager::updateScreen() {
drawOverlayOpenGLShaders(); drawOverlayOpenGLShaders();
#endif #endif
} }
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
if (_frameBuffer) {
_frameBuffer->attach();
}
} else } else
#endif #endif
{ {
SDL_Rect dstrect;
dstrect.x = _gameRect.getTopLeft().getX();
dstrect.y = _gameRect.getTopLeft().getY();
dstrect.w = _gameRect.getWidth();
dstrect.h = _gameRect.getHeight();
SDL_BlitSurface(_subScreen, NULL, _screen, &dstrect);
if (_overlayVisible) { if (_overlayVisible) {
drawOverlay(); drawOverlay();
} }
@ -567,12 +765,28 @@ void SurfaceSdlGraphicsManager::fillScreen(uint32 col) {
int16 SurfaceSdlGraphicsManager::getHeight() { int16 SurfaceSdlGraphicsManager::getHeight() {
// ResidualVM specific // ResidualVM specific
return _screen->h; #ifdef USE_OPENGL
if (_frameBuffer)
return _frameBuffer->getHeight();
else
#endif
if (_subScreen)
return _subScreen->h;
else
return _screen->h;
} }
int16 SurfaceSdlGraphicsManager::getWidth() { int16 SurfaceSdlGraphicsManager::getWidth() {
// ResidualVM specific // ResidualVM specific
return _screen->w; #ifdef USE_OPENGL
if (_frameBuffer)
return _frameBuffer->getWidth();
else
#endif
if (_subScreen)
return _subScreen->w;
else
return _screen->w;
} }
void SurfaceSdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) { void SurfaceSdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
@ -749,6 +963,11 @@ void SurfaceSdlGraphicsManager::closeOverlay() {
_overlayNumTex = 0; _overlayNumTex = 0;
} }
if (_frameBuffer) {
delete _frameBuffer;
_frameBuffer = nullptr;
}
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
glDeleteBuffers(1, &_boxVerticesVBO); glDeleteBuffers(1, &_boxVerticesVBO);
_boxVerticesVBO = 0; _boxVerticesVBO = 0;
@ -756,6 +975,9 @@ void SurfaceSdlGraphicsManager::closeOverlay() {
delete _boxShader; delete _boxShader;
_boxShader = nullptr; _boxShader = nullptr;
#endif #endif
} else if (_subScreen) {
SDL_FreeSurface(_subScreen);
_subScreen = nullptr;
} }
#endif #endif
} }
@ -781,6 +1003,25 @@ bool SurfaceSdlGraphicsManager::lockMouse(bool lock) {
void SurfaceSdlGraphicsManager::warpMouse(int x, int y) { void SurfaceSdlGraphicsManager::warpMouse(int x, int y) {
//ResidualVM specific //ResidualVM specific
#ifdef USE_OPENGL
if (_frameBuffer) {
// Scale from game coordinates to screen coordinates
x = (x * _gameRect.getWidth() * _screen->w) / _frameBuffer->getWidth();
y = (y * _gameRect.getHeight() * _screen->h) / _frameBuffer->getHeight();
x += _gameRect.getTopLeft().getX() * _screen->w;
y += _gameRect.getTopLeft().getY() * _screen->h;
} else
#endif
if (_subScreen) {
// Scale from game coordinates to screen coordinates
x = (x * _gameRect.getWidth()) / _subScreen->w;
y = (y * _gameRect.getHeight()) / _subScreen->h;
x += _gameRect.getTopLeft().getX();
y += _gameRect.getTopLeft().getY();
}
SDL_WarpMouse(x, y); SDL_WarpMouse(x, y);
} }
@ -836,7 +1077,40 @@ void SurfaceSdlGraphicsManager::notifyVideoExpose() {
} }
void SurfaceSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) { void SurfaceSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
return; // ResidualVM: not use it bool frames = _subScreen
#ifdef USE_OPENGL
|| _frameBuffer
#endif
;
if (_overlayVisible || !frames)
return;
#ifdef USE_OPENGL
if (_frameBuffer) {
// Scale from screen coordinates to game coordinates
point.x -= _gameRect.getTopLeft().getX() * _screen->w;
point.y -= _gameRect.getTopLeft().getY() * _screen->h;
point.x = (point.x * _frameBuffer->getWidth()) / (_gameRect.getWidth() * _screen->w);
point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _screen->h);
// Make sure we only supply valid coordinates.
point.x = CLIP<int16>(point.x, 0, _frameBuffer->getWidth() - 1);
point.y = CLIP<int16>(point.y, 0, _frameBuffer->getHeight() - 1);
} else
#endif
{
// Scale from screen coordinates to game coordinates
point.x -= _gameRect.getTopLeft().getX();
point.y -= _gameRect.getTopLeft().getY();
point.x = (point.x * _subScreen->w) / _gameRect.getWidth();
point.y = (point.y * _subScreen->h) / _gameRect.getHeight();
// Make sure we only supply valid coordinates.
point.x = CLIP<int16>(point.x, 0, _subScreen->w - 1);
point.y = CLIP<int16>(point.y, 0, _subScreen->h - 1);
}
} }
void SurfaceSdlGraphicsManager::notifyMousePos(Common::Point mouse) { void SurfaceSdlGraphicsManager::notifyMousePos(Common::Point mouse) {

View File

@ -25,7 +25,9 @@
#ifdef USE_OPENGL #ifdef USE_OPENGL
#include "graphics/opengles2/system_headers.h" #include "graphics/opengles2/system_headers.h"
#include "graphics/opengles2/framebuffer.h"
#endif #endif
#undef ARRAYSIZE #undef ARRAYSIZE
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
@ -38,6 +40,7 @@
#include "graphics/scaler.h" #include "graphics/scaler.h"
#include "common/events.h" #include "common/events.h"
#include "common/system.h" #include "common/system.h"
#include "math/rect2d.h"
#include "backends/events/sdl/sdl-events.h" #include "backends/events/sdl/sdl-events.h"
@ -132,6 +135,7 @@ protected:
SDL_Surface *_screen; SDL_Surface *_screen;
SDL_Surface *_subScreen;
#ifdef USE_RGB_COLOR #ifdef USE_RGB_COLOR
Graphics::PixelFormat _screenFormat; Graphics::PixelFormat _screenFormat;
Common::List<Graphics::PixelFormat> _supportedFormats; Common::List<Graphics::PixelFormat> _supportedFormats;
@ -140,6 +144,7 @@ protected:
#ifdef USE_OPENGL #ifdef USE_OPENGL
bool _opengl; bool _opengl;
#endif #endif
bool _lockAspectRatio;
bool _fullscreen; bool _fullscreen;
// overlay // overlay
@ -149,6 +154,9 @@ protected:
int _overlayWidth, _overlayHeight; int _overlayWidth, _overlayHeight;
bool _overlayDirty; bool _overlayDirty;
uint _desktopW, _desktopH;
Math::Rect2d _gameRect;
#ifdef USE_OPENGL #ifdef USE_OPENGL
// Antialiasing // Antialiasing
int _antialiasing; int _antialiasing;
@ -161,13 +169,16 @@ protected:
void updateOverlayTextures(); void updateOverlayTextures();
void drawOverlayOpenGL(); void drawOverlayOpenGL();
void drawFramebufferOpenGL();
Graphics::FrameBuffer *_frameBuffer;
#ifdef USE_OPENGL_SHADERS #ifdef USE_OPENGL_SHADERS
// Overlay
Graphics::Shader *_boxShader; Graphics::Shader *_boxShader;
GLuint _boxVerticesVBO; GLuint _boxVerticesVBO;
void drawOverlayOpenGLShaders(); void drawOverlayOpenGLShaders();
void drawFramebufferOpenGLShaders();
#endif #endif
#endif #endif

View File

@ -37,7 +37,7 @@ namespace Common {
struct HardwareInput; struct HardwareInput;
class Keymap; class Keymap;
#define ACTION_ID_SIZE (4) #define ACTION_ID_SIZE (5)
struct KeyActionEntry { struct KeyActionEntry {
const KeyState ks; const KeyState ks;

View File

@ -38,4 +38,4 @@ endif
cp $(srcdir)/NEWS ResidualVM/NEWS.txt cp $(srcdir)/NEWS ResidualVM/NEWS.txt
cp $(srcdir)/doc/QuickStart ResidualVM/QuickStart.txt cp $(srcdir)/doc/QuickStart ResidualVM/QuickStart.txt
cp $(srcdir)/README.md ResidualVM/README.txt cp $(srcdir)/README.md ResidualVM/README.txt
lha a residualvm-amigaos4.lha ResidualVM ResidualVM.info zip -r residualvm-amigaos4.zip ResidualVM ResidualVM.info

View File

@ -62,7 +62,7 @@ void OSystem_PS3::initBackend() {
ConfMan.set("joystick_num", 0); ConfMan.set("joystick_num", 0);
ConfMan.set("vkeybdpath", PREFIX "/data"); ConfMan.set("vkeybdpath", PREFIX "/data");
ConfMan.registerDefault("fullscreen", true); ConfMan.registerDefault("fullscreen", true);
//ConfMan.registerDefault("aspect_ratio", true); //ResidualVM: not used ConfMan.registerDefault("aspect_ratio", true);
// Create the savefile manager // Create the savefile manager
if (_savefileManager == 0) if (_savefileManager == 0)

View File

@ -345,7 +345,7 @@ Common::String OSystem_SDL::getSystemLanguage() const {
#else // WIN32 #else // WIN32
// Activating current locale settings // Activating current locale settings
const Common::String locale = setlocale(LC_ALL, ""); const Common::String locale = setlocale(LC_ALL, "");
// Restore default C locale to prevent issues with // Restore default C locale to prevent issues with
// portability of sscanf(), atof(), etc. // portability of sscanf(), atof(), etc.
// See bug #3615148 // See bug #3615148

View File

@ -26,6 +26,8 @@
#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_UNITY) #if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_UNITY)
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "backends/taskbar/unity/unity-taskbar.h" #include "backends/taskbar/unity/unity-taskbar.h"
#include "common/textconsole.h" #include "common/textconsole.h"
@ -33,7 +35,12 @@
#include <unity.h> #include <unity.h>
UnityTaskbarManager::UnityTaskbarManager() { UnityTaskbarManager::UnityTaskbarManager() {
g_type_init(); /*
* Deprecated in Glib >= 2.36.0
*/
if (!glib_check_version(2, 36, 0)) {
g_type_init();
}
_loop = g_main_loop_new(NULL, FALSE); _loop = g_main_loop_new(NULL, FALSE);

View File

@ -117,6 +117,7 @@ static const char HELP_STRING[] =
" --no-show-fps Set the turn off display FPS info\n" " --no-show-fps Set the turn off display FPS info\n"
" --soft-renderer Switch to 3D software renderer\n" " --soft-renderer Switch to 3D software renderer\n"
" --no-soft-renderer Switch to 3D hardware renderer\n" " --no-soft-renderer Switch to 3D hardware renderer\n"
" --aspect-ratio Enable aspect ratio correction\n"
#ifdef ENABLE_EVENTRECORDER #ifdef ENABLE_EVENTRECORDER
" --record-mode=MODE Specify record mode for event recorder (record, playback,\n" " --record-mode=MODE Specify record mode for event recorder (record, playback,\n"
" passthrough [default])\n" " passthrough [default])\n"
@ -159,6 +160,7 @@ void registerDefaults() {
ConfMan.registerDefault("fullscreen", false); ConfMan.registerDefault("fullscreen", false);
ConfMan.registerDefault("soft_renderer", false); ConfMan.registerDefault("soft_renderer", false);
ConfMan.registerDefault("show_fps", false); ConfMan.registerDefault("show_fps", false);
ConfMan.registerDefault("aspect_ratio", false);
// Sound & Music // Sound & Music
ConfMan.registerDefault("music_volume", 192); ConfMan.registerDefault("music_volume", 192);

View File

@ -146,4 +146,12 @@ const char *gScummVMFeatures = ""
#ifdef USE_PNG #ifdef USE_PNG
"PNG " "PNG "
#endif #endif
#ifdef ENABLE_KEYMAPPER
"keymapper "
#endif
#ifdef ENABLE_VKEYBD
"virtual keyboard "
#endif
; ;

View File

@ -45,7 +45,7 @@ List<Event> DefaultEventMapper::mapEvent(const Event &ev, EventSource *source) {
if (ev.type == EVENT_MBUTTONUP) { if (ev.type == EVENT_MBUTTONUP) {
if ((g_system->getMillis() - vkeybdThen) >= vkeybdTime) { if ((g_system->getMillis() - vkeybdThen) >= vkeybdTime) {
mappedEvent.type = EVENT_VIRTUAL_KEYBOARD; mappedEvent.type = EVENT_VIRTUAL_KEYBOARD;
// Avoid blocking event from engine. // Avoid blocking event from engine.
addDelayedEvent(100, ev); addDelayedEvent(100, ev);
} }
@ -59,7 +59,7 @@ List<Event> DefaultEventMapper::mapEvent(const Event &ev, EventSource *source) {
#ifdef ENABLE_VKEYBD #ifdef ENABLE_VKEYBD
else if (ev.kbd.hasFlags(KBD_CTRL) && ev.kbd.keycode == KEYCODE_F7) { else if (ev.kbd.hasFlags(KBD_CTRL) && ev.kbd.keycode == KEYCODE_F7) {
mappedEvent.type = EVENT_VIRTUAL_KEYBOARD; mappedEvent.type = EVENT_VIRTUAL_KEYBOARD;
// Avoid blocking CTRL-F7 events from engine. // Avoid blocking CTRL-F7 events from engine.
addDelayedEvent(100, ev); addDelayedEvent(100, ev);
} }
@ -67,7 +67,7 @@ List<Event> DefaultEventMapper::mapEvent(const Event &ev, EventSource *source) {
#ifdef ENABLE_KEYMAPPER #ifdef ENABLE_KEYMAPPER
else if (ev.kbd.hasFlags(KBD_CTRL) && ev.kbd.keycode == KEYCODE_F8) { else if (ev.kbd.hasFlags(KBD_CTRL) && ev.kbd.keycode == KEYCODE_F8) {
mappedEvent.type = EVENT_KEYMAPPER_REMAP; mappedEvent.type = EVENT_KEYMAPPER_REMAP;
// Avoid blocking CTRL-F8 events from engine. // Avoid blocking CTRL-F8 events from engine.
addDelayedEvent(100, ev); addDelayedEvent(100, ev);
} }

View File

@ -32,13 +32,19 @@
// though. // though.
// //
#if !defined(nullptr) // XCode 5.0.1 has __cplusplus=199711 but defines this #if !defined(nullptr) // XCode 5.0.1 has __cplusplus=199711 but defines this
// MSVC 2010 and newer fully support nullptr: http://msdn.microsoft.com/en-us/library/hh567368.aspx
#if !defined(_MSC_VER) || _MSC_VER < 1600
#define nullptr 0 #define nullptr 0
#endif #endif
#endif
// //
// Replacement for the override keyword. This allows compilation of code // Replacement for the override keyword. This allows compilation of code
// which uses it, but does not feature any semantic. // which uses it, but does not feature any semantic.
// //
// MSVC 2012 and newer fully support override: http://msdn.microsoft.com/en-us/library/hh567368.aspx
#if !defined(_MSC_VER) || _MSC_VER < 1700
#define override #define override
#endif
#endif #endif

View File

@ -25,6 +25,8 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#if __cplusplus < 201103L
namespace Common { namespace Common {
class _Foreach_Container_Base_ { class _Foreach_Container_Base_ {
@ -66,4 +68,10 @@ for (const Common::_Foreach_Container_Base_ &_FOREACH_CONTAINER_ = Common::_Crea
for (var = *Common::_Get_Foreach_Container_(&_FOREACH_CONTAINER_, container)->i;\ for (var = *Common::_Get_Foreach_Container_(&_FOREACH_CONTAINER_, container)->i;\
_FOREACH_CONTAINER_.brk > 0; --_FOREACH_CONTAINER_.brk) _FOREACH_CONTAINER_.brk > 0; --_FOREACH_CONTAINER_.brk)
#else
#define foreach(var, container) for (var : container)
#endif
#endif #endif

View File

@ -148,7 +148,7 @@
#endif #endif
#endif #endif
// The following math constants are usually defined by the system math.h header, but // The following math constants are usually defined by the system math.h header, but
// they are not part of the ANSI C++ standards and so can NOT be relied upon to be // they are not part of the ANSI C++ standards and so can NOT be relied upon to be
// present i.e. when -std=c++11 is passed to GCC, enabling strict ANSI compliance. // present i.e. when -std=c++11 is passed to GCC, enabling strict ANSI compliance.
// As we rely on these being present, we define them if they are not set. // As we rely on these being present, we define them if they are not set.

View File

@ -69,7 +69,7 @@ bool XMLParser::loadBuffer(const byte *buffer, uint32 size, DisposeAfterUse::Fla
bool XMLParser::loadStream(SeekableReadStream *stream) { bool XMLParser::loadStream(SeekableReadStream *stream) {
_stream = stream; _stream = stream;
_fileName = "File Stream"; _fileName = "File Stream";
return true; return _stream != nullptr;
} }
void XMLParser::close() { void XMLParser::close() {

31
configure vendored
View File

@ -1297,7 +1297,7 @@ caanoo)
_host_cpu=arm _host_cpu=arm
_host_alias=arm-none-linux-gnueabi _host_alias=arm-none-linux-gnueabi
;; ;;
dingux) dingux | gcw0)
_host_os=linux _host_os=linux
_host_cpu=mipsel _host_cpu=mipsel
_host_alias=mipsel-linux _host_alias=mipsel-linux
@ -2118,6 +2118,8 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp" CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
CXXFLAGS="$CXXFLAGS -mfpu=neon" CXXFLAGS="$CXXFLAGS -mfpu=neon"
ABI="armeabi-v7a" ABI="armeabi-v7a"
ANDROID_PLATFORM=4
ANDROID_PLATFORM_ARCH="arm"
;; ;;
esac esac
@ -2587,6 +2589,25 @@ if test -n "$_host"; then
add_line_to_config_h "/* #define DEBUG_WII_GDB */" add_line_to_config_h "/* #define DEBUG_WII_GDB */"
add_line_to_config_h "#define USE_WII_DI" add_line_to_config_h "#define USE_WII_DI"
;; ;;
gcw0)
DEFINES="$DEFINES -DDINGUX -DGCW0"
DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
ASFLAGS="$ASFLAGS"
CXXFLAGS="$CXXFLAGS -mips32"
_backend="dingux"
_mt32emu=no
_optimization_level=-O3
# Disable alsa midi to get the port build on OpenDingux toolchain
_alsa=no
_vkeybd=yes
_build_hq_scalers=no
_keymapper=yes
# Force disable vorbis on dingux, it has terrible performance compared to tremor
_vorbis=no
# Force disable seq on dingux, no way to use it and it would get enabled by default with configure
_seq_midi=no
_port_mk="backends/platform/dingux/dingux.mk"
;;
gp2x) gp2x)
DEFINES="$DEFINES -DGP2X" DEFINES="$DEFINES -DGP2X"
CXXFLAGS="$CXXFLAGS -march=armv4t" CXXFLAGS="$CXXFLAGS -march=armv4t"
@ -3847,8 +3868,8 @@ if test "$_libunity" = auto ; then
;; ;;
*) *)
# Unity has a lots of dependencies, update the libs and cflags var with them # Unity has a lots of dependencies, update the libs and cflags var with them
LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs unity = 3.8.4 2>> "$TMPLOG"`" LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs 'unity > 3.8.1' 2>> "$TMPLOG"`"
LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags unity = 3.8.4 2>> "$TMPLOG"`" LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags 'unity > 3.8.1' 2>> "$TMPLOG"`"
_libunity=no _libunity=no
cat > $TMPC << EOF cat > $TMPC << EOF
#include <unity.h> #include <unity.h>
@ -3862,6 +3883,10 @@ EOF
esac esac
fi fi
if test "$_libunity" = yes ; then if test "$_libunity" = yes ; then
if test "$LIBUNITY_CFLAGS" = "" || test "$LIBUNITY_LIBS" = ""; then
LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs 'unity > 3.8.1' 2>> "$TMPLOG"`"
LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags 'unity > 3.8.1' 2>> "$TMPLOG"`"
fi
LIBS="$LIBS $LIBUNITY_LIBS" LIBS="$LIBS $LIBUNITY_LIBS"
INCLUDES="$INCLUDES $LIBUNITY_CFLAGS" INCLUDES="$INCLUDES $LIBUNITY_CFLAGS"
fi fi

View File

@ -61,4 +61,5 @@ credits:
# $(srcdir)/devtools/credits.pl --text > $@ # $(srcdir)/devtools/credits.pl --text > $@
#gui/credits.h: $(srcdir)/devtools/credits.pl #gui/credits.h: $(srcdir)/devtools/credits.pl
# $(srcdir)/devtools/credits.pl --cpp > $@.PHONY: clean-devtools devtools credits # $(srcdir)/devtools/credits.pl --cpp > $@
.PHONY: clean-devtools devtools credits

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#include "base/version.h" #include "base/version.h"

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#ifndef GLOBAL_DIALOGS_H #ifndef GLOBAL_DIALOGS_H

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#define FORBIDDEN_SYMBOL_EXCEPTION_getcwd #define FORBIDDEN_SYMBOL_EXCEPTION_getcwd

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#ifndef ENGINES_ENGINE_H #ifndef ENGINES_ENGINE_H
@ -128,7 +129,15 @@ public:
* If this feature is supported, then the corresponding MetaEngine *must* * If this feature is supported, then the corresponding MetaEngine *must*
* support the kSupportsListSaves feature. * support the kSupportsListSaves feature.
*/ */
kSupportsSavingDuringRuntime kSupportsSavingDuringRuntime,
/**
* Arbitrary resolutions are supported, that is, this engine allows
* the backend to override the resolution passed to OSystem::setupScreen.
* The engine will need to read the actual resolution used by the
* backend using OSystem::getWidth and OSystem::getHeight.
*/
kSupportsArbitraryResolutions // ResidualVM specific
}; };

View File

@ -87,7 +87,7 @@ Actor::Actor() :
_pitch(0), _yaw(0), _roll(0), _walkRate(0.3f), _pitch(0), _yaw(0), _roll(0), _walkRate(0.3f),
_turnRateMultiplier(0.f), _talkAnim(0), _turnRateMultiplier(0.f), _talkAnim(0),
_reflectionAngle(80), _scale(1.f), _timeScale(1.f), _reflectionAngle(80), _scale(1.f), _timeScale(1.f),
_visible(true), _lipSync(nullptr), _turning(false), _walking(false), _visible(true), _lipSync(nullptr), _turning(false), _singleTurning(false), _walking(false),
_walkedLast(false), _walkedCur(false), _walkedLast(false), _walkedCur(false),
_collisionMode(CollisionOff), _collisionScale(1.f), _collisionMode(CollisionOff), _collisionScale(1.f),
_lastTurnDir(0), _currTurnDir(0), _lastTurnDir(0), _currTurnDir(0),
@ -184,6 +184,7 @@ void Actor::saveState(SaveGame *savedState) const {
} }
savedState->writeBool(_turning); savedState->writeBool(_turning);
savedState->writeBool(_singleTurning);
savedState->writeFloat(_moveYaw.getDegrees()); savedState->writeFloat(_moveYaw.getDegrees());
savedState->writeFloat(_movePitch.getDegrees()); savedState->writeFloat(_movePitch.getDegrees());
savedState->writeFloat(_moveRoll.getDegrees()); savedState->writeFloat(_moveRoll.getDegrees());
@ -349,6 +350,9 @@ bool Actor::restoreState(SaveGame *savedState) {
} }
_turning = savedState->readBool(); _turning = savedState->readBool();
if (savedState->saveMinorVersion() > 25) {
_singleTurning = savedState->readBool();
}
_moveYaw = savedState->readFloat(); _moveYaw = savedState->readFloat();
if (savedState->saveMinorVersion() > 6) { if (savedState->saveMinorVersion() > 6) {
_movePitch = savedState->readFloat(); _movePitch = savedState->readFloat();
@ -519,6 +523,13 @@ void Actor::setPos(const Math::Vector3d &position) {
if (_followBoxes) { if (_followBoxes) {
g_grim->getCurrSet()->findClosestSector(_pos, nullptr, &_pos); g_grim->getCurrSet()->findClosestSector(_pos, nullptr, &_pos);
} }
if (g_grim->getGameType() == GType_MONKEY4) {
Math::Vector3d moveVec = position - _pos;
foreach (Actor *a, g_grim->getActiveActors()) {
handleCollisionWith(a, _collisionMode, &moveVec);
}
}
} }
void Actor::calculateOrientation(const Math::Vector3d &pos, Math::Angle *pitch, Math::Angle *yaw, Math::Angle *roll) { void Actor::calculateOrientation(const Math::Vector3d &pos, Math::Angle *pitch, Math::Angle *yaw, Math::Angle *roll) {
@ -573,6 +584,7 @@ bool Actor::singleTurnTo(const Math::Vector3d &pos) {
_moveYaw = _yaw; _moveYaw = _yaw;
_movePitch = _pitch; _movePitch = _pitch;
_moveRoll = _roll; _moveRoll = _roll;
_singleTurning = !done;
return done; return done;
} }
@ -749,6 +761,9 @@ bool Actor::isWalking() const {
} }
bool Actor::isTurning() const { bool Actor::isTurning() const {
if (g_grim->getGameType() == GType_MONKEY4)
if (_singleTurning)
return true;
if (_turning) if (_turning)
return true; return true;
@ -795,6 +810,13 @@ void Actor::walkForward() {
if ((dist > 0 && dist > _walkRate / 5.f) || (dist < 0 && dist < _walkRate / 5.f)) if ((dist > 0 && dist > _walkRate / 5.f) || (dist < 0 && dist < _walkRate / 5.f))
dist = _walkRate / 5.f; dist = _walkRate / 5.f;
// Handle special case where actor is trying to walk but _walkRate is
// currently set to 0.0f by _walkChore to simulate roboter-like walk style:
// set _walkedCur to true to keep _walkChore playing in Actor::update()
if (_walkRate == 0.0f) {
_walkedCur = true;
}
_walking = false; _walking = false;
if (!_followBoxes) { if (!_followBoxes) {
@ -1695,7 +1717,7 @@ void Actor::draw() {
// FIXME: if isAttached(), factor in the joint rotation as well. // FIXME: if isAttached(), factor in the joint rotation as well.
const Math::Vector3d &absPos = getWorldPos(); const Math::Vector3d &absPos = getWorldPos();
if (!_costumeStack.empty()) { if (!_costumeStack.empty()) {
g_grim->getCurrSet()->setupLights(absPos); g_grim->getCurrSet()->setupLights(absPos, _inOverworld);
if (g_grim->getGameType() == GType_GRIM) { if (g_grim->getGameType() == GType_GRIM) {
Costume *costume = _costumeStack.back(); Costume *costume = _costumeStack.back();
drawCostume(costume); drawCostume(costume);

View File

@ -611,6 +611,7 @@ private:
// Variables for gradual turning // Variables for gradual turning
bool _turning; bool _turning;
bool _singleTurning;
// NOTE: The movement direction is separate from the direction // NOTE: The movement direction is separate from the direction
// the actor's model is facing. The model's direction is gradually // the actor's model is facing. The model's direction is gradually
// updated to match the movement direction. This produces a smooth // updated to match the movement direction. This produces a smooth

View File

@ -334,6 +334,23 @@ static const GrimGameDescription gameDescriptions[] = {
}, },
GType_MONKEY4 GType_MONKEY4
}, },
{
// Escape from Monkey Island German (Mac)
{
"monkey4",
"",
{
{"artAll.m4b", 0, "007a33881478be6b6e0228d8888536ae", 18512568},
{"EFMI Installer", 0, "54298c7440dafedf33d2b27c7bb24052", 9241784},
AD_LISTEND
},
Common::DE_DEU,
Common::kPlatformMacintosh,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_LOAD_DATAUSR)
},
GType_MONKEY4
},
{ {
// Escape from Monkey Island English PS2 // Escape from Monkey Island English PS2
{ {

View File

@ -35,6 +35,9 @@ public:
protected: protected:
virtual bool findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) override; virtual bool findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) override;
void setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore); void setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore);
static uint convertEmiVolumeToMixer(uint emiVolume);
static uint convertMixerVolumeToEmi(uint volume);
static const uint MAX_EMI_VOLUME = 100;
DECLARE_LUA_OPCODE(UndimAll); DECLARE_LUA_OPCODE(UndimAll);
DECLARE_LUA_OPCODE(SetActorLocalAlpha); DECLARE_LUA_OPCODE(SetActorLocalAlpha);

View File

@ -20,10 +20,13 @@
* *
*/ */
#include "common/debug-channels.h"
#include "engines/grim/emi/lua_v2.h" #include "engines/grim/emi/lua_v2.h"
#include "engines/grim/lua/lua.h" #include "engines/grim/lua/lua.h"
#include "engines/grim/actor.h" #include "engines/grim/actor.h"
#include "engines/grim/debug.h"
#include "engines/grim/grim.h" #include "engines/grim/grim.h"
#include "engines/grim/costume.h" #include "engines/grim/costume.h"
#include "engines/grim/set.h" #include "engines/grim/set.h"
@ -712,6 +715,7 @@ void Lua_V2::GetActorChores() {
lua_pushobject(result); lua_pushobject(result);
} }
// Helper function, not called from LUA directly
bool Lua_V2::findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) { bool Lua_V2::findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) {
*costume = nullptr; *costume = nullptr;
if (lua_isnil(costumeObj)) { if (lua_isnil(costumeObj)) {
@ -970,7 +974,7 @@ void Lua_V2::AttachActor() {
} }
attached->attachToActor(actor, joint); attached->attachToActor(actor, joint);
warning("Lua_V2::AttachActor: attaching %s to %s (on %s)", attached->getName().c_str(), actor->getName().c_str(), joint ? joint : "(none)"); Debug::debug(Debug::Actors | Debug::Scripts, "Lua_V2::AttachActor: attaching %s to %s (on %s)", attached->getName().c_str(), actor->getName().c_str(), joint ? joint : "(none)");
g_emi->invalidateSortOrder(); g_emi->invalidateSortOrder();
} }
@ -986,7 +990,7 @@ void Lua_V2::DetachActor() {
if (!attached) if (!attached)
return; return;
warning("Lua_V2::DetachActor: detaching %s from parent actor", attached->getName().c_str()); Debug::debug(Debug::Actors | Debug::Scripts, "Lua_V2::DetachActor: detaching %s from parent actor", attached->getName().c_str());
attached->detach(); attached->detach();
g_emi->invalidateSortOrder(); g_emi->invalidateSortOrder();
@ -1083,6 +1087,7 @@ void Lua_V2::EnableActorPuck() {
warning("Lua_V2::EnableActorPuck: stub, actor: %s enable: %s", actor->getName().c_str(), enable ? "TRUE" : "FALSE"); warning("Lua_V2::EnableActorPuck: stub, actor: %s enable: %s", actor->getName().c_str(), enable ? "TRUE" : "FALSE");
} }
// Helper function, not called from LUA directly
void Lua_V2::setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore) { void Lua_V2::setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore) {
if (lua_isnil(choreObj)) { if (lua_isnil(choreObj)) {
return; return;

View File

@ -37,6 +37,22 @@
namespace Grim { namespace Grim {
// Helper function, not called from LUA directly
uint Lua_V2::convertEmiVolumeToMixer(uint emiVolume) {
// EmiVolume range: 0 .. 100
// Mixer range: 0 .. kMaxChannelVolume
float vol = float(emiVolume) / MAX_EMI_VOLUME * Audio::Mixer::kMaxChannelVolume;
return CLIP<uint>(uint(vol), 0, Audio::Mixer::kMaxChannelVolume);
}
// Helper function, not called from LUA directly
uint Lua_V2::convertMixerVolumeToEmi(uint volume) {
float vol = float(volume) * MAX_EMI_VOLUME / Audio::Mixer::kMaxChannelVolume;
return CLIP<uint>(uint(vol), 0, MAX_EMI_VOLUME);
}
// Note: debug output for volume values uses the engine's mixer range
void Lua_V2::ImGetMillisecondPosition() { void Lua_V2::ImGetMillisecondPosition() {
lua_Object soundObj = lua_getparam(1); lua_Object soundObj = lua_getparam(1);
@ -146,15 +162,14 @@ void Lua_V2::SetGroupVolume() {
return; return;
int group = (int)lua_getnumber(groupObj); int group = (int)lua_getnumber(groupObj);
int volume = 100; int volume = Audio::Mixer::kMaxChannelVolume;
if (lua_isnumber(volumeObj)) if (lua_isnumber(volumeObj))
volume = (int)lua_getnumber(volumeObj); volume = convertEmiVolumeToMixer((int)lua_getnumber(volumeObj));
volume = (volume * Audio::Mixer::kMaxMixerVolume) / 100;
switch (group) { switch (group) {
case 1: // SFX case 1: // SFX
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
break; break;
case 2: // Voice case 2: // Voice
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume); g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@ -185,6 +200,7 @@ void Lua_V2::EnableAudioGroup() {
switch (group) { switch (group) {
case 1: // SFX case 1: // SFX
g_system->getMixer()->muteSoundType(Audio::Mixer::kSFXSoundType, !state); g_system->getMixer()->muteSoundType(Audio::Mixer::kSFXSoundType, !state);
g_system->getMixer()->muteSoundType(Audio::Mixer::kPlainSoundType, !state);
break; break;
case 2: // Voice case 2: // Voice
g_system->getMixer()->muteSoundType(Audio::Mixer::kSpeechSoundType, !state); g_system->getMixer()->muteSoundType(Audio::Mixer::kSpeechSoundType, !state);
@ -261,7 +277,11 @@ void Lua_V2::PlayLoadedSound() {
/*lua_Object bool2Obj =*/ lua_getparam(4); /*lua_Object bool2Obj =*/ lua_getparam(4);
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) { if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
error("Lua_V2::PlayLoadedSound - ERROR: Unknown parameters"); // can't use error since it actually may happen:
// when entering the bait shop after the termites were already put on Mandrill's cane,
// the LUA code will not load the termite sound files but the script which starts
// the sounds is running anyway
warning("Lua_V2::PlayLoadedSound - ERROR: Unknown parameters");
return; return;
} }
@ -273,7 +293,7 @@ void Lua_V2::PlayLoadedSound() {
return; return;
} }
int volume = 100; int volume = MAX_EMI_VOLUME;
if (!lua_isnumber(volumeObj)) { if (!lua_isnumber(volumeObj)) {
// In the demo when the dart hits the balloon in the scumm bar, nil is passed // In the demo when the dart hits the balloon in the scumm bar, nil is passed
// to the volume parameter. // to the volume parameter.
@ -281,7 +301,7 @@ void Lua_V2::PlayLoadedSound() {
} else { } else {
volume = (int)lua_getnumber(volumeObj); volume = (int)lua_getnumber(volumeObj);
} }
sound->setVolume(volume); sound->setVolume(convertEmiVolumeToMixer(volume));
sound->play(looping); sound->play(looping);
} }
@ -308,7 +328,7 @@ void Lua_V2::PlayLoadedSoundFrom() {
float y = lua_getnumber(yObj); float y = lua_getnumber(yObj);
float z = lua_getnumber(zObj); float z = lua_getnumber(zObj);
int volume = 100; int volume = MAX_EMI_VOLUME;
bool looping = false; bool looping = false;
if (lua_isnumber(volumeOrLoopingObj)) { if (lua_isnumber(volumeOrLoopingObj)) {
@ -329,7 +349,7 @@ void Lua_V2::PlayLoadedSoundFrom() {
return; return;
} }
Math::Vector3d pos(x, y, z); Math::Vector3d pos(x, y, z);
sound->setVolume(volume); sound->setVolume(convertEmiVolumeToMixer(volume));
sound->playFrom(pos, looping); sound->playFrom(pos, looping);
} }
@ -381,7 +401,7 @@ void Lua_V2::PlaySound() {
} }
const char *str = lua_getstring(strObj); const char *str = lua_getstring(strObj);
int volume = 100; int volume = MAX_EMI_VOLUME;
if (!lua_isnumber(volumeObj)) { if (!lua_isnumber(volumeObj)) {
warning("Lua_V2::PlaySound - Unexpected parameter(s) found, using default volume for %s", str); warning("Lua_V2::PlaySound - Unexpected parameter(s) found, using default volume for %s", str);
} else { } else {
@ -390,7 +410,7 @@ void Lua_V2::PlaySound() {
Common::String filename = addSoundSuffix(str); Common::String filename = addSoundSuffix(str);
if (!g_emiSound->startSfx(filename, volume)) { if (!g_emiSound->startSfx(filename, convertEmiVolumeToMixer(volume))) {
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySound: Could not open sound '%s'", filename.c_str()); Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySound: Could not open sound '%s'", filename.c_str());
} }
} }
@ -404,7 +424,7 @@ void Lua_V2::PlaySoundFrom() {
lua_Object volumeOrUnknownObj = lua_getparam(5); lua_Object volumeOrUnknownObj = lua_getparam(5);
lua_Object volumeObj = lua_getparam(6); lua_Object volumeObj = lua_getparam(6);
int volume = 100; int volume = MAX_EMI_VOLUME;
if (!lua_isstring(strObj)) { if (!lua_isstring(strObj)) {
error("Lua_V2::PlaySoundFrom - ERROR: Unknown parameters"); error("Lua_V2::PlaySoundFrom - ERROR: Unknown parameters");
@ -434,7 +454,7 @@ void Lua_V2::PlaySoundFrom() {
Math::Vector3d pos(x, y, z); Math::Vector3d pos(x, y, z);
if (!g_emiSound->startSfxFrom(filename.c_str(), pos, volume)) { if (!g_emiSound->startSfxFrom(filename.c_str(), pos, convertEmiVolumeToMixer(volume))) {
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySoundFrom: Could not open sound '%s'", filename.c_str()); Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySoundFrom: Could not open sound '%s'", filename.c_str());
} }
} }
@ -447,10 +467,10 @@ void Lua_V2::GetSoundVolume() {
} }
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj)); PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
if (sound) { if (sound) {
lua_pushnumber(sound->getVolume()); lua_pushnumber(convertMixerVolumeToEmi(sound->getVolume()));
} else { } else {
warning("Lua_V2::GetSoundVolume: can't find sound track"); warning("Lua_V2::GetSoundVolume: can't find sound track");
lua_pushnumber(Audio::Mixer::kMaxMixerVolume); lua_pushnumber(convertMixerVolumeToEmi(Audio::Mixer::kMaxChannelVolume));
} }
} }
@ -470,7 +490,7 @@ void Lua_V2::SetSoundVolume() {
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj)); PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
if (sound) { if (sound) {
sound->setVolume(volume); sound->setVolume(convertEmiVolumeToMixer(volume));
} else { } else {
warning("Lua_V2:SetSoundVolume: can't find sound track"); warning("Lua_V2:SetSoundVolume: can't find sound track");
} }
@ -505,7 +525,7 @@ void Lua_V2::ImSetMusicVol() {
if (!lua_isnumber(volumeObj)) if (!lua_isnumber(volumeObj))
return; return;
int volume = (int)lua_getnumber(volumeObj); int volume = (int)lua_getnumber(volumeObj);
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetMusicVol: implement opcode, wants volume %d", volume); Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetMusicVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
} }
void Lua_V2::ImSetSfxVol() { void Lua_V2::ImSetSfxVol() {
@ -515,7 +535,7 @@ void Lua_V2::ImSetSfxVol() {
if (!lua_isnumber(volumeObj)) if (!lua_isnumber(volumeObj))
return; return;
int volume = (int)lua_getnumber(volumeObj); int volume = (int)lua_getnumber(volumeObj);
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetSfxVol: implement opcode, wants volume %d", volume); Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetSfxVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
} }
void Lua_V2::ImSetVoiceVol() { void Lua_V2::ImSetVoiceVol() {
@ -525,7 +545,7 @@ void Lua_V2::ImSetVoiceVol() {
if (!lua_isnumber(volumeObj)) if (!lua_isnumber(volumeObj))
return; return;
int volume = (int)lua_getnumber(volumeObj); int volume = (int)lua_getnumber(volumeObj);
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetVoiceVol: implement opcode, wants volume %d", volume); Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetVoiceVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
} }
void Lua_V2::ImSetVoiceEffect() { void Lua_V2::ImSetVoiceEffect() {

View File

@ -320,7 +320,9 @@ void EMIModel::updateLighting(const Math::Matrix4 &modelToWorld) {
Common::Array<Grim::Light *> activeLights; Common::Array<Grim::Light *> activeLights;
bool hasAmbient = false; bool hasAmbient = false;
foreach(Light *l, g_grim->getCurrSet()->getLights()) { Actor *actor = _costume->getOwner();
foreach(Light *l, g_grim->getCurrSet()->getLights(actor->isInOverworld())) {
if (l->_enabled) { if (l->_enabled) {
activeLights.push_back(l); activeLights.push_back(l);
if (l->_type == Light::Ambient) if (l->_type == Light::Ambient)

View File

@ -53,9 +53,9 @@ class EMISound {
public: public:
EMISound(int fps); EMISound(int fps);
~EMISound(); ~EMISound();
bool startVoice(const Common::String &soundName, int volume = 100, int pan = 64); bool startVoice(const Common::String &soundName, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume), int pan = 64);
bool startSfx(const Common::String &soundName, int volume = 100, int pan = 64); bool startSfx(const Common::String &soundName, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume), int pan = 64);
bool startSfxFrom(const Common::String &soundName, const Math::Vector3d &pos, int volume = 100); bool startSfxFrom(const Common::String &soundName, const Math::Vector3d &pos, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume));
bool getSoundStatus(const Common::String &soundName); bool getSoundStatus(const Common::String &soundName);
void stopSound(const Common::String &soundName); void stopSound(const Common::String &soundName);
int32 getPosIn16msTicks(const Common::String &soundName); int32 getPosIn16msTicks(const Common::String &soundName);

View File

@ -39,7 +39,7 @@ SoundTrack::SoundTrack() {
_paused = false; _paused = false;
_positioned = false; _positioned = false;
_balance = 0; _balance = 0;
_volume = 100; _volume = Audio::Mixer::kMaxChannelVolume;
_disposeAfterPlaying = DisposeAfterUse::YES; _disposeAfterPlaying = DisposeAfterUse::YES;
_sync = 0; _sync = 0;
_fadeMode = FadeNone; _fadeMode = FadeNone;
@ -64,10 +64,7 @@ void SoundTrack::setSoundName(const Common::String &name) {
} }
void SoundTrack::setVolume(int volume) { void SoundTrack::setVolume(int volume) {
if (volume > 100) { _volume = MIN(volume, static_cast<int>(Audio::Mixer::kMaxChannelVolume));
volume = 100;
}
_volume = volume;
if (_handle) { if (_handle) {
g_system->getMixer()->setChannelVolume(*_handle, (byte)getEffectiveVolume()); g_system->getMixer()->setChannelVolume(*_handle, (byte)getEffectiveVolume());
} }
@ -88,7 +85,10 @@ void SoundTrack::updatePosition() {
Math::Vector3d cameraPos = setup->_pos; Math::Vector3d cameraPos = setup->_pos;
Math::Vector3d vector = _pos - cameraPos; Math::Vector3d vector = _pos - cameraPos;
float distance = vector.getMagnitude(); float distance = vector.getMagnitude();
_attenuation = MAX(0.0f, 1.0f - distance / _volume); _attenuation = MAX(0.0f, 1.0f - distance / (_volume * 100.0f / Audio::Mixer::kMaxChannelVolume));
if (!isfinite(_attenuation)) {
_attenuation = 0.0f;
}
Math::Matrix4 worldRot = setup->_rot; Math::Matrix4 worldRot = setup->_rot;
Math::Vector3d relPos = (_pos - setup->_pos); Math::Vector3d relPos = (_pos - setup->_pos);
@ -146,8 +146,7 @@ void SoundTrack::setFade(float fade) {
} }
int SoundTrack::getEffectiveVolume() { int SoundTrack::getEffectiveVolume() {
int mixerVolume = _volume * Audio::Mixer::kMaxChannelVolume / 100; return _volume * _attenuation * _fade;
return mixerVolume * _attenuation * _fade;
} }
} // end of namespace Grim } // end of namespace Grim

View File

@ -1577,6 +1577,30 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
int width = frame->w; int width = frame->w;
byte *bitmap = (byte *)frame->getPixels(); byte *bitmap = (byte *)frame->getPixels();
GLenum format;
GLenum dataType;
int bytesPerPixel = frame->format.bytesPerPixel;
// Aspyr Logo format
if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0)) {
format = GL_BGRA;
dataType = GL_UNSIGNED_INT_8_8_8_8;
} else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
format = GL_RGB;
dataType = GL_UNSIGNED_SHORT_5_6_5;
} else {
error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
frame->format.bytesPerPixel,
-(frame->format.rLoss - 8),
-(frame->format.gLoss - 8),
-(frame->format.bLoss - 8),
-(frame->format.aLoss - 8),
frame->format.rShift,
frame->format.gShift,
frame->format.bShift,
frame->format.aShift);
}
// remove if already exist // remove if already exist
if (_smushNumTex > 0) { if (_smushNumTex > 0) {
glDeleteTextures(_smushNumTex, _smushTexIds); glDeleteTextures(_smushNumTex, _smushTexIds);
@ -1595,10 +1619,10 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, dataType, nullptr);
} }
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // 16 bit RGB 565 bitmap glPixelStorei(GL_UNPACK_ALIGNMENT, bytesPerPixel); // 16 bit RGB 565 bitmap/32 bit BGR
glPixelStorei(GL_UNPACK_ROW_LENGTH, width); glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
int curTexIdx = 0; int curTexIdx = 0;
@ -1607,7 +1631,7 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
int t_width = (x + BITMAP_TEXTURE_SIZE >= width) ? (width - x) : BITMAP_TEXTURE_SIZE; int t_width = (x + BITMAP_TEXTURE_SIZE >= width) ? (width - x) : BITMAP_TEXTURE_SIZE;
int t_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE; int t_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE;
glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]); glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap + (y * 2 * width) + (2 * x)); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, format, dataType, bitmap + (y * bytesPerPixel * width) + (bytesPerPixel * x));
curTexIdx++; curTexIdx++;
} }
} }
@ -2015,6 +2039,7 @@ void GfxOpenGL::drawDimPlane() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, _dimLevel); glColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glVertex2f(0, 0); glVertex2f(0, 0);
glVertex2f(1.0, 0); glVertex2f(1.0, 0);
@ -2022,6 +2047,8 @@ void GfxOpenGL::drawDimPlane() {
glVertex2f(0, 1.0); glVertex2f(0, 1.0);
glEnd(); glEnd();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);

View File

@ -191,6 +191,20 @@ Math::Matrix4 makeRotationMatrix(const Math::Angle& angle, Math::Vector3d axis)
return rotate; return rotate;
} }
Math::Matrix4 makeFrustumMatrix(double left, double right, double bottom, double top, double nclip, double fclip) {
Math::Matrix4 proj;
proj(0, 0) = (2.0f * nclip) / (right - left);
proj(1, 1) = (2.0f * nclip) / (top - bottom);
proj(2, 0) = (right + left) / (right - left);
proj(2, 1) = (top + bottom) / (top - bottom);
proj(2, 2) = -(fclip + nclip) / (fclip - nclip);
proj(2, 3) = -1.0f;
proj(3, 2) = -(2.0f * fclip * nclip) / (fclip - nclip);
proj(3, 3) = 0.0f;
return proj;
}
GfxBase *CreateGfxOpenGL() { GfxBase *CreateGfxOpenGL() {
return new GfxOpenGLS(); return new GfxOpenGLS();
} }
@ -219,6 +233,9 @@ GfxOpenGLS::GfxOpenGLS() {
_dimProgram = nullptr; _dimProgram = nullptr;
_dimPlaneProgram = nullptr; _dimPlaneProgram = nullptr;
_dimRegionProgram = nullptr; _dimRegionProgram = nullptr;
float div = 6.0f;
_overworldProjMatrix = makeFrustumMatrix(-1.f / div, 1.f / div, -0.75f / div, 0.75f / div, 1.0f / div, 3276.8f);
} }
GfxOpenGLS::~GfxOpenGLS() { GfxOpenGLS::~GfxOpenGLS() {
@ -428,21 +445,9 @@ void GfxOpenGLS::setupCameraFrustum(float fov, float nclip, float fclip) {
_fov = fov; _nclip = nclip; _fclip = fclip; _fov = fov; _nclip = nclip; _fclip = fclip;
float right = nclip * tan(fov / 2 * (LOCAL_PI / 180)); float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
float left = -right;
float top = right * 0.75; float top = right * 0.75;
float bottom = -right * 0.75;
Math::Matrix4 proj; _projMatrix = makeFrustumMatrix(-right, right, -top, top, nclip, fclip);
proj(0, 0) = (2.0f * nclip) / (right - left);
proj(1, 1) = (2.0f * nclip) / (top - bottom);
proj(2, 0) = (right + left) / (right - left);
proj(2, 1) = (top + bottom) / (top - bottom);
proj(2, 2) = -(fclip + nclip) / (fclip - nclip);
proj(2, 3) = -1.0f;
proj(3, 2) = -(2.0f * fclip * nclip) / (fclip - nclip);
proj(3, 3) = 0.0f;
_projMatrix = proj;
} }
void GfxOpenGLS::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) { void GfxOpenGLS::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
@ -671,9 +676,8 @@ void GfxOpenGLS::startActorDraw(const Actor *actor) {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glFrontFace(GL_CW); glFrontFace(GL_CW);
/* FIXME: set correct projection matrix/frustum when if (actor->isInOverworld())
* drawing in the Overworld viewMatrix = Math::Matrix4();
*/
Math::Vector4d color(1.0f, 1.0f, 1.0f, actor->getEffectiveAlpha()); Math::Vector4d color(1.0f, 1.0f, 1.0f, actor->getEffectiveAlpha());
@ -685,11 +689,17 @@ void GfxOpenGLS::startActorDraw(const Actor *actor) {
modelMatrix.transpose(); modelMatrix.transpose();
_actorProgram->setUniform("modelMatrix", modelMatrix); _actorProgram->setUniform("modelMatrix", modelMatrix);
_actorProgram->setUniform("viewMatrix", viewRot); if (actor->isInOverworld()) {
_actorProgram->setUniform("projMatrix", _projMatrix); _actorProgram->setUniform("viewMatrix", viewMatrix);
_actorProgram->setUniform("projMatrix", _overworldProjMatrix);
_actorProgram->setUniform("cameraPos", Math::Vector3d(0,0,0));
} else {
_actorProgram->setUniform("viewMatrix", viewRot);
_actorProgram->setUniform("projMatrix", _projMatrix);
_actorProgram->setUniform("cameraPos", _currentPos);
}
_actorProgram->setUniform("normalMatrix", normalMatrix); _actorProgram->setUniform("normalMatrix", normalMatrix);
_actorProgram->setUniform("cameraPos", _currentPos);
_actorProgram->setUniform("actorPos", pos); _actorProgram->setUniform("actorPos", pos);
_actorProgram->setUniform("isBillboard", GL_FALSE); _actorProgram->setUniform("isBillboard", GL_FALSE);
_actorProgram->setUniform("useVertexAlpha", GL_FALSE); _actorProgram->setUniform("useVertexAlpha", GL_FALSE);
@ -2034,8 +2044,8 @@ static void readPixels(int x, int y, int width, int height, byte *buffer) {
} }
Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) { Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
#ifndef USE_GLES2
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES); Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
#ifndef USE_GLES2
if (useStored) { if (useStored) {
glBindTexture(GL_TEXTURE_2D, _storedDisplay); glBindTexture(GL_TEXTURE_2D, _storedDisplay);
char *buffer = new char[_screenWidth * _screenHeight * 4]; char *buffer = new char[_screenWidth * _screenHeight * 4];
@ -2044,13 +2054,12 @@ Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
memcpy(src.getRawBuffer(), buffer, _screenWidth * _screenHeight * 4); memcpy(src.getRawBuffer(), buffer, _screenWidth * _screenHeight * 4);
delete[] buffer; delete[] buffer;
} else { } else
#endif
{
readPixels(0, 0, _screenWidth, _screenHeight, src.getRawBuffer()); readPixels(0, 0, _screenWidth, _screenHeight, src.getRawBuffer());
} }
return createScreenshotBitmap(src, w, h, false); return createScreenshotBitmap(src, w, h, true);
#else
return nullptr;
#endif
} }
void GfxOpenGLS::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) { void GfxOpenGLS::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {

View File

@ -251,6 +251,7 @@ private:
Math::Matrix4 _projMatrix; Math::Matrix4 _projMatrix;
Math::Matrix4 _viewMatrix; Math::Matrix4 _viewMatrix;
Math::Matrix4 _mvpMatrix; Math::Matrix4 _mvpMatrix;
Math::Matrix4 _overworldProjMatrix;
void setupTexturedCenteredQuad(); void setupTexturedCenteredQuad();

View File

@ -1397,7 +1397,7 @@ void GfxTinyGL::drawLine(const PrimitiveObject *primitive) {
_zb->writePixel(_gameWidth * y + x1, color.getRed(), color.getGreen(), color.getBlue()); _zb->writePixel(_gameWidth * y + x1, color.getRed(), color.getGreen(), color.getBlue());
} }
} else { } else {
float m = (y2 - y1) / (x2 - x1); float m = (y2 - y1) / (float)(x2 - x1);
int b = (int)(-m * x1 + y1); int b = (int)(-m * x1 + y1);
for (int x = x1; x <= x2; x++) { for (int x = x1; x <= x2; x++) {
int y = (int)(m * x) + b; int y = (int)(m * x) + b;
@ -1424,6 +1424,7 @@ void GfxTinyGL::drawDimPlane() {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA); tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
tglColor4f(0.0f, 0.0f, 0.0f, _dimLevel); tglColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
tglBegin(TGL_QUADS); tglBegin(TGL_QUADS);
tglVertex2f(-1, -1); tglVertex2f(-1, -1);
tglVertex2f(1.0, -1); tglVertex2f(1.0, -1);
@ -1431,6 +1432,8 @@ void GfxTinyGL::drawDimPlane() {
tglVertex2f(-1, 1.0); tglVertex2f(-1, 1.0);
tglEnd(); tglEnd();
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
tglDisable(TGL_BLEND); tglDisable(TGL_BLEND);
tglDepthMask(TGL_TRUE); tglDepthMask(TGL_TRUE);
tglEnable(TGL_DEPTH_TEST); tglEnable(TGL_DEPTH_TEST);

View File

@ -248,13 +248,24 @@ const char *GrimEngine::getUpdateFilename() {
Common::Error GrimEngine::run() { Common::Error GrimEngine::run() {
// Try to see if we have the EMI Mac installer present // Try to see if we have the EMI Mac installer present
// Currently, this requires the data fork to be standalone // Currently, this requires the data fork to be standalone
if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("Monkey Island 4 Installer")) { if (getGameType() == GType_MONKEY4) {
StuffItArchive *archive = new StuffItArchive(); if (SearchMan.hasFile("Monkey Island 4 Installer")) {
StuffItArchive *archive = new StuffItArchive();
if (archive->open("Monkey Island 4 Installer")) if (archive->open("Monkey Island 4 Installer"))
SearchMan.add("Monkey Island 4 Installer", archive, 0, true); SearchMan.add("Monkey Island 4 Installer", archive, 0, true);
else else
delete archive; delete archive;
}
if (SearchMan.hasFile("EFMI Installer")) {
StuffItArchive *archive = new StuffItArchive();
if (archive->open("EFMI Installer"))
SearchMan.add("EFMI Installer", archive, 0, true);
else
delete archive;
}
} }
ConfMan.registerDefault("check_gamedata", true); ConfMan.registerDefault("check_gamedata", true);
@ -300,8 +311,8 @@ Common::Error GrimEngine::run() {
g_driver->loadEmergFont(); g_driver->loadEmergFont();
if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) { if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) {
// TODO: Play EMI Mac Aspyr logo // Play EMI Mac Aspyr logo
warning("TODO: Play Aspyr logo"); playAspyrLogo();
} }
Bitmap *splash_bm = nullptr; Bitmap *splash_bm = nullptr;
@ -347,6 +358,52 @@ Common::Error GrimEngine::run() {
return Common::kNoError; return Common::kNoError;
} }
void GrimEngine::playAspyrLogo() {
// A trimmed down version of the code found in mainloop
// for the purpose of playing the Aspyr-logo.
// The reason for this, is that the logo needs a different
// codec than all the other videos (which are Bink).
// Code is provided to keep within the fps-limit, as well as to
// allow for pressing ESC to skip the movie.
MoviePlayer *defaultPlayer = g_movie;
g_movie = CreateQuickTimePlayer();
g_movie->play("AMWI.m4b", false, 0, 0);
setMode(SmushMode);
while (g_movie->isPlaying()) {
_doFlip = true;
uint32 startTime = g_system->getMillis();
updateDisplayScene();
if (_doFlip) {
doFlip();
}
// Process events to allow the user to skip the logo.
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
// Ignore everything but ESC when movies are playing
Common::EventType type = event.type;
if (type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) {
g_movie->stop();
break;
}
}
uint32 endTime = g_system->getMillis();
if (startTime > endTime)
continue;
uint32 diffTime = endTime - startTime;
if (_speedLimitMs == 0)
continue;
if (diffTime < _speedLimitMs) {
uint32 delayTime = _speedLimitMs - diffTime;
g_system->delayMillis(delayTime);
}
}
delete g_movie;
setMode(NormalMode);
g_movie = defaultPlayer;
}
Common::Error GrimEngine::loadGameState(int slot) { Common::Error GrimEngine::loadGameState(int slot) {
assert(slot >= 0); assert(slot >= 0);
if (getGameType() == GType_MONKEY4) { if (getGameType() == GType_MONKEY4) {

View File

@ -201,6 +201,7 @@ protected:
void buildActiveActorsList(); void buildActiveActorsList();
void savegameCallback(); void savegameCallback();
void createRenderer(); void createRenderer();
void playAspyrLogo();
virtual LuaBase *createLua(); virtual LuaBase *createLua();
virtual void updateNormalMode(); virtual void updateNormalMode();
virtual void updateDrawMode(); virtual void updateDrawMode();

View File

@ -22,6 +22,7 @@
#include "common/file.h" #include "common/file.h"
#include "common/substream.h" #include "common/substream.h"
#include "common/memstream.h"
#include "engines/grim/grim.h" #include "engines/grim/grim.h"
#include "engines/grim/lab.h" #include "engines/grim/lab.h"
@ -37,7 +38,15 @@ Common::SeekableReadStream *LabEntry::createReadStream() const {
return _parent->createReadStreamForMember(_name); return _parent->createReadStreamForMember(_name);
} }
bool Lab::open(const Common::String &filename) { Lab::Lab() {
_stream = nullptr;
}
Lab::~Lab() {
delete _stream;
}
bool Lab::open(const Common::String &filename, bool keepStream) {
_labFileName = filename; _labFileName = filename;
bool result = true; bool result = true;
@ -53,6 +62,12 @@ bool Lab::open(const Common::String &filename) {
else else
parseMonkey4FileTable(file); parseMonkey4FileTable(file);
} }
if (keepStream) {
file->seek(0, SEEK_SET);
byte *data = new byte[file->size()];
file->read(data, file->size());
_stream = new Common::MemoryReadStream(data, file->size(), DisposeAfterUse::YES);
}
delete file; delete file;
return result; return result;
@ -165,9 +180,16 @@ Common::SeekableReadStream *Lab::createReadStreamForMember(const Common::String
fname.toLowercase(); fname.toLowercase();
LabEntryPtr i = _entries[fname]; LabEntryPtr i = _entries[fname];
Common::File *file = new Common::File(); if (!_stream) {
file->open(_labFileName); Common::File *file = new Common::File();
return new Common::SeekableSubReadStream(file, i->_offset, i->_offset + i->_len, DisposeAfterUse::YES); file->open(_labFileName);
return new Common::SeekableSubReadStream(file, i->_offset, i->_offset + i->_len, DisposeAfterUse::YES);
} else {
byte *data = new byte[i->_len];
_stream->seek(i->_offset, SEEK_SET);
_stream->read(data, i->_len);
return new Common::MemoryReadStream(data, i->_len, DisposeAfterUse::YES);
}
} }
} // end of namespace Grim } // end of namespace Grim

View File

@ -46,8 +46,9 @@ public:
class Lab : public Common::Archive { class Lab : public Common::Archive {
public: public:
bool open(const Common::String &filename); bool open(const Common::String &filename, bool keepStream = false);
Lab();
virtual ~Lab();
// Common::Archive implementation // Common::Archive implementation
virtual bool hasFile(const Common::String &name) const override; virtual bool hasFile(const Common::String &name) const override;
virtual int listMembers(Common::ArchiveMemberList &list) const override; virtual int listMembers(Common::ArchiveMemberList &list) const override;
@ -62,6 +63,7 @@ private:
typedef Common::SharedPtr<LabEntry> LabEntryPtr; typedef Common::SharedPtr<LabEntry> LabEntryPtr;
typedef Common::HashMap<Common::String, LabEntryPtr, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> LabMap; typedef Common::HashMap<Common::String, LabEntryPtr, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> LabMap;
LabMap _entries; LabMap _entries;
Common::SeekableReadStream *_stream;
}; };
} // end of namespace Grim } // end of namespace Grim

View File

@ -177,10 +177,10 @@ void Lua_V1::DrawPolygon() {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
// Get X // Get X
lua_pushobject(tableObj1); lua_pushobject(tableObj1);
lua_pushnumber(i * 2); lua_pushnumber(i * 2 + 1);
pointObj = lua_gettable(); pointObj = lua_gettable();
if (!lua_isnumber(pointObj)) { if (!lua_isnumber(pointObj)) {
warning("Lua_V1::DrawPolygon: %i Point Parameter X isn't a number!", i * 2); warning("Lua_V1::DrawPolygon: %i Point Parameter X isn't a number!", i * 2 + 1);
return; return;
} }
if (g_grim->getGameType() == GType_GRIM) if (g_grim->getGameType() == GType_GRIM)
@ -190,10 +190,10 @@ void Lua_V1::DrawPolygon() {
// Get Y // Get Y
lua_pushobject(tableObj1); lua_pushobject(tableObj1);
lua_pushnumber(i * 2 + 1); lua_pushnumber(i * 2 + 2);
pointObj = lua_gettable(); pointObj = lua_gettable();
if (!lua_isnumber(pointObj)) { if (!lua_isnumber(pointObj)) {
warning("Lua_V1::DrawPolygon: %i Point Parameter Y isn't a number!", i * 2); warning("Lua_V1::DrawPolygon: %i Point Parameter Y isn't a number!", i * 2 + 2);
return; return;
} }
if (g_grim->getGameType() == GType_GRIM) if (g_grim->getGameType() == GType_GRIM)

View File

@ -230,7 +230,7 @@ const char *emi_sfx[] = {
}; };
const char *emi_voiceAll[] = { const char *emi_voiceAll[] = {
"18d3996c7de4d460b4cd4ee5897a90ae", // english patched "18d3996c7de4d460b4cd4ee5897a90ae", // english patched
"4e2ae54188a96dfb8ecbd39bf322b3f5", // german patched "e65a13f2906899ab6eca2cce3c4cb514", // german patched
"073ecbe5f23d17536dce591174bac593", // spanish patched "073ecbe5f23d17536dce591174bac593", // spanish patched
"86126ac852312452ee79558a5e76d7fd", // french patched "86126ac852312452ee79558a5e76d7fd", // french patched
"9b6b4748e872712c267d65778a3ed2da", // italian patched "9b6b4748e872712c267d65778a3ed2da", // italian patched
@ -333,6 +333,11 @@ const char *emid_voice[] = {
"7f9867d48b5e0af5cb3fbd8d79741f5d", // english patched "7f9867d48b5e0af5cb3fbd8d79741f5d", // english patched
}; };
// EMI Macintosh
const char *emi_installer[] = {
"93a639e3221405862dc46e9706216c00", // German (EFMI Installer)
"a42f8aa079a6d23c285fceba191e67a4", // English (Monkey Island 4 Installer)
};
bool MD5Check::_initted = false; bool MD5Check::_initted = false;
Common::Array<MD5Check::MD5Sum> *MD5Check::_files = nullptr; Common::Array<MD5Check::MD5Sum> *MD5Check::_files = nullptr;
@ -402,6 +407,15 @@ void MD5Check::init() {
MD5SUM("voiceMel.m4b", emiPS2_voiceMel) MD5SUM("voiceMel.m4b", emiPS2_voiceMel)
MD5SUM("voiceMon.m4b", emiPS2_voiceMon) MD5SUM("voiceMon.m4b", emiPS2_voiceMon)
} else { } else {
if (g_grim->getGamePlatform() == Common::kPlatformMacintosh) {
if (g_grim->getGameLanguage() == Common::DE_DEU) {
// Known to be the correct filename for german
MD5SUM("EFMI Installer", emi_installer)
} else {
// Known to be the correct filename for english
MD5SUM("Monkey Island 4 Installer", emi_installer)
}
}
MD5SUM("artAll.m4b", emi_artAll) MD5SUM("artAll.m4b", emi_artAll)
MD5SUM("artJam.m4b", emi_artJam) MD5SUM("artJam.m4b", emi_artJam)
MD5SUM("artLuc.m4b", emi_artLuc) MD5SUM("artLuc.m4b", emi_artLuc)

View File

@ -80,6 +80,7 @@ MODULE_OBJS := \
movie/bink.o \ movie/bink.o \
movie/mpeg.o \ movie/mpeg.o \
movie/movie.o \ movie/movie.o \
movie/quicktime.o \
movie/smush.o \ movie/smush.o \
update/packfile.o \ update/packfile.o \
update/mscab.o \ update/mscab.o \

View File

@ -174,6 +174,7 @@ protected:
MoviePlayer *CreateMpegPlayer(); MoviePlayer *CreateMpegPlayer();
MoviePlayer *CreateSmushPlayer(bool demo); MoviePlayer *CreateSmushPlayer(bool demo);
MoviePlayer *CreateBinkPlayer(bool demo); MoviePlayer *CreateBinkPlayer(bool demo);
MoviePlayer *CreateQuickTimePlayer();
extern MoviePlayer *g_movie; extern MoviePlayer *g_movie;
} // end of namespace Grim } // end of namespace Grim

View File

@ -0,0 +1,53 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/system.h"
#include "video/qt_decoder.h"
#include "engines/grim/movie/quicktime.h"
#include "engines/grim/grim.h"
namespace Grim {
MoviePlayer *CreateQuickTimePlayer() {
return new QuickTimePlayer();
}
QuickTimePlayer::QuickTimePlayer() : MoviePlayer() {
_videoDecoder = new Video::QuickTimeDecoder();
}
bool QuickTimePlayer::loadFile(const Common::String &filename) {
_fname = filename;
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(_fname);
if (!stream)
return false;
_videoDecoder->loadStream(stream);
_videoDecoder->start();
return true;
}
} // end of namespace Grim

View File

@ -0,0 +1,39 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRIM_QUICKTIME_PLAYER_H
#define GRIM_QUICKTIME_PLAYER_H
#include "engines/grim/movie/movie.h"
namespace Grim {
class QuickTimePlayer : public MoviePlayer {
public:
QuickTimePlayer();
private:
bool loadFile(const Common::String &filename) override;
};
} // end of namespace Grim
#endif

View File

@ -73,6 +73,7 @@ public:
ResourceLoader::ResourceLoader() { ResourceLoader::ResourceLoader() {
_cacheDirty = false; _cacheDirty = false;
_cacheMemorySize = 0; _cacheMemorySize = 0;
_localArchive = nullptr;
Lab *l; Lab *l;
Common::ArchiveMemberList files, updFiles; Common::ArchiveMemberList files, updFiles;
@ -149,6 +150,16 @@ ResourceLoader::ResourceLoader() {
SearchMan.listMatchingMembers(files, emi_patches_filename); SearchMan.listMatchingMembers(files, emi_patches_filename);
// This is neccessary to speed up the launch of the mac version,
// we _COULD_ protect this with a platform check, but the file isn't
// really big anyhow...
Lab *localLab = new Lab();
if (localLab->open("local.m4b", true)) {
_localArchive = localLab;
} else {
delete localLab;
}
if (g_grim->getGameFlags() & ADGF_DEMO) { if (g_grim->getGameFlags() & ADGF_DEMO) {
SearchMan.listMatchingMembers(files, "i9n.lab"); SearchMan.listMatchingMembers(files, "i9n.lab");
SearchMan.listMatchingMembers(files, "lip.lab"); SearchMan.listMatchingMembers(files, "lip.lab");
@ -257,7 +268,9 @@ ResourceLoader::ResourceCache *ResourceLoader::getEntryFromCache(const Common::S
Common::SeekableReadStream *ResourceLoader::loadFile(const Common::String &filename) const { Common::SeekableReadStream *ResourceLoader::loadFile(const Common::String &filename) const {
Common::SeekableReadStream *rs = nullptr; Common::SeekableReadStream *rs = nullptr;
if (SearchMan.hasFile(filename)) if (_localArchive && _localArchive->hasFile(filename)) {
rs = _localArchive->createReadStreamForMember(filename);
} else if (SearchMan.hasFile(filename))
rs = SearchMan.createReadStreamForMember(filename); rs = SearchMan.createReadStreamForMember(filename);
else else
return nullptr; return nullptr;

View File

@ -103,6 +103,8 @@ private:
mutable bool _cacheDirty; mutable bool _cacheDirty;
mutable int32 _cacheMemorySize; mutable int32 _cacheMemorySize;
Common::Archive *_localArchive;
Common::List<EMIModel *> _emiModels; Common::List<EMIModel *> _emiModels;
Common::List<Model *> _models; Common::List<Model *> _models;
Common::List<CMap *> _colormaps; Common::List<CMap *> _colormaps;

View File

@ -35,7 +35,7 @@ namespace Grim {
#define SAVEGAME_FOOTERTAG 'ESAV' #define SAVEGAME_FOOTERTAG 'ESAV'
uint SaveGame::SAVEGAME_MAJOR_VERSION = 22; uint SaveGame::SAVEGAME_MAJOR_VERSION = 22;
uint SaveGame::SAVEGAME_MINOR_VERSION = 25; uint SaveGame::SAVEGAME_MINOR_VERSION = 26;
SaveGame *SaveGame::openForLoading(const Common::String &filename) { SaveGame *SaveGame::openForLoading(const Common::String &filename) {
Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename); Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename);

View File

@ -51,6 +51,7 @@ Set::Set(const Common::String &sceneName, Common::SeekableReadStream *data) :
} else { } else {
loadBinary(data); loadBinary(data);
} }
setupOverworldLights();
} }
Set::Set() : Set::Set() :
@ -59,6 +60,7 @@ Set::Set() :
_maxVolume(0), _numCmaps(0), _numShadows(0), _currSetup(nullptr), _maxVolume(0), _numCmaps(0), _numShadows(0), _currSetup(nullptr),
_setups(nullptr), _lights(nullptr), _sectors(nullptr), _shadows(nullptr) { _setups(nullptr), _lights(nullptr), _sectors(nullptr), _shadows(nullptr) {
setupOverworldLights();
} }
Set::~Set() { Set::~Set() {
@ -82,6 +84,33 @@ Set::~Set() {
} }
delete[] _shadows; delete[] _shadows;
} }
foreach (Light *l, _overworldLightsList) {
delete l;
}
}
void Set::setupOverworldLights() {
Light *l;
l = new Light();
l->_name = "Overworld Light 1";
l->_enabled = true;
l->_type = Light::Ambient;
l->_pos = Math::Vector3d(0, 0, 0);
l->_dir = Math::Vector3d(0, 0, 0);
l->_color = Color(255, 255, 255);
l->_intensity = 0.5f;
_overworldLightsList.push_back(l);
l = new Light();
l->_name = "Overworld Light 2";
l->_enabled = true;
l->_type = Light::Direct;
l->_pos = Math::Vector3d(0, 0, 0);
l->_dir = Math::Vector3d(0, 0, -1);
l->_color = Color(255, 255, 255);
l->_intensity = 0.6f;
_overworldLightsList.push_back(l);
} }
void Set::loadText(TextSplitter &ts) { void Set::loadText(TextSplitter &ts) {
@ -675,7 +704,7 @@ void SetShadow::loadBinary(Common::SeekableReadStream *data, Set *set) {
_shadowPoint = Math::Vector3d::getVector3d(v); _shadowPoint = Math::Vector3d::getVector3d(v);
if (lightNameLen > 0) { if (lightNameLen > 0) {
for (Common::List<Light *>::const_iterator it = set->getLights().begin(); it != set->getLights().end(); ++it) { for (Common::List<Light *>::const_iterator it = set->getLights(false).begin(); it != set->getLights(false).end(); ++it) {
if ((*it)->_name.equals(lightName)) { if ((*it)->_name.equals(lightName)) {
_shadowPoint = (*it)->_pos; _shadowPoint = (*it)->_pos;
break; break;
@ -758,7 +787,7 @@ public:
Math::Vector3d _pos; Math::Vector3d _pos;
}; };
void Set::setupLights(const Math::Vector3d &pos) { void Set::setupLights(const Math::Vector3d &pos, bool inOverworld) {
if (g_grim->getGameType() == GType_MONKEY4 && !g_driver->supportsShaders()) { if (g_grim->getGameType() == GType_MONKEY4 && !g_driver->supportsShaders()) {
// If shaders are not available, we do lighting in software for EMI. // If shaders are not available, we do lighting in software for EMI.
g_driver->disableLights(); g_driver->disableLights();
@ -772,10 +801,11 @@ void Set::setupLights(const Math::Vector3d &pos) {
// Sort the ligths from the nearest to the farthest to the pos. // Sort the ligths from the nearest to the farthest to the pos.
Sorter sorter(pos); Sorter sorter(pos);
Common::sort(_lightsList.begin(), _lightsList.end(), sorter); Common::List<Light *>* lightsList = inOverworld ? &_overworldLightsList : &_lightsList;
Common::sort(lightsList->begin(), lightsList->end(), sorter);
int count = 0; int count = 0;
foreach (Light *l, _lightsList) { foreach (Light *l, *lightsList) {
if (l->_enabled) { if (l->_enabled) {
g_driver->setupLight(l, count); g_driver->setupLight(l, count);
++count; ++count;

View File

@ -51,6 +51,7 @@ public:
void loadText(TextSplitter &ts); void loadText(TextSplitter &ts);
void loadBinary(Common::SeekableReadStream *data); void loadBinary(Common::SeekableReadStream *data);
void setupOverworldLights();
void saveState(SaveGame *savedState) const; void saveState(SaveGame *savedState) const;
bool restoreState(SaveGame *savedState); bool restoreState(SaveGame *savedState);
@ -63,7 +64,7 @@ public:
void drawBitmaps(ObjectState::Position stage); void drawBitmaps(ObjectState::Position stage);
void setupCamera(); void setupCamera();
void setupLights(const Math::Vector3d &pos); void setupLights(const Math::Vector3d &pos, bool inOverworld);
void setSoundPosition(const char *soundName, const Math::Vector3d &pos); void setSoundPosition(const char *soundName, const Math::Vector3d &pos);
void setSoundPosition(const char *soundName, const Math::Vector3d &pos, int minVol, int maxVol); void setSoundPosition(const char *soundName, const Math::Vector3d &pos, int minVol, int maxVol);
@ -143,7 +144,7 @@ public:
}; };
Setup *getCurrSetup() { return _currSetup; } Setup *getCurrSetup() { return _currSetup; }
const Common::List<Light *> &getLights() { return _lightsList; } const Common::List<Light *> &getLights(bool inOverworld) { return (inOverworld ? _overworldLightsList : _lightsList); }
const Math::Frustum &getFrustum() { return _frustum; } const Math::Frustum &getFrustum() { return _frustum; }
int getShadowCount() const { return _numShadows; } int getShadowCount() const { return _numShadows; }
@ -160,6 +161,7 @@ private:
Sector **_sectors; Sector **_sectors;
Light *_lights; Light *_lights;
Common::List<Light *> _lightsList; Common::List<Light *> _lightsList;
Common::List<Light *> _overworldLightsList;
Setup *_setups; Setup *_setups;
SetShadow *_shadows; SetShadow *_shadows;

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#ifndef ENGINES_METAENGINE_H #ifndef ENGINES_METAENGINE_H

View File

@ -81,14 +81,19 @@ void BaseRenderer::computeScreenViewport() {
int32 screenWidth = _system->getWidth(); int32 screenWidth = _system->getWidth();
int32 screenHeight = _system->getHeight(); int32 screenHeight = _system->getHeight();
// Aspect ratio correction if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight); // Aspect ratio correction
int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth); int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
_screenViewport = Common::Rect(viewportWidth, viewportHeight); int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
_screenViewport = Common::Rect(viewportWidth, viewportHeight);
// Pillarboxing // Pillarboxing
_screenViewport.translate((screenWidth - viewportWidth) / 2, _screenViewport.translate((screenWidth - viewportWidth) / 2,
(screenHeight - viewportHeight) / 2); (screenHeight - viewportHeight) / 2);
} else {
// Aspect ratio correction disabled, just stretch
_screenViewport = Common::Rect(screenWidth, screenHeight);
}
} }
Common::Point BaseRenderer::frameCenter() const { Common::Point BaseRenderer::frameCenter() const {

View File

@ -378,7 +378,7 @@ Graphics::Surface *OpenGLRenderer::getScreenshot() {
void OpenGLRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { void OpenGLRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) {
// Screen coords to 3D coords // Screen coords to 3D coords
Math::Vector3d obj; Math::Vector3d obj;
Math::gluMathUnProject<double, int>(Math::Vector3d(screen.x, _system->getHeight() - screen.y, 0.9), Math::gluMathUnProject<double, int>(Math::Vector3d(screen.x, _system->getHeight() - screen.y, 0.9f),
_cubeModelViewMatrix, _cubeProjectionMatrix, _cubeViewport, obj); _cubeModelViewMatrix, _cubeProjectionMatrix, _cubeViewport, obj);
// 3D coords to polar coords // 3D coords to polar coords

View File

@ -328,7 +328,7 @@ Graphics::Surface *TinyGLRenderer::getScreenshot() {
void TinyGLRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { void TinyGLRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) {
// Screen coords to 3D coords // Screen coords to 3D coords
Math::Vector3d obj; Math::Vector3d obj;
Math::gluMathUnProject<float, int>(Math::Vector3d(screen.x, kOriginalHeight - screen.y, 0.9), Math::gluMathUnProject<float, int>(Math::Vector3d(screen.x, kOriginalHeight - screen.y, 0.9f),
_cubeModelViewMatrix, _cubeProjectionMatrix, _cubeViewport, obj); _cubeModelViewMatrix, _cubeProjectionMatrix, _cubeViewport, obj);
// 3D coords to polar coords // 3D coords to polar coords

View File

@ -135,9 +135,13 @@ Myst3Engine::~Myst3Engine() {
} }
bool Myst3Engine::hasFeature(EngineFeature f) const { bool Myst3Engine::hasFeature(EngineFeature f) const {
// The TinyGL renderer does not support arbitrary resolutions for now
bool softRenderer = ConfMan.getBool("soft_renderer");
return return
(f == kSupportsRTL) || (f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime); (f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsArbitraryResolutions && !softRenderer);
} }
Common::Error Myst3Engine::run() { Common::Error Myst3Engine::run() {

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/ */
#ifndef ENGINES_UTIL_H #ifndef ENGINES_UTIL_H

View File

@ -105,7 +105,7 @@ VectorRenderer *createRenderer(int mode);
*/ */
class VectorRenderer { class VectorRenderer {
public: public:
VectorRenderer() : _activeSurface(NULL), _fillMode(kFillDisabled), _shadowOffset(0), _shadowFillMode(kShadowExponential), VectorRenderer() : _activeSurface(NULL), _fillMode(kFillDisabled), _shadowOffset(0), _shadowFillMode(kShadowExponential),
_disableShadows(false), _strokeWidth(1), _gradientFactor(1) { _disableShadows(false), _strokeWidth(1), _gradientFactor(1) {
} }

View File

@ -1134,7 +1134,7 @@ void VectorRendererSpec<PixelType>::
drawTabShadow(int x1, int y1, int w, int h, int r) { drawTabShadow(int x1, int y1, int w, int h, int r) {
int offset = 3; int offset = 3;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3; uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
@ -1162,7 +1162,7 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
// this is ok on filled circles, but when blending on surfaces, // this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful. // we cannot let it blend twice. awful.
uint32 hb = 0; uint32 hb = 0;
while (x++ < y) { while (x++ < y) {
BE_ALGORITHM(); BE_ALGORITHM();
@ -1176,7 +1176,7 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
hb |= (1 << y); hb |= (1 << y);
} }
} }
ptr_fill += pitch * r; ptr_fill += pitch * r;
while (short_h--) { while (short_h--) {
blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha); blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha);
@ -1189,7 +1189,7 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
alpha = (alpha * (expFactor << 8)) >> 9; alpha = (alpha * (expFactor << 8)) >> 9;
} }
} }
/** BEVELED TABS FOR CLASSIC THEME **/ /** BEVELED TABS FOR CLASSIC THEME **/
template<typename PixelType> template<typename PixelType>
void VectorRendererSpec<PixelType>:: void VectorRendererSpec<PixelType>::
@ -1647,7 +1647,7 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
BE_RESET(); BE_RESET();
r--; r--;
int alphaStep_tr = ((alpha_t - alpha_r)/(y+1)); int alphaStep_tr = ((alpha_t - alpha_r)/(y+1));
int alphaStep_br = ((alpha_r - alpha_b)/(y+1)); int alphaStep_br = ((alpha_r - alpha_b)/(y+1));
int alphaStep_bl = ((alpha_b - alpha_l)/(y+1)); int alphaStep_bl = ((alpha_b - alpha_l)/(y+1));
@ -1657,16 +1657,16 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
while (x++ < (y - 2)) { while (x++ < (y - 2)) {
BE_ALGORITHM(); BE_ALGORITHM();
BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x))); BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x))); BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x))); BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)));
BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x))); BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)));
BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x))); BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x))); BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x))); BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)));
BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x))); BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)));
if (Base::_strokeWidth > 1) { if (Base::_strokeWidth > 1) {
BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py); BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py);
BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py); BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py);
@ -1754,7 +1754,7 @@ void VectorRendererSpec<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0; const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127; const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255; const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63; const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255; const uint8 bevelAlpha_t = 255;
@ -1876,7 +1876,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3; uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
// These constants ensure a border of 2px on the left and of each rounded square // These constants ensure a border of 2px on the left and of each rounded square
int xstart = (x1 > 2) ? x1 - 2 : x1; int xstart = (x1 > 2) ? x1 - 2 : x1;
int ystart = y1; int ystart = y1;
@ -1886,7 +1886,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
for (int i = offset; i >= 0; i--) { for (int i = offset; i >= 0; i--) {
int f, ddF_x, ddF_y; int f, ddF_x, ddF_y;
int x, y, px, py; int x, y, px, py;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r); PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r);
@ -1903,14 +1903,14 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
// this is ok on filled circles, but when blending on surfaces, // this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful. // we cannot let it blend twice. awful.
uint32 hb = 0; uint32 hb = 0;
while (x++ < y) { while (x++ < y) {
BE_ALGORITHM(); BE_ALGORITHM();
if (((1 << x) & hb) == 0) { if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha); blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
// Will create a dark line of pixles if left out // Will create a dark line of pixles if left out
if (hb > 0) { if (hb > 0) {
blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha); blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha);
@ -1924,7 +1924,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
hb |= (1 << y); hb |= (1 << y);
} }
} }
ptr_fill += pitch * r; ptr_fill += pitch * r;
while (short_h--) { while (short_h--) {
blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha); blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha);
@ -1936,7 +1936,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
ystart += 1; ystart += 1;
width -= 2; width -= 2;
height -= 2; height -= 2;
if (_shadowFillMode == kShadowExponential) if (_shadowFillMode == kShadowExponential)
// Multiply with expfactor // Multiply with expfactor
alpha = (alpha * (expFactor << 8)) >> 9; alpha = (alpha * (expFactor << 8)) >> 9;
@ -2178,14 +2178,14 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
// only when the inside isn't filled // only when the inside isn't filled
if (sw != strokeWidth || fill_m != Base::kFillDisabled) if (sw != strokeWidth || fill_m != Base::kFillDisabled)
a2 = 255; a2 = 255;
// inner arc // inner arc
WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a2) >> 16)); WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a2) >> 16));
@ -2196,8 +2196,8 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a1) >> 16)); WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a1) >> 16));
@ -2220,7 +2220,7 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
int x, y; int x, y;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py; int px, py;
uint32 rsq = r*r; uint32 rsq = r*r;
frac_t T = 0, oldT; frac_t T = 0, oldT;
uint8 a1, a2; uint8 a1, a2;
@ -2318,14 +2318,14 @@ void VectorRendererAA<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0; const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127; const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255; const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63; const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255; const uint8 bevelAlpha_t = 255;
const uint8 bevelAlpha_r = 31; const uint8 bevelAlpha_r = 31;
const uint8 bevelAlpha_b = 0; const uint8 bevelAlpha_b = 0;
const uint8 bevelAlpha_l = 127; const uint8 bevelAlpha_l = 127;
if (Base::_strokeWidth) { if (Base::_strokeWidth) {
if (r != 0 && Base::_bevel > 0) { if (r != 0 && Base::_bevel > 0) {
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l); drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
@ -2334,7 +2334,7 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255); drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
} }
} }
// If only border is visible // If only border is visible
if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) { if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
if (fill_m == Base::kFillBackground) if (fill_m == Base::kFillBackground)

View File

@ -301,7 +301,7 @@ protected:
virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m); virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m);
virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_l, uint8 alpha_r, uint8 alpha_b); virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_l, uint8 alpha_r, uint8 alpha_b);
virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m); virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m);
virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset) { virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset) {

View File

@ -27,13 +27,15 @@
#include "graphics/opengles2/system_headers.h" #include "graphics/opengles2/system_headers.h"
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS) #ifdef USE_OPENGL
namespace Graphics { namespace Graphics {
static Common::List<Common::String> g_extensions; static Common::List<Common::String> g_extensions;
void initExtensions() { void initExtensions() {
g_extensions.clear();
const char *exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); const char *exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
Common::StringTokenizer tokenizer(exts, " "); Common::StringTokenizer tokenizer(exts, " ");
while (!tokenizer.empty()) { while (!tokenizer.empty()) {

View File

@ -22,9 +22,24 @@
#include "common/textconsole.h" #include "common/textconsole.h"
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS) #if defined(USE_OPENGL) && !defined(AMIGAOS)
#ifdef USE_OPENGL_SHADERS
#include "graphics/opengles2/framebuffer.h" #include "graphics/opengles2/framebuffer.h"
#elif defined(SDL_BACKEND)
#define GL_GLEXT_PROTOTYPES // For the GL_EXT_framebuffer_object extension
#include "graphics/opengles2/framebuffer.h"
#define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#define GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
#define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
#define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
#define GL_RENDERBUFFER GL_RENDERBUFFER_EXT
#define GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
#define GL_STENCIL_INDEX8 GL_STENCIL_INDEX8_EXT
#define GL_DEPTH24_STENCIL8 0x88F0
#include "backends/platform/sdl/sdl-sys.h"
#endif // defined(SDL_BACKEND)
#include "graphics/opengles2/extensions.h" #include "graphics/opengles2/extensions.h"
#ifdef USE_GLES2 #ifdef USE_GLES2
@ -33,33 +48,130 @@
namespace Graphics { namespace Graphics {
#if defined(SDL_BACKEND) && !defined(USE_OPENGL_SHADERS)
static bool framebuffer_object_functions = false;
static PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebuffer;
static PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbuffer;
static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
static PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffers;
static PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffers;
static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbuffer;
static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2D;
static PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffers;
static PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffers;
static PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorage;
static void grabFramebufferObjectPointers() {
if (framebuffer_object_functions)
return;
framebuffer_object_functions = true;
union {
void *obj_ptr;
void (APIENTRY *func_ptr)();
} u;
// We're casting from an object pointer to a function pointer, the
// sizes need to be the same for this to work.
assert(sizeof(u.obj_ptr) == sizeof(u.func_ptr));
u.obj_ptr = SDL_GL_GetProcAddress("glBindFramebuffer");
glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glBindRenderbuffer");
glBindRenderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glCheckFramebufferStatus");
glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glDeleteFramebuffers");
glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glDeleteRenderbuffers");
glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glFramebufferRenderbuffer");
glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glFramebufferTexture2D");
glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glGenFramebuffers");
glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glGenRenderbuffers");
glGenRenderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)u.func_ptr;
u.obj_ptr = SDL_GL_GetProcAddress("glRenderbufferStorage");
glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)u.func_ptr;
}
#endif // defined(SDL_BACKEND) && !defined(USE_OPENGL_SHADERS)
template<class T>
static T nextHigher2(T k) {
if (k == 0)
return 1;
--k;
for (uint i = 1; i < sizeof(T) * 8; i <<= 1)
k = k | k >> i;
return k + 1;
}
static bool usePackedBuffer() { static bool usePackedBuffer() {
#ifdef USE_GLES2 #ifdef USE_GLES2
return Graphics::isExtensionSupported("GL_OES_packed_depth_stencil"); return Graphics::isExtensionSupported("GL_OES_packed_depth_stencil");
#endif
#ifndef USE_OPENGL_SHADERS
return Graphics::isExtensionSupported("GL_EXT_packed_depth_stencil");
#endif #endif
return true; return true;
} }
FrameBuffer::FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height) : _colorTexture(texture_name), _width(width), _height(height) { FrameBuffer::FrameBuffer(uint width, uint height) :
_managedTexture(true), _width(width), _height(height),
_texWidth(nextHigher2(width)), _texHeight(nextHigher2(height)) {
#if defined(SDL_BACKEND) && !defined(USE_OPENGL_SHADERS)
if (!Graphics::isExtensionSupported("GL_EXT_framebuffer_object")) {
error("GL_EXT_framebuffer_object extension is not supported!");
}
grabFramebufferObjectPointers();
#endif
glGenTextures(1, &_colorTexture);
glBindTexture(GL_TEXTURE_2D, _colorTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _texWidth, _texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
init();
}
FrameBuffer::FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height) :
_managedTexture(false), _colorTexture(texture_name), _width(width), _height(height),
_texWidth(texture_width), _texHeight(texture_height) {
init();
}
FrameBuffer::~FrameBuffer() {
glDeleteRenderbuffers(2, &_renderBuffers[0]);
glDeleteFramebuffers(1, &_frameBuffer);
if (_managedTexture)
glDeleteTextures(1, &_colorTexture);
}
void FrameBuffer::init() {
glGenFramebuffers(1, &_frameBuffer); glGenFramebuffers(1, &_frameBuffer);
glGenRenderbuffers(2, &_renderBuffers[0]); glGenRenderbuffers(2, &_renderBuffers[0]);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_name, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorTexture, 0);
if (usePackedBuffer()) { if (usePackedBuffer()) {
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]); glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, texture_width, texture_height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _texWidth, _texHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} else { } else {
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]); glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture_width, texture_height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _texWidth, _texHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[1]); glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[1]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, texture_width, texture_height); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, _texWidth, _texHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[1]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[1]);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
@ -73,11 +185,6 @@ FrameBuffer::FrameBuffer(GLuint texture_name, uint width, uint height, uint text
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
FrameBuffer::~FrameBuffer() {
glDeleteRenderbuffers(2, &_renderBuffers[0]);
glDeleteFramebuffers(1, &_frameBuffer);
}
void FrameBuffer::attach() { void FrameBuffer::attach() {
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
glViewport(0,0, _width, _height); glViewport(0,0, _width, _height);

View File

@ -29,19 +29,34 @@ namespace Graphics {
class FrameBuffer { class FrameBuffer {
public: public:
FrameBuffer(uint width, uint height);
FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height); FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height);
#ifdef AMIGAOS
~FrameBuffer() {}
void attach() {}
void detach() {}
#else
~FrameBuffer(); ~FrameBuffer();
void attach(); void attach();
void detach(); void detach();
#endif
GLuint getColorTextureName() const { return _colorTexture; } GLuint getColorTextureName() const { return _colorTexture; }
uint getWidth() const { return _width; }
uint getHeight() const { return _height; }
uint getTexWidth() const { return _texWidth; }
uint getTexHeight() const { return _texHeight; }
private: private:
void init();
bool _managedTexture;
GLuint _colorTexture; GLuint _colorTexture;
GLuint _renderBuffers[2]; GLuint _renderBuffers[2];
GLuint _frameBuffer; GLuint _frameBuffer;
uint _width, _height; uint _width, _height;
uint _texWidth, _texHeight;
}; };
} }

View File

@ -228,7 +228,7 @@ public:
* @param srcSurface The source of the bitmap data * @param srcSurface The source of the bitmap data
* @param destX The x coordinate of the destination rectangle * @param destX The x coordinate of the destination rectangle
* @param destY The y coordinate of the destination rectangle * @param destY The y coordinate of the destination rectangle
* @param subRect The subRect of surface to be blitted * @param subRect The subRect of surface to be blitted
*/ */
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect); void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect);

View File

@ -109,7 +109,7 @@ void tglColor3f(float x, float y, float z) {
tglColor4f(x, y, z, 1); tglColor4f(x, y, z, 1);
} }
void glColor3fv(float *v) { void tglColor3fv(float *v) {
tglColor4f(v[0], v[1], v[2], 1); tglColor4f(v[0], v[1], v[2], 1);
} }

View File

@ -216,7 +216,7 @@ void glopTexEnv(GLContext *, GLParam *p) {
if (target != TGL_TEXTURE_ENV) { if (target != TGL_TEXTURE_ENV) {
error: error:
error("glTexParameter: unsupported option"); error("tglTexParameter: unsupported option");
} }
if (pname != TGL_TEXTURE_ENV_MODE) if (pname != TGL_TEXTURE_ENV_MODE)
@ -234,7 +234,7 @@ void glopTexParameter(GLContext *, GLParam *p) {
if (target != TGL_TEXTURE_2D) { if (target != TGL_TEXTURE_2D) {
error: error:
error("glTexParameter: unsupported option"); error("tglTexParameter: unsupported option");
} }
switch (pname) { switch (pname) {
@ -253,7 +253,7 @@ void glopPixelStore(GLContext *, GLParam *p) {
int param = p[2].i; int param = p[2].i;
if (pname != TGL_UNPACK_ALIGNMENT || param != 1) { if (pname != TGL_UNPACK_ALIGNMENT || param != 1) {
error("glPixelStore: unsupported option"); error("tglPixelStore: unsupported option");
} }
} }

View File

@ -48,7 +48,7 @@ const int32 kDefaultHotspotX = 0;
const int32 kDefaultHotspotY = 0; const int32 kDefaultHotspotY = 0;
const int32 kDefaultOffsetX = 0; const int32 kDefaultOffsetX = 0;
const int32 kDefaultOffsetY = 0; const int32 kDefaultOffsetY = 0;
const int32 kDefaultAngle = 0; const int32 kDefaultAngle = 0;
struct TransformStruct { struct TransformStruct {
private: private:

View File

@ -28,7 +28,7 @@
namespace Graphics { namespace Graphics {
static const float kEpsilon = 0.00001; // arbitrarily taken number static const float kEpsilon = 0.00001f; // arbitrarily taken number
struct FloatPoint { struct FloatPoint {
float x; float x;

View File

@ -241,7 +241,7 @@ void AboutDialog::drawDialog() {
while (*str && *str == ' ') while (*str && *str == ' ')
str++; str++;
if (*str) if (*str)
g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleBold, ThemeEngine::kFontColorNormal, true, _textDrawableArea); g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleBold, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
y += _lineHeight; y += _lineHeight;
} }

View File

@ -61,7 +61,8 @@ enum {
kChooseExtraDirCmd = 'chex', kChooseExtraDirCmd = 'chex',
kExtraPathClearCmd = 'clex', kExtraPathClearCmd = 'clex',
kChoosePluginsDirCmd = 'chpl', kChoosePluginsDirCmd = 'chpl',
kChooseThemeCmd = 'chtf' kChooseThemeCmd = 'chtf',
kFullscreenToggled = 'oful' // ResidualVM specific
}; };
enum { enum {
@ -209,15 +210,12 @@ void OptionsDialog::open() {
#ifdef SMALL_SCREEN_DEVICE #ifdef SMALL_SCREEN_DEVICE
_fullscreenCheckbox->setState(true); _fullscreenCheckbox->setState(true);
_fullscreenCheckbox->setEnabled(false); _fullscreenCheckbox->setEnabled(false);
#if 0 // ResidualVM specific
_aspectCheckbox->setState(false); _aspectCheckbox->setState(false);
_aspectCheckbox->setEnabled(false); _aspectCheckbox->setEnabled(false);
#endif
#else // !SMALL_SCREEN_DEVICE #else // !SMALL_SCREEN_DEVICE
// Fullscreen setting // Fullscreen setting
_fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain)); _fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain));
#if 0 // ResidualVM specific
// Aspect ratio setting // Aspect ratio setting
if (_guioptions.contains(GUIO_NOASPECT)) { if (_guioptions.contains(GUIO_NOASPECT)) {
_aspectCheckbox->setState(false); _aspectCheckbox->setState(false);
@ -226,12 +224,13 @@ void OptionsDialog::open() {
_aspectCheckbox->setEnabled(true); _aspectCheckbox->setEnabled(true);
_aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain)); _aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain));
} }
#endif
#endif // SMALL_SCREEN_DEVICE #endif // SMALL_SCREEN_DEVICE
// Software rendering setting - ResidualVM specific lines // Software rendering setting - ResidualVM specific lines
_softwareRenderingCheckbox->setEnabled(true); _softwareRenderingCheckbox->setEnabled(true);
_softwareRenderingCheckbox->setState(ConfMan.getBool("soft_renderer", _domain)); _softwareRenderingCheckbox->setState(ConfMan.getBool("soft_renderer", _domain));
} else {
_aspectCheckbox->setState(false);
} }
// Audio options // Audio options
@ -335,13 +334,11 @@ void OptionsDialog::close() {
if (_enableGraphicSettings) { if (_enableGraphicSettings) {
if (ConfMan.getBool("fullscreen", _domain) != _fullscreenCheckbox->getState()) if (ConfMan.getBool("fullscreen", _domain) != _fullscreenCheckbox->getState())
graphicsModeChanged = true; graphicsModeChanged = true;
#if 0 // ResidualVM specific
if (ConfMan.getBool("aspect_ratio", _domain) != _aspectCheckbox->getState()) if (ConfMan.getBool("aspect_ratio", _domain) != _aspectCheckbox->getState())
graphicsModeChanged = true; graphicsModeChanged = true;
#endif
ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain); ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain);
#if 0 // ResidualVM specific
ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain); ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
#if 0 // ResidualVM specific
bool isSet = false; bool isSet = false;
@ -370,8 +367,8 @@ void OptionsDialog::close() {
ConfMan.setBool("soft_renderer", _softwareRenderingCheckbox->getState(), _domain); ConfMan.setBool("soft_renderer", _softwareRenderingCheckbox->getState(), _domain);
} else { } else {
ConfMan.removeKey("fullscreen", _domain); ConfMan.removeKey("fullscreen", _domain);
#if 0 // ResidualVM specific
ConfMan.removeKey("aspect_ratio", _domain); ConfMan.removeKey("aspect_ratio", _domain);
#if 0 // ResidualVM specific
ConfMan.removeKey("gfx_mode", _domain); ConfMan.removeKey("gfx_mode", _domain);
ConfMan.removeKey("render_mode", _domain); ConfMan.removeKey("render_mode", _domain);
#endif #endif
@ -602,6 +599,11 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
_soundFontClearButton->setEnabled(false); _soundFontClearButton->setEnabled(false);
draw(); draw();
break; break;
// ResidualVM specific
case kFullscreenToggled:
_aspectCheckbox->setEnabled(_fullscreenCheckbox->getState());
draw();
break;
case kOKCmd: case kOKCmd:
setResult(1); setResult(1);
close(); close();
@ -629,13 +631,11 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
#endif #endif
#ifndef SMALL_SCREEN_DEVICE #ifndef SMALL_SCREEN_DEVICE
_fullscreenCheckbox->setEnabled(enabled); _fullscreenCheckbox->setEnabled(enabled);
#if 0 // ResidualVM specific if (_guioptions.contains(GUIO_NOASPECT) || !_fullscreenCheckbox->getState())
if (_guioptions.contains(GUIO_NOASPECT))
_aspectCheckbox->setEnabled(false); _aspectCheckbox->setEnabled(false);
else else
_aspectCheckbox->setEnabled(enabled); _aspectCheckbox->setEnabled(enabled);
#endif #endif
#endif
// ResidualVM specific: // ResidualVM specific:
if (enabled) if (enabled)
_softwareRenderingCheckbox->setEnabled(true); _softwareRenderingCheckbox->setEnabled(true);
@ -789,12 +789,10 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
} }
#endif #endif
// Fullscreen checkbox // Fullscreen checkbox
_fullscreenCheckbox = new CheckboxWidget(boss, prefix + "grFullscreenCheckbox", _("Fullscreen mode")); _fullscreenCheckbox = new CheckboxWidget(boss, prefix + "grFullscreenCheckbox", _("Fullscreen mode"), 0, kFullscreenToggled);
#if 0 // ResidualVM specific // ResidualVM specific description
// Aspect ratio checkbox _aspectCheckbox = new CheckboxWidget(boss, prefix + "grAspectCheckbox", _("Preserve aspect ratio"), _("Preserve the aspect ratio in fullscreen mode"));
_aspectCheckbox = new CheckboxWidget(boss, prefix + "grAspectCheckbox", _("Aspect ratio correction"), _("Correct aspect ratio for 320x200 games"));
#endif
// ResidualVM specific option: // ResidualVM specific option:
_softwareRenderingCheckbox = new CheckboxWidget(boss, prefix + "grSoftwareRendering", _("Software Rendering"), _("Enable software rendering")); _softwareRenderingCheckbox = new CheckboxWidget(boss, prefix + "grSoftwareRendering", _("Software Rendering"), _("Enable software rendering"));
_enableGraphicSettings = true; _enableGraphicSettings = true;

Binary file not shown.

View File

@ -1172,9 +1172,9 @@
height = 'Globals.Line.Height' height = 'Globals.Line.Height'
/> />
<widget name = 'HelpText' <widget name = 'HelpText'
height = '220' height = '228'
/> />
<layout type = 'horizontal' padding = '0, 0, 16, 0'> <layout type = 'horizontal' padding = '0, 0, 8, 0'>
<widget name = 'Prev' <widget name = 'Prev'
type = 'Button' type = 'Button'
/> />

View File

@ -94,7 +94,7 @@ void EditTextWidget::drawWidget() {
// Draw the text // Draw the text
adjustOffset(); adjustOffset();
const Common::Rect &r = Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 8, _y + _h); const Common::Rect &r = Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 8, _y + _h);
setTextDrawableArea(r); setTextDrawableArea(r);

View File

@ -28,7 +28,7 @@
#include "common/array.h" #include "common/array.h"
namespace GUI { namespace GUI {
enum { enum {
kTabForwards = 1, kTabForwards = 1,
kTabBackwards = -1 kTabBackwards = -1

View File

@ -62,7 +62,7 @@ namespace Graphics {
struct Surface; struct Surface;
} }
namespace Image { namespace Image {
/** /**
* MPEG 1/2 video decoder. * MPEG 1/2 video decoder.

View File

@ -31,7 +31,7 @@ namespace Image {
IFFDecoder::IFFDecoder() { IFFDecoder::IFFDecoder() {
_surface = 0; _surface = 0;
_palette = 0; _palette = 0;
// these 2 properties are not reset by destroy(), so the default is set here. // these 2 properties are not reset by destroy(), so the default is set here.
_numRelevantPlanes = 8; _numRelevantPlanes = 8;
_pixelPacking = false; _pixelPacking = false;

View File

@ -48,7 +48,7 @@ public:
/** /**
* Load an image from the specified stream * Load an image from the specified stream
* *
* loadStream() should implicitly call destroy() to free the memory * loadStream() should implicitly call destroy() to free the memory
* of the last loadStream() call. * of the last loadStream() call.
* *

View File

@ -104,7 +104,7 @@ Quaternion& Quaternion::normalize() {
const float scale = sqrtf(square(x()) + square(y()) + square(z()) + square(w())); const float scale = sqrtf(square(x()) + square(y()) + square(z()) + square(w()));
// Already normalized if the scale is 1.0 // Already normalized if the scale is 1.0
if (scale != 1.0f) if (scale != 1.0f && scale != 0.0f)
set(x() / scale, y() / scale, z() / scale, w() / scale); set(x() / scale, y() / scale, z() / scale, w() / scale);
return *this; return *this;

View File

@ -13,6 +13,8 @@ install:
$(INSTALL) -c -m 644 "$(srcdir)/dists/residualvm.6" "$(DESTDIR)$(mandir)/man6/residualvm.6" $(INSTALL) -c -m 644 "$(srcdir)/dists/residualvm.6" "$(DESTDIR)$(mandir)/man6/residualvm.6"
$(INSTALL) -d "$(DESTDIR)$(datarootdir)/pixmaps/" $(INSTALL) -d "$(DESTDIR)$(datarootdir)/pixmaps/"
$(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.xpm" "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm" $(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.xpm" "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm"
$(INSTALL) -d "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/apps/"
$(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/apps/residualvm.svg"
$(INSTALL) -d "$(DESTDIR)$(docdir)" $(INSTALL) -d "$(DESTDIR)$(docdir)"
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) "$(DESTDIR)$(docdir)" $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) "$(DESTDIR)$(docdir)"
$(INSTALL) -d "$(DESTDIR)$(datadir)" $(INSTALL) -d "$(DESTDIR)$(datadir)"
@ -34,6 +36,8 @@ install-strip:
$(INSTALL) -c -m 644 "$(srcdir)/dists/residualvm.6" "$(DESTDIR)$(mandir)/man6/residualvm.6" $(INSTALL) -c -m 644 "$(srcdir)/dists/residualvm.6" "$(DESTDIR)$(mandir)/man6/residualvm.6"
$(INSTALL) -d "$(DESTDIR)$(datarootdir)/pixmaps/" $(INSTALL) -d "$(DESTDIR)$(datarootdir)/pixmaps/"
$(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.xpm" "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm" $(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.xpm" "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm"
$(INSTALL) -d "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/apps/"
$(INSTALL) -c -m 644 "$(srcdir)/icons/residualvm.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/apps/residualvm.svg"
$(INSTALL) -d "$(DESTDIR)$(docdir)" $(INSTALL) -d "$(DESTDIR)$(docdir)"
$(INSTALL) -c -m 644 $(DIST_FILES_DOCS) "$(DESTDIR)$(docdir)" $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) "$(DESTDIR)$(docdir)"
$(INSTALL) -d "$(DESTDIR)$(datadir)" $(INSTALL) -d "$(DESTDIR)$(datadir)"
@ -52,6 +56,7 @@ uninstall:
rm -f "$(DESTDIR)$(bindir)/$(EXECUTABLE)" rm -f "$(DESTDIR)$(bindir)/$(EXECUTABLE)"
rm -f "$(DESTDIR)$(mandir)/man6/residualvm.6" rm -f "$(DESTDIR)$(mandir)/man6/residualvm.6"
rm -f "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm" rm -f "$(DESTDIR)$(datarootdir)/pixmaps/residualvm.xpm"
rm -f "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/apps/residualvm.svg"
rm -rf "$(DESTDIR)$(docdir)" rm -rf "$(DESTDIR)$(docdir)"
rm -rf "$(DESTDIR)$(datadir)" rm -rf "$(DESTDIR)$(datadir)"
ifdef DYNAMIC_MODULES ifdef DYNAMIC_MODULES

View File

@ -149,7 +149,7 @@ bool AVIDecoder::parseNextChunk() {
skipChunk(size); skipChunk(size);
break; break;
case ID_IDX1: case ID_IDX1:
readOldIndex(size); readOldIndex(size);
break; break;
default: default:
error("Unknown tag \'%s\' found", tag2str(tag)); error("Unknown tag \'%s\' found", tag2str(tag));
@ -319,8 +319,25 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
return false; return false;
} }
// Seek back to the start of the MOVI list // Create the status entries
_fileStream->seek(_movieListStart); uint32 index = 0;
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
TrackStatus status;
status.track = *it;
status.index = index;
status.chunkSearchOffset = _movieListStart;
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
_videoTracks.push_back(status);
else
_audioTracks.push_back(status);
}
if (_videoTracks.size() != 1) {
warning("Unhandled AVI video track count: %d", _videoTracks.size());
close();
return false;
}
// Check if this is a special Duck Truemotion video // Check if this is a special Duck Truemotion video
checkTruemotion1(); checkTruemotion1();
@ -340,79 +357,138 @@ void AVIDecoder::close() {
_indexEntries.clear(); _indexEntries.clear();
memset(&_header, 0, sizeof(_header)); memset(&_header, 0, sizeof(_header));
_videoTracks.clear();
_audioTracks.clear();
} }
void AVIDecoder::readNextPacket() { void AVIDecoder::readNextPacket() {
if ((uint32)_fileStream->pos() >= _movieListEnd) { // Shouldn't get this unless called on a non-open video
// Ugh, reached the end premature. if (_videoTracks.empty())
forceVideoEnd(); return;
// Get the video frame first
handleNextPacket(_videoTracks[0]);
// Handle audio tracks next
for (uint32 i = 0; i < _audioTracks.size(); i++)
handleNextPacket(_audioTracks[i]);
}
void AVIDecoder::handleNextPacket(TrackStatus &status) {
// If there's no more to search, bail out
if (status.chunkSearchOffset + 8 >= _movieListEnd) {
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
// Horrible AVI video has a premature end
// Force the frame to be the last frame
debug(0, "Forcing end of AVI video");
((AVIVideoTrack *)status.track)->forceTrackEnd();
}
return; return;
} }
uint32 nextTag = _fileStream->readUint32BE(); // See if audio needs to be buffered and break out if not
uint32 size = _fileStream->readUint32LE(); if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status))
if (_fileStream->eos()) {
// Also premature end.
forceVideoEnd();
return; return;
}
if (nextTag == ID_LIST) { // Seek to where we shall start searching
// A list of audio/video chunks _fileStream->seek(status.chunkSearchOffset);
int32 startPos = _fileStream->pos();
if (_fileStream->readUint32BE() != ID_REC) for (;;) {
error("Expected 'rec ' LIST"); // If there's no more to search, bail out
if ((uint32)_fileStream->pos() + 8 >= _movieListEnd) {
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
// Horrible AVI video has a premature end
// Force the frame to be the last frame
debug(0, "Forcing end of AVI video");
((AVIVideoTrack *)status.track)->forceTrackEnd();
}
size -= 4; // subtract list type break;
}
// Decode chunks in the list uint32 nextTag = _fileStream->readUint32BE();
while (_fileStream->pos() < startPos + (int32)size) uint32 size = _fileStream->readUint32LE();
readNextPacket();
return; if (nextTag == ID_LIST) {
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { // A list of audio/video chunks
skipChunk(size); if (_fileStream->readUint32BE() != ID_REC)
return; error("Expected 'rec ' LIST");
}
Track *track = getTrack(getStreamIndex(nextTag)); continue;
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
skipChunk(size);
continue;
}
if (!track) // Only accept chunks for this stream
error("Cannot get track from tag '%s'", tag2str(nextTag)); uint32 streamIndex = getStreamIndex(nextTag);
if (streamIndex != status.index) {
skipChunk(size);
continue;
}
Common::SeekableReadStream *chunk = 0; Common::SeekableReadStream *chunk = 0;
if (size != 0) { if (size != 0) {
chunk = _fileStream->readStream(size); chunk = _fileStream->readStream(size);
_fileStream->skip(size & 1); _fileStream->skip(size & 1);
} }
if (track->getTrackType() == Track::kTrackTypeAudio) { if (status.track->getTrackType() == Track::kTrackTypeAudio) {
if (getStreamType(nextTag) != kStreamTypeAudio) if (getStreamType(nextTag) != kStreamTypeAudio)
error("Invalid audio track tag '%s'", tag2str(nextTag)); error("Invalid audio track tag '%s'", tag2str(nextTag));
assert(chunk); assert(chunk);
((AVIAudioTrack *)track)->queueSound(chunk); ((AVIAudioTrack *)status.track)->queueSound(chunk);
} else {
AVIVideoTrack *videoTrack = (AVIVideoTrack *)track;
if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Break out if we have enough audio
// Palette Change if (!shouldQueueAudio(status))
videoTrack->loadPaletteFromChunk(chunk); break;
} else { } else {
// Otherwise, assume it's a compressed frame AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track;
videoTrack->decodeFrame(chunk);
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
// Palette Change
videoTrack->loadPaletteFromChunk(chunk);
} else {
// Otherwise, assume it's a compressed frame
videoTrack->decodeFrame(chunk);
break;
}
} }
} }
// Start us off in this position next time
status.chunkSearchOffset = _fileStream->pos();
}
bool AVIDecoder::shouldQueueAudio(TrackStatus& status) {
// Sanity check:
if (status.track->getTrackType() != Track::kTrackTypeAudio)
return false;
// If video is done, make sure that the rest of the audio is queued
// (I guess this is also really a sanity check)
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
if (videoTrack->endOfTrack())
return true;
// Being three frames ahead should be enough for any video.
return ((AVIAudioTrack *)status.track)->getCurChunk() < (uint32)(videoTrack->getCurFrame() + 3);
} }
bool AVIDecoder::rewind() { bool AVIDecoder::rewind() {
if (!VideoDecoder::rewind()) if (!VideoDecoder::rewind())
return false; return false;
_fileStream->seek(_movieListStart); for (uint32 i = 0; i < _videoTracks.size(); i++)
_videoTracks[i].chunkSearchOffset = _movieListStart;
for (uint32 i = 0; i < _audioTracks.size(); i++)
_audioTracks[i].chunkSearchOffset = _movieListStart;
return true; return true;
} }
@ -421,29 +497,9 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
if (time > getDuration()) if (time > getDuration())
return false; return false;
// Track down our video track. // Get our video
// We only support seeking with one video track right now. AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
AVIVideoTrack *videoTrack = 0; uint32 videoIndex = _videoTracks[0].index;
int videoIndex = -1;
uint trackID = 0;
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, trackID++) {
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
if (videoTrack) {
// Already have one
// -> Not supported
return false;
}
videoTrack = (AVIVideoTrack *)*it;
videoIndex = trackID;
}
}
// Need a video track to go forwards
// If there isn't a video track, why would anyone be using AVI then?
if (!videoTrack)
return false;
// If we seek directly to the end, just mark the tracks as over // If we seek directly to the end, just mark the tracks as over
if (time == getDuration()) { if (time == getDuration()) {
@ -464,7 +520,6 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
int lastKeyFrame = -1; int lastKeyFrame = -1;
int frameIndex = -1; int frameIndex = -1;
int lastRecord = -1;
uint curFrame = 0; uint curFrame = 0;
// Go through and figure out where we should be // Go through and figure out where we should be
@ -472,40 +527,40 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
for (uint32 i = 0; i < _indexEntries.size(); i++) { for (uint32 i = 0; i < _indexEntries.size(); i++) {
const OldIndex &index = _indexEntries[i]; const OldIndex &index = _indexEntries[i];
if (index.id == ID_REC) { // We don't care about RECs
// Keep track of any records we find if (index.id == ID_REC)
lastRecord = i; continue;
// We're only looking at entries for this track
if (getStreamIndex(index.id) != videoIndex)
continue;
uint16 streamType = getStreamType(index.id);
if (streamType == kStreamTypePaletteChange) {
// We need to handle any palette change we see since there's no
// flag to tell if this is a "key" palette.
// Decode the palette
_fileStream->seek(_indexEntries[i].offset + 8);
Common::SeekableReadStream *chunk = 0;
if (_indexEntries[i].size != 0)
chunk = _fileStream->readStream(_indexEntries[i].size);
videoTrack->loadPaletteFromChunk(chunk);
} else { } else {
if (getStreamIndex(index.id) != videoIndex) // Check to see if this is a keyframe
continue; // The first frame has to be a keyframe
if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
lastKeyFrame = i;
uint16 streamType = getStreamType(index.id); // Did we find the target frame?
if (frame == curFrame) {
if (streamType == kStreamTypePaletteChange) { frameIndex = i;
// We need to handle any palette change we see since there's no break;
// flag to tell if this is a "key" palette.
// Decode the palette
_fileStream->seek(_indexEntries[i].offset + 8);
Common::SeekableReadStream *chunk = 0;
if (_indexEntries[i].size != 0)
chunk = _fileStream->readStream(_indexEntries[i].size);
videoTrack->loadPaletteFromChunk(chunk);
} else {
// Check to see if this is a keyframe
// The first frame has to be a keyframe
if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
lastKeyFrame = i;
// Did we find the target frame?
if (frame == curFrame) {
frameIndex = i;
break;
}
curFrame++;
} }
curFrame++;
} }
} }
@ -513,54 +568,36 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
return false; return false;
// Update all the audio tracks // Update all the audio tracks
uint audioIndex = 0; for (uint32 i = 0; i < _audioTracks.size(); i++) {
AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track;
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, audioIndex++) {
if ((*it)->getTrackType() != Track::kTrackTypeAudio)
continue;
AVIAudioTrack *audioTrack = (AVIAudioTrack *)*it;
// We need to find where the start of audio should be.
// Which is exactly 'initialFrames' audio chunks back from where
// our found frame is.
// Recreate the audio stream // Recreate the audio stream
audioTrack->resetStream(); audioTrack->resetStream();
uint framesNeeded = _header.initialFrames; // Set the chunk index for the track
uint startAudioChunk = 0; audioTrack->setCurChunk(frame);
int startAudioSearch = (lastRecord < 0) ? (frameIndex - 1) : (lastRecord - 1);
for (int i = startAudioSearch; i >= 0; i--) { uint32 chunksFound = 0;
if (getStreamIndex(_indexEntries[i].id) != audioIndex) for (uint32 j = 0; j < _indexEntries.size(); j++) {
const OldIndex &index = _indexEntries[j];
// Continue ignoring RECs
if (index.id == ID_REC)
continue; continue;
assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio); if (getStreamIndex(index.id) == _audioTracks[i].index) {
if (chunksFound == frame) {
_fileStream->seek(index.offset + 8);
Common::SeekableReadStream *audioChunk = _fileStream->readStream(index.size);
audioTrack->queueSound(audioChunk);
_audioTracks[i].chunkSearchOffset = (j == _indexEntries.size() - 1) ? _movieListEnd : _indexEntries[j + 1].offset;
break;
}
framesNeeded--; chunksFound++;
if (framesNeeded == 0) {
startAudioChunk = i;
break;
} }
} }
// Now go forward and queue them all
for (int i = startAudioChunk; i <= startAudioSearch; i++) {
if (_indexEntries[i].id == ID_REC)
continue;
if (getStreamIndex(_indexEntries[i].id) != audioIndex)
continue;
assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio);
_fileStream->seek(_indexEntries[i].offset + 8);
Common::SeekableReadStream *chunk = _fileStream->readStream(_indexEntries[i].size);
audioTrack->queueSound(chunk);
}
// Skip any audio to bring us to the right time // Skip any audio to bring us to the right time
audioTrack->skipAudio(time, videoTrack->getFrameTime(frame)); audioTrack->skipAudio(time, videoTrack->getFrameTime(frame));
} }
@ -589,15 +626,11 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
videoTrack->decodeFrame(chunk); videoTrack->decodeFrame(chunk);
} }
// Seek to the right spot // Set the video track's frame
// To the beginning of the last record, or frame if that doesn't exist
if (lastRecord >= 0)
_fileStream->seek(_indexEntries[lastRecord].offset);
else
_fileStream->seek(_indexEntries[frameIndex].offset);
videoTrack->setCurFrame((int)frame - 1); videoTrack->setCurFrame((int)frame - 1);
// Set the video track's search offset to the right spot
_videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset;
return true; return true;
} }
@ -620,7 +653,7 @@ void AVIDecoder::readOldIndex(uint32 size) {
OldIndex firstEntry; OldIndex firstEntry;
firstEntry.id = _fileStream->readUint32BE(); firstEntry.id = _fileStream->readUint32BE();
firstEntry.flags = _fileStream->readUint32LE(); firstEntry.flags = _fileStream->readUint32LE();
firstEntry.offset = _fileStream->readUint32LE(); firstEntry.offset = _fileStream->readUint32LE();
firstEntry.size = _fileStream->readUint32LE(); firstEntry.size = _fileStream->readUint32LE();
// Check if the offset is already absolute // Check if the offset is already absolute
@ -651,45 +684,22 @@ void AVIDecoder::readOldIndex(uint32 size) {
} }
} }
void AVIDecoder::forceVideoEnd() {
// Horrible AVI video has a premature end
// Force the frame to be the last frame
debug(0, "Forcing end of AVI video");
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
((AVIVideoTrack *)*it)->forceTrackEnd();
}
void AVIDecoder::checkTruemotion1() { void AVIDecoder::checkTruemotion1() {
AVIVideoTrack *track = 0; // If we got here from loadStream(), we know the track is valid
assert(!_videoTracks.empty());
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) { TrackStatus &status = _videoTracks[0];
if ((*it)->getTrackType() == Track::kTrackTypeVideo) { AVIVideoTrack *track = (AVIVideoTrack *)status.track;
if (track) {
// Multiple tracks; isn't going to be truemotion 1
return;
}
track = (AVIVideoTrack *)*it;
}
}
// No track found?
if (!track)
return;
// Ignore non-truemotion tracks // Ignore non-truemotion tracks
if (!track->isTruemotion1()) if (!track->isTruemotion1())
return; return;
// Search for a non-empty frame // Read the next video packet
const Graphics::Surface *frame = 0; handleNextPacket(status);
for (int i = 0; i < 10 && !frame; i++)
frame = decodeNextFrame();
const Graphics::Surface *frame = track->decodeNextFrame();
if (!frame) { if (!frame) {
// Probably shouldn't happen
rewind(); rewind();
return; return;
} }
@ -806,7 +816,7 @@ void AVIDecoder::AVIVideoTrack::forceTrackEnd() {
} }
AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType)
: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) { : _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType), _curChunk(0) {
_audStream = createAudioStream(); _audStream = createAudioStream();
} }
@ -833,12 +843,12 @@ void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
} else if (_wvInfo.tag == kWaveFormatDK3) { } else if (_wvInfo.tag == kWaveFormatDK3) {
_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
} else if (_wvInfo.tag == kWaveFormatMP3) {
warning("AVI: MP3 audio stream is not supported");
} }
} else { } else {
delete stream; delete stream;
} }
_curChunk++;
} }
void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) { void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) {
@ -859,6 +869,7 @@ void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Au
void AVIDecoder::AVIAudioTrack::resetStream() { void AVIDecoder::AVIAudioTrack::resetStream() {
delete _audStream; delete _audStream;
_audStream = createAudioStream(); _audStream = createAudioStream();
_curChunk = 0;
} }
bool AVIDecoder::AVIAudioTrack::rewind() { bool AVIDecoder::AVIAudioTrack::rewind() {
@ -871,12 +882,17 @@ Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const {
} }
Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() { Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() {
if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3 || _wvInfo.tag == kWaveFormatMP3) if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3)
return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2); return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
else if (_wvInfo.tag == kWaveFormatMP3)
warning("Unsupported AVI MP3 tracks");
else if (_wvInfo.tag != kWaveFormatNone) // No sound else if (_wvInfo.tag != kWaveFormatNone) // No sound
warning("Unsupported AVI audio format %d", _wvInfo.tag); warning("Unsupported AVI audio format %d", _wvInfo.tag);
return 0; return 0;
} }
AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
}
} // End of namespace Video } // End of namespace Video

View File

@ -215,7 +215,9 @@ protected:
virtual void queueSound(Common::SeekableReadStream *stream); virtual void queueSound(Common::SeekableReadStream *stream);
Audio::Mixer::SoundType getSoundType() const { return _soundType; } Audio::Mixer::SoundType getSoundType() const { return _soundType; }
void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime); void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime);
void resetStream(); virtual void resetStream();
uint32 getCurChunk() const { return _curChunk; }
void setCurChunk(uint32 chunk) { _curChunk = chunk; }
bool isRewindable() const { return true; } bool isRewindable() const { return true; }
bool rewind(); bool rewind();
@ -238,6 +240,15 @@ protected:
Audio::Mixer::SoundType _soundType; Audio::Mixer::SoundType _soundType;
Audio::QueuingAudioStream *_audStream; Audio::QueuingAudioStream *_audStream;
Audio::QueuingAudioStream *createAudioStream(); Audio::QueuingAudioStream *createAudioStream();
uint32 _curChunk;
};
struct TrackStatus {
TrackStatus();
Track *track;
uint32 index;
uint32 chunkSearchOffset;
}; };
AVIHeader _header; AVIHeader _header;
@ -260,9 +271,12 @@ protected:
void handleStreamHeader(uint32 size); void handleStreamHeader(uint32 size);
uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; } uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; }
byte getStreamIndex(uint32 tag) const; byte getStreamIndex(uint32 tag) const;
void forceVideoEnd();
void checkTruemotion1(); void checkTruemotion1();
void handleNextPacket(TrackStatus& status);
bool shouldQueueAudio(TrackStatus& status);
Common::Array<TrackStatus> _videoTracks, _audioTracks;
public: public:
virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo); virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo);
}; };