EMI: Implement screenshot thumbnails for savegames
This commit is contained in:
parent
81745bfe62
commit
1e82136592
18 changed files with 280 additions and 253 deletions
|
@ -29,6 +29,7 @@
|
|||
#include "engines/grim/set.h"
|
||||
#include "engines/grim/gfx_base.h"
|
||||
#include "engines/grim/actor.h"
|
||||
#include "graphics/pixelbuffer.h"
|
||||
|
||||
|
||||
namespace Grim {
|
||||
|
@ -184,6 +185,42 @@ void EMIEngine::drawNormalMode() {
|
|||
|
||||
}
|
||||
|
||||
void EMIEngine::storeSaveGameImage(SaveGame *state) {
|
||||
unsigned int width = 160, height = 120;
|
||||
Bitmap *screenshot = g_driver->getScreenshot(width, height, true);
|
||||
assert(screenshot);
|
||||
|
||||
// screenshots are not using the whole size of the texture
|
||||
// copy the actual screenshot to the correct position
|
||||
unsigned int texWidth = 256, texHeight = 128;
|
||||
Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(texWidth * texHeight, DisposeAfterUse::YES);
|
||||
buffer.clear(texWidth * texHeight);
|
||||
for (unsigned int j = 0; j < 120; j++) {
|
||||
buffer.copyBuffer(j * texWidth, j * width, width, screenshot->getData(0));
|
||||
}
|
||||
|
||||
Bitmap *newscreenshot = new Bitmap(buffer, texWidth, texHeight, "screenshot");
|
||||
state->beginSection('SIMG');
|
||||
if (newscreenshot) {
|
||||
int size = newscreenshot->getWidth() * newscreenshot->getHeight();
|
||||
uint16 *data = (uint16 *)newscreenshot->getData(0).getRawBuffer();
|
||||
for (int l = 0; l < size; l++) {
|
||||
state->writeLEUint16(data[l]);
|
||||
}
|
||||
} else {
|
||||
error("Unable to store screenshot");
|
||||
}
|
||||
state->endSection();
|
||||
delete newscreenshot;
|
||||
delete screenshot;
|
||||
}
|
||||
|
||||
void EMIEngine::temporaryStoreSaveGameImage() {
|
||||
// store current rendered screen in g_driver
|
||||
g_grim->updateDisplayScene();
|
||||
g_driver->storeDisplay();
|
||||
}
|
||||
|
||||
void EMIEngine::updateDrawMode() {
|
||||
// For EMI, draw mode is just like normal mode with frozen frame time.
|
||||
updateNormalMode();
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
void invalidateTextObjectsSortOrder() override;
|
||||
void invalidateSortOrder();
|
||||
void sortActiveActorsList();
|
||||
void temporaryStoreSaveGameImage();
|
||||
void storeSaveGameImage(SaveGame *state) override;
|
||||
|
||||
private:
|
||||
LuaBase *createLua() override;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "engines/grim/emi/lua_v2.h"
|
||||
#include "engines/grim/emi/emi_registry.h"
|
||||
#include "engines/grim/lua/lauxlib.h"
|
||||
#include "graphics/pixelbuffer.h"
|
||||
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/set.h"
|
||||
|
@ -116,7 +117,7 @@ void Lua_V2::MakeScreenTextures() {
|
|||
/*int index = (int)lua_getnumber(indexObj);*/
|
||||
// The index does not seem to matter
|
||||
|
||||
g_driver->createSpecialtyTextures();
|
||||
g_driver->makeScreenTextures();
|
||||
lua_pushnumber(1.0);
|
||||
} else {
|
||||
lua_pushnil();
|
||||
|
@ -285,7 +286,7 @@ void Lua_V2::ClearOverworld() {
|
|||
}
|
||||
|
||||
void Lua_V2::ScreenshotForSavegame() {
|
||||
warning("Lua_V2::ScreenshotForSavegame: implement opcode");
|
||||
g_emi->temporaryStoreSaveGameImage();
|
||||
}
|
||||
|
||||
void Lua_V2::EngineDisplay() {
|
||||
|
@ -385,10 +386,50 @@ void Lua_V2::ThumbnailFromFile() {
|
|||
lua_Object texIdObj = lua_getparam(1);
|
||||
lua_Object filenameObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isnumber(texIdObj) || !lua_isstring(filenameObj))
|
||||
if (!lua_isnumber(texIdObj) || !lua_isstring(filenameObj)) {
|
||||
warning("Lua_V2::ThumbnailFromFile: wrong parameters");
|
||||
return;
|
||||
}
|
||||
int index = (int)lua_getnumber(texIdObj);
|
||||
const char *filename = lua_getstring(filenameObj);
|
||||
|
||||
int width = 256, height = 128;
|
||||
Bitmap *screenshot;
|
||||
|
||||
SaveGame *savedState = SaveGame::openForLoading(filename);
|
||||
if (!savedState || !savedState->isCompatible()) {
|
||||
delete savedState;
|
||||
warning("Lua_V2::ThumbnailFromFile: savegame %s not compatible", filename);
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
int dataSize = savedState->beginSection('SIMG');
|
||||
if (dataSize != width * height * 2) {
|
||||
warning("Lua_V2::ThumbnailFromFile: savegame uses unexpected thumbnail size, ignore it");
|
||||
lua_pushnil();
|
||||
delete savedState;
|
||||
return;
|
||||
}
|
||||
uint16 *data = new uint16[dataSize / 2];
|
||||
for (int l = 0; l < dataSize / 2; l++) {
|
||||
data[l] = savedState->readLEUint16();
|
||||
}
|
||||
Graphics::PixelBuffer buf(Graphics::createPixelFormat<565>(), (byte *)data);
|
||||
screenshot = new Bitmap(buf, width, height, "screenshot");
|
||||
if (!screenshot) {
|
||||
lua_pushnil();
|
||||
warning("Lua_V2::ThumbnailFromFile: Could not restore screenshot from file %s", filename);
|
||||
delete[] data;
|
||||
delete savedState;
|
||||
return;
|
||||
}
|
||||
|
||||
screenshot->_data->convertToColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
||||
g_driver->createSpecialtyTexture(index, (char*)screenshot->getData(0).getRawBuffer(), width, height);
|
||||
delete[] data;
|
||||
savedState->endSection();
|
||||
delete savedState;
|
||||
|
||||
warning("Lua_V2::ThumbnailFromFile: implement opcode, pushing true");
|
||||
pushbool(true);
|
||||
}
|
||||
|
||||
|
@ -577,7 +618,6 @@ static void stubError(const char *funcName) {
|
|||
// STUB_FUNC2(Lua_V2::SetLightPosition)
|
||||
// STUB_FUNC2(Lua_V2::GetAngleBetweenVectors)
|
||||
// STUB_FUNC2(Lua_V2::IsPointInSector)
|
||||
// STUB_FUNC2(Lua_V2::ThumbnailFromFile)
|
||||
|
||||
// Stubbed functions with semi-known arguments:
|
||||
// TODO: Verify and implement these: (And add type-checking), also rename params
|
||||
|
|
|
@ -263,11 +263,8 @@ void EMIModel::prepareForRender() {
|
|||
void EMIModel::prepareTextures() {
|
||||
_mats = new Material*[_numTextures];
|
||||
for (uint32 i = 0; i < _numTextures; i++) {
|
||||
// HACK: As we dont know what specialty-textures are yet, we skip loading them
|
||||
if (!_texNames[i].contains("specialty"))
|
||||
// FIXME: should specialty textures be clamped?
|
||||
_mats[i] = _costume->loadMaterial(_texNames[i], false);
|
||||
else
|
||||
_mats[i] = g_driver->getSpecialtyTexture(_texNames[i][9] - '0');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
#include "engines/grim/gfx_base.h"
|
||||
#include "engines/grim/savegame.h"
|
||||
#include "engines/grim/bitmap.h"
|
||||
#include "engines/grim/grim.h"
|
||||
|
||||
#include "engines/grim/model.h"
|
||||
|
||||
|
@ -49,7 +51,9 @@ GfxBase::GfxBase() :
|
|||
_screenWidth(0), _screenHeight(0), _isFullscreen(false),
|
||||
_scaleW(1.0f), _scaleH(1.0f), _currentShadowArray(nullptr),
|
||||
_shadowColorR(255), _shadowColorG(255), _shadowColorB(255) {
|
||||
|
||||
for (int i = 0; i < _numSpecialtyTextures; i++) {
|
||||
_specialtyTextures[i]._isShared = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GfxBase::setShadowMode() {
|
||||
|
@ -112,22 +116,6 @@ GfxBase *CreateGfxOpenGL() {
|
|||
}
|
||||
#endif // USE_OPENGL
|
||||
|
||||
void SpecialtyMaterial::select() const {
|
||||
if (_texture) {
|
||||
g_driver->selectTexture(_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialtyMaterial::create(const char *data, int width, int height) {
|
||||
delete _texture;
|
||||
_texture = new Texture();
|
||||
_texture->_width = width;
|
||||
_texture->_height = height;
|
||||
_texture->_bpp = 4;
|
||||
_texture->_colorFormat = BM_RGBA;
|
||||
g_driver->createTexture(_texture, data, nullptr, false);
|
||||
}
|
||||
|
||||
Math::Matrix4 GfxBase::makeLookMatrix(const Math::Vector3d& pos, const Math::Vector3d& interest, const Math::Vector3d& up) {
|
||||
Math::Vector3d f = (interest - pos).getNormalized();
|
||||
Math::Vector3d u = up.getNormalized();
|
||||
|
@ -172,4 +160,84 @@ Math::Matrix4 GfxBase::makeProjMatrix(float fov, float nclip, float fclip) {
|
|||
return proj;
|
||||
}
|
||||
|
||||
|
||||
void GfxBase::createSpecialtyTexture(unsigned int id, const char *data, int width, int height) {
|
||||
if (id >= _numSpecialtyTextures) return;
|
||||
if (_specialtyTextures[id]._texture) {
|
||||
destroyTexture(&_specialtyTextures[id]);
|
||||
}
|
||||
delete[] _specialtyTextures[id]._data;
|
||||
_specialtyTextures[id]._width = width;
|
||||
_specialtyTextures[id]._height = height;
|
||||
_specialtyTextures[id]._bpp = 4;
|
||||
_specialtyTextures[id]._colorFormat = BM_RGBA;
|
||||
g_driver->createTexture(&_specialtyTextures[id], data, nullptr, false);
|
||||
}
|
||||
|
||||
Bitmap *GfxBase::createScreenshotBitmap(const Graphics::PixelBuffer src, int w, int h, bool flipOrientation) {
|
||||
Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(w * h, DisposeAfterUse::YES);
|
||||
|
||||
int i1 = (_screenWidth * w - 1) / _screenWidth + 1;
|
||||
int j1 = (_screenHeight * h - 1) / _screenHeight + 1;
|
||||
|
||||
for (int j = 0; j < j1; j++) {
|
||||
for (int i = 0; i < i1; i++) {
|
||||
int x0 = i * _screenWidth / w;
|
||||
int x1 = ((i + 1) * _screenWidth - 1) / w + 1;
|
||||
int y0 = j * _screenHeight / h;
|
||||
int y1 = ((j + 1) * _screenHeight - 1) / h + 1;
|
||||
uint16 sr = 0, sg = 0, sb = 0;
|
||||
for (int y = y0; y < y1; y++) {
|
||||
for (int x = x0; x < x1; x++) {
|
||||
uint8 r, g, b;
|
||||
src.getRGBAt(y * _screenWidth + x, r, g, b);
|
||||
sr += r;
|
||||
sg += g;
|
||||
sb += b;
|
||||
}
|
||||
}
|
||||
sr /= (x1 - x0) * (y1 - y0);
|
||||
sg /= (x1 - x0) * (y1 - y0);
|
||||
sb /= (x1 - x0) * (y1 - y0);
|
||||
if (g_grim->getGameType() == GType_MONKEY4) {
|
||||
buffer.setPixelAt( (flipOrientation ? j : (h - j - 1) ) * w + i, sr, sg, sb);
|
||||
} else {
|
||||
uint32 color = (sr + sg + sb) / 3;
|
||||
buffer.setPixelAt( (flipOrientation ? j : (h - j - 1) ) * w + i, color, color, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *screenshot = new Bitmap(buffer, w, h, "screenshot");
|
||||
return screenshot;
|
||||
}
|
||||
|
||||
void GfxBase::makeScreenTextures() {
|
||||
//make a buffer big enough to hold any of the textures
|
||||
char *buffer = new char[256 * 256 * 4];
|
||||
|
||||
// TODO: Handle screen resolutions other than 640 x 480
|
||||
createSpecialtyTextureFromScreen(0, buffer, 0, 0, 256, 256);
|
||||
createSpecialtyTextureFromScreen(1, buffer, 256, 0, 256, 256);
|
||||
createSpecialtyTextureFromScreen(2, buffer, 512, 0, 128, 128);
|
||||
createSpecialtyTextureFromScreen(3, buffer, 512, 128, 128, 128);
|
||||
createSpecialtyTextureFromScreen(4, buffer, 0, 256, 256, 256);
|
||||
createSpecialtyTextureFromScreen(5, buffer, 256, 256, 256, 256);
|
||||
createSpecialtyTextureFromScreen(6, buffer, 512, 256, 128, 128);
|
||||
createSpecialtyTextureFromScreen(7, buffer, 512, 384, 128, 128);
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
Texture *GfxBase::getSpecialtyTexturePtr(Common::String name) {
|
||||
assert(name.hasPrefix("specialty"));
|
||||
name.erase(0, 9);
|
||||
unsigned int id;
|
||||
sscanf(name.c_str(), "%u", &id);
|
||||
if (id >= _numSpecialtyTextures) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_specialtyTextures[id];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "math/quat.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/pixelbuffer.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/grim/material.h"
|
||||
|
||||
|
@ -46,7 +48,6 @@ class Color;
|
|||
class PrimitiveObject;
|
||||
class Font;
|
||||
class TextObject;
|
||||
class Material;
|
||||
class EMIModel;
|
||||
class EMIMeshFace;
|
||||
class ModelNode;
|
||||
|
@ -56,15 +57,6 @@ class Sprite;
|
|||
class Light;
|
||||
class Texture;
|
||||
|
||||
class SpecialtyMaterial : public Material {
|
||||
public:
|
||||
SpecialtyMaterial() { _texture = NULL; }
|
||||
~SpecialtyMaterial() { delete _texture; }
|
||||
void create(const char *data, int width, int height);
|
||||
virtual void select() const override;
|
||||
Texture *_texture;
|
||||
};
|
||||
|
||||
/**
|
||||
* The Color-formats used for bitmaps in Grim Fandango/Escape From Monkey Island
|
||||
*/
|
||||
|
@ -205,7 +197,7 @@ public:
|
|||
virtual void drawTextObject(const TextObject *text) = 0;
|
||||
virtual void destroyTextObject(TextObject *text) = 0;
|
||||
|
||||
virtual Bitmap *getScreenshot(int w, int h) = 0;
|
||||
virtual Bitmap *getScreenshot(int w, int h, bool useStored) = 0;
|
||||
virtual void storeDisplay() = 0;
|
||||
virtual void copyStoredToDisplay() = 0;
|
||||
|
||||
|
@ -264,8 +256,7 @@ public:
|
|||
virtual void renderBitmaps(bool render);
|
||||
virtual void renderZBitmaps(bool render);
|
||||
|
||||
virtual void createSpecialtyTextures() = 0;
|
||||
virtual Material *getSpecialtyTexture(int n) { return &_specialty[n]; }
|
||||
virtual void makeScreenTextures();
|
||||
|
||||
virtual void createMesh(Mesh *mesh) {}
|
||||
virtual void destroyMesh(const Mesh *mesh) {}
|
||||
|
@ -279,10 +270,17 @@ public:
|
|||
virtual void drawBuffers() {}
|
||||
virtual void refreshBuffers() {}
|
||||
|
||||
virtual void createSpecialtyTexture(unsigned int id, const char *data, int width, int height);
|
||||
virtual void createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) = 0;
|
||||
|
||||
static Math::Matrix4 makeLookMatrix(const Math::Vector3d& pos, const Math::Vector3d& interest, const Math::Vector3d& up);
|
||||
static Math::Matrix4 makeProjMatrix(float fov, float nclip, float fclip);
|
||||
|
||||
Texture *getSpecialtyTexturePtr(unsigned int id) { if (id >= _numSpecialtyTextures) return nullptr; return &_specialtyTextures[id]; };
|
||||
Texture *getSpecialtyTexturePtr(Common::String name);
|
||||
protected:
|
||||
Bitmap *createScreenshotBitmap(const Graphics::PixelBuffer src, int w, int h, bool flipOrientation);
|
||||
static const int _numSpecialtyTextures = 22;
|
||||
Texture _specialtyTextures[_numSpecialtyTextures];
|
||||
static const int _gameHeight = 480;
|
||||
static const int _gameWidth = 640;
|
||||
float _scaleW, _scaleH;
|
||||
|
@ -296,7 +294,6 @@ protected:
|
|||
bool _renderZBitmaps;
|
||||
bool _shadowModeActive;
|
||||
Graphics::PixelFormat _pixelFormat;
|
||||
SpecialtyMaterial _specialty[8];
|
||||
Math::Vector3d _currentPos;
|
||||
Math::Quaternion _currentQuat;
|
||||
float _dimLevel;
|
||||
|
|
|
@ -1616,35 +1616,14 @@ void GfxOpenGL::drawEmergString(int x, int y, const char *text, const Color &fgC
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
Bitmap *GfxOpenGL::getScreenshot(int w, int h) {
|
||||
Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(w * h, DisposeAfterUse::YES);
|
||||
Bitmap *GfxOpenGL::getScreenshot(int w, int h, bool useStored) {
|
||||
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
||||
if (useStored) {
|
||||
memcpy(src.getRawBuffer(), _storedDisplay, _screenWidth * _screenHeight * 4);
|
||||
} else {
|
||||
glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getRawBuffer());
|
||||
|
||||
int i1 = (_screenWidth * w - 1) / _screenWidth + 1;
|
||||
int j1 = (_screenHeight * h - 1) / _screenHeight + 1;
|
||||
|
||||
for (int j = 0; j < j1; j++) {
|
||||
for (int i = 0; i < i1; i++) {
|
||||
int x0 = i * _screenWidth / w;
|
||||
int x1 = ((i + 1) * _screenWidth - 1) / w + 1;
|
||||
int y0 = j * _screenHeight / h;
|
||||
int y1 = ((j + 1) * _screenHeight - 1) / h + 1;
|
||||
uint32 color = 0;
|
||||
for (int y = y0; y < y1; y++) {
|
||||
for (int x = x0; x < x1; x++) {
|
||||
uint8 lr, lg, lb;
|
||||
src.getRGBAt(y * _screenWidth + x, lr, lg, lb);
|
||||
color += (lr + lg + lb) / 3;
|
||||
}
|
||||
}
|
||||
color /= (x1 - x0) * (y1 - y0);
|
||||
buffer.setPixelAt((h - j - 1) * w + i, color, color, color);
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *screenshot = new Bitmap(buffer, w, h, "screenshot");
|
||||
return screenshot;
|
||||
return createScreenshotBitmap(src, w, h, false);
|
||||
}
|
||||
|
||||
void GfxOpenGL::storeDisplay() {
|
||||
|
@ -1976,36 +1955,9 @@ static void readPixels(int x, int y, int width, int height, char *buffer) {
|
|||
}
|
||||
}
|
||||
|
||||
void GfxOpenGL::createSpecialtyTextures() {
|
||||
//make a buffer big enough to hold any of the textures
|
||||
char *buffer = new char[256 * 256 * 4];
|
||||
|
||||
// TODO: Handle screen resolutions other than 640 x 480
|
||||
readPixels(0, 0, 256, 256, buffer);
|
||||
_specialty[0].create(buffer, 256, 256);
|
||||
|
||||
readPixels(256, 0, 256, 256, buffer);
|
||||
_specialty[1].create(buffer, 256, 256);
|
||||
|
||||
readPixels(512, 0, 128, 128, buffer);
|
||||
_specialty[2].create(buffer, 128, 128);
|
||||
|
||||
readPixels(512, 128, 128, 128, buffer);
|
||||
_specialty[3].create(buffer, 128, 128);
|
||||
|
||||
readPixels(0, 256, 256, 256, buffer);
|
||||
_specialty[4].create(buffer, 256, 256);
|
||||
|
||||
readPixels(256, 256, 256, 256, buffer);
|
||||
_specialty[5].create(buffer, 256, 256);
|
||||
|
||||
readPixels(512, 256, 128, 128, buffer);
|
||||
_specialty[6].create(buffer, 128, 128);
|
||||
|
||||
readPixels(512, 384, 128, 128, buffer);
|
||||
_specialty[7].create(buffer, 128, 128);
|
||||
|
||||
delete[] buffer;
|
||||
void GfxOpenGL::createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) {
|
||||
readPixels(x, y, width, height, data);
|
||||
createSpecialtyTexture(id, data, width, height);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
|
|
|
@ -107,7 +107,7 @@ public:
|
|||
void drawTextObject(const TextObject *text) override;
|
||||
void destroyTextObject(TextObject *text) override;
|
||||
|
||||
Bitmap *getScreenshot(int w, int h) override;
|
||||
Bitmap *getScreenshot(int w, int h, bool useStored) override;
|
||||
void storeDisplay() override;
|
||||
void copyStoredToDisplay() override;
|
||||
void dimScreen() override;
|
||||
|
@ -125,9 +125,8 @@ public:
|
|||
void drawMovieFrame(int offsetX, int offsetY) override;
|
||||
void releaseMovieFrame() override;
|
||||
|
||||
void createSpecialtyTextures() override;
|
||||
|
||||
protected:
|
||||
void createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) override;
|
||||
void drawDepthBitmap(int x, int y, int w, int h, char *data);
|
||||
void initExtensions();
|
||||
private:
|
||||
|
|
|
@ -1492,38 +1492,6 @@ void GfxOpenGLS::destroyTextObject(TextObject *text) {
|
|||
delete td;
|
||||
}
|
||||
|
||||
|
||||
Bitmap *GfxOpenGLS::getScreenshot(int w, int h) {
|
||||
Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(w * h, DisposeAfterUse::YES);
|
||||
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
||||
glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getRawBuffer());
|
||||
|
||||
int i1 = (_screenWidth * w - 1) / _screenWidth + 1;
|
||||
int j1 = (_screenHeight * h - 1) / _screenHeight + 1;
|
||||
|
||||
for (int j = 0; j < j1; j++) {
|
||||
for (int i = 0; i < i1; i++) {
|
||||
int x0 = i * _screenWidth / w;
|
||||
int x1 = ((i + 1) * _screenWidth - 1) / w + 1;
|
||||
int y0 = j * _screenHeight / h;
|
||||
int y1 = ((j + 1) * _screenHeight - 1) / h + 1;
|
||||
uint32 color = 0;
|
||||
for (int y = y0; y < y1; y++) {
|
||||
for (int x = x0; x < x1; x++) {
|
||||
uint8 lr, lg, lb;
|
||||
src.getRGBAt(y * _screenWidth + x, lr, lg, lb);
|
||||
color += (lr + lg + lb) / 3;
|
||||
}
|
||||
}
|
||||
color /= (x1 - x0) * (y1 - y0);
|
||||
buffer.setPixelAt((h - j - 1) * w + i, color, color, color);
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *screenshot = new Bitmap(buffer, w, h, "screenshot");
|
||||
return screenshot;
|
||||
}
|
||||
|
||||
void GfxOpenGLS::storeDisplay() {
|
||||
glBindTexture(GL_TEXTURE_2D, _storedDisplay);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _screenWidth, _screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
@ -1857,37 +1825,6 @@ void GfxOpenGLS::renderZBitmaps(bool render) {
|
|||
}
|
||||
|
||||
|
||||
void GfxOpenGLS::createSpecialtyTextures() {
|
||||
//make a buffer big enough to hold any of the textures
|
||||
char *buffer = new char[256 * 256 * 4];
|
||||
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[0].create(buffer, 256, 256);
|
||||
|
||||
glReadPixels(256, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[1].create(buffer, 256, 256);
|
||||
|
||||
glReadPixels(512, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[2].create(buffer, 128, 128);
|
||||
|
||||
glReadPixels(512, 128, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[3].create(buffer, 128, 128);
|
||||
|
||||
glReadPixels(0, 256, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[4].create(buffer, 256, 256);
|
||||
|
||||
glReadPixels(256, 256, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[5].create(buffer, 256, 256);
|
||||
|
||||
glReadPixels(512, 256, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[6].create(buffer, 128, 128);
|
||||
|
||||
glReadPixels(512, 384, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
_specialty[7].create(buffer, 128, 128);
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void GfxOpenGLS::createEMIModel(EMIModel *model) {
|
||||
EMIModelUserData *mud = new EMIModelUserData;
|
||||
model->_userData = mud;
|
||||
|
@ -1977,6 +1914,34 @@ void GfxOpenGLS::destroyMesh(const Mesh *mesh) {
|
|||
delete mud;
|
||||
}
|
||||
|
||||
static void readPixels(int x, int y, int width, int height, char *buffer) {
|
||||
char *p = buffer;
|
||||
for (int i = y; i < y + height; i++) {
|
||||
glReadPixels(x, 479 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
|
||||
p += width * 4;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
|
||||
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
||||
if (useStored) {
|
||||
glBindTexture(GL_TEXTURE_2D, _storedDisplay);
|
||||
char *buffer = new char[_screenWidth * _screenHeight * 4];
|
||||
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
memcpy(src.getRawBuffer(), buffer, _screenWidth * _screenHeight * 4);
|
||||
|
||||
delete[] buffer;
|
||||
} else {
|
||||
readPixels(0, 0, _screenWidth, _screenHeight, reinterpret_cast<char *>(src.getRawBuffer()));
|
||||
}
|
||||
return createScreenshotBitmap(src, w, h, false);
|
||||
}
|
||||
|
||||
void GfxOpenGLS::createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) {
|
||||
readPixels(x, y, width, height, data);
|
||||
createSpecialtyTexture(id, data, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ public:
|
|||
virtual void drawTextObject(const TextObject *text) override;
|
||||
virtual void destroyTextObject(TextObject *text) override;
|
||||
|
||||
virtual Bitmap *getScreenshot(int w, int h) override;
|
||||
virtual Bitmap *getScreenshot(int w, int h, bool useStored) override;
|
||||
virtual void storeDisplay() override;
|
||||
virtual void copyStoredToDisplay() override;
|
||||
|
||||
|
@ -198,8 +198,6 @@ public:
|
|||
virtual void renderBitmaps(bool render) override;
|
||||
virtual void renderZBitmaps(bool render) override;
|
||||
|
||||
virtual void createSpecialtyTextures() override;
|
||||
|
||||
virtual void createMesh(Mesh *mesh) override;
|
||||
virtual void destroyMesh(const Mesh *mesh) override;
|
||||
virtual void createEMIModel(EMIModel *model) override;
|
||||
|
@ -209,6 +207,7 @@ protected:
|
|||
void setupShaders();
|
||||
GLuint compileShader(const char *vertex, const char *fragment);
|
||||
GLuint compileShader(const char *shader) { return compileShader(shader, shader); }
|
||||
void createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) override;
|
||||
|
||||
private:
|
||||
const Actor *_currentActor;
|
||||
|
|
|
@ -1437,33 +1437,19 @@ void GfxTinyGL::drawEmergString(int x, int y, const char *text, const Color &fgC
|
|||
}
|
||||
}
|
||||
|
||||
Bitmap *GfxTinyGL::getScreenshot(int w, int h) {
|
||||
Graphics::PixelBuffer buffer = Graphics::PixelBuffer::createBuffer<565>(w * h, DisposeAfterUse::YES);
|
||||
|
||||
int i1 = (_gameWidth * w - 1) / _gameWidth + 1;
|
||||
int j1 = (_gameHeight * h - 1) / _gameHeight + 1;
|
||||
|
||||
for (int j = 0; j < j1; j++) {
|
||||
for (int i = 0; i < i1; i++) {
|
||||
int x0 = i * _gameWidth / w;
|
||||
int x1 = ((i + 1) * _gameWidth - 1) / w + 1;
|
||||
int y0 = j * _gameHeight / h;
|
||||
int y1 = ((j + 1) * _gameHeight - 1) / h + 1;
|
||||
uint32 color = 0;
|
||||
for (int y = y0; y < y1; y++) {
|
||||
for (int x = x0; x < x1; x++) {
|
||||
uint8 lr, lg, lb;
|
||||
_zb->readPixelRGB(y * _gameWidth + x, lr, lg, lb);
|
||||
color += (lr + lg + lb) / 3;
|
||||
}
|
||||
}
|
||||
color /= (x1 - x0) * (y1 - y0);
|
||||
buffer.setPixelAt(j * w + i, color, color, color);
|
||||
Bitmap *GfxTinyGL::getScreenshot(int w, int h, bool useStored) {
|
||||
if (useStored) {
|
||||
return createScreenshotBitmap(_storedDisplay, w, h, true);
|
||||
} else {
|
||||
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
||||
_zb->copyToBuffer(src);
|
||||
return createScreenshotBitmap(src, w, h, true);
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *screenshot = new Bitmap(buffer, w, h, "screenshot");
|
||||
return screenshot;
|
||||
void GfxTinyGL::createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height) {
|
||||
readPixels(x, y, width, height, (uint8*)data);
|
||||
createSpecialtyTexture(id, data, width, height);
|
||||
}
|
||||
|
||||
void GfxTinyGL::storeDisplay() {
|
||||
|
@ -1612,35 +1598,4 @@ void GfxTinyGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
|
|||
}
|
||||
}
|
||||
|
||||
void GfxTinyGL::createSpecialtyTextures() {
|
||||
//make a buffer big enough to hold any of the textures
|
||||
uint8 *buffer = new uint8[256 * 256 * 4];
|
||||
|
||||
readPixels(0, 0, 256, 256, buffer);
|
||||
_specialty[0].create((const char *)buffer, 256, 256);
|
||||
|
||||
readPixels(256, 0, 256, 256, buffer);
|
||||
_specialty[1].create((const char *)buffer, 256, 256);
|
||||
|
||||
readPixels(512, 0, 128, 128, buffer);
|
||||
_specialty[2].create((const char *)buffer, 128, 128);
|
||||
|
||||
readPixels(512, 128, 128, 128, buffer);
|
||||
_specialty[3].create((const char *)buffer, 128, 128);
|
||||
|
||||
readPixels(0, 256, 256, 224, buffer);
|
||||
_specialty[4].create((const char *)buffer, 256, 256);
|
||||
|
||||
readPixels(256, 256, 256, 224, buffer);
|
||||
_specialty[5].create((const char *)buffer, 256, 256);
|
||||
|
||||
readPixels(512, 256, 128, 128, buffer);
|
||||
_specialty[6].create((const char *)buffer, 128, 128);
|
||||
|
||||
readPixels(512, 384, 128, 96, buffer);
|
||||
_specialty[7].create((const char *)buffer, 128, 128);
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
void dimRegion(int x, int y, int w, int h, float level) override;
|
||||
void irisAroundRegion(int x1, int y1, int x2, int y2) override;
|
||||
|
||||
Bitmap *getScreenshot(int w, int h) override;
|
||||
Bitmap *getScreenshot(int w, int h, bool useStored) override;
|
||||
void storeDisplay() override;
|
||||
void copyStoredToDisplay() override;
|
||||
|
||||
|
@ -123,8 +123,6 @@ public:
|
|||
void drawMovieFrame(int offsetX, int offsetY) override;
|
||||
void releaseMovieFrame() override;
|
||||
|
||||
void createSpecialtyTextures() override;
|
||||
|
||||
int genBuffer() override;
|
||||
void delBuffer(int buffer) override;
|
||||
void selectBuffer(int buffer) override;
|
||||
|
@ -133,6 +131,7 @@ public:
|
|||
void refreshBuffers() override;
|
||||
|
||||
protected:
|
||||
void createSpecialtyTextureFromScreen(unsigned int id, char *data, int x, int y, int width, int height);
|
||||
|
||||
private:
|
||||
TinyGL::FrameBuffer *_zb;
|
||||
|
|
|
@ -946,7 +946,7 @@ void GrimEngine::storeSaveGameImage(SaveGame *state) {
|
|||
g_grim->setMode(_previousMode);
|
||||
g_grim->updateDisplayScene();
|
||||
g_driver->storeDisplay();
|
||||
screenshot = g_driver->getScreenshot(width, height);
|
||||
screenshot = g_driver->getScreenshot(width, height, false);
|
||||
g_grim->setMode(mode);
|
||||
state->beginSection('SIMG');
|
||||
if (screenshot) {
|
||||
|
|
|
@ -212,7 +212,7 @@ protected:
|
|||
void savegameRestore();
|
||||
void restoreGRIM();
|
||||
|
||||
void storeSaveGameImage(SaveGame *savedState);
|
||||
virtual void storeSaveGameImage(SaveGame *savedState);
|
||||
|
||||
bool _savegameLoadRequest;
|
||||
bool _savegameSaveRequest;
|
||||
|
|
|
@ -456,7 +456,7 @@ void Lua_V1::ScreenShot() {
|
|||
GrimEngine::EngineMode mode = g_grim->getMode();
|
||||
g_grim->setMode(GrimEngine::NormalMode);
|
||||
g_grim->updateDisplayScene();
|
||||
Bitmap *screenshot = g_driver->getScreenshot(width, height);
|
||||
Bitmap *screenshot = g_driver->getScreenshot(width, height, false);
|
||||
g_grim->setMode(mode);
|
||||
if (screenshot) {
|
||||
lua_pushusertag(screenshot->getId(), MKTAG('V','B','U','F'));
|
||||
|
|
|
@ -54,7 +54,7 @@ void MaterialData::initGrim(Common::SeekableReadStream *data) {
|
|||
|
||||
data->seek(12, SEEK_SET);
|
||||
_numImages = data->readUint32LE();
|
||||
_textures = new Texture[_numImages];
|
||||
_textures = new Texture*[_numImages];
|
||||
/* Discovered by diffing orange.mat with pink.mat and blue.mat .
|
||||
* Actual meaning unknown, so I prefer to use it as an enum-ish
|
||||
* at the moment, to detect unexpected values.
|
||||
|
@ -68,7 +68,7 @@ void MaterialData::initGrim(Common::SeekableReadStream *data) {
|
|||
|
||||
data->seek(60 + _numImages * 40 + offset, SEEK_SET);
|
||||
for (int i = 0; i < _numImages; ++i) {
|
||||
Texture *t = _textures + i;
|
||||
Texture *t = _textures[i] = new Texture();
|
||||
t->_width = data->readUint32LE();
|
||||
t->_height = data->readUint32LE();
|
||||
t->_hasAlpha = data->readUint32LE();
|
||||
|
@ -118,9 +118,9 @@ void loadTGA(Common::SeekableReadStream *data, Texture *t) {
|
|||
}
|
||||
|
||||
void MaterialData::initEMI(Common::SeekableReadStream *data) {
|
||||
Common::Array<Common::String> texFileNames;
|
||||
|
||||
if (_fname.hasSuffix(".sur")) { // This expects that we want all the materials in the sur-file
|
||||
Common::Array<Common::String> texFileNames;
|
||||
char readFileName[64];
|
||||
TextSplitter *ts = new TextSplitter(_fname, data);
|
||||
ts->setLineNumber(2); // Skip copyright-line
|
||||
|
@ -133,30 +133,39 @@ void MaterialData::initEMI(Common::SeekableReadStream *data) {
|
|||
Common::String mFileName(readFileName);
|
||||
texFileNames.push_back(ResourceLoader::fixFilename(mFileName, false));
|
||||
}
|
||||
_textures = new Texture[texFileNames.size()];
|
||||
_textures = new Texture*[texFileNames.size()];
|
||||
for (uint i = 0; i < texFileNames.size(); i++) {
|
||||
Common::String name = texFileNames[i];
|
||||
if (name.hasPrefix("specialty")) {
|
||||
_textures[i] = g_driver->getSpecialtyTexturePtr(name);
|
||||
} else {
|
||||
_textures[i] = new Texture();
|
||||
Common::SeekableReadStream *texData = g_resourceloader->openNewStreamFile(texFileNames[i].c_str(), true);
|
||||
if (!texData) {
|
||||
warning("Couldn't find tex-file: %s", texFileNames[i].c_str());
|
||||
_textures[i]._width = 0;
|
||||
_textures[i]._height = 0;
|
||||
_textures[i]._texture = new int(1); // HACK to avoid initializing.
|
||||
_textures[i]._data = nullptr;
|
||||
_textures[i]->_width = 0;
|
||||
_textures[i]->_height = 0;
|
||||
_textures[i]->_texture = new int(1); // HACK to avoid initializing.
|
||||
_textures[i]->_data = nullptr;
|
||||
continue;
|
||||
}
|
||||
loadTGA(texData, _textures + i);
|
||||
loadTGA(texData, _textures[i]);
|
||||
delete texData;
|
||||
}
|
||||
}
|
||||
_numImages = texFileNames.size();
|
||||
delete ts;
|
||||
return;
|
||||
} else if (_fname.hasSuffix(".tga")) {
|
||||
_numImages = 1;
|
||||
_textures = new Texture();
|
||||
loadTGA(data, _textures);
|
||||
// texFileNames.push_back(filename);
|
||||
_textures = new Texture*[1];
|
||||
_textures[0] = new Texture();
|
||||
loadTGA(data, _textures[0]);
|
||||
return;
|
||||
|
||||
} else if (_fname.hasPrefix("specialty")) {
|
||||
_numImages = 1;
|
||||
_textures = new Texture*[1];
|
||||
_textures[0] = g_driver->getSpecialtyTexturePtr(_fname);
|
||||
} else {
|
||||
warning("Unknown material-format: %s", _fname.c_str());
|
||||
}
|
||||
|
@ -170,10 +179,13 @@ MaterialData::~MaterialData() {
|
|||
}
|
||||
|
||||
for (int i = 0; i < _numImages; ++i) {
|
||||
Texture *t = _textures + i;
|
||||
Texture *t = _textures[i];
|
||||
if (!t) continue;
|
||||
if (t->_isShared) continue; // don't delete specialty textures
|
||||
if (t->_width && t->_height && t->_texture)
|
||||
g_driver->destroyTexture(t);
|
||||
delete[] t->_data;
|
||||
delete t;
|
||||
}
|
||||
delete[] _textures;
|
||||
}
|
||||
|
@ -225,14 +237,16 @@ void Material::reload(CMap *cmap) {
|
|||
}
|
||||
|
||||
void Material::select() const {
|
||||
Texture *t = _data->_textures + _currImage;
|
||||
if (t->_width && t->_height) {
|
||||
Texture *t = _data->_textures[_currImage];
|
||||
if (t && t->_width && t->_height) {
|
||||
if (!t->_texture) {
|
||||
g_driver->createTexture(t, t->_data, _data->_cmap, _clampTexture);
|
||||
delete[] t->_data;
|
||||
t->_data = nullptr;
|
||||
}
|
||||
g_driver->selectTexture(t);
|
||||
} else {
|
||||
warning("Can't select material: %s", getFilename().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ class CMap;
|
|||
|
||||
class Texture {
|
||||
public:
|
||||
Texture() :
|
||||
_width(0), _height(0), _colorFormat(0), _bpp(0), _hasAlpha(false), _texture(nullptr), _data(nullptr), _isShared(false) {};
|
||||
int _width;
|
||||
int _height;
|
||||
int _colorFormat;
|
||||
|
@ -38,6 +40,7 @@ public:
|
|||
bool _hasAlpha;
|
||||
void *_texture;
|
||||
char *_data;
|
||||
bool _isShared;
|
||||
};
|
||||
|
||||
class MaterialData {
|
||||
|
@ -51,7 +54,7 @@ public:
|
|||
Common::String _fname;
|
||||
const ObjectPtr<CMap> _cmap;
|
||||
int _numImages;
|
||||
Texture *_textures;
|
||||
Texture **_textures;
|
||||
int _refCount;
|
||||
|
||||
private:
|
||||
|
|
|
@ -407,7 +407,7 @@ Material *ResourceLoader::loadMaterial(const Common::String &filename, CMap *c,
|
|||
Common::SeekableReadStream *stream;
|
||||
|
||||
stream = openNewStreamFile(fname.c_str(), true);
|
||||
if (!stream) {
|
||||
if (!stream && !filename.hasPrefix("specialty")) {
|
||||
// FIXME: EMI demo references files that aren't included. Return a known material.
|
||||
// This should be fixed in the data files instead.
|
||||
if (g_grim->getGameType() == GType_MONKEY4 && g_grim->getGameFlags() & ADGF_DEMO) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue