1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2013 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 // This class handles VEF files of BG2/ToB it is closely related to VVC (ScriptedAnimation)
22
23 #include "VEFObject.h"
24
25 #define YESNO(x) ( (x)?"Yes":"No")
26
27 #include "Game.h"
28 #include "GameData.h"
29 #include "Interface.h"
30 #include "ScriptedAnimation.h"
31 #include "TableMgr.h"
32 #include "Video.h"
33 #include "System/DataStream.h"
34
35 namespace GemRB {
36
VEFObject()37 VEFObject::VEFObject()
38 {
39 ResName[0]=0;
40 SingleObject=false;
41 }
42
VEFObject(ScriptedAnimation * sca)43 VEFObject::VEFObject(ScriptedAnimation *sca)
44 {
45 Pos = sca->Pos;
46 strnlwrcpy(ResName, sca->ResName, 8);
47 SingleObject=true;
48 ScheduleEntry entry;
49 entry.start = core->GetGame()->GameTime;
50 if (sca->Duration==0xffffffff) entry.length = 0xffffffff;
51 else entry.length = sca->Duration+entry.start;
52 entry.offset = Point(0,0);
53 entry.type = VEF_VVC;
54 entry.ptr = sca;
55 memcpy(entry.resourceName, sca->ResName, sizeof(ieResRef) );
56 entries.push_back(entry);
57 }
58
~VEFObject()59 VEFObject::~VEFObject()
60 {
61 Init();
62 }
63
Init()64 void VEFObject::Init()
65 {
66 for(auto& entry : entries) {
67 if (!entry.ptr) continue;
68 switch(entry.type) {
69 case VEF_BAM:
70 case VEF_VVC:
71 delete (ScriptedAnimation *)entry.ptr;
72 break;
73 case VEF_VEF:
74 case VEF_2DA:
75 delete (VEFObject *)entry.ptr;
76 break;
77 default:; //error, no suitable destructor
78 }
79 }
80 }
81
AddEntry(const ieResRef res,ieDword st,ieDword len,Point pos,ieDword type,ieDword gtime)82 void VEFObject::AddEntry(const ieResRef res, ieDword st, ieDword len, Point pos, ieDword type, ieDword gtime)
83 {
84 ScheduleEntry entry;
85
86 memcpy(entry.resourceName, res, sizeof(ieResRef) );
87 entry.start = gtime+st;
88 if (len!=0xffffffff) len+=entry.start;
89 entry.length = len;
90 entry.offset = pos;
91 entry.type = type;
92 entry.ptr = NULL;
93 entries.push_back(entry);
94 }
95
CreateCell(const ieResRef res,ieDword start,ieDword end)96 ScriptedAnimation *VEFObject::CreateCell(const ieResRef res, ieDword start, ieDword end)
97 {
98 ScriptedAnimation *sca = gamedata->GetScriptedAnimation( res, false);
99 if (sca && end!=0xffffffff) {
100 sca->SetDefaultDuration(AI_UPDATE_TIME*(end-start) );
101 }
102 return sca;
103 }
104
CreateObject(const ieResRef res,SClass_ID id)105 VEFObject *VEFObject::CreateObject(const ieResRef res, SClass_ID id)
106 {
107 if (gamedata->Exists( res, id, true) ) {
108 VEFObject *obj = new VEFObject();
109
110 if (id==IE_2DA_CLASS_ID) {
111 obj->Load2DA(res);
112 } else {
113 DataStream* stream = gamedata->GetResource(res, id);
114 strnlwrcpy(obj->ResName, res, 8);
115 obj->LoadVEF(stream);
116 }
117 return obj;
118 }
119 return NULL;
120 }
121
UpdateDrawingState(int orientation)122 bool VEFObject::UpdateDrawingState(int orientation)
123 {
124 drawQueue.clear();
125 ieDword GameTime = core->GetGame()->GameTime;
126 for (auto& entry : entries) {
127 //don't render the animation if it is outside of the cycle
128 if (entry.start > GameTime) continue;
129 if (entry.length < GameTime) continue;
130
131 if (!entry.ptr) {
132 switch(entry.type) {
133 case VEF_2DA: //original gemrb implementation of composite video effects
134 entry.ptr = CreateObject(entry.resourceName, IE_2DA_CLASS_ID);
135 if (entry.ptr) {
136 break;
137 }
138 // fall back to VEF
139 // intentional fallthrough
140 case VEF_VEF: //vanilla engine implementation of composite video effects
141 entry.ptr = CreateObject(entry.resourceName, IE_VEF_CLASS_ID);
142 if (entry.ptr ) {
143 break;
144 }
145 // fall back to BAM or VVC
146 // intentional fallthrough
147 case VEF_BAM: //just a BAM
148 case VEF_VVC: //videocell (can contain a BAM)
149 entry.ptr = CreateCell(entry.resourceName, entry.length, entry.start);
150 break;
151 default:;
152 }
153 }
154
155 if (!entry.ptr) entry.type = VEF_INVALID;
156
157 bool ended = true;
158 switch(entry.type) {
159 case VEF_BAM:
160 case VEF_VVC:
161 ended = ((ScriptedAnimation *) entry.ptr)->UpdateDrawingState(orientation);
162 break;
163 case VEF_2DA:
164 case VEF_VEF:
165 ended = ((VEFObject *) entry.ptr)->UpdateDrawingState(orientation);
166 break;
167 }
168
169 if (ended) return true;
170
171 drawQueue.push_back(entry);
172 }
173 return false;
174 }
175
Draw(const Region & vp,const Color & p_tint,int height,BlitFlags flags) const176 void VEFObject::Draw(const Region &vp, const Color &p_tint, int height, BlitFlags flags) const
177 {
178 for (const auto& entry : drawQueue) {
179 switch (entry.type) {
180 case VEF_BAM:
181 case VEF_VVC:
182 ((ScriptedAnimation *)entry.ptr)->Draw(vp, p_tint, height, flags);
183 break;
184 case VEF_2DA:
185 case VEF_VEF:
186 ((VEFObject *)entry.ptr)->Draw(vp, p_tint, height, flags);
187 break;
188 }
189 }
190 }
191
Load2DA(const ieResRef resource)192 void VEFObject::Load2DA(const ieResRef resource)
193 {
194 Init();
195 AutoTable tab(resource);
196
197 if (!tab) {
198 return;
199 }
200 SingleObject = false;
201 strnlwrcpy(ResName, resource, 8);
202 ieDword GameTime = core->GetGame()->GameTime;
203 int rows = tab->GetRowCount();
204 while(rows--) {
205 Point offset;
206 int delay, duration;
207 ieResRef resource;
208
209 offset.x=atoi(tab->QueryField(rows,0));
210 offset.y=atoi(tab->QueryField(rows,1));
211 delay = atoi(tab->QueryField(rows,3));
212 duration = atoi(tab->QueryField(rows,4));
213 strnuprcpy(resource, tab->QueryField(rows,2), 8);
214 AddEntry(resource, delay, duration, offset, VEF_VVC, GameTime);
215 }
216 }
217
ReadEntry(DataStream * stream)218 void VEFObject::ReadEntry(DataStream *stream)
219 {
220 ieDword start;
221 ieDword tmp;
222 ieDword length;
223 ieResRef resource;
224 ieDword type;
225 ieDword continuous;
226 Point position;
227
228 stream->ReadDword( &start);
229 position.x = 0;
230 position.y = 0;
231 stream->ReadDword( &tmp); //unknown field (could be position?)
232 stream->ReadDword( &length);
233 stream->ReadDword( &type);
234 stream->ReadResRef( resource);
235 stream->ReadDword( &continuous);
236 stream->Seek( 49*4, GEM_CURRENT_POS); //skip empty fields
237
238 if (continuous) length = -1;
239 ieDword GameTime = core->GetGame()->GameTime;
240 AddEntry(resource, start, length, position, type, GameTime);
241 }
242
LoadVEF(DataStream * stream)243 void VEFObject::LoadVEF(DataStream *stream)
244 {
245 Init();
246 if (!stream) {
247 return;
248 }
249 ieDword i;
250 ieResRef Signature;
251 ieDword offset1, offset2;
252 ieDword count1, count2;
253
254 stream->ReadResRef( Signature);
255 if (strncmp( Signature, "VEF V1.0", 8 ) != 0) {
256 Log(ERROR, "VEFObject", "Not a valid VEF File: %s", ResName);
257 delete stream;
258 return;
259 }
260 SingleObject = false;
261 stream->ReadDword( &offset1);
262 stream->ReadDword( &count1);
263 stream->ReadDword( &offset2);
264 stream->ReadDword( &count2);
265
266 stream->Seek(offset1, GEM_STREAM_START);
267 for (i=0;i<count1;i++) {
268 ReadEntry(stream);
269 }
270
271 stream->Seek(offset2, GEM_STREAM_START);
272 for (i=0;i<count2;i++) {
273 ReadEntry(stream);
274 }
275 }
276
GetSingleObject() const277 ScriptedAnimation *VEFObject::GetSingleObject() const
278 {
279 ScriptedAnimation *sca = NULL;
280
281 if (SingleObject) {
282 if (entries.size()) {
283 const ScheduleEntry& entry = entries[0];
284 if (entry.type==VEF_VVC || entry.type==VEF_BAM) {
285 sca = (ScriptedAnimation *)entry.ptr;
286 }
287 }
288 }
289 return sca;
290 }
291
292 }
293