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
* A copy of the Escape from Monkey Monkey Island update EXE
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
---------- |---------------------------------------------------------
@ -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
some of them might make ResidualVM crash, or behave in weird ways.
Setting | Values | Effect
-------------- | ----------- | ---------------------------------------------------
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_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.
Setting | Values | Effect
-------------- | ----------------- | ---------------------------------------------------
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_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.
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

View File

@ -62,7 +62,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode() {
_bIsDirectory = true;
_sPath = "";
_pFileLock = 0;
_nProt = 0; // protection is ignored for the root volume
_nProt = 0; // Protection is ignored for the root volume
LEAVE();
}
@ -84,7 +84,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_bIsDirectory = 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);
if (pExd) {
_nProt = pExd->Protection;
@ -93,7 +93,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
_bIsValid = (_pFileLock != 0);
// Add a trailing slash if it is needed
// Add a trailing slash if needed
const char c = _sPath.lastChar();
if (c != '/' && c != ':')
_sPath += '/';
@ -134,7 +134,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
delete[] n;
}
_bIsValid = false;
_bIsValid = false;
_bIsDirectory = false;
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END);
@ -188,10 +188,10 @@ bool AmigaOSFilesystemNode::exists() const {
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.
// 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
// BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
@ -237,8 +237,8 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
ENTER();
bool ret = false;
//TODO: honor the hidden flag
// There is nothing like a hidden flag under AmigaOS...
// TODO: Honor the hidden flag
// There is no such thing as a hidden flag in AmigaOS...
if (!_bIsValid) {
debug(6, "Invalid node");
@ -252,7 +252,7 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
return false; // Empty list
}
if (_pFileLock == 0) {
if (isRootNode()) {
debug(6, "Root node");
LEAVE();
myList = listVolumes();
@ -264,7 +264,7 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE),
TAG_END);
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 ;
while ( (pExd = IDOS->ExamineDir(context)) ) {
@ -307,21 +307,33 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
ENTER();
if (_pFileLock == 0) {
if (isRootNode()) {
debug(6, "Root node");
LEAVE();
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;
BPTR parentDir = IDOS->ParentDir( _pFileLock );
BPTR parentDir = IDOS->ParentDir( pLock );
if (parentDir) {
node = new AmigaOSFilesystemNode(parentDir);
IDOS->UnLock(parentDir);
} else
node = new AmigaOSFilesystemNode();
if (!_bIsDirectory) {
IDOS->UnLock(pLock);
}
LEAVE();
return node;
@ -332,9 +344,9 @@ bool AmigaOSFilesystemNode::isReadable() const {
return false;
// Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is readable whatever the
// protection says
bool readable = !(_nProt & EXDF_OTR_READ) || _pFileLock == 0;
// Moreover, a pseudo root filesystem is readable whatever the
// protection says.
bool readable = !(_nProt & EXDF_OTR_READ) || isRootNode();
return readable;
}
@ -344,9 +356,9 @@ bool AmigaOSFilesystemNode::isWritable() const {
return false;
// Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is never writable whatever
// the protection says (because of the pseudo nature)
bool writable = !(_nProt & EXDF_OTR_WRITE) && _pFileLock !=0;
// Moreover, a pseudo root filesystem is never writable whatever
// the protection says (Because of it's pseudo nature).
bool writable = !(_nProt & EXDF_OTR_WRITE) && !isRootNode();
return writable;
}
@ -371,12 +383,13 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
if (dosList->dol_Type == DLT_VOLUME &&
dosList->dol_Name) {
// Original was
// dosList->dol_Name &&
// dosList->dol_Task) {
// The original line was
//if (dosList->dol_Type == DLT_VOLUME &&
//dosList->dol_Name &&
//dosList->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
// 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
IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN);
@ -410,7 +423,7 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
delete[] volName;
}
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
}
IDOS->UnLockDosList(kLockFlags);

View File

@ -62,6 +62,11 @@ protected:
*/
virtual AbstractFSList listVolumes() const;
/**
* True if this is the pseudo root filesystem.
*/
bool isRootNode() const { return _bIsValid && _bIsDirectory && _pFileLock == 0; }
public:
/**
* Creates an AmigaOSFilesystemNode with the root node as path.
@ -76,19 +81,19 @@ public:
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 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);
/**
* Copy constructor.
*
* @note Needed because it duplicates the file lock
* @note Needed because it duplicates the file lock.
*/
AmigaOSFilesystemNode(const AmigaOSFilesystemNode &node);

View File

@ -20,6 +20,8 @@
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_putenv
#include "common/scummsys.h"
#if defined(SDL_BACKEND)
@ -42,6 +44,10 @@
#include "graphics/pixelbuffer.h"
#include "gui/EventRecorder.h"
#ifdef USE_OPENGL
#include "graphics/opengles2/extensions.h"
#endif
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{0, 0, 0}
};
@ -50,18 +56,25 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
:
SdlGraphicsManager(sdlEventSource),
_screen(0),
_subScreen(0),
_overlayVisible(false),
_overlayscreen(0),
_overlayWidth(0), _overlayHeight(0),
_overlayDirty(true),
_screenChangeCount(0)
_screenChangeCount(0),
_lockAspectRatio(true),
_gameRect()
#ifdef USE_OPENGL
, _opengl(false), _overlayNumTex(0), _overlayTexIds(0)
, _frameBuffer(nullptr)
#endif
#ifdef USE_OPENGL_SHADERS
, _boxShader(nullptr), _boxVerticesVBO(0)
#endif
{
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
_desktopW = vi->current_w;
_desktopH = vi->current_h;
}
SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() {
@ -92,7 +105,8 @@ bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) {
return
(f == OSystem::kFeatureFullscreenMode) ||
#ifdef USE_OPENGL
(f == OSystem::kFeatureOpenGL);
(f == OSystem::kFeatureOpenGL) ||
(f == OSystem::kFeatureAspectRatioCorrection);
#else
false;
#endif
@ -103,6 +117,9 @@ void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
case OSystem::kFeatureFullscreenMode:
_fullscreen = enable;
break;
case OSystem::kFeatureAspectRatioCorrection:
_lockAspectRatio = enable;
break;
default:
break;
}
@ -112,6 +129,9 @@ bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
switch (f) {
case OSystem::kFeatureFullscreenMode:
return _fullscreen;
case OSystem::kFeatureAspectRatioCorrection:
return _lockAspectRatio;
break;
default:
return false;
}
@ -172,7 +192,61 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
#endif
_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
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 (ConfMan.hasKey("antialiasing"))
_antialiasing = ConfMan.getInt("antialiasing");
@ -195,6 +269,15 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
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)
sdlflags |= SDL_FULLSCREEN;
@ -281,9 +364,8 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::setupScreen(uint screenW, uint
#ifdef USE_OPENGL_SHADERS
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
debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION));
GLenum err = glewInit();
if (err != GLEW_OK) {
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);
#endif
Graphics::initExtensions();
}
#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,
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);
}
@ -472,6 +569,68 @@ void SurfaceSdlGraphicsManager::drawOverlayOpenGL() {
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
void SurfaceSdlGraphicsManager::drawOverlayOpenGLShaders() {
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
@ -527,6 +703,17 @@ void SurfaceSdlGraphicsManager::drawOverlay() {
void SurfaceSdlGraphicsManager::updateScreen() {
#ifdef USE_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 (_overlayDirty) {
updateOverlayTextures();
@ -538,10 +725,21 @@ void SurfaceSdlGraphicsManager::updateScreen() {
drawOverlayOpenGLShaders();
#endif
}
SDL_GL_SwapBuffers();
if (_frameBuffer) {
_frameBuffer->attach();
}
} else
#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) {
drawOverlay();
}
@ -567,12 +765,28 @@ void SurfaceSdlGraphicsManager::fillScreen(uint32 col) {
int16 SurfaceSdlGraphicsManager::getHeight() {
// 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() {
// 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) {
@ -749,6 +963,11 @@ void SurfaceSdlGraphicsManager::closeOverlay() {
_overlayNumTex = 0;
}
if (_frameBuffer) {
delete _frameBuffer;
_frameBuffer = nullptr;
}
#ifdef USE_OPENGL_SHADERS
glDeleteBuffers(1, &_boxVerticesVBO);
_boxVerticesVBO = 0;
@ -756,6 +975,9 @@ void SurfaceSdlGraphicsManager::closeOverlay() {
delete _boxShader;
_boxShader = nullptr;
#endif
} else if (_subScreen) {
SDL_FreeSurface(_subScreen);
_subScreen = nullptr;
}
#endif
}
@ -781,6 +1003,25 @@ bool SurfaceSdlGraphicsManager::lockMouse(bool lock) {
void SurfaceSdlGraphicsManager::warpMouse(int x, int y) {
//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);
}
@ -836,7 +1077,40 @@ void SurfaceSdlGraphicsManager::notifyVideoExpose() {
}
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) {

View File

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

View File

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

View File

@ -38,4 +38,4 @@ endif
cp $(srcdir)/NEWS ResidualVM/NEWS.txt
cp $(srcdir)/doc/QuickStart ResidualVM/QuickStart.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("vkeybdpath", PREFIX "/data");
ConfMan.registerDefault("fullscreen", true);
//ConfMan.registerDefault("aspect_ratio", true); //ResidualVM: not used
ConfMan.registerDefault("aspect_ratio", true);
// Create the savefile manager
if (_savefileManager == 0)

View File

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

View File

@ -26,6 +26,8 @@
#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_UNITY)
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "backends/taskbar/unity/unity-taskbar.h"
#include "common/textconsole.h"
@ -33,7 +35,12 @@
#include <unity.h>
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);

View File

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

View File

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

View File

@ -32,13 +32,19 @@
// though.
//
#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
#endif
#endif
//
// Replacement for the override keyword. This allows compilation of code
// 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
#endif
#endif

View File

@ -25,6 +25,8 @@
#include "common/scummsys.h"
#if __cplusplus < 201103L
namespace Common {
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;\
_FOREACH_CONTAINER_.brk > 0; --_FOREACH_CONTAINER_.brk)
#else
#define foreach(var, container) for (var : container)
#endif
#endif

View File

@ -148,7 +148,7 @@
#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
// 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.

View File

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

31
configure vendored
View File

@ -1297,7 +1297,7 @@ caanoo)
_host_cpu=arm
_host_alias=arm-none-linux-gnueabi
;;
dingux)
dingux | gcw0)
_host_os=linux
_host_cpu=mipsel
_host_alias=mipsel-linux
@ -2118,6 +2118,8 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
CXXFLAGS="$CXXFLAGS -mfpu=neon"
ABI="armeabi-v7a"
ANDROID_PLATFORM=4
ANDROID_PLATFORM_ARCH="arm"
;;
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 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)
DEFINES="$DEFINES -DGP2X"
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
LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs unity = 3.8.4 2>> "$TMPLOG"`"
LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags 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.1' 2>> "$TMPLOG"`"
_libunity=no
cat > $TMPC << EOF
#include <unity.h>
@ -3862,6 +3883,10 @@ EOF
esac
fi
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"
INCLUDES="$INCLUDES $LIBUNITY_CFLAGS"
fi

View File

@ -61,4 +61,5 @@ credits:
# $(srcdir)/devtools/credits.pl --text > $@
#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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "base/version.h"

View File

@ -17,6 +17,7 @@
* 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 GLOBAL_DIALOGS_H

View File

@ -17,6 +17,7 @@
* 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.
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_getcwd

View File

@ -17,6 +17,7 @@
* 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 ENGINES_ENGINE_H
@ -128,7 +129,15 @@ public:
* If this feature is supported, then the corresponding MetaEngine *must*
* 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),
_turnRateMultiplier(0.f), _talkAnim(0),
_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),
_collisionMode(CollisionOff), _collisionScale(1.f),
_lastTurnDir(0), _currTurnDir(0),
@ -184,6 +184,7 @@ void Actor::saveState(SaveGame *savedState) const {
}
savedState->writeBool(_turning);
savedState->writeBool(_singleTurning);
savedState->writeFloat(_moveYaw.getDegrees());
savedState->writeFloat(_movePitch.getDegrees());
savedState->writeFloat(_moveRoll.getDegrees());
@ -349,6 +350,9 @@ bool Actor::restoreState(SaveGame *savedState) {
}
_turning = savedState->readBool();
if (savedState->saveMinorVersion() > 25) {
_singleTurning = savedState->readBool();
}
_moveYaw = savedState->readFloat();
if (savedState->saveMinorVersion() > 6) {
_movePitch = savedState->readFloat();
@ -519,6 +523,13 @@ void Actor::setPos(const Math::Vector3d &position) {
if (_followBoxes) {
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) {
@ -573,6 +584,7 @@ bool Actor::singleTurnTo(const Math::Vector3d &pos) {
_moveYaw = _yaw;
_movePitch = _pitch;
_moveRoll = _roll;
_singleTurning = !done;
return done;
}
@ -749,6 +761,9 @@ bool Actor::isWalking() const {
}
bool Actor::isTurning() const {
if (g_grim->getGameType() == GType_MONKEY4)
if (_singleTurning)
return true;
if (_turning)
return true;
@ -795,6 +810,13 @@ void Actor::walkForward() {
if ((dist > 0 && dist > _walkRate / 5.f) || (dist < 0 && 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;
if (!_followBoxes) {
@ -1695,7 +1717,7 @@ void Actor::draw() {
// FIXME: if isAttached(), factor in the joint rotation as well.
const Math::Vector3d &absPos = getWorldPos();
if (!_costumeStack.empty()) {
g_grim->getCurrSet()->setupLights(absPos);
g_grim->getCurrSet()->setupLights(absPos, _inOverworld);
if (g_grim->getGameType() == GType_GRIM) {
Costume *costume = _costumeStack.back();
drawCostume(costume);

View File

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

View File

@ -334,6 +334,23 @@ static const GrimGameDescription gameDescriptions[] = {
},
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
{

View File

@ -35,6 +35,9 @@ public:
protected:
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);
static uint convertEmiVolumeToMixer(uint emiVolume);
static uint convertMixerVolumeToEmi(uint volume);
static const uint MAX_EMI_VOLUME = 100;
DECLARE_LUA_OPCODE(UndimAll);
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/lua/lua.h"
#include "engines/grim/actor.h"
#include "engines/grim/debug.h"
#include "engines/grim/grim.h"
#include "engines/grim/costume.h"
#include "engines/grim/set.h"
@ -712,6 +715,7 @@ void Lua_V2::GetActorChores() {
lua_pushobject(result);
}
// Helper function, not called from LUA directly
bool Lua_V2::findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) {
*costume = nullptr;
if (lua_isnil(costumeObj)) {
@ -970,7 +974,7 @@ void Lua_V2::AttachActor() {
}
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();
}
@ -986,7 +990,7 @@ void Lua_V2::DetachActor() {
if (!attached)
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();
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");
}
// Helper function, not called from LUA directly
void Lua_V2::setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore) {
if (lua_isnil(choreObj)) {
return;

View File

@ -37,6 +37,22 @@
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() {
lua_Object soundObj = lua_getparam(1);
@ -146,15 +162,14 @@ void Lua_V2::SetGroupVolume() {
return;
int group = (int)lua_getnumber(groupObj);
int volume = 100;
int volume = Audio::Mixer::kMaxChannelVolume;
if (lua_isnumber(volumeObj))
volume = (int)lua_getnumber(volumeObj);
volume = (volume * Audio::Mixer::kMaxMixerVolume) / 100;
volume = convertEmiVolumeToMixer((int)lua_getnumber(volumeObj));
switch (group) {
case 1: // SFX
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
break;
case 2: // Voice
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@ -185,6 +200,7 @@ void Lua_V2::EnableAudioGroup() {
switch (group) {
case 1: // SFX
g_system->getMixer()->muteSoundType(Audio::Mixer::kSFXSoundType, !state);
g_system->getMixer()->muteSoundType(Audio::Mixer::kPlainSoundType, !state);
break;
case 2: // Voice
g_system->getMixer()->muteSoundType(Audio::Mixer::kSpeechSoundType, !state);
@ -261,7 +277,11 @@ void Lua_V2::PlayLoadedSound() {
/*lua_Object bool2Obj =*/ lua_getparam(4);
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;
}
@ -273,7 +293,7 @@ void Lua_V2::PlayLoadedSound() {
return;
}
int volume = 100;
int volume = MAX_EMI_VOLUME;
if (!lua_isnumber(volumeObj)) {
// In the demo when the dart hits the balloon in the scumm bar, nil is passed
// to the volume parameter.
@ -281,7 +301,7 @@ void Lua_V2::PlayLoadedSound() {
} else {
volume = (int)lua_getnumber(volumeObj);
}
sound->setVolume(volume);
sound->setVolume(convertEmiVolumeToMixer(volume));
sound->play(looping);
}
@ -308,7 +328,7 @@ void Lua_V2::PlayLoadedSoundFrom() {
float y = lua_getnumber(yObj);
float z = lua_getnumber(zObj);
int volume = 100;
int volume = MAX_EMI_VOLUME;
bool looping = false;
if (lua_isnumber(volumeOrLoopingObj)) {
@ -329,7 +349,7 @@ void Lua_V2::PlayLoadedSoundFrom() {
return;
}
Math::Vector3d pos(x, y, z);
sound->setVolume(volume);
sound->setVolume(convertEmiVolumeToMixer(volume));
sound->playFrom(pos, looping);
}
@ -381,7 +401,7 @@ void Lua_V2::PlaySound() {
}
const char *str = lua_getstring(strObj);
int volume = 100;
int volume = MAX_EMI_VOLUME;
if (!lua_isnumber(volumeObj)) {
warning("Lua_V2::PlaySound - Unexpected parameter(s) found, using default volume for %s", str);
} else {
@ -390,7 +410,7 @@ void Lua_V2::PlaySound() {
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());
}
}
@ -404,7 +424,7 @@ void Lua_V2::PlaySoundFrom() {
lua_Object volumeOrUnknownObj = lua_getparam(5);
lua_Object volumeObj = lua_getparam(6);
int volume = 100;
int volume = MAX_EMI_VOLUME;
if (!lua_isstring(strObj)) {
error("Lua_V2::PlaySoundFrom - ERROR: Unknown parameters");
@ -434,7 +454,7 @@ void Lua_V2::PlaySoundFrom() {
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());
}
}
@ -447,10 +467,10 @@ void Lua_V2::GetSoundVolume() {
}
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
if (sound) {
lua_pushnumber(sound->getVolume());
lua_pushnumber(convertMixerVolumeToEmi(sound->getVolume()));
} else {
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));
if (sound) {
sound->setVolume(volume);
sound->setVolume(convertEmiVolumeToMixer(volume));
} else {
warning("Lua_V2:SetSoundVolume: can't find sound track");
}
@ -505,7 +525,7 @@ void Lua_V2::ImSetMusicVol() {
if (!lua_isnumber(volumeObj))
return;
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() {
@ -515,7 +535,7 @@ void Lua_V2::ImSetSfxVol() {
if (!lua_isnumber(volumeObj))
return;
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() {
@ -525,7 +545,7 @@ void Lua_V2::ImSetVoiceVol() {
if (!lua_isnumber(volumeObj))
return;
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() {

View File

@ -320,7 +320,9 @@ void EMIModel::updateLighting(const Math::Matrix4 &modelToWorld) {
Common::Array<Grim::Light *> activeLights;
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) {
activeLights.push_back(l);
if (l->_type == Light::Ambient)

View File

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

View File

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

View File

@ -1577,6 +1577,30 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
int width = frame->w;
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
if (_smushNumTex > 0) {
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_WRAP_S, 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);
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_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE;
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++;
}
}
@ -2015,6 +2039,7 @@ void GfxOpenGL::drawDimPlane() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(1.0, 0);
@ -2022,6 +2047,8 @@ void GfxOpenGL::drawDimPlane() {
glVertex2f(0, 1.0);
glEnd();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);

View File

@ -191,6 +191,20 @@ Math::Matrix4 makeRotationMatrix(const Math::Angle& angle, Math::Vector3d axis)
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() {
return new GfxOpenGLS();
}
@ -219,6 +233,9 @@ GfxOpenGLS::GfxOpenGLS() {
_dimProgram = nullptr;
_dimPlaneProgram = 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() {
@ -428,21 +445,9 @@ void GfxOpenGLS::setupCameraFrustum(float fov, float nclip, float fclip) {
_fov = fov; _nclip = nclip; _fclip = fclip;
float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
float left = -right;
float top = right * 0.75;
float bottom = -right * 0.75;
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;
_projMatrix = proj;
_projMatrix = makeFrustumMatrix(-right, right, -top, top, nclip, fclip);
}
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);
glFrontFace(GL_CW);
/* FIXME: set correct projection matrix/frustum when
* drawing in the Overworld
*/
if (actor->isInOverworld())
viewMatrix = Math::Matrix4();
Math::Vector4d color(1.0f, 1.0f, 1.0f, actor->getEffectiveAlpha());
@ -685,11 +689,17 @@ void GfxOpenGLS::startActorDraw(const Actor *actor) {
modelMatrix.transpose();
_actorProgram->setUniform("modelMatrix", modelMatrix);
_actorProgram->setUniform("viewMatrix", viewRot);
_actorProgram->setUniform("projMatrix", _projMatrix);
if (actor->isInOverworld()) {
_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("cameraPos", _currentPos);
_actorProgram->setUniform("actorPos", pos);
_actorProgram->setUniform("isBillboard", 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) {
#ifndef USE_GLES2
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
#ifndef USE_GLES2
if (useStored) {
glBindTexture(GL_TEXTURE_2D, _storedDisplay);
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);
delete[] buffer;
} else {
} else
#endif
{
readPixels(0, 0, _screenWidth, _screenHeight, src.getRawBuffer());
}
return createScreenshotBitmap(src, w, h, false);
#else
return nullptr;
#endif
return createScreenshotBitmap(src, w, h, true);
}
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 _viewMatrix;
Math::Matrix4 _mvpMatrix;
Math::Matrix4 _overworldProjMatrix;
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());
}
} else {
float m = (y2 - y1) / (x2 - x1);
float m = (y2 - y1) / (float)(x2 - x1);
int b = (int)(-m * x1 + y1);
for (int x = x1; x <= x2; x++) {
int y = (int)(m * x) + b;
@ -1424,6 +1424,7 @@ void GfxTinyGL::drawDimPlane() {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
tglColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
tglBegin(TGL_QUADS);
tglVertex2f(-1, -1);
tglVertex2f(1.0, -1);
@ -1431,6 +1432,8 @@ void GfxTinyGL::drawDimPlane() {
tglVertex2f(-1, 1.0);
tglEnd();
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
tglDisable(TGL_BLEND);
tglDepthMask(TGL_TRUE);
tglEnable(TGL_DEPTH_TEST);

View File

@ -248,13 +248,24 @@ const char *GrimEngine::getUpdateFilename() {
Common::Error GrimEngine::run() {
// Try to see if we have the EMI Mac installer present
// Currently, this requires the data fork to be standalone
if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("Monkey Island 4 Installer")) {
StuffItArchive *archive = new StuffItArchive();
if (getGameType() == GType_MONKEY4) {
if (SearchMan.hasFile("Monkey Island 4 Installer")) {
StuffItArchive *archive = new StuffItArchive();
if (archive->open("Monkey Island 4 Installer"))
SearchMan.add("Monkey Island 4 Installer", archive, 0, true);
else
delete archive;
if (archive->open("Monkey Island 4 Installer"))
SearchMan.add("Monkey Island 4 Installer", archive, 0, true);
else
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);
@ -300,8 +311,8 @@ Common::Error GrimEngine::run() {
g_driver->loadEmergFont();
if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) {
// TODO: Play EMI Mac Aspyr logo
warning("TODO: Play Aspyr logo");
// Play EMI Mac Aspyr logo
playAspyrLogo();
}
Bitmap *splash_bm = nullptr;
@ -347,6 +358,52 @@ Common::Error GrimEngine::run() {
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) {
assert(slot >= 0);
if (getGameType() == GType_MONKEY4) {

View File

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

View File

@ -22,6 +22,7 @@
#include "common/file.h"
#include "common/substream.h"
#include "common/memstream.h"
#include "engines/grim/grim.h"
#include "engines/grim/lab.h"
@ -37,7 +38,15 @@ Common::SeekableReadStream *LabEntry::createReadStream() const {
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;
bool result = true;
@ -53,6 +62,12 @@ bool Lab::open(const Common::String &filename) {
else
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;
return result;
@ -165,9 +180,16 @@ Common::SeekableReadStream *Lab::createReadStreamForMember(const Common::String
fname.toLowercase();
LabEntryPtr i = _entries[fname];
Common::File *file = new Common::File();
file->open(_labFileName);
return new Common::SeekableSubReadStream(file, i->_offset, i->_offset + i->_len, DisposeAfterUse::YES);
if (!_stream) {
Common::File *file = new Common::File();
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

View File

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

View File

@ -177,10 +177,10 @@ void Lua_V1::DrawPolygon() {
for (int i = 0; i < 4; i++) {
// Get X
lua_pushobject(tableObj1);
lua_pushnumber(i * 2);
lua_pushnumber(i * 2 + 1);
pointObj = lua_gettable();
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;
}
if (g_grim->getGameType() == GType_GRIM)
@ -190,10 +190,10 @@ void Lua_V1::DrawPolygon() {
// Get Y
lua_pushobject(tableObj1);
lua_pushnumber(i * 2 + 1);
lua_pushnumber(i * 2 + 2);
pointObj = lua_gettable();
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;
}
if (g_grim->getGameType() == GType_GRIM)

View File

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

View File

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

View File

@ -174,6 +174,7 @@ protected:
MoviePlayer *CreateMpegPlayer();
MoviePlayer *CreateSmushPlayer(bool demo);
MoviePlayer *CreateBinkPlayer(bool demo);
MoviePlayer *CreateQuickTimePlayer();
extern MoviePlayer *g_movie;
} // 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() {
_cacheDirty = false;
_cacheMemorySize = 0;
_localArchive = nullptr;
Lab *l;
Common::ArchiveMemberList files, updFiles;
@ -149,6 +150,16 @@ ResourceLoader::ResourceLoader() {
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) {
SearchMan.listMatchingMembers(files, "i9n.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 *rs = nullptr;
if (SearchMan.hasFile(filename))
if (_localArchive && _localArchive->hasFile(filename)) {
rs = _localArchive->createReadStreamForMember(filename);
} else if (SearchMan.hasFile(filename))
rs = SearchMan.createReadStreamForMember(filename);
else
return nullptr;

View File

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

View File

@ -35,7 +35,7 @@ namespace Grim {
#define SAVEGAME_FOOTERTAG 'ESAV'
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) {
Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename);

View File

@ -51,6 +51,7 @@ Set::Set(const Common::String &sceneName, Common::SeekableReadStream *data) :
} else {
loadBinary(data);
}
setupOverworldLights();
}
Set::Set() :
@ -59,6 +60,7 @@ Set::Set() :
_maxVolume(0), _numCmaps(0), _numShadows(0), _currSetup(nullptr),
_setups(nullptr), _lights(nullptr), _sectors(nullptr), _shadows(nullptr) {
setupOverworldLights();
}
Set::~Set() {
@ -82,6 +84,33 @@ Set::~Set() {
}
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) {
@ -675,7 +704,7 @@ void SetShadow::loadBinary(Common::SeekableReadStream *data, Set *set) {
_shadowPoint = Math::Vector3d::getVector3d(v);
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)) {
_shadowPoint = (*it)->_pos;
break;
@ -758,7 +787,7 @@ public:
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 shaders are not available, we do lighting in software for EMI.
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.
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;
foreach (Light *l, _lightsList) {
foreach (Light *l, *lightsList) {
if (l->_enabled) {
g_driver->setupLight(l, count);
++count;

View File

@ -51,6 +51,7 @@ public:
void loadText(TextSplitter &ts);
void loadBinary(Common::SeekableReadStream *data);
void setupOverworldLights();
void saveState(SaveGame *savedState) const;
bool restoreState(SaveGame *savedState);
@ -63,7 +64,7 @@ public:
void drawBitmaps(ObjectState::Position stage);
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, int minVol, int maxVol);
@ -143,7 +144,7 @@ public:
};
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; }
int getShadowCount() const { return _numShadows; }
@ -160,6 +161,7 @@ private:
Sector **_sectors;
Light *_lights;
Common::List<Light *> _lightsList;
Common::List<Light *> _overworldLightsList;
Setup *_setups;
SetShadow *_shadows;

View File

@ -17,6 +17,7 @@
* 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 ENGINES_METAENGINE_H

View File

@ -81,14 +81,19 @@ void BaseRenderer::computeScreenViewport() {
int32 screenWidth = _system->getWidth();
int32 screenHeight = _system->getHeight();
// Aspect ratio correction
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
_screenViewport = Common::Rect(viewportWidth, viewportHeight);
if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
// Aspect ratio correction
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
_screenViewport = Common::Rect(viewportWidth, viewportHeight);
// Pillarboxing
_screenViewport.translate((screenWidth - viewportWidth) / 2,
(screenHeight - viewportHeight) / 2);
// Pillarboxing
_screenViewport.translate((screenWidth - viewportWidth) / 2,
(screenHeight - viewportHeight) / 2);
} else {
// Aspect ratio correction disabled, just stretch
_screenViewport = Common::Rect(screenWidth, screenHeight);
}
}
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) {
// Screen coords to 3D coords
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);
// 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) {
// Screen coords to 3D coords
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);
// 3D coords to polar coords

View File

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

View File

@ -17,6 +17,7 @@
* 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 ENGINES_UTIL_H

View File

@ -105,7 +105,7 @@ VectorRenderer *createRenderer(int mode);
*/
class VectorRenderer {
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) {
}

View File

@ -1134,7 +1134,7 @@ void VectorRendererSpec<PixelType>::
drawTabShadow(int x1, int y1, int w, int h, int r) {
int offset = 3;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3;
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,
// we cannot let it blend twice. awful.
uint32 hb = 0;
while (x++ < y) {
BE_ALGORITHM();
@ -1176,7 +1176,7 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
hb |= (1 << y);
}
}
ptr_fill += pitch * r;
while (short_h--) {
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;
}
}
/** BEVELED TABS FOR CLASSIC THEME **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@ -1647,7 +1647,7 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
BE_RESET();
r--;
int alphaStep_tr = ((alpha_t - alpha_r)/(y+1));
int alphaStep_br = ((alpha_r - alpha_b)/(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)) {
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_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_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_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)));
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, 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) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63;
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)
uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
// These constants ensure a border of 2px on the left and of each rounded square
int xstart = (x1 > 2) ? x1 - 2 : x1;
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--) {
int f, ddF_x, ddF_y;
int x, y, px, py;
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_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,
// we cannot let it blend twice. awful.
uint32 hb = 0;
while (x++ < y) {
BE_ALGORITHM();
if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
// Will create a dark line of pixles if left out
if (hb > 0) {
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);
}
}
ptr_fill += pitch * r;
while (short_h--) {
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;
width -= 2;
height -= 2;
if (_shadowFillMode == kShadowExponential)
// Multiply with expfactor
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
if (sw != strokeWidth || fill_m != Base::kFillDisabled)
a2 = 255;
// 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));
// 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_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_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_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));
@ -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_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_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_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));
@ -2220,7 +2220,7 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
int x, y;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py;
uint32 rsq = r*r;
frac_t T = 0, oldT;
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) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255;
const uint8 bevelAlpha_r = 31;
const uint8 bevelAlpha_b = 0;
const uint8 bevelAlpha_l = 127;
if (Base::_strokeWidth) {
if (r != 0 && Base::_bevel > 0) {
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);
}
}
// If only border is visible
if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
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 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 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"
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
#ifdef USE_OPENGL
namespace Graphics {
static Common::List<Common::String> g_extensions;
void initExtensions() {
g_extensions.clear();
const char *exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
Common::StringTokenizer tokenizer(exts, " ");
while (!tokenizer.empty()) {

View File

@ -22,9 +22,24 @@
#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"
#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"
#ifdef USE_GLES2
@ -33,33 +48,130 @@
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() {
#ifdef USE_GLES2
return Graphics::isExtensionSupported("GL_OES_packed_depth_stencil");
#endif
#ifndef USE_OPENGL_SHADERS
return Graphics::isExtensionSupported("GL_EXT_packed_depth_stencil");
#endif
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);
glGenRenderbuffers(2, &_renderBuffers[0]);
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()) {
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_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
} else {
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]);
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]);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
@ -73,11 +185,6 @@ FrameBuffer::FrameBuffer(GLuint texture_name, uint width, uint height, uint text
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
FrameBuffer::~FrameBuffer() {
glDeleteRenderbuffers(2, &_renderBuffers[0]);
glDeleteFramebuffers(1, &_frameBuffer);
}
void FrameBuffer::attach() {
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
glViewport(0,0, _width, _height);

View File

@ -29,19 +29,34 @@ namespace Graphics {
class FrameBuffer {
public:
FrameBuffer(uint width, uint height);
FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height);
#ifdef AMIGAOS
~FrameBuffer() {}
void attach() {}
void detach() {}
#else
~FrameBuffer();
void attach();
void detach();
#endif
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:
void init();
bool _managedTexture;
GLuint _colorTexture;
GLuint _renderBuffers[2];
GLuint _frameBuffer;
uint _width, _height;
uint _texWidth, _texHeight;
};
}

View File

@ -228,7 +228,7 @@ public:
* @param srcSurface The source of the bitmap data
* @param destX The x 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);

View File

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

View File

@ -216,7 +216,7 @@ void glopTexEnv(GLContext *, GLParam *p) {
if (target != TGL_TEXTURE_ENV) {
error:
error("glTexParameter: unsupported option");
error("tglTexParameter: unsupported option");
}
if (pname != TGL_TEXTURE_ENV_MODE)
@ -234,7 +234,7 @@ void glopTexParameter(GLContext *, GLParam *p) {
if (target != TGL_TEXTURE_2D) {
error:
error("glTexParameter: unsupported option");
error("tglTexParameter: unsupported option");
}
switch (pname) {
@ -253,7 +253,7 @@ void glopPixelStore(GLContext *, GLParam *p) {
int param = p[2].i;
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 kDefaultOffsetX = 0;
const int32 kDefaultOffsetY = 0;
const int32 kDefaultAngle = 0;
const int32 kDefaultAngle = 0;
struct TransformStruct {
private:

View File

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

View File

@ -241,7 +241,7 @@ void AboutDialog::drawDialog() {
while (*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);
y += _lineHeight;
}

View File

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

Binary file not shown.

View File

@ -1172,9 +1172,9 @@
height = 'Globals.Line.Height'
/>
<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'
type = 'Button'
/>

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@ public:
/**
* Load an image from the specified stream
*
*
* loadStream() should implicitly call destroy() to free the memory
* 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()));
// 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);
return *this;

View File

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

View File

@ -149,7 +149,7 @@ bool AVIDecoder::parseNextChunk() {
skipChunk(size);
break;
case ID_IDX1:
readOldIndex(size);
readOldIndex(size);
break;
default:
error("Unknown tag \'%s\' found", tag2str(tag));
@ -319,8 +319,25 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
return false;
}
// Seek back to the start of the MOVI list
_fileStream->seek(_movieListStart);
// Create the status entries
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
checkTruemotion1();
@ -340,79 +357,138 @@ void AVIDecoder::close() {
_indexEntries.clear();
memset(&_header, 0, sizeof(_header));
_videoTracks.clear();
_audioTracks.clear();
}
void AVIDecoder::readNextPacket() {
if ((uint32)_fileStream->pos() >= _movieListEnd) {
// Ugh, reached the end premature.
forceVideoEnd();
// Shouldn't get this unless called on a non-open video
if (_videoTracks.empty())
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;
}
uint32 nextTag = _fileStream->readUint32BE();
uint32 size = _fileStream->readUint32LE();
if (_fileStream->eos()) {
// Also premature end.
forceVideoEnd();
// See if audio needs to be buffered and break out if not
if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status))
return;
}
if (nextTag == ID_LIST) {
// A list of audio/video chunks
int32 startPos = _fileStream->pos();
// Seek to where we shall start searching
_fileStream->seek(status.chunkSearchOffset);
if (_fileStream->readUint32BE() != ID_REC)
error("Expected 'rec ' LIST");
for (;;) {
// 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
while (_fileStream->pos() < startPos + (int32)size)
readNextPacket();
uint32 nextTag = _fileStream->readUint32BE();
uint32 size = _fileStream->readUint32LE();
return;
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
skipChunk(size);
return;
}
if (nextTag == ID_LIST) {
// A list of audio/video chunks
if (_fileStream->readUint32BE() != ID_REC)
error("Expected 'rec ' LIST");
Track *track = getTrack(getStreamIndex(nextTag));
continue;
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
skipChunk(size);
continue;
}
if (!track)
error("Cannot get track from tag '%s'", tag2str(nextTag));
// Only accept chunks for this stream
uint32 streamIndex = getStreamIndex(nextTag);
if (streamIndex != status.index) {
skipChunk(size);
continue;
}
Common::SeekableReadStream *chunk = 0;
Common::SeekableReadStream *chunk = 0;
if (size != 0) {
chunk = _fileStream->readStream(size);
_fileStream->skip(size & 1);
}
if (size != 0) {
chunk = _fileStream->readStream(size);
_fileStream->skip(size & 1);
}
if (track->getTrackType() == Track::kTrackTypeAudio) {
if (getStreamType(nextTag) != kStreamTypeAudio)
error("Invalid audio track tag '%s'", tag2str(nextTag));
if (status.track->getTrackType() == Track::kTrackTypeAudio) {
if (getStreamType(nextTag) != kStreamTypeAudio)
error("Invalid audio track tag '%s'", tag2str(nextTag));
assert(chunk);
((AVIAudioTrack *)track)->queueSound(chunk);
} else {
AVIVideoTrack *videoTrack = (AVIVideoTrack *)track;
assert(chunk);
((AVIAudioTrack *)status.track)->queueSound(chunk);
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
// Palette Change
videoTrack->loadPaletteFromChunk(chunk);
// Break out if we have enough audio
if (!shouldQueueAudio(status))
break;
} else {
// Otherwise, assume it's a compressed frame
videoTrack->decodeFrame(chunk);
AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track;
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() {
if (!VideoDecoder::rewind())
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;
}
@ -421,29 +497,9 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
if (time > getDuration())
return false;
// Track down our video track.
// We only support seeking with one video track right now.
AVIVideoTrack *videoTrack = 0;
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;
// Get our video
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
uint32 videoIndex = _videoTracks[0].index;
// If we seek directly to the end, just mark the tracks as over
if (time == getDuration()) {
@ -464,7 +520,6 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
int lastKeyFrame = -1;
int frameIndex = -1;
int lastRecord = -1;
uint curFrame = 0;
// 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++) {
const OldIndex &index = _indexEntries[i];
if (index.id == ID_REC) {
// Keep track of any records we find
lastRecord = i;
// We don't care about RECs
if (index.id == ID_REC)
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 {
if (getStreamIndex(index.id) != videoIndex)
continue;
// 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;
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 {
// 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++;
// Did we find the target frame?
if (frame == curFrame) {
frameIndex = i;
break;
}
curFrame++;
}
}
@ -513,54 +568,36 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
return false;
// Update all the audio tracks
uint audioIndex = 0;
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.
for (uint32 i = 0; i < _audioTracks.size(); i++) {
AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track;
// Recreate the audio stream
audioTrack->resetStream();
uint framesNeeded = _header.initialFrames;
uint startAudioChunk = 0;
int startAudioSearch = (lastRecord < 0) ? (frameIndex - 1) : (lastRecord - 1);
// Set the chunk index for the track
audioTrack->setCurChunk(frame);
for (int i = startAudioSearch; i >= 0; i--) {
if (getStreamIndex(_indexEntries[i].id) != audioIndex)
uint32 chunksFound = 0;
for (uint32 j = 0; j < _indexEntries.size(); j++) {
const OldIndex &index = _indexEntries[j];
// Continue ignoring RECs
if (index.id == ID_REC)
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--;
if (framesNeeded == 0) {
startAudioChunk = i;
break;
chunksFound++;
}
}
// 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
audioTrack->skipAudio(time, videoTrack->getFrameTime(frame));
}
@ -589,15 +626,11 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
videoTrack->decodeFrame(chunk);
}
// Seek to the right spot
// 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);
// Set the video track's frame
videoTrack->setCurFrame((int)frame - 1);
// Set the video track's search offset to the right spot
_videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset;
return true;
}
@ -620,7 +653,7 @@ void AVIDecoder::readOldIndex(uint32 size) {
OldIndex firstEntry;
firstEntry.id = _fileStream->readUint32BE();
firstEntry.flags = _fileStream->readUint32LE();
firstEntry.offset = _fileStream->readUint32LE();
firstEntry.offset = _fileStream->readUint32LE();
firstEntry.size = _fileStream->readUint32LE();
// 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() {
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++) {
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
if (track) {
// Multiple tracks; isn't going to be truemotion 1
return;
}
track = (AVIVideoTrack *)*it;
}
}
// No track found?
if (!track)
return;
TrackStatus &status = _videoTracks[0];
AVIVideoTrack *track = (AVIVideoTrack *)status.track;
// Ignore non-truemotion tracks
if (!track->isTruemotion1())
return;
// Search for a non-empty frame
const Graphics::Surface *frame = 0;
for (int i = 0; i < 10 && !frame; i++)
frame = decodeNextFrame();
// Read the next video packet
handleNextPacket(status);
const Graphics::Surface *frame = track->decodeNextFrame();
if (!frame) {
// Probably shouldn't happen
rewind();
return;
}
@ -806,7 +816,7 @@ void AVIDecoder::AVIVideoTrack::forceTrackEnd() {
}
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();
}
@ -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);
} else if (_wvInfo.tag == kWaveFormatDK3) {
_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 {
delete stream;
}
_curChunk++;
}
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() {
delete _audStream;
_audStream = createAudioStream();
_curChunk = 0;
}
bool AVIDecoder::AVIAudioTrack::rewind() {
@ -871,12 +882,17 @@ Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const {
}
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);
else if (_wvInfo.tag == kWaveFormatMP3)
warning("Unsupported AVI MP3 tracks");
else if (_wvInfo.tag != kWaveFormatNone) // No sound
warning("Unsupported AVI audio format %d", _wvInfo.tag);
return 0;
}
AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
}
} // End of namespace Video

View File

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