1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "engines/grim/grim.h"
24 #include "engines/grim/lua_v1.h"
25 #include "engines/grim/resource.h"
26 #include "engines/grim/bitmap.h"
27 #include "engines/grim/primitives.h"
28 #include "engines/grim/iris.h"
29 #include "engines/grim/gfx_base.h"
30 #include "engines/grim/set.h"
31 #include "actor.h"
32 
33 #include "engines/grim/movie/movie.h"
34 
35 #include "engines/grim/lua/lua.h"
36 
37 namespace Grim {
38 
GetImage()39 void Lua_V1::GetImage() {
40 	lua_Object nameObj = lua_getparam(1);
41 	if (!lua_isstring(nameObj)) {
42 		lua_pushnil();
43 		return;
44 	}
45 	const char *bitmapName = lua_getstring(nameObj);
46 	Bitmap *b = Bitmap::create(bitmapName);
47 	lua_pushusertag(b->getId(), MKTAG('V','B','U','F'));
48 }
49 
FreeImage()50 void Lua_V1::FreeImage() {
51 	lua_Object param = lua_getparam(1);
52 	if (!lua_isuserdata(param) || lua_tag(param) != MKTAG('V','B','U','F'))
53 		return;
54 	Bitmap *bitmap = getbitmap(param);
55 	delete bitmap;
56 }
57 
BlastImage()58 void Lua_V1::BlastImage() {
59 	lua_Object param = lua_getparam(1);
60 	if (!lua_isuserdata(param) || lua_tag(param) != MKTAG('V','B','U','F'))
61 		return;
62 	Bitmap *bitmap = getbitmap(param);
63 	lua_Object xObj = lua_getparam(2);
64 	lua_Object yObj = lua_getparam(3);
65 	if (!lua_isnumber(xObj) || !lua_isnumber(yObj))
66 		return;
67 
68 	int x = (int)lua_getnumber(xObj);
69 	int y = (int)lua_getnumber(yObj);
70 //	bool transparent = getbool(4); // TODO transparent/masked copy into display
71 	bitmap->draw(x, y);
72 }
73 
CleanBuffer()74 void Lua_V1::CleanBuffer() {
75 	g_driver->copyStoredToDisplay();
76 }
77 
StartFullscreenMovie()78 void Lua_V1::StartFullscreenMovie() {
79 	lua_Object name = lua_getparam(1);
80 	if (!lua_isstring(name)) {
81 		lua_pushnil();
82 		return;
83 	}
84 	Lua_V1::CleanBuffer();
85 
86 	GrimEngine::EngineMode prevEngineMode = g_grim->getMode();
87 	g_grim->setMode(GrimEngine::SmushMode);
88 	g_grim->setMovieSubtitle(nullptr);
89 	bool looping = getbool(2);
90 	bool result = g_movie->play(lua_getstring(name), looping, 0, 0);
91 	if (!result)
92 		g_grim->setMode(prevEngineMode);
93 	pushbool(result);
94 }
95 
StartMovie()96 void Lua_V1::StartMovie() {
97 	lua_Object name = lua_getparam(1);
98 	if (!lua_isstring(name)) {
99 		lua_pushnil();
100 		return;
101 	}
102 	int x = 0, y = 0;
103 	if (!lua_isnil(lua_getparam(3)))
104 		x = (int)lua_getnumber(lua_getparam(3));
105 	if (!lua_isnil(lua_getparam(4)))
106 		y = (int)lua_getnumber(lua_getparam(4));
107 
108 	GrimEngine::EngineMode prevEngineMode = g_grim->getMode();
109 	g_grim->setMode(GrimEngine::NormalMode);
110 
111 	bool looping = getbool(2);
112 	bool result = g_movie->play(lua_getstring(name), looping, x, y);
113 	g_grim->setMovieSetup();
114 	if (!result)
115 		g_grim->setMode(prevEngineMode);
116 	pushbool(result);
117 }
118 
119 /* Fullscreen movie playing query and normal movie
120  * query should actually detect correctly and not
121  * just return true whenever ANY movie is playing
122  */
IsFullscreenMoviePlaying()123 void Lua_V1::IsFullscreenMoviePlaying() {
124 	pushbool(g_movie->isPlaying());
125 }
126 
IsMoviePlaying()127 void Lua_V1::IsMoviePlaying() {
128 	// Previously, if the game was *not* the demo, this checked also if the mode
129 	// was GrimEngine::NormalMode. This doesn't seem to be what original does, and causes
130 	// bug #301 because the movie eldepot.snm is played before legslide.snm ends.
131 	pushbool(g_movie->isPlaying());
132 }
133 
StopMovie()134 void Lua_V1::StopMovie() {
135 	g_movie->stop();
136 	// Delete subtitles that may have not expired.
137 	g_grim->setMovieSubtitle(nullptr);
138 }
139 
PauseMovie()140 void Lua_V1::PauseMovie() {
141 	g_movie->pause(lua_isnil(lua_getparam(1)) == 0);
142 }
143 
PurgePrimitiveQueue()144 void Lua_V1::PurgePrimitiveQueue() {
145 	PrimitiveObject::getPool().deleteObjects();
146 }
147 
DrawPolygon()148 void Lua_V1::DrawPolygon() {
149 	lua_Object tableObj1 = lua_getparam(1);
150 	if (!lua_istable(tableObj1)) {
151 		lua_pushnil();
152 		return;
153 	}
154 
155 	//int layer = 2;
156 	Color color;
157 	lua_Object tableObj2 = lua_getparam(2);
158 	if (lua_istable(tableObj2)) {
159 		lua_pushobject(tableObj2);
160 		lua_pushstring("color");
161 		lua_Object colorObj = lua_gettable();
162 		if (lua_isuserdata(colorObj) && lua_tag(colorObj) == MKTAG('C','O','L','R')) {
163 			color = getcolor(colorObj);
164 		}
165 		lua_pushobject(tableObj2);
166 		lua_pushstring("layer");
167 		lua_Object layerObj = lua_gettable();
168 		if (lua_isnumber(layerObj))
169 			/*layer = (int)*/lua_getnumber(layerObj);
170 	}
171 
172 	// This code only supports 4 point polygons because the game doesn't
173 	// use other than that. However, the original engine can support
174 	// many points per polygon
175 	lua_Object pointObj;
176 	Common::Point p[4];
177 	for (int i = 0; i < 4; i++) {
178 		// Get X
179 		lua_pushobject(tableObj1);
180 		lua_pushnumber(i * 2 + 1);
181 		pointObj = lua_gettable();
182 		if (!lua_isnumber(pointObj)) {
183 			warning("Lua_V1::DrawPolygon: %i Point Parameter X isn't a number!", i * 2 + 1);
184 			return;
185 		}
186 		if (g_grim->getGameType() == GType_GRIM)
187 			p[i].x = (int)lua_getnumber(pointObj);
188 		else
189 			p[i].x = (int)((lua_getnumber(pointObj) + 1) * 320);
190 
191 		// Get Y
192 		lua_pushobject(tableObj1);
193 		lua_pushnumber(i * 2 + 2);
194 		pointObj = lua_gettable();
195 		if (!lua_isnumber(pointObj)) {
196 			warning("Lua_V1::DrawPolygon: %i Point Parameter Y isn't a number!", i * 2 + 2);
197 			return;
198 		}
199 		if (g_grim->getGameType() == GType_GRIM)
200 			p[i].y = (int)lua_getnumber(pointObj);
201 		else
202 			p[i].y = (int)((1 - lua_getnumber(pointObj)) * 240);
203 	}
204 
205 	PrimitiveObject *prim = new PrimitiveObject();
206 	prim->createPolygon(p[0], p[1], p[2], p[3], color);
207 	lua_pushusertag(prim->getId(), MKTAG('P','R','I','M'));
208 }
209 
DrawLine()210 void Lua_V1::DrawLine() {
211 	Common::Point p1, p2;
212 	Color color;
213 	lua_Object x1Obj = lua_getparam(1);
214 	lua_Object y1Obj = lua_getparam(2);
215 	lua_Object x2Obj = lua_getparam(3);
216 	lua_Object y2Obj = lua_getparam(4);
217 	lua_Object tableObj = lua_getparam(5);
218 
219 	if (!lua_isnumber(x1Obj) || !lua_isnumber(y1Obj) || !lua_isnumber(x2Obj) || !lua_isnumber(y2Obj)) {
220 		lua_pushnil();
221 		return;
222 	}
223 
224 	if (g_grim->getGameType() == GType_GRIM) {
225 		p1.x = (int)lua_getnumber(x1Obj);
226 		p1.y = (int)lua_getnumber(y1Obj);
227 		p2.x = (int)lua_getnumber(x2Obj);
228 		p2.y = (int)lua_getnumber(y2Obj);
229 	} else {
230 		p1.x = (int)((lua_getnumber(x1Obj) + 1) * 320);
231 		p1.y = (int)((1 - lua_getnumber(y1Obj)) * 240);
232 		p2.x = (int)((lua_getnumber(x2Obj) + 1) * 320);
233 		p2.y = (int)((1 - lua_getnumber(y2Obj)) * 240);
234 	}
235 
236 	//int layer = 2;
237 	if (lua_istable(tableObj)) {
238 		lua_pushobject(tableObj);
239 		lua_pushstring("color");
240 		lua_Object colorObj = lua_gettable();
241 		if (lua_isuserdata(colorObj) && lua_tag(colorObj) == MKTAG('C','O','L','R')) {
242 			color = getcolor(colorObj);
243 		}
244 		lua_pushobject(tableObj);
245 		lua_pushstring("layer");
246 		lua_Object layerObj = lua_gettable();
247 		if (lua_isnumber(layerObj))
248 			/*layer = (int)*/lua_getnumber(layerObj);
249 	}
250 
251 	PrimitiveObject *p = new PrimitiveObject();
252 	p->createLine(p1, p2, color); // TODO Add layer support
253 	lua_pushusertag(p->getId(), MKTAG('P','R','I','M'));
254 }
255 
ChangePrimitive()256 void Lua_V1::ChangePrimitive() {
257 	lua_Object param1 = lua_getparam(1);
258 	if (!lua_isuserdata(param1) || lua_tag(param1) != MKTAG('P','R','I','M'))
259 		return;
260 
261 	lua_Object tableObj = lua_getparam(2);
262 	if (!lua_istable(tableObj))
263 		return;
264 
265 	PrimitiveObject *pmodify = getprimitive(param1);
266 	assert(pmodify);
267 
268 	Color color;
269 	lua_pushobject(tableObj);
270 	lua_pushstring("color");
271 	lua_Object colorObj = lua_gettable();
272 	if (lua_isuserdata(colorObj) && lua_tag(colorObj) == MKTAG('C','O','L','R')) {
273 		color = getcolor(colorObj);
274 		pmodify->setColor(color);
275 	}
276 
277 	lua_pushobject(tableObj);
278 	lua_pushstring("layer");
279 	lua_Object layer = lua_gettable();
280 	if (lua_isnumber(layer)) {
281 		// TODO pmodify->setLayer(lua_getnumber(layer));
282 		warning("Not implemented: PrimitiveObject::setLayer. Layer: %d", (int)lua_getnumber(layer));
283 	}
284 
285 	lua_pushobject(tableObj);
286 	lua_pushstring("xoffset");
287 	lua_Object xObj = lua_gettable();
288 	lua_pushobject(tableObj);
289 	lua_pushstring("yoffset");
290 	lua_Object yObj = lua_gettable();
291 	if (lua_isnumber(xObj) || lua_isnumber(yObj)) {
292 		//int x = 0;
293 		//int y = 0;
294 		if (lua_isnumber(xObj))
295 			/*x = (int)*/lua_getnumber(xObj);
296 		if (lua_isnumber(yObj))
297 			/*y = (int)*/lua_getnumber(yObj);
298 		// TODO pmodify->setOffets(x, y);
299 		assert(0);
300 	}
301 
302 	lua_pushobject(tableObj);
303 	lua_pushstring("x");
304 	xObj = lua_gettable();
305 	lua_pushobject(tableObj);
306 	lua_pushstring("y");
307 	yObj = lua_gettable();
308 	if (lua_isnumber(xObj) || lua_isnumber(yObj)) {
309 		int x = -1;
310 		int y = -1;
311 		if (lua_isnumber(xObj)) {
312 			if (g_grim->getGameType() == GType_GRIM)
313 				x = (int)lua_getnumber(xObj);
314 			else
315 				x = (int)((lua_getnumber(xObj) + 1) * 320);
316 		}
317 		if (lua_isnumber(yObj)) {
318 			if (g_grim->getGameType() == GType_GRIM)
319 				y = (int)lua_getnumber(yObj);
320 			else
321 				y = (int)((1 - lua_getnumber(yObj)) * 240);
322 		}
323 		pmodify->setPos(x, y);
324 	}
325 
326 	lua_pushobject(tableObj);
327 	lua_pushstring("x2");
328 	xObj = lua_gettable();
329 	lua_pushobject(tableObj);
330 	lua_pushstring("y2");
331 	yObj = lua_gettable();
332 	if (lua_isnumber(xObj) || lua_isnumber(yObj)) {
333 		int x = -1;
334 		int y = -1;
335 		if (lua_isnumber(xObj)) {
336 			if (g_grim->getGameType() == GType_GRIM)
337 				x = (int)lua_getnumber(xObj);
338 			else
339 				x = (int)((lua_getnumber(xObj) + 1) * 320);
340 		}
341 		if (lua_isnumber(yObj)) {
342 			if (g_grim->getGameType() == GType_GRIM)
343 				y = (int)lua_getnumber(yObj);
344 			else
345 				y = (int)((1 - lua_getnumber(yObj)) * 240);
346 		}
347 		pmodify->setEndpoint(x, y);
348 	}
349 
350 	lua_pushobject(tableObj);
351 	lua_pushstring("width");
352 	lua_Object width = lua_gettable();
353 	lua_pushobject(tableObj);
354 	lua_pushstring("height");
355 	lua_Object height = lua_gettable();
356 	if (lua_isnumber(width) || lua_isnumber(height)) {
357 		//int x = -1;
358 		//int y = -1;
359 		if (lua_isnumber(width))
360 			/*x = (int)*/lua_getnumber(width);
361 		if (lua_isnumber(height))
362 			/*y = (int)*/lua_getnumber(height);
363 		// TODO pmodify->setSize(x, y);
364 		assert(0);
365 	}
366 }
367 
DrawRectangle()368 void Lua_V1::DrawRectangle() {
369 	Common::Point p1, p2;
370 	Color color;
371 	lua_Object x1Obj = lua_getparam(1);
372 	lua_Object y1Obj = lua_getparam(2);
373 	lua_Object x2Obj = lua_getparam(3);
374 	lua_Object y2Obj = lua_getparam(4);
375 	lua_Object tableObj = lua_getparam(5);
376 
377 	if (!lua_isnumber(x1Obj) || !lua_isnumber(y1Obj) || !lua_isnumber(x2Obj) || !lua_isnumber(y2Obj)) {
378 		lua_pushnil();
379 		return;
380 	}
381 
382 	if (g_grim->getGameType() == GType_GRIM) {
383 		p1.x = (int)lua_getnumber(x1Obj);
384 		p1.y = (int)lua_getnumber(y1Obj);
385 		p2.x = (int)lua_getnumber(x2Obj);
386 		p2.y = (int)lua_getnumber(y2Obj);
387 	} else {
388 		p1.x = (int)((lua_getnumber(x1Obj) + 1) * 320);
389 		p1.y = (int)((1 - lua_getnumber(y1Obj)) * 240);
390 		p2.x = (int)((lua_getnumber(x2Obj) + 1) * 320);
391 		p2.y = (int)((1 - lua_getnumber(y2Obj)) * 240);
392 	}
393 	bool filled = false;
394 
395 	if (lua_istable(tableObj)) {
396 		lua_pushobject(tableObj);
397 		lua_pushstring("color");
398 		lua_Object colorObj = lua_gettable();
399 		if (lua_isuserdata(colorObj) && lua_tag(colorObj) == MKTAG('C','O','L','R')) {
400 			color = getcolor(colorObj);
401 		}
402 
403 		lua_pushobject(tableObj);
404 		lua_pushstring("filled");
405 		lua_Object objFilled = lua_gettable();
406 		if (!lua_isnil(objFilled))
407 			filled = true;
408 	}
409 
410 	PrimitiveObject *p = new PrimitiveObject();
411 	p->createRectangle(p1, p2, color, filled);
412 	lua_pushusertag(p->getId(), MKTAG('P','R','I','M')); // FIXME: we use PRIM usetag here
413 }
414 
BlastRect()415 void Lua_V1::BlastRect() {
416 	Common::Point p1, p2;
417 	Color color;
418 	lua_Object x1Obj = lua_getparam(1);
419 	lua_Object y1Obj = lua_getparam(2);
420 	lua_Object x2Obj = lua_getparam(3);
421 	lua_Object y2Obj = lua_getparam(4);
422 	lua_Object tableObj = lua_getparam(5);
423 
424 	if (!lua_isnumber(x1Obj) || !lua_isnumber(y1Obj) || !lua_isnumber(x2Obj) || !lua_isnumber(y2Obj)) {
425 		lua_pushnil();
426 		return;
427 	}
428 	if (g_grim->getGameType() == GType_GRIM) {
429 		p1.x = (int)lua_getnumber(x1Obj);
430 		p1.y = (int)lua_getnumber(y1Obj);
431 		p2.x = (int)lua_getnumber(x2Obj);
432 		p2.y = (int)lua_getnumber(y2Obj);
433 	} else {
434 		p1.x = (int)((lua_getnumber(x1Obj) + 1) * 320);
435 		p1.y = (int)((1 - lua_getnumber(y1Obj)) * 240);
436 		p2.x = (int)((lua_getnumber(x2Obj) + 1) * 320);
437 		p2.y = (int)((1 - lua_getnumber(y2Obj)) * 240);
438 	}
439 	bool filled = false;
440 
441 	if (lua_istable(tableObj)) {
442 		lua_pushobject(tableObj);
443 		lua_pushstring("color");
444 		lua_Object colorObj = lua_gettable();
445 		if (lua_isuserdata(colorObj) && lua_tag(colorObj) == MKTAG('C','O','L','R')) {
446 			color = getcolor(colorObj);
447 		}
448 
449 		lua_pushobject(tableObj);
450 		lua_pushstring("filled");
451 		lua_Object objFilled = lua_gettable();
452 		if (!lua_isnil(objFilled))
453 			filled = true;
454 	}
455 
456 	PrimitiveObject *p = new PrimitiveObject();
457 	p->createRectangle(p1, p2, color, filled);
458 	p->draw();
459 	delete p;
460 }
461 
KillPrimitive()462 void Lua_V1::KillPrimitive() {
463 	lua_Object primObj = lua_getparam(1);
464 
465 	if (!lua_isuserdata(primObj) || lua_tag(primObj) != MKTAG('P','R','I','M'))
466 		return;
467 
468 	PrimitiveObject *prim = getprimitive(primObj);
469 	delete prim;
470 }
471 
DimScreen()472 void Lua_V1::DimScreen() {
473 	g_driver->storeDisplay();
474 	g_driver->dimScreen();
475 }
476 
DimRegion()477 void Lua_V1::DimRegion() {
478 	int x = (int)lua_getnumber(lua_getparam(1));
479 	int y = (int)lua_getnumber(lua_getparam(2));
480 	int w = (int)lua_getnumber(lua_getparam(3));
481 	int h = (int)lua_getnumber(lua_getparam(4));
482 	float level = lua_getnumber(lua_getparam(5));
483 	g_driver->dimRegion(x, y, w, h, level);
484 }
485 
ScreenShot()486 void Lua_V1::ScreenShot() {
487 	int width = (int)lua_getnumber(lua_getparam(1));
488 	int height = (int)lua_getnumber(lua_getparam(2));
489 	GrimEngine::EngineMode mode = g_grim->getMode();
490 	g_grim->setMode(GrimEngine::NormalMode);
491 	g_grim->updateDisplayScene();
492 	Bitmap *screenshot = g_driver->getScreenshot(width, height, false);
493 	g_grim->setMode(mode);
494 	if (screenshot) {
495 		lua_pushusertag(screenshot->getId(), MKTAG('V','B','U','F'));
496 	} else {
497 		lua_pushnil();
498 	}
499 }
500 
SetGamma()501 void Lua_V1::SetGamma() {
502 	lua_Object levelObj = lua_getparam(1);
503 
504 	if (!lua_isnumber(levelObj))
505 		return;
506 	double level = lua_getnumber(levelObj);
507 
508 	// FIXME: func(level)
509 	warning("Lua_V1::SetGamma, implement opcode, level: %f", level);
510 }
511 
Display()512 void Lua_V1::Display() {
513 	if (g_grim->getFlipEnable()) {
514 		g_driver->flipBuffer();
515 	}
516 }
517 
EngineDisplay()518 void Lua_V1::EngineDisplay() {
519 	// it enable/disable updating display
520 	g_grim->setFlipEnable((bool)lua_getnumber(lua_getparam(1)));
521 }
522 
ForceRefresh()523 void Lua_V1::ForceRefresh() {
524 	// Nothing to do, no off-screen buffers
525 }
526 
RenderModeUser()527 void Lua_V1::RenderModeUser() {
528 	lua_Object param1 = lua_getparam(1);
529 	if (!lua_isnil(param1) && g_grim->getMode() != GrimEngine::DrawMode) {
530 		g_grim->setPreviousMode(g_grim->getMode());
531 		g_movie->pause(true);
532 		g_grim->setMode(GrimEngine::DrawMode);
533 	} else if (lua_isnil(param1) && g_grim->getMode() == GrimEngine::DrawMode) {
534 		g_movie->pause(false);
535 		g_grim->setMode(g_grim->getPreviousMode());
536 	}
537 }
538 
IrisUp()539 void Lua_V1::IrisUp() {
540 	lua_Object xObj = lua_getparam(1);
541 	lua_Object yObj = lua_getparam(2);
542 	lua_Object timeObj = lua_getparam(3);
543 
544 	g_grim->playIrisAnimation(Iris::Open, (int)lua_getnumber(xObj), (int)lua_getnumber(yObj), (int)lua_getnumber(timeObj));
545 }
546 
IrisDown()547 void Lua_V1::IrisDown() {
548 	lua_Object xObj = lua_getparam(1);
549 	lua_Object yObj = lua_getparam(2);
550 	lua_Object timeObj = lua_getparam(3);
551 
552 	g_grim->playIrisAnimation(Iris::Close, (int)lua_getnumber(xObj), (int)lua_getnumber(yObj), (int)lua_getnumber(timeObj));
553 }
554 
PreRender()555 void Lua_V1::PreRender() {
556 	g_driver->renderBitmaps(getbool(1));
557 	g_driver->renderZBitmaps(getbool(2));
558 }
559 
560 } // end of namespace Grim
561