Initial commit
This commit is contained in:
219
engines/watchmaker/3d/movie.cpp
Normal file
219
engines/watchmaker/3d/movie.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "watchmaker/3d/movie.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
gMovie::gMovie(Common::SharedPtr<Common::SeekableReadStream> stream, Texture *texture, const Common::String &name) : _name(name), _stream(stream), _texture(texture) {
|
||||
_numFrames = stream->readUint16LE();
|
||||
_width = stream->readUint16LE();
|
||||
_height = stream->readUint16LE();
|
||||
_keyFrame = stream->readByte();
|
||||
_frameRate = stream->readByte();
|
||||
|
||||
_header = DDSHeader(*stream);
|
||||
_numBlocks = _width * _height / 16;
|
||||
_curFrame = 0xFFFF;
|
||||
|
||||
_frameOffsets = new uint32[_numFrames] {};
|
||||
if (!_frameOffsets) {
|
||||
error("gLoadMovie FAILED: Can't alloc Movie->frameOffsets struct");
|
||||
}
|
||||
|
||||
_buffer = new uint8[bufferSize()] {};
|
||||
_surfaceBuffer = new uint8[_header.dataSize()] {};
|
||||
_frameStream = new Common::MemoryReadStream(_surfaceBuffer, _header.dataSize(), DisposeAfterUse::NO);
|
||||
if (!_buffer) {
|
||||
error("gLoadMovie FAILED: Can't alloc Movie->buffer struct");
|
||||
}
|
||||
|
||||
//read frame offsets
|
||||
for (int i = 0; i < _numFrames; i++) {
|
||||
_frameOffsets[i] = _stream->readUint32LE();
|
||||
}
|
||||
|
||||
_startTime = 0;
|
||||
}
|
||||
|
||||
gMovie::~gMovie() {
|
||||
delete[] _frameOffsets;
|
||||
delete[] _buffer;
|
||||
delete[] _surfaceBuffer;
|
||||
delete _frameStream;
|
||||
}
|
||||
|
||||
Common::SharedPtr<gMovie> gLoadMovie(WorkDirs &workDirs, const char *TextName, Texture *texture) {
|
||||
//convert .avi name in .wmm
|
||||
Common::String finalName = replaceExtension(TextName, "wmm");
|
||||
|
||||
auto stream = workDirs.resolveFile(finalName);
|
||||
if (!stream) {
|
||||
DebugLogFile("gLoadMovie FAILED: Can't find movie file\n");
|
||||
return nullptr;
|
||||
}
|
||||
auto Movie = Common::SharedPtr<gMovie>(new gMovie(stream, texture, TextName));
|
||||
Movie->_name = TextName;
|
||||
if (!Movie) {
|
||||
DebugLogFile("gLoadMovie FAILED: Can't alloc Movie struct");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Movie->frameRate=240;
|
||||
return Movie;
|
||||
}
|
||||
|
||||
void gMovie::loadThisFrameData(uint16 frame) {
|
||||
_stream->seek(_frameOffsets[frame], SEEK_SET);
|
||||
//read frame data
|
||||
int32 size = 0;
|
||||
if ((frame + 1) == _numFrames) {
|
||||
size = _stream->size() - _frameOffsets[frame];
|
||||
} else {
|
||||
size = _frameOffsets[frame + 1] - _frameOffsets[frame];
|
||||
}
|
||||
assert(size <= (int32)bufferSize());
|
||||
_stream->read(_buffer, size);
|
||||
}
|
||||
|
||||
//build a new frame by difference from previous
|
||||
void gMovie::buildNewFrame(byte *surf, uint16 frame) {
|
||||
loadThisFrameData(frame);
|
||||
|
||||
DWORD bitArraySize = _numBlocks >> 3;
|
||||
byte *buf = &_buffer[bitArraySize];
|
||||
WORD curBlock = 0;
|
||||
|
||||
for (int i = 0; i < bitArraySize; i++) {
|
||||
byte block = _buffer[i];
|
||||
if (!block) {
|
||||
curBlock += 8;
|
||||
continue; //everything is equal
|
||||
}
|
||||
|
||||
for (int j = 0; j < 8; j++, curBlock++) {
|
||||
if (block & (1 << j)) {
|
||||
memcpy(&surf[curBlock << 3], buf, 8);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool gMovie::setFrame(uint16 newFrame) {
|
||||
warning("Set Frame: %d\t%s", newFrame, _name.c_str());
|
||||
if (_curFrame == newFrame)
|
||||
return true;
|
||||
|
||||
//do we have to replace the whole frame or do we have to built it?
|
||||
bool rebuildFrame = true;
|
||||
if (_curFrame == 0xFFFF) rebuildFrame = false;
|
||||
else if (!(newFrame % _keyFrame)) rebuildFrame = false; //it's a keyframe
|
||||
|
||||
_header.dataSize();
|
||||
#if 0
|
||||
DDSURFACEDESC2 ddsd2;
|
||||
ddsd2.dwSize = sizeof(DDSURFACEDESC2);
|
||||
|
||||
if ((mv->surf->Lock(NULL, &ddsd2, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL))) { // Lock and fill with the dds
|
||||
DebugLogFile("gMovie_SetFrame: Can't lock surface DDS");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (!rebuildFrame) {
|
||||
loadThisFrameData(newFrame);
|
||||
memcpy(_surfaceBuffer, _buffer, _header.dataSize());
|
||||
} else {
|
||||
if ((_curFrame + 1) != newFrame) { //we can't directly build this frame because the current frame is not his previous
|
||||
uint16 startFrame;
|
||||
uint16 prevKey = (newFrame / _keyFrame) * _keyFrame;
|
||||
|
||||
if ((_curFrame > newFrame) || (_curFrame < prevKey)) {
|
||||
loadThisFrameData(prevKey);
|
||||
memcpy(_surfaceBuffer, _buffer, _header.dataSize());
|
||||
startFrame = prevKey + 1;
|
||||
} else startFrame = _curFrame + 1;
|
||||
for (uint16 i = startFrame; i < newFrame; i++) {
|
||||
buildNewFrame(_surfaceBuffer, i);
|
||||
}
|
||||
}
|
||||
buildNewFrame(_surfaceBuffer, newFrame);
|
||||
}
|
||||
|
||||
_frameStream->seek(0, SEEK_SET);
|
||||
auto tex = loadDdsTexture(*_frameStream, _header);
|
||||
_texture->assignData(*tex);
|
||||
#if 0
|
||||
if (mat->Texture->lpDDSurface->Blt(NULL, mv->surf, NULL, DDBLT_WAIT, NULL) != DD_OK) {
|
||||
DebugLogFile("gMovie_SetFrame: Can't Blit DDS texture");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
_curFrame = newFrame;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
bool gMovie::updateMovie() {
|
||||
int16 newFrame = 0;
|
||||
|
||||
if (_paused)
|
||||
return TRUE;
|
||||
|
||||
warning("Update Movie: %s", _name.c_str());
|
||||
|
||||
if ((_curFrame == 0xFFFF) || (!_startTime)) {
|
||||
_startTime = timeGetTime();
|
||||
newFrame = 0;
|
||||
} else {
|
||||
// Use the time to find which frame we should be drawing
|
||||
uint32 curTime = timeGetTime();
|
||||
DWORD elapsedTime = curTime - _startTime;
|
||||
newFrame = (WORD)((float)elapsedTime / (1000.f / (float)_frameRate));
|
||||
|
||||
if (newFrame >= _numFrames) {
|
||||
_startTime = curTime;
|
||||
newFrame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return setFrame(newFrame);
|
||||
}
|
||||
|
||||
int gMovie::frameSize(int index) {
|
||||
if ((index + 1) < _numFrames) {
|
||||
return _frameOffsets[index + 1] - _frameOffsets[index];
|
||||
} else {
|
||||
return _stream->size() - _frameOffsets[index];
|
||||
}
|
||||
}
|
||||
|
||||
uint32 gMovie::bufferSize() const {
|
||||
return (_numBlocks / 8) + 8 * _numBlocks; //bit array + max different blocks
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
Reference in New Issue
Block a user