[Scummvm-cvs-logs] CVS: residual lipsynch.cpp,NONE,1.1 lipsynch.h,NONE,1.1 Makefile.common,1.3,1.4 README,1.17,1.18 actor.cpp,1.28,1.29 actor.h,1.13,1.14 resource.cpp,1.10,1.11 resource.h,1.7,1.8 sound.h,1.5,1.6

James Brown ender at users.sourceforge.net
Sat Sep 11 07:10:04 CEST 2004


Update of /cvsroot/scummvm/residual
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15593

Modified Files:
	Makefile.common README actor.cpp actor.h resource.cpp 
	resource.h sound.h 
Added Files:
	lipsynch.cpp lipsynch.h 
Log Message:
Lipsync support by salty-horse. Now rejoice! REJOIIIIICE!


--- NEW FILE: lipsynch.cpp ---
// Residual - Virtual machine to run LucasArts' 3D adventure games
// Copyright (C) 2003 The ScummVM-Residual Team (www.scummvm.org)
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

#include "stdafx.h"
#include "lipsynch.h"
#include "bits.h"
#include "debug.h"
#include <cstring>
#include <SDL_endian.h>

// A new define that'll be around when theres a configure script :)
#undef DEBUG_VERBOSE

LipSynch::LipSynch(const char *filename, const char *data, int len) :
	Resource(filename) {
	uint16 readPhoneme;
	int j;

	if (std::memcmp(data, "LIP!", 4) != 0) {
		error("Invalid file format in %s\n", filename);
	} else {
		numEntries_ = (len - 8) / 4;
		
		// There are cases where the lipsync file has no entries
		if (numEntries_ == 0)
			status_ = false;
		else {
		    status_ = true;
			data += 8;
			#ifdef DEBUG_VERBOSE
			printf("Reading LipSynch %s, %d entries\n", filename, numEntries_);
			#endif
			entries_ = new LipEntry[numEntries_];
			for (int i = 0; i < numEntries_; i++) {
				entries_[i].frame = READ_LE_UINT16(data);
				readPhoneme = READ_LE_UINT16(data + 2);

				// Look for the animation corresponding to the phoneme
				for (j = 0; j < animTableSize_ &&
						 readPhoneme != animTable_[j].phoneme; j++);
				if ( readPhoneme != animTable_[j].phoneme) {
					warning("Unknown phoneme: 0x%X in file %s\n", readPhoneme, filename);
					entries_[i].anim = 1;
				} else
					entries_[i].anim = animTable_[j].anim;
				data += 4;
			}
			#ifdef DEBUG_VERBOSE
				for (int j = 0; j < numEntries_; j++)
					printf("LIP %d) frame %d, anim %d\n", j, entries_[j].frame, entries_[j].anim);
			#endif
		    currEntry_ = 0;
		}    
	}
}

LipSynch::~LipSynch() {
	delete[] entries_;
}

LipSynch::LipEntry LipSynch::getCurrEntry() {
	return entries_[currEntry_];
}

void LipSynch::advanceEntry() {
	if (currEntry_ < numEntries_)
		currEntry_++;
}

const LipSynch::PhonemeAnim LipSynch::animTable_[] = {
	{0x005F, 0}, {0x0251, 1}, {0x0061, 1}, {0x00E6, 1}, {0x028C, 8}, 
	{0x0254, 1}, {0x0259, 1}, {0x0062, 6}, {0x02A7, 2}, {0x0064, 2}, 
	{0x00F0, 5}, {0x025B, 8}, {0x0268, 8}, {0x025A, 9}, {0x025D, 9}, 
	{0x0065, 1}, {0x0066, 4}, {0x0067, 8}, {0x0261, 8}, {0x0068, 8}, 
	{0x026A, 8}, {0x0069, 3}, {0x02A4, 2}, {0x006B, 2}, {0x006C, 5}, 
	{0x026B, 5}, {0x006D, 6}, {0x006E, 8}, {0x014B, 8}, {0x006F, 7}, 
	{0x0070, 6}, {0x0072, 2}, {0x027B, 2}, {0x0279, 2}, {0x0073, 2}, 
	{0x0283, 2}, {0x0074, 2}, {0x027E, 2}, {0x03B8, 5}, {0x028A, 9}, 
	{0x0075, 9}, {0x0076, 4}, {0x0077, 9}, {0x006A, 8}, {0x007A, 2}, 
	{0x0292, 2}, {0x002E, 2}
};

const int LipSynch::animTableSize_ = sizeof(LipSynch::animTable_) / sizeof(LipSynch::animTable_[0]);


--- NEW FILE: lipsynch.h ---
// Residual - Virtual machine to run LucasArts' 3D adventure games

// Copyright (C) 2003-2004 The ScummVM-Residual Team (www.scummvm.org)

//

//  This library is free software; you can redistribute it and/or

//  modify it under the terms of the GNU Lesser General Public

//  License as published by the Free Software Foundation; either

//  version 2.1 of the License, or (at your option) any later version.

//

//  This library 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

//  Lesser General Public License for more details.

//

//  You should have received a copy of the GNU Lesser General Public

//  License along with this library; if not, write to the Free Software

//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA



#ifndef LIPSYNCH_H

#define LIPSYNCH_H



#include "bits.h"

#include "resource.h"

#include <list>



class LipSynch : public Resource {

public:

	LipSynch(const char *filename, const char *data, int len);

	~LipSynch();



	struct LipEntry {

		uint16 frame;

		uint16 anim;

	};



	LipEntry getCurrEntry();

	void advanceEntry();

	bool getStatus() const { return status_; }



private:

	LipEntry *entries_;

	int numEntries_;

	int currEntry_;

	bool status_;

	

	struct PhonemeAnim {

		uint16 phoneme;

		uint16 anim;

	};

	static const PhonemeAnim animTable_[];

	static const int animTableSize_;

};



#endif


Index: Makefile.common
===================================================================
RCS file: /cvsroot/scummvm/residual/Makefile.common,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Makefile.common	5 Apr 2004 19:06:44 -0000	1.3
+++ Makefile.common	11 Sep 2004 14:09:42 -0000	1.4
@@ -1,53 +1,54 @@
-OBJS =\

-	actor.o \

-	bitmap.o \

-	blocky16.o \

-	costume.o \

-	debug.o \

-	driver_gl.o \

-	engine.o \

-	keyframe.o \

-	lab.o \

-	localize.o \

-	lua.o \

-	main.o \

-	material.o \

-	matrix3.o \

-	matrix4.o \

-	model.o \

-	objectstate.o \

-	registry.o \

-	resource.o \

-	scene.o \

-	screen.o \

-	smush.o \

-	sound.o \

-	textobject.o \

-	textsplit.o \

-	timer.o \

-	vima.o \

-	walkplane.o \

-	mixer/mixer.o \

-	mixer/rate.o \

-	mixer/audiostream.o

-

-DEPS = $(OBJS:.o=.d)

-

-residual: $(OBJS) lua/lib/liblua.a lua/lib/liblualib.a

-	$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

-

-.cpp.o:

-	$(CXX) $(CXXFLAGS) -MMD -c $(<) -o $*.o

-

-lua/lib/liblua.a lua/lib/liblualib.a: lua-build

-

-lua-build:

-	$(MAKE) -C lua

-

-clean: lua-clean

-	-rm -f residual$(EXEEXT) *.o mixer\*.o *.d mixer\*.d *~

-

-lua-clean:

-	$(MAKE) -C lua clean

-

--include $(DEPS)

+OBJS =\
+	actor.o \
+	bitmap.o \
+	blocky16.o \
+	costume.o \
+	debug.o \
+	driver_gl.o \
+	engine.o \
+	keyframe.o \
+	lab.o \
+	localize.o \
+	lua.o \
+	main.o \
+	material.o \
+	matrix3.o \
+	matrix4.o \
+	model.o \
+	objectstate.o \
+	registry.o \
+	resource.o \
+	scene.o \
+	screen.o \
+	smush.o \
+	sound.o \
+	lipsynch.o \
+	textobject.o \
+	textsplit.o \
+	timer.o \
+	vima.o \
+	walkplane.o \
+	mixer/mixer.o \
+	mixer/rate.o \
+	mixer/audiostream.o
+
+DEPS = $(OBJS:.o=.d)
+
+residual: $(OBJS) lua/lib/liblua.a lua/lib/liblualib.a
+	$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+.cpp.o:
+	$(CXX) $(CXXFLAGS) -MMD -c $(<) -o $*.o
+
+lua/lib/liblua.a lua/lib/liblualib.a: lua-build
+
+lua-build:
+	$(MAKE) -C lua
+
+clean: lua-clean
+	-rm -f residual$(EXEEXT) *.o mixer\*.o *.d mixer\*.d *~
+
+lua-clean:
+	$(MAKE) -C lua clean
+
+-include $(DEPS)

Index: README
===================================================================
RCS file: /cvsroot/scummvm/residual/README,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- README	15 Jun 2004 06:04:32 -0000	1.17
+++ README	11 Sep 2004 14:09:42 -0000	1.18
@@ -1,6 +1,6 @@
-Residual: A LucasArts 3D game interpreter           Version:      0.03-CVS
-(C) 2003-2004 The ScummVM-Residual team             Last Updated: 26th Mar 2004
--------------------------------------------------------------------------------
+Residual: A LucasArts 3D game interpreter           Version:      0.04-CVS
+(C) 2003-2004 The ScummVM-Residual team             Last Updated: 11 Sept 2004
+------------------------------------------------------------------------------
 
 What is Residual?
 -----------------
@@ -54,10 +54,9 @@
 
 What is the state of Residual? 
 ------------------------------- 
-Many features are not yet supported. Cutscenes work, you can interact with
-objects and play at least some of the game.
-
-HOWEVER: It may crash. There is no lighting, menus, save/load, etc.
+Basic gameplay works, including cutscenes. Some of the game is playable,
+but many features are either missing or unstable. There are no menus,
+save/load features, lighting, etc. Crashes are likely.
 
 What are the default keys?
 --------------------------
@@ -102,13 +101,14 @@
 Credits:
 ------------------------------
 ScummVM-Residual Team:
- James Brown          	 Core developer. ScummVM co-lead dev.
- Pawel Kolodziejski      Core developer. SMUSH implemention.
+ James 'Ender' Brown          	    Core developer. ScummVM co-lead dev
+ Pawel 'aquadran' Kolodziejski      Core developer. SMUSH implemention
 
 Contributors:
- Daniel Schepler         Initial engine code and LUA tweaks.
- Vincent Hamm            Various engine code
- Lionel Ulmer            OpenGL optimisations
+ Daniel Schepler                    Initial engine codebase, LUA support
+ Vincent Hamm                       Various engine code
+ Lionel 'bbrox' Ulmer               OpenGL optimisations
+ Ori 'salty-horse' Avtalion         Lipsync support
 
 Special Thanks To:
 ------------------ 

Index: actor.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/actor.cpp,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- actor.cpp	26 Mar 2004 09:28:13 -0000	1.28
+++ actor.cpp	11 Sep 2004 14:09:42 -0000	1.29
@@ -20,15 +20,19 @@
 #include "engine.h"
 #include "costume.h"
 #include "sound.h"
+#include "lipsynch.h"
 #include "localize.h"
 #include <cmath>
 #include <cstring>
 #include "driver_gl.h"
+#include "mixer/mixer.h"
+
+extern SoundMixer *g_mixer;
 
 Actor::Actor(const char *name) :
 		name_(name), talkColor_(255, 255, 255), pos_(0, 0, 0),
 		pitch_(0), yaw_(0), roll_(0), walkRate_(0), turnRate_(0),
-		visible_(true), talkSound_(NULL), turning_(false), walking_(false),
+		visible_(true), talkSound_(NULL), lipSynch_(NULL), turning_(false), walking_(false),
 		restCostume_(NULL), restChore_(-1),
 		walkCostume_(NULL), walkChore_(-1), walkedLast_(false), walkedCur_(-1),
 		turnCostume_(NULL), leftTurnChore_(-1), rightTurnChore_(-1),
@@ -192,9 +196,7 @@
 }
 
 void Actor::sayLine(const char *msg) {
-	// For now, just play the appropriate sound if found.  Eventually,
-	// this needs to handle possibly displaying text, starting up
-	// appropriate talking chores, etc.
+	// TODO - Display text
 
 	// Find the message identifier
 	if (msg[0] != '/')
@@ -202,15 +204,33 @@
 	const char *secondSlash = std::strchr(msg + 1, '/');
 	if (secondSlash == NULL)
 		return;
-	if (talkSound_) // Only once line at a time, please :)
+	if (talkSound_) // Only one line at a time, please :)
 		shutUp();
 	std::string msgText = Localizer::instance()->localize(secondSlash + 1);
  	std::string msgId(msg + 1, secondSlash);
+
 	talkSound_ = ResourceLoader::instance()->loadSound((msgId + ".wav").c_str());
+	lipSynch_ = ResourceLoader::instance()->loadLipSynch((msgId + ".lip").c_str());
+
 	if (talkSound_ != NULL) {
 		Mixer::instance()->playVoice(talkSound_);
-		if (mumbleChore_ >= 0)
-			mumbleCostume_->playChoreLooping(mumbleChore_);
+
+		// Sometimes actors speak offscreen before they, including their 
+		// talk chores are initialized.
+		// For example, when reading the work order (a LIP file exists for no reason).
+		// Also, some lip synch files have no entries
+		// In these case, revert to using the mumble chore.
+		if (lipSynch_ != NULL && lipSynch_->getStatus()) {
+			talkAnim_ = lipSynch_->getCurrEntry().anim;
+		    if (talkChore_[talkAnim_] >= 0) {
+				talkCostume_[talkAnim_]->playChoreLooping(talkChore_[talkAnim_]);
+				lipSynch_->advanceEntry();
+			}			
+		} else {
+		    lipSynch_ = NULL;
+      		if (mumbleChore_ >= 0)
+      			mumbleCostume_->playChoreLooping(mumbleChore_);
+		}		
 	}
 }
 
@@ -221,9 +241,13 @@
 void Actor::shutUp() {
 	if (talkSound_) {
 		Mixer::instance()->stopVoice(talkSound_);
-		talkSound_ = NULL;
-		if (mumbleChore_ >= 0)
+		if (lipSynch_ != NULL) {
+			if (talkChore_[talkAnim_] >= 0)
+				talkCostume_[talkAnim_]->stopChore(talkChore_[talkAnim_]);
+			lipSynch_ = NULL;
+		} else if (mumbleChore_ >= 0)
 			mumbleCostume_->stopChore(mumbleChore_);
+		talkSound_ = NULL;
 	}
 }
 
@@ -353,11 +377,25 @@
 	lastTurnDir_ = currTurnDir_;
 	currTurnDir_ = 0;
 
-	if (talkSound_ != NULL && talkSound_->done()) {
-		talkSound_ = NULL;
-		if (mumbleChore_ >= 0)
-			mumbleCostume_->stopChore(mumbleChore_);
-	}
+	// Update lip synching
+	if (lipSynch_ != NULL && talkSound_ != NULL &&
+		talkSound_->hasReachedPos(lipSynch_->getCurrEntry().frame * 
+			g_mixer->getOutputRate() / 60)) {
+
+		///printf("Reached beyond frame %d (=pos %d). Playing anim %d\n",
+  		//	lipSynch_->getCurrEntry().frame, lipSynch_->getCurrEntry().frame * 
+		//	g_mixer->getOutputRate() / 60,lipSynch_->getCurrEntry().anim);
+
+		if (talkChore_[talkAnim_] >= 0)
+			talkCostume_[talkAnim_]->stopChore(talkChore_[talkAnim_]);
+		talkAnim_ = lipSynch_->getCurrEntry().anim;
+		if (talkChore_[talkAnim_] >= 0)
+			talkCostume_[talkAnim_]->playChoreLooping(talkChore_[talkAnim_]);
+		lipSynch_->advanceEntry();
+	}	
+
+	if (talkSound_ != NULL && talkSound_->done())
+		shutUp();
 
 	for (std::list<Costume *>::iterator i = costumeStack_.begin();
 		i != costumeStack_.end(); i++) {

Index: actor.h
===================================================================
RCS file: /cvsroot/scummvm/residual/actor.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- actor.h	25 Mar 2004 15:43:05 -0000	1.13
+++ actor.h	11 Sep 2004 14:09:42 -0000	1.14
@@ -26,6 +26,7 @@
 
 class Sound;
 class Costume;
+class LipSynch;
 
 class Actor {
 public:
@@ -125,6 +126,7 @@
 	bool visible_;
 	bool lookingMode_;
 	ResPtr<Sound> talkSound_;
+	ResPtr<LipSynch> lipSynch_;
 	std::list<Costume *> costumeStack_;
 
 	// Variables for gradual turning
@@ -149,6 +151,7 @@
 
 	Costume *talkCostume_[10];
 	int talkChore_[10];
+	int talkAnim_;
 
 	Costume *mumbleCostume_;
 	int mumbleChore_;

Index: resource.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/resource.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- resource.cpp	24 Feb 2004 22:43:32 -0000	1.10
+++ resource.cpp	11 Sep 2004 14:09:43 -0000	1.11
@@ -25,6 +25,7 @@
 #include "material.h"
 #include "model.h"
 #include "sound.h"
+#include "lipsynch.h"
 #include "debug.h"
 #include <cstring>
 #include <cctype>
@@ -67,7 +68,10 @@
 			Lab *l = new Lab(fullname.c_str());
 			lab_counter++;
 			if (l->isOpen())
-				labs_.push_back(l);
+				if (strstr(de->d_name, "005"))
+					labs_.push_front(l);
+				else
+					labs_.push_back(l);
 			else
 				delete l;
 		}
@@ -82,11 +86,16 @@
 			Lab *l = new Lab(fullname.c_str());
 			lab_counter++;
 			if (l->isOpen())
-				labs_.push_back(l);
+				// Handle the Grim 1.1 patch's datafile
+				if (strstr(de->d_name, "005"))
+					labs_.push_front(l);
+				else
+					labs_.push_back(l);
 			else
 				delete l;
 		}
 	}
+
 	closedir(d);
 #endif
 
@@ -142,9 +151,9 @@
 	if (b == NULL) {	// Grim sometimes asks for non-existant bitmaps (eg, ha_overhead)
 		warning("Could not find bitmap %s\n", filename);
 	return NULL;
-}
+	}
 
-Bitmap *result = new Bitmap(filename, b->data(), b->len());
+	Bitmap *result = new Bitmap(filename, b->data(), b->len());
 	delete b;
 	cache_[fname] = result;
 	return result;
@@ -195,6 +204,29 @@
 	return result;
 }
 
+LipSynch *ResourceLoader::loadLipSynch(const char *filename) {
+	std::string fname = filename;
+	LipSynch *result;
+
+	makeLower(fname);
+	cache_type::iterator i = cache_.find(fname);
+	if (i != cache_.end()) {
+		return dynamic_cast<LipSynch *>(i->second);
+	}
+
+	Block *b = getFileBlock(filename);
+	if (b == NULL) {
+		warning("Could not find lipsynch file %s\n", filename);
+		result = NULL;
+	} else {
+		result = new LipSynch(filename, b->data(), b->len());
+		delete b;
+		cache_[fname] = result;
+	}	
+
+	return result;
+}
+
 Material *ResourceLoader::loadMaterial(const char *filename, const CMap &c) {
 	std::string fname = filename;
 	makeLower(fname);

Index: resource.h
===================================================================
RCS file: /cvsroot/scummvm/residual/resource.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- resource.h	22 Mar 2004 11:23:37 -0000	1.7
+++ resource.h	11 Sep 2004 14:09:43 -0000	1.8
@@ -30,6 +30,7 @@
 class Material;
 class Model;
 class Sound;
+class LipSynch;
 
 class Resource {
 public:
@@ -102,6 +103,7 @@
 	Material *loadMaterial(const char *fname, const CMap &c);
 	Model *loadModel(const char *fname, const CMap &c);
 	Sound *loadSound(const char *fname);
+	LipSynch *loadLipSynch(const char *fname);
 	void uncache(const char *fname);
 
 private:

Index: sound.h
===================================================================
RCS file: /cvsroot/scummvm/residual/sound.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- sound.h	25 Feb 2004 08:21:30 -0000	1.5
+++ sound.h	11 Sep 2004 14:09:43 -0000	1.6
@@ -28,6 +28,8 @@
 	~Sound();
 
 	bool done() const { return currPos_ >= numSamples_; }
+	bool hasReachedPos(int position) const { return currPos_ >= position; }
+	int  getCurrPos() const {return currPos_;}
 
 private:
 	int numSamples_, numChannels_, currPos_;





More information about the Scummvm-git-logs mailing list