mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
Merge remote-tracking branch 'origin/master' into tlj
This commit is contained in:
commit
bba76f503f
14
README.md
14
README.md
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -146,4 +146,12 @@ const char *gScummVMFeatures = ""
|
||||
#ifdef USE_PNG
|
||||
"PNG "
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KEYMAPPER
|
||||
"keymapper "
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VKEYBD
|
||||
"virtual keyboard "
|
||||
#endif
|
||||
;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
31
configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -251,6 +251,7 @@ private:
|
||||
Math::Matrix4 _projMatrix;
|
||||
Math::Matrix4 _viewMatrix;
|
||||
Math::Matrix4 _mvpMatrix;
|
||||
Math::Matrix4 _overworldProjMatrix;
|
||||
|
||||
void setupTexturedCenteredQuad();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -201,6 +201,7 @@ protected:
|
||||
void buildActiveActorsList();
|
||||
void savegameCallback();
|
||||
void createRenderer();
|
||||
void playAspyrLogo();
|
||||
virtual LuaBase *createLua();
|
||||
virtual void updateNormalMode();
|
||||
virtual void updateDrawMode();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
53
engines/grim/movie/quicktime.cpp
Normal file
53
engines/grim/movie/quicktime.cpp
Normal 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
|
||||
|
39
engines/grim/movie/quicktime.h
Normal file
39
engines/grim/movie/quicktime.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
@ -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'
|
||||
/>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "common/array.h"
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
||||
enum {
|
||||
kTabForwards = 1,
|
||||
kTabBackwards = -1
|
||||
|
@ -62,7 +62,7 @@ namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
namespace Image {
|
||||
|
||||
/**
|
||||
* MPEG 1/2 video decoder.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
5
ports.mk
5
ports.mk
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user