Merge branch 'master' into tinygl-dirty-rects

Conflicts:
	graphics/tinygl/zbuffer.cpp
	graphics/tinygl/zbuffer.h
This commit is contained in:
Stefano Musumeci 2014-08-13 14:06:34 +02:00
commit 8abb5b008c
33 changed files with 283 additions and 136 deletions

View File

@ -97,9 +97,9 @@ Actor::Actor() :
_mustPlaceText(false),
_puckOrient(false), _talking(false),
_inOverworld(false), _drawnToClean(false), _backgroundTalk(false),
_sortOrder(0), _haveSectorSortOrder(false), _sectorSortOrder(0),
_cleanBuffer(0), _lightMode(LightFastDyn), _hasFollowedBoxes(false),
_lookAtActor(0) {
_sortOrder(0), _haveSectorSortOrder(false), _useParentSortOrder(false),
_sectorSortOrder(0), _cleanBuffer(0), _lightMode(LightFastDyn),
_hasFollowedBoxes(false), _lookAtActor(0) {
// Some actors don't set walk and turn rates, so we default the
// _turnRate so Doug at the cat races can turn and we set the
@ -247,6 +247,7 @@ void Actor::saveState(SaveGame *savedState) const {
savedState->writeBool(_inOverworld);
savedState->writeLESint32(_sortOrder);
savedState->writeBool(_useParentSortOrder);
savedState->writeLESint32(_attachedActor);
savedState->writeString(_attachedJoint);
@ -422,6 +423,9 @@ bool Actor::restoreState(SaveGame *savedState) {
_inOverworld = savedState->readBool();
_sortOrder = savedState->readLESint32();
if (savedState->saveMinorVersion() >= 22)
_useParentSortOrder = savedState->readBool();
if (savedState->saveMinorVersion() < 18)
savedState->readBool(); // Used to be _shadowActive.
@ -1436,7 +1440,7 @@ void Actor::update(uint frameTime) {
set->findClosestSector(_pos, nullptr, &_pos);
}
if (g_grim->getGameType() == GType_MONKEY4) {
if (_followBoxes && g_grim->getGameType() == GType_MONKEY4) {
// Check for sort order information in the current sector
int oldSortOrder = getEffectiveSortOrder();
@ -2266,16 +2270,22 @@ Math::Vector3d Actor::getHeadPos() const {
return getWorldPos();
}
void Actor::setSortOrder(const int order) {
_sortOrder = order;
// If this actor is attached to another actor, we'll use the
// explicitly specified sort order instead of the parent actor's
// sort order from now on.
if (_useParentSortOrder)
_useParentSortOrder = false;
}
int Actor::getSortOrder() const {
if (_attachedActor != 0) {
Actor *attachedActor = Actor::getPool().getObject(_attachedActor);
return attachedActor->getSortOrder();
}
return _sortOrder;
}
int Actor::getEffectiveSortOrder() const {
if (_attachedActor != 0) {
if (_useParentSortOrder && _attachedActor != 0) {
Actor *attachedActor = Actor::getPool().getObject(_attachedActor);
return attachedActor->getEffectiveSortOrder();
}
@ -2377,12 +2387,24 @@ void Actor::attachToActor(Actor *other, const char *joint) {
// Save the attachement info
_attachedActor = other->getId();
_attachedJoint = jointStr;
// Use the parent actor's sort order.
_useParentSortOrder = true;
}
void Actor::detach() {
if (!isAttached())
return;
// Replace our sort order with the parent actor's sort order. Note
// that we do this even if a sort order was explicitly specified for
// the actor during the time it was attached (in which case the actor
// doesn't respect the parent actor's sort order). This seems weird,
// but matches the behavior of the original engine.
Actor *attachedActor = Actor::getPool().getObject(_attachedActor);
_sortOrder = attachedActor->getEffectiveSortOrder();
_useParentSortOrder = false;
// FIXME: Use last known position of attached joint
Math::Vector3d oldPos = getWorldPos();
_attachedActor = 0;

View File

@ -540,7 +540,7 @@ public:
void setAlphaMode(AlphaMode mode) { _alphaMode = mode; }
int getSortOrder() const;
void setSortOrder(const int order) { _sortOrder = order; }
void setSortOrder(const int order);
int getEffectiveSortOrder() const;
void activateShadow(bool active, const char *shadowName);
@ -708,6 +708,7 @@ private:
int _sortOrder;
bool _haveSectorSortOrder;
int _sectorSortOrder;
bool _useParentSortOrder;
int _cleanBuffer;
bool _drawnToClean;

View File

@ -46,6 +46,7 @@ void Debug::registerDebugChannels() {
DebugMan.addDebugChannel(TextObjects, "textobjects", "");
DebugMan.addDebugChannel(Patchr, "patchr", "");
DebugMan.addDebugChannel(Lipsync, "lipsync", "");
DebugMan.addDebugChannel(Sprites, "sprites", "");
}
bool Debug::isChannelEnabled(DebugChannel chan) {

View File

@ -50,7 +50,8 @@ public:
Sets = 2 << 15,
TextObjects = 2 << 16,
Patchr = 2 << 17,
Lipsync = 2 << 18
Lipsync = 2 << 18,
Sprites = 2 << 19
};
static void registerDebugChannels();

View File

@ -100,7 +100,7 @@ Bone::~Bone() {
AnimationStateEmi::AnimationStateEmi(const Common::String &anim) :
_skel(nullptr), _looping(false), _active(false),
_fadeMode(Animation::None), _fade(1.0f), _fadeLength(0), _time(0.0f), _startFade(1.0f),
_fadeMode(Animation::None), _fade(1.0f), _fadeLength(0), _time(0), _startFade(1.0f),
_boneJoints(nullptr) {
_anim = g_resourceloader->getAnimationEmi(anim);
if (_anim)
@ -138,9 +138,10 @@ void AnimationStateEmi::update(uint time) {
}
if (!_paused) {
if (_time > _anim->_duration) {
uint durationMs = (uint)_anim->_duration;
if (_time >= durationMs) {
if (_looping) {
_time = 0.0f;
_time = _time % durationMs;
} else {
if (_fadeMode != Animation::FadeOut)
deactivate();
@ -284,7 +285,7 @@ void AnimationStateEmi::animate() {
void AnimationStateEmi::play() {
if (!_active) {
_time = 0.f;
_time = 0;
if (_fadeMode == Animation::FadeOut)
_fadeMode = Animation::None;
if (_fadeMode == Animation::FadeIn || _fade > 0.f)
@ -295,7 +296,7 @@ void AnimationStateEmi::play() {
void AnimationStateEmi::stop() {
_fadeMode = Animation::None;
_time = 0.f;
_time = 0;
deactivate();
}
@ -342,7 +343,7 @@ void AnimationStateEmi::saveState(SaveGame *state) {
state->writeBool(_looping);
state->writeBool(_active);
state->writeBool(_paused);
state->writeFloat(_time);
state->writeLEUint32(_time);
state->writeFloat(_fade);
state->writeFloat(_startFade);
state->writeLESint32((int)_fadeMode);
@ -354,7 +355,11 @@ void AnimationStateEmi::restoreState(SaveGame *state) {
_looping = state->readBool();
bool active = state->readBool();
_paused = state->readBool();
_time = state->readFloat();
if (state->saveMinorVersion() < 22) {
_time = (uint)state->readFloat();
} else {
_time = state->readLEUint32();
}
_fade = state->readFloat();
_startFade = state->readFloat();
_fadeMode = (Animation::FadeMode)state->readLESint32();

View File

@ -99,7 +99,7 @@ private:
bool _looping;
bool _active;
bool _paused;
float _time;
uint _time;
float _fade;
float _startFade;
Animation::FadeMode _fadeMode;

View File

@ -48,9 +48,6 @@ void EMISpriteComponent::reset() {
}
void EMISpriteComponent::draw() {
// HACK: don't draw _masks for now.
if (_name.contains("_mask"))
return;
if (_sprite) {
_sprite->draw();
}

View File

@ -271,7 +271,13 @@ void EMIEngine::sortTextObjects() {
bool EMIEngine::compareActor(const Actor *x, const Actor *y) {
if (x->getEffectiveSortOrder() == y->getEffectiveSortOrder()) {
return x->getId() < y->getId();
float xDist = (g_grim->getCurrSet()->getCurrSetup()->_pos - x->getWorldPos()).getSquareMagnitude();
float yDist = (g_grim->getCurrSet()->getCurrSetup()->_pos - y->getWorldPos()).getSquareMagnitude();
if (fabs(xDist - yDist) < 0.001f) {
return x->getId() < y->getId();
} else {
return xDist > yDist;
}
}
return x->getEffectiveSortOrder() > y->getEffectiveSortOrder();
}

View File

@ -130,6 +130,8 @@ protected:
DECLARE_LUA_OPCODE(ImStateHasEnded);
DECLARE_LUA_OPCODE(ImPushState);
DECLARE_LUA_OPCODE(ImPopState);
DECLARE_LUA_OPCODE(ImPause);
DECLARE_LUA_OPCODE(ImResume);
DECLARE_LUA_OPCODE(GetSectorName);
DECLARE_LUA_OPCODE(GetCameraPosition);
DECLARE_LUA_OPCODE(GetCameraYaw);

View File

@ -421,7 +421,7 @@ void Lua_V2::GetActorSortOrder() {
return;
Actor *actor = getactor(actorObj);
lua_pushnumber(actor->getSortOrder());
lua_pushnumber(actor->getEffectiveSortOrder());
}
void Lua_V2::ActorActivateShadow() {

View File

@ -573,4 +573,14 @@ void Lua_V2::ImPopState() {
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImPopState: currently guesswork");
}
// Used in the demo only.
void Lua_V2::ImPause() {
g_emiSound->pause(true);
}
// Used in the demo only.
void Lua_V2::ImResume() {
g_emiSound->pause(false);
}
} // end of namespace Grim

View File

@ -92,8 +92,10 @@ EMIMeshFace::~EMIMeshFace() {
}
void EMIModel::setTex(uint32 index) {
if (index < _numTextures && _mats[index])
if (index < _numTextures && _mats[index]) {
_mats[index]->select();
g_driver->setBlendMode(_texFlags[index] & BlendAdditive);
}
}
void EMIModel::loadMesh(Common::SeekableReadStream *data) {
@ -114,12 +116,14 @@ void EMIModel::loadMesh(Common::SeekableReadStream *data) {
_numTextures = data->readUint32LE();
_texNames = new Common::String[_numTextures];
_texFlags = new uint32[_numTextures];
for (uint32 i = 0; i < _numTextures; i++) {
_texNames[i] = readLAString(data);
// Every texname seems to be followed by 4 0-bytes (Ref mk1.mesh,
// this is intentional)
data->skip(4);
_texFlags[i] = data->readUint32LE();
if (_texFlags[i] & ~(BlendAdditive)) {
Debug::debug(Debug::Models, "Model %s has unknown flags (%d) for texture %s", nameString.c_str(), _texFlags[i], _texNames[i].c_str());
}
}
prepareTextures();
@ -292,14 +296,21 @@ void EMIModel::draw() {
_lightingDirty = false;
}
}
} else {
if (actor->getLightMode() == Actor::LightNone) {
g_driver->disableLights();
}
}
// We will need to add a call to the skeleton, to get the modified vertices, but for now,
// I'll be happy with just static drawing
for (uint32 i = 0; i < _numFaces; i++) {
setTex(_faces[i]._texID);
g_driver->drawEMIModelFace(this, &_faces[i]);
}
if (g_driver->supportsShaders() && actor->getLightMode() == Actor::LightNone) {
g_driver->enableLights();
}
}
void EMIModel::updateLighting(const Math::Matrix4 &modelToWorld) {
@ -438,6 +449,7 @@ EMIModel::EMIModel(const Common::String &filename, Common::SeekableReadStream *d
_boneNames = nullptr;
_lighting = nullptr;
_lightingDirty = true;
_texFlags = nullptr;
loadMesh(data);
g_driver->createEMIModel(this);
@ -457,6 +469,7 @@ EMIModel::~EMIModel() {
delete[] _vertexBoneInfo;
delete[] _boneNames;
delete[] _lighting;
delete[] _texFlags;
delete _center;
delete _boxData;
delete _boxData2;

View File

@ -62,6 +62,10 @@ public:
uint32 _flags;
EMIModel *_parent;
enum MeshFaceFlags {
kAlphaBlend = 0x10000
};
EMIMeshFace() : _faceLength(0), _numFaces(0), _hasTexture(0), _texID(0), _flags(0), _indexes(NULL), _parent(NULL), _indicesEBO(0) { }
~EMIMeshFace();
void loadFace(Common::SeekableReadStream *data);
@ -74,6 +78,11 @@ public:
*/
class EMIModel : public Object {
public:
enum TextureFlags {
BlendAdditive = 0x400
// There are more flags, but their purpose is currently unknown.
};
int _numVertices;
Math::Vector3d *_vertices;
Math::Vector3d *_drawVertices;
@ -87,6 +96,7 @@ public:
EMIMeshFace *_faces;
uint32 _numTextures;
Common::String *_texNames;
uint32 *_texFlags;
Material **_mats;
Skeleton *_skeleton;

View File

@ -184,6 +184,7 @@ void EMISound::timerHandler(void *refCon) {
EMISound::EMISound(int fps) {
_curMusicState = -1;
_numMusicStates = 0;
_musicTrack = nullptr;
_curTrackId = 0;
_callbackFps = fps;
@ -396,7 +397,7 @@ SoundTrack *EMISound::initTrack(const Common::String &soundName, Audio::Mixer::S
soundNameLower.toLowercase();
if (soundNameLower.hasSuffix(".scx")) {
track = new SCXTrack(soundType);
} else if (soundNameLower.hasSuffix(".m4b")) {
} else if (soundNameLower.hasSuffix(".m4b") || soundNameLower.hasSuffix(".lab")) {
track = new MP3Track(soundType);
} else if (soundNameLower.hasSuffix(".aif")) {
track = new AIFFTrack(soundType);
@ -439,6 +440,10 @@ bool EMISound::stateHasEnded(int stateId) {
void EMISound::setMusicState(int stateId) {
Common::StackLock lock(_mutex);
// The demo calls ImSetState with state id 1000, which exceeds the number of states in the
// music table.
if (stateId >= _numMusicStates)
stateId = 0;
if (stateId == _curMusicState)
return;
@ -519,13 +524,14 @@ uint32 EMISound::getMsPos(int stateId) {
return _musicTrack->getPos().msecs();
}
MusicEntry *initMusicTableDemo(const Common::String &filename) {
MusicEntry *EMISound::initMusicTableDemo(const Common::String &filename) {
Common::SeekableReadStream *data = g_resourceloader->openNewStreamFile(filename);
if (!data)
error("Couldn't open %s", filename.c_str());
// FIXME, for now we use a fixed-size table, as I haven't looked at the retail-data yet.
MusicEntry *musicTable = new MusicEntry[15];
_numMusicStates = 15;
MusicEntry *musicTable = new MusicEntry[_numMusicStates];
for (int i = 0; i < 15; ++i) {
musicTable->_x = 0;
musicTable->_y = 0;
@ -559,7 +565,7 @@ MusicEntry *initMusicTableDemo(const Common::String &filename) {
return musicTable;
}
MusicEntry *initMusicTableRetail(MusicEntry *table, const Common::String &filename) {
MusicEntry *EMISound::initMusicTableRetail(MusicEntry *table, const Common::String &filename) {
Common::SeekableReadStream *data = g_resourceloader->openNewStreamFile(filename);
// Remember to check, in case we forgot to copy over those files from the CDs.
@ -571,14 +577,15 @@ MusicEntry *initMusicTableRetail(MusicEntry *table, const Common::String &filena
MusicEntry *musicTable = table;
if (!table) {
musicTable = new MusicEntry[126];
}
for (int i = 0; i < 126; ++i) {
musicTable->_x = 0;
musicTable->_y = 0;
musicTable->_sync = 0;
musicTable->_trim = 0;
musicTable->_id = i;
_numMusicStates = 126;
musicTable = new MusicEntry[_numMusicStates];
for (int i = 0; i < 126; ++i) {
musicTable->_x = 0;
musicTable->_y = 0;
musicTable->_sync = 0;
musicTable->_trim = 0;
musicTable->_id = i;
}
}
TextSplitter *ts = new TextSplitter(filename, data);
@ -629,6 +636,7 @@ void EMISound::initMusicTable() {
_musicPrefix = "Music/";
} else if (g_grim->getGamePlatform() == Common::kPlatformPS2) {
_musicTable = emiPS2MusicTable;
_numMusicStates = ARRAYSIZE(emiPS2MusicTable);
_musicPrefix = "";
} else {
_musicTable = nullptr;

View File

@ -107,6 +107,7 @@ private:
TrackMap _preloadedTrackMap;
int _curMusicState;
int _numMusicStates;
int _callbackFps;
int _curTrackId;
@ -125,6 +126,8 @@ private:
bool startSound(const Common::String &soundName, Audio::Mixer::SoundType soundType, int volume, int pan);
void saveTrack(SoundTrack *track, SaveGame *savedState);
SoundTrack *restoreTrack(SaveGame *savedState);
MusicEntry *initMusicTableDemo(const Common::String &filename);
MusicEntry *initMusicTableRetail(MusicEntry *table, const Common::String &filename);
};
extern EMISound *g_emiSound;

View File

@ -34,6 +34,7 @@ namespace Grim {
SCXTrack::SCXTrack(Audio::Mixer::SoundType soundType) {
_disposeAfterPlaying = DisposeAfterUse::NO;
_soundType = soundType;
_looping = false;
}
SCXTrack::~SCXTrack() {

View File

@ -279,6 +279,8 @@ public:
static Math::Matrix4 makeProjMatrix(float fov, float nclip, float fclip);
Texture *getSpecialtyTexturePtr(uint id) { if (id >= _numSpecialtyTextures) return nullptr; return &_specialtyTextures[id]; };
Texture *getSpecialtyTexturePtr(Common::String name);
virtual void setBlendMode(bool additive) = 0;
protected:
Bitmap *createScreenshotBitmap(const Graphics::PixelBuffer src, int w, int h, bool flipOrientation);
static const unsigned int _numSpecialtyTextures = 22;

View File

@ -634,11 +634,6 @@ void GfxOpenGL::startActorDraw(const Actor *actor) {
glScalef(scale, scale, scale);
glMultMatrixf(quat.toMatrix().getData());
}
if (!_currentShadowArray && actor->getSortOrder() >= 100) {
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_TRUE);
}
}
void GfxOpenGL::finishActorDraw() {
@ -760,6 +755,8 @@ void GfxOpenGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face)
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
if (face->_flags & EMIMeshFace::kAlphaBlend)
glEnable(GL_BLEND);
glBegin(GL_TRIANGLES);
float dim = 1.0f - _dimLevel;
@ -835,7 +832,7 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
act(3, 1) = modelview[13];
act(3, 2) = modelview[14];
glLoadMatrixf(act.getData());
glTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
glTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
} else {
glTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
GLdouble modelview[16];
@ -854,7 +851,7 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
glLoadMatrixd(modelview);
}
if (sprite->_blendMode == Sprite::BlendAdditive) {
if (sprite->_flags1 & Sprite::BlendAdditive) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} else {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -862,35 +859,27 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
glDisable(GL_LIGHTING);
if (sprite->_alphaTest) {
if (sprite->_flags2 & Sprite::AlphaTest) {
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GEQUAL, g_grim->getGameType() == GType_MONKEY4 ? 0.1f : 0.5f);
} else {
glDisable(GL_ALPHA_TEST);
}
if (sprite->_writeDepth) {
if (sprite->_flags2 & Sprite::DepthTest) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
if (g_grim->getGameType() == GType_MONKEY4) {
if (_currentActor->isInOverworld()) {
// The Overworld actors don't have a proper sort order
// so we rely on the z coordinates
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
glDepthMask(GL_TRUE);
float halfWidth = sprite->_width / 2;
float halfHeight = sprite->_height / 2;
float dim = 1.0f - _dimLevel;
float texCoordsX[] = { 0.0f, 0.0f, 1.0f, 1.0f };
float texCoordsY[] = { 1.0f, 0.0f, 0.0f, 1.0f };
float vertexX[] = { -1.0f, -1.0f, 1.0f, 1.0f };
float vertexY[] = { -1.0f, 1.0f, 1.0f, -1.0f };
float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
glBegin(GL_POLYGON);
for (int i = 0; i < 4; ++i) {
@ -900,7 +889,7 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
float a = sprite->_alpha[i] * dim * _alpha / 255.0f;
glColor4f(r, g, b, a);
glTexCoord2f(texCoordsX[i], texCoordsY[i]);
glTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
glVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
}
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
@ -1151,6 +1140,7 @@ void GfxOpenGL::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
@ -2048,6 +2038,14 @@ void GfxOpenGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, in
createSpecialtyTexture(id, data, width, height);
}
void GfxOpenGL::setBlendMode(bool additive) {
if (additive) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} else {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
} // end of namespace Grim
#endif

View File

@ -125,6 +125,8 @@ public:
void drawMovieFrame(int offsetX, int offsetY) override;
void releaseMovieFrame() override;
void setBlendMode(bool additive) override;
protected:
void createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) override;
void drawDepthBitmap(int x, int y, int w, int h, char *data);

View File

@ -907,6 +907,8 @@ void GfxOpenGLS::updateEMIModel(const EMIModel* model) {
}
void GfxOpenGLS::drawEMIModelFace(const EMIModel* model, const EMIMeshFace* face) {
if (face->_flags & EMIMeshFace::kAlphaBlend)
glEnable(GL_BLEND);
const EMIModelUserData *mud = (const EMIModelUserData *)model->_userData;
mud->_shader->use();
bool textured = face->_hasTexture && !_currentShadowArray;
@ -962,9 +964,13 @@ void GfxOpenGLS::drawModelFace(const Mesh *mesh, const MeshFace *face) {
}
void GfxOpenGLS::drawSprite(const Sprite *sprite) {
glDepthMask(GL_FALSE);
if (g_grim->getGameType() == GType_MONKEY4) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
if (sprite->_blendMode == Sprite::BlendAdditive) {
if (sprite->_flags1 & Sprite::BlendAdditive) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} else {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -972,7 +978,7 @@ void GfxOpenGLS::drawSprite(const Sprite *sprite) {
// FIXME: depth test does not work yet because final z coordinates
// for Sprites and actor textures are inconsistently calculated
if (sprite->_writeDepth || _currentActor->isInOverworld()) {
if (sprite->_flags2 & Sprite::DepthTest || _currentActor->isInOverworld()) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
@ -988,16 +994,16 @@ void GfxOpenGLS::drawSprite(const Sprite *sprite) {
extraMatrix(0, 0) = sprite->_width;
extraMatrix(1, 1) = sprite->_height;
extraMatrix = extraMatrix * rotateMatrix;
extraMatrix = rotateMatrix * extraMatrix;
extraMatrix.transpose();
_spriteProgram->setUniform("extraMatrix", extraMatrix);
_spriteProgram->setUniform("textured", GL_TRUE);
_spriteProgram->setUniform("isBillboard", GL_TRUE);
_spriteProgram->setUniform("lightsEnabled", false);
if (sprite->_alphaTest) {
_spriteProgram->setUniform("alphaRef", g_grim->getGameType() == GType_MONKEY4 ? 0.1f : 0.5f);
if (sprite->_flags2 & Sprite::AlphaTest) {
_spriteProgram->setUniform1f("alphaRef", g_grim->getGameType() == GType_MONKEY4 ? 0.1f : 0.5f);
} else {
_spriteProgram->setUniform("alphaRef", 0.0f);
_spriteProgram->setUniform1f("alphaRef", 0.0f);
}
// FIXME: Currently vertex-specific colors are not supported for sprites.
@ -2020,6 +2026,14 @@ void GfxOpenGLS::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, i
createSpecialtyTexture(id, data, width, height);
}
void GfxOpenGLS::setBlendMode(bool additive) {
if (additive) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} else {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
}
#endif

View File

@ -205,6 +205,8 @@ public:
virtual void createEMIModel(EMIModel *model) override;
virtual void updateEMIModel(const EMIModel* model) override;
virtual void setBlendMode(bool additive) override;
protected:
void setupShaders();
GLuint compileShader(const char *vertex, const char *fragment);

View File

@ -568,11 +568,6 @@ void GfxTinyGL::startActorDraw(const Actor *actor) {
tglScalef(scale, scale, scale);
tglMultMatrixf(quat.toMatrix().getData());
}
if (!_currentShadowArray && actor->getSortOrder() >= 100) {
tglColorMask(TGL_FALSE, TGL_FALSE, TGL_FALSE, TGL_FALSE);
tglDepthMask(TGL_TRUE);
}
}
void GfxTinyGL::finishActorDraw() {
@ -681,6 +676,8 @@ void GfxTinyGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face)
tglEnable(TGL_TEXTURE_2D);
else
tglDisable(TGL_TEXTURE_2D);
if (face->_flags & EMIMeshFace::kAlphaBlend)
tglEnable(TGL_BLEND);
tglBegin(TGL_TRIANGLES);
float dim = 1.0f - _dimLevel;
@ -751,7 +748,7 @@ void GfxTinyGL::drawSprite(const Sprite *sprite) {
act(3, 1) = modelview[13];
act(3, 2) = modelview[14];
tglLoadMatrixf(act.getData());
tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
} else {
tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
TGLfloat modelview[16];
@ -770,7 +767,7 @@ void GfxTinyGL::drawSprite(const Sprite *sprite) {
tglLoadMatrixf(modelview);
}
if (sprite->_blendMode == Sprite::BlendAdditive) {
if (sprite->_flags1 & Sprite::BlendAdditive) {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
} else {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
@ -778,35 +775,27 @@ void GfxTinyGL::drawSprite(const Sprite *sprite) {
tglDisable(TGL_LIGHTING);
if (sprite->_alphaTest) {
if (sprite->_flags2 & Sprite::AlphaTest) {
tglEnable(TGL_ALPHA_TEST);
tglAlphaFunc(TGL_GEQUAL, g_grim->getGameType() == GType_MONKEY4 ? 0.1f : 0.5f);
} else {
tglDisable(TGL_ALPHA_TEST);
}
if (sprite->_writeDepth) {
if (sprite->_flags2 & Sprite::DepthTest) {
tglEnable(TGL_DEPTH_TEST);
} else {
tglDisable(TGL_DEPTH_TEST);
}
if (g_grim->getGameType() == GType_MONKEY4) {
if (_currentActor->isInOverworld()) {
// The Overworld actors don't have a proper sort order
// so we rely on the z coordinates
tglDepthMask(TGL_TRUE);
} else {
tglDepthMask(TGL_FALSE);
}
tglDepthMask(TGL_TRUE);
float halfWidth = sprite->_width / 2;
float halfHeight = sprite->_height / 2;
float dim = 1.0f - _dimLevel;
float texCoordsX[] = { 0.0f, 0.0f, 1.0f, 1.0f };
float texCoordsY[] = { 1.0f, 0.0f, 0.0f, 1.0f };
float vertexX[] = { -1.0f, -1.0f, 1.0f, 1.0f };
float vertexY[] = { -1.0f, 1.0f, 1.0f, -1.0f };
float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
tglBegin(TGL_POLYGON);
for (int i = 0; i < 4; ++i) {
@ -816,11 +805,11 @@ void GfxTinyGL::drawSprite(const Sprite *sprite) {
float a = sprite->_alpha[i] * dim * _alpha / 255.0f;
tglColor4f(r, g, b, a);
tglTexCoord2f(texCoordsX[i], texCoordsY[i]);
tglTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
tglVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
}
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
tglEnd();
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
} else {
// In Grim, the bottom edge of the sprite is at y=0 and
// the texture is flipped along the X-axis.
@ -1454,4 +1443,12 @@ void GfxTinyGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
}
}
void GfxTinyGL::setBlendMode(bool additive) {
if (additive) {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
} else {
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
}
}
} // end of namespace Grim

View File

@ -131,6 +131,8 @@ public:
void drawBuffers() override;
void refreshBuffers() override;
void setBlendMode(bool additive) override;
protected:
void createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height);

View File

@ -1278,7 +1278,8 @@ void GrimEngine::openMainMenuDialog() {
void GrimEngine::pauseEngineIntern(bool pause) {
if (g_imuse)
g_imuse->pause(pause);
g_movie->pause(pause);
if (g_movie)
g_movie->pause(pause);
if (pause) {
_pauseStartTime = _system->getMillis();

View File

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

View File

@ -206,7 +206,7 @@ void Set::loadBinary(Common::SeekableReadStream *data) {
_shadows = new SetShadow[_numShadows];
for (int i = 0; i < _numShadows; ++i) {
_shadows[i].loadBinary(data);
_shadows[i].loadBinary(data, this);
}
// Enable lights by default
@ -593,23 +593,29 @@ bool Light::restoreState(SaveGame *savedState) {
SetShadow::SetShadow() : _numSectors(0) {
}
void SetShadow::loadBinary(Common::SeekableReadStream *data) {
void SetShadow::loadBinary(Common::SeekableReadStream *data, Set *set) {
uint32 nameLen = data->readUint32LE();
char *name = new char[nameLen];
data->read(name, nameLen);
_name = Common::String(name);
int numUnknownBytes = data->readSint32LE();
// The following bytes seem to be always 0. Perhaps padding of some sort?
for (int i = 0; i < numUnknownBytes; ++i) {
byte value = data->readByte();
assert(value == 0);
}
int lightNameLen = data->readSint32LE();
char *lightName = new char[lightNameLen];
data->read(lightName, lightNameLen);
char v[sizeof(float) * 3];
data->read(v, sizeof(float) * 3);
_shadowPoint = Math::Vector3d::getVector3d(v);
if (lightNameLen > 0) {
for (Common::List<Light *>::const_iterator it = set->getLights().begin(); it != set->getLights().end(); ++it) {
if ((*it)->_name.equals(lightName)) {
_shadowPoint = (*it)->_pos;
break;
}
}
}
int numSectors = data->readSint32LE();
for (int i = 0; i < numSectors; ++i) {
uint32 sectorNameLen = data->readUint32LE();

View File

@ -195,7 +195,7 @@ struct Light {
*/
struct SetShadow {
SetShadow();
void loadBinary(Common::SeekableReadStream *data);
void loadBinary(Common::SeekableReadStream *data, Set *set);
void saveState(SaveGame *savedState) const;
void restoreState(SaveGame *savedState);

View File

@ -22,6 +22,7 @@
#include "common/endian.h"
#include "engines/grim/debug.h"
#include "engines/grim/sprite.h"
#include "engines/grim/resource.h"
#include "engines/grim/gfx_base.h"
@ -31,8 +32,8 @@
namespace Grim {
Sprite::Sprite() :
_width(0), _height(0), _visible(false), _material(nullptr), _next(nullptr), _blendMode(BlendNormal),
_writeDepth(true), _alphaTest(true) {
_width(0), _height(0), _visible(false), _material(nullptr), _next(nullptr),
_flags1(0), _flags2(0) {
}
@ -65,41 +66,36 @@ void Sprite::loadBinary(Common::SeekableReadStream *stream, EMICostume *costume)
uint32 texnamelength = stream->readUint32LE();
char *texname = new char[texnamelength];
stream->read(texname, texnamelength);
stream->readByte(); // Unknown
byte blendMode = stream->readByte();
if (blendMode == 4)
_blendMode = BlendAdditive;
else if (blendMode != 0)
warning("Unknown blend mode value %d for sprite %s", blendMode, name);
stream->skip(2); // Unknown
float width, height;
float offX, offY;
char data[16];
_flags1 = stream->readUint32LE();
if (_flags1 & ~(BlendAdditive)) {
Debug::debug(Debug::Sprites, "Sprite %s has unknown flags (%d) in first flag field", name, _flags1);
}
char data[20];
stream->read(data, sizeof(data));
width = get_float(data);
height = get_float(data + 4);
offX = get_float(data + 8);
offY = get_float(data + 12);
stream->skip(4);//Unknown
_width = get_float(data);
_height = get_float(data + 4);
_pos = Math::Vector3d::getVector3d(data + 8);
for (int i = 0; i < 4; ++i) {
_alpha[i] = stream->readSint32LE();
_red[i] = stream->readSint32LE();
_green[i] = stream->readSint32LE();
_blue[i] = stream->readSint32LE();
}
stream->skip(8 * 4); // 8 floats (texcoords?)
stream->readByte(); // Unknown (seems to always be 4)
if (stream->readByte() == 2)
_writeDepth = false;
if (stream->readByte() < 2)
_alphaTest = false;
for (int i = 0; i < 4; ++i) {
char f[4];
stream->read(f, 4);
_texCoordX[i] = get_float(f);
stream->read(f, 4);
_texCoordY[i] = get_float(f);
}
_flags2 = stream->readUint32LE();
if (_flags2 & ~(DepthTest | AlphaTest)) {
Debug::debug(Debug::Sprites, "Sprite %s has unknown flags (%d) in second flag field", name, _flags1);
}
_material = costume->loadMaterial(texname, true);
_width = width;
_height = height;
_next = nullptr;
_visible = true;
_pos.set(offX, offY, 0);
delete[] name;
delete[] texname;

View File

@ -38,9 +38,12 @@ class EMICostume;
class Sprite {
public:
enum BlendMode {
BlendNormal = 0,
BlendAdditive = 1
enum SpriteFlags1 {
BlendAdditive = 0x400
};
enum SpriteFlags2 {
DepthTest = 0x100,
AlphaTest = 0x20000
};
Sprite();
@ -54,13 +57,14 @@ public:
bool _visible;
Material *_material;
Sprite *_next;
BlendMode _blendMode;
uint32 _flags1;
int _red[4];
int _green[4];
int _blue[4];
int _alpha[4];
bool _writeDepth;
bool _alphaTest;
float _texCoordX[4];
float _texCoordY[4];
uint32 _flags2;
};
} // end of namespace Grim

View File

@ -63,7 +63,7 @@ TinyGLTexture::TinyGLTexture(const Graphics::Surface *surface, bool nonPoTSuppor
tglGenTextures(1, &id);
tglBindTexture(TGL_TEXTURE_2D, id);
tglTexImage2D(TGL_TEXTURE_2D, 0, internalFormat, internalWidth, internalHeight, 0, internalFormat, sourceFormat, 0);
tglTexImage2D(TGL_TEXTURE_2D, 0, 3, internalWidth, internalHeight, 0, internalFormat, sourceFormat, 0);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
@ -82,7 +82,7 @@ TinyGLTexture::~TinyGLTexture() {
void TinyGLTexture::update(const Graphics::Surface *surface) {
tglBindTexture(TGL_TEXTURE_2D, id);
tglTexImage2D(TGL_TEXTURE_2D, 0, internalFormat, internalWidth, internalHeight, 0,
tglTexImage2D(TGL_TEXTURE_2D, 0, 3, internalWidth, internalHeight, 0,
internalFormat, sourceFormat, const_cast<void *>(surface->getPixels())); // TESTME: Not sure if it works.
Graphics::tglUploadBlitImage(_blitImage, *surface, 0, false);
}

View File

@ -60,6 +60,7 @@ void glopEnableDisable(GLContext *c, GLParam *p) {
break;
case TGL_DEPTH_TEST:
c->depth_test = v;
c->fb->enableDepthTest(v);
break;
case TGL_ALPHA_TEST:
c->fb->enableAlphaTest(v);

View File

@ -89,6 +89,7 @@ FrameBuffer::FrameBuffer(int width, int height, const Graphics::PixelBuffer &fra
this->buffer.zbuf = this->_zbuf;
_blendingEnabled = false;
_alphaTestEnabled = false;
_depthTestEnabled = false;
_depthFunc = TGL_LESS;
}
@ -180,4 +181,34 @@ void FrameBuffer::setTexture(const Graphics::PixelBuffer &texture) {
current_texture = texture;
}
void FrameBuffer::setBlendingFactors(int sFactor, int dFactor) {
_sourceBlendingFactor = sFactor;
_destinationBlendingFactor = dFactor;
}
void FrameBuffer::enableBlending(bool enable) {
_blendingEnabled = enable;
}
void FrameBuffer::setAlphaTestFunc(int func, float ref) {
_alphaTestFunc = func;
_alphaTestRefVal = (int)(ref * 255);
}
void FrameBuffer::enableAlphaTest(bool enable) {
_alphaTestEnabled = enable;
}
void FrameBuffer::setDepthFunc(int func) {
_depthFunc = func;
}
void FrameBuffer::enableDepthTest(bool enable) {
_depthTestEnabled = enable;
}
void FrameBuffer::enableAlphaTest(bool enable) {
_alphaTestEnabled = enable;
}
} // end of namespace TinyGL

View File

@ -85,6 +85,9 @@ struct FrameBuffer {
}
FORCEINLINE bool compareDepth(unsigned int &zSrc, unsigned int &zDst) {
if (!_depthTestEnabled)
return true;
switch (_depthFunc) {
case TGL_NEVER:
break;
@ -306,6 +309,13 @@ struct FrameBuffer {
_blendingEnabled = enable;
}
void enableBlending(bool enable);
void setBlendingFactors(int sfactor, int dfactor);
void enableAlphaTest(bool enable);
void enableDepthTest(bool enable);
void setAlphaTestFunc(int func, float ref);
void setDepthFunc(int func);
void setBlendingFactors(int sFactor, int dFactor) {
_sourceBlendingFactor = sFactor;
_destinationBlendingFactor = dFactor;
@ -413,6 +423,7 @@ private:
int _sourceBlendingFactor;
int _destinationBlendingFactor;
bool _alphaTestEnabled;
bool _depthTestEnabled;
int _alphaTestFunc;
int _alphaTestRefVal;
int _depthFunc;