1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM 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 "ags/lib/allegro.h"
24 #include "ags/plugins/ags_pal_render/ags_pal_render.h"
25 #include "ags/plugins/ags_pal_render/pal_render.h"
26 #include "ags/plugins/ags_pal_render/raycast.h"
27 #include "ags/ags.h"
28 
29 namespace AGS3 {
30 namespace Plugins {
31 namespace AGSPalRender {
32 
33 #define MAX_OVERLAYS 128
34 #define MAX_STARS 1024
35 #define MAX_DEPTH 64
36 
37 #define PI         (3.1415926535f)
38 #define HALF_PI    (0.5f * PI)
39 #define TWO_PI     (2.0f * PI)
40 #define TWO_PI_INV (1.0f / TWO_PI)
41 
42 const float halfpi = (0.5f * PI);
43 const float twopi  = (2.0f * PI);
44 const float twopi_inv = (1.0f / TWO_PI);
45 const float pisquared = PI * PI;
46 const float picubed = PI * PI * PI;
47 
48 IAGSEngine *engine;
49 //unsigned char clut[256][256];
50 unsigned char clut[65536];
51 
52 struct transoverlaytype {
53 	int sprite;
54 	int spritemask;
55 	int blendtype;
56 	int x;
57 	int y;
58 	int trans;
59 	int level;
60 	bool enabled;
61 } overlay[MAX_OVERLAYS];
62 
63 int clutslot;
64 int drawreflections;
65 byte cycle_remap[256];
66 
67 struct starstype {
68 	float x;
69 	float y;
70 	float z;
71 	unsigned char color;
72 	long sprite;
73 	int maxrad;
74 	int scaleboost;
75 };
76 starstype *stars;
77 
78 struct starsoptions {
79 	float speed;
80 	int maxstars;
81 	int depthmultiplier;
82 	int originx;
83 	int originy;
84 	int overscan;
85 } Starfield;
86 long *reflectionmap;
87 BITMAP *rcolormap;
88 BITMAP *ralphamap;
89 
90 struct charrefopt {
91 	int8 reflect;
92 	int replaceview;
93 };
94 
95 struct objrefopt {
96 	int8 reflect;
97 	int8 ignorescaling;
98 };
99 
100 struct reflectionopt {
101 	charrefopt *Characters;
102 	objrefopt *Objects;
103 	int blendslot;
104 	int blendamount;
105 } Reflection;
106 
107 int dummy;
108 
109 #define LENS_WIDTH 150
110 
111 struct LensDistort {
112 	int xoffset;
113 	int yoffset;
114 };
115 
116 LensDistort *lens;
117 struct LensOpt {
118 	bool draw;
119 	int lenswidth;
120 	int lenszoom;
121 	int level;
122 	int x;
123 	int y;
124 	int clampoffset;
125 } LensOption;
126 
127 const int alphamultiply [4096] = {
128 //#include "alphamultiply.txt"
129 };
130 float rot_sine_LUT[360];
131 float rot_cos_LUT[360];
132 
133 BITMAP *backgroundimage;
134 
135 PALSTRUCT objectivepal[256];
136 int bgimgspr;
137 
WriteObjectivePalette(ScriptMethodParams & params)138 void AGSPalRender::WriteObjectivePalette(ScriptMethodParams &params) {
139 	PARAMS4(unsigned char, index, unsigned char, r, unsigned char, b, unsigned char, g);
140 	objectivepal[index].r = r;
141 	objectivepal[index].b = b;
142 	objectivepal[index].g = g;
143 }
144 
ReadObjectivePaletteR(ScriptMethodParams & params)145 void AGSPalRender::ReadObjectivePaletteR(ScriptMethodParams &params) {
146 	PARAMS1(unsigned char, index);
147 	params._result = (int)objectivepal[index].r;
148 }
149 
ReadObjectivePaletteB(ScriptMethodParams & params)150 void AGSPalRender::ReadObjectivePaletteB(ScriptMethodParams &params) {
151 	PARAMS1(unsigned char, index);
152 	params._result = (int)objectivepal[index].b;
153 }
ReadObjectivePaletteG(ScriptMethodParams & params)154 void AGSPalRender::ReadObjectivePaletteG(ScriptMethodParams &params) {
155 	PARAMS1(unsigned char, index);
156 	params._result = (int)objectivepal[index].g;
157 }
158 
159 
160 #define SQRT_MAGIC_F 0x5f3759df
q3sqrt(const float x)161 float  q3sqrt(const float x) {
162 	const float xhalf = 0.5f * x;
163 
164 	union { // get bits for floating value
165 		float x;
166 		int i;
167 	} u;
168 	u.x = x;
169 	u.i = SQRT_MAGIC_F - (u.i >> 1);  // gives initial guess y0
170 	return x * u.x * (1.5f - xhalf * u.x * u.x); // Newton step, repeating increases accuracy
171 }
172 
Make_Sin_Lut()173 void Make_Sin_Lut() {
174 	for (int angle = 0; angle < 360; angle++) {
175 		double rad = (angle * PI) / 180.0;
176 		rot_sine_LUT [angle] = static_cast<float>(sin(rad));
177 		rot_cos_LUT [angle]  = static_cast<float>(cos(rad));
178 	}
179 }
180 
181 /*
182 void PreMultiply_Alphas () //Ha ha, this isn't the kind of premultiplcation you're thinking of.
183 {
184 	for (int y=0;y<64;y++)
185 		for (int x=0;x<64;x++)
186 			alphamultiply [y*64+x] = y*x;
187 }
188 */
189 
GetModifiedBackgroundImage(ScriptMethodParams & params)190 void AGSPalRender::GetModifiedBackgroundImage(ScriptMethodParams &params) {
191 	params._result = bgimgspr;
192 }
193 
root(unsigned short x)194 unsigned short root(unsigned short x) {
195 	unsigned short a, b;
196 	b = x;
197 	a = x = 0x3f;
198 	x = b / x;
199 	a = x = (x + a) >> 1;
200 	x = b / x;
201 	a = x = (x + a) >> 1;
202 	x = b / x;
203 	x = (x + a) >> 1;
204 	return (x);
205 }
206 
207 
Hill(float x)208 float Hill(float x) {
209 	const float a0 = 1.0f;
210 	const float a2 = 2.0f / PI - 12.0f / (pisquared);
211 	const float a3 = 16.0f / (picubed) - 4.0f / (pisquared);
212 	const float xx = x * x;
213 	const float xxx = xx * x;
214 
215 	return a0 + a2 * xx + a3 * xxx;
216 }
217 
FastSin(float x)218 float FastSin(float x) {
219 	// wrap x within [0, TWO_PI)
220 	const float a = x * twopi_inv;
221 	x -= static_cast<int>(a) * twopi;
222 	if (x < 0.0f)
223 		x += twopi;
224 
225 	// 4 pieces of hills
226 	if (x < halfpi)
227 		return Hill(halfpi - x);
228 	else if (x < PI)
229 		return Hill(x - halfpi);
230 	else if (x < 3.0f * halfpi)
231 		return -Hill(3.0f * halfpi - x);
232 	else
233 		return -Hill(x - 3.0f * halfpi);
234 }
235 
FastCos(float x)236 float FastCos(float x) {
237 	return FastSin(x + halfpi);
238 }
239 
AGSFastRoot(ScriptMethodParams & params)240 void AGSPalRender::AGSFastRoot(ScriptMethodParams &params) {
241 	PARAMS1(unsigned short, x);
242 	x = root(x);
243 	params._result = (int)x;
244 }
245 
AGSFastSin(ScriptMethodParams & params)246 void AGSPalRender::AGSFastSin(ScriptMethodParams &params) {
247 	PARAMS1(int32, xi);
248 	float x = PARAM_TO_FLOAT(xi);
249 	x = FastSin(x);
250 	params._result = PARAM_FROM_FLOAT(x);
251 }
252 
AGSFastCos(ScriptMethodParams & params)253 void AGSPalRender::AGSFastCos(ScriptMethodParams &params) {
254 	PARAMS1(int32, xi);
255 	float x = PARAM_TO_FLOAT(xi);
256 	x = FastSin(x + halfpi);
257 	params._result = PARAM_FROM_FLOAT(x);
258 }
259 
260 
DrawLens(int ox,int oy)261 void DrawLens(int ox, int oy) {
262 	int32 sh, sw = 0;
263 	engine->GetScreenDimensions(&sw, &sh, nullptr);
264 	BITMAP *virtsc = engine->GetVirtualScreen();
265 	if (!virtsc) engine->AbortGame("DrawLens: Cannot get virtual screen.");
266 	BITMAP *lenswrite = engine->CreateBlankBitmap(LensOption.lenswidth, LensOption.lenswidth, 8);
267 	uint8 *vScreen = engine->GetRawBitmapSurface(virtsc);
268 	uint8 *lensarray = engine->GetRawBitmapSurface(lenswrite);
269 	int virtscPitch = engine->GetBitmapPitch(virtsc);
270 	int lenswritePitch = engine->GetBitmapPitch(lenswrite);
271 	int radius = LensOption.lenswidth >> 1;
272 	for (int y = 0, lensy = 0; y < LensOption.lenswidth; y++, lensy += lenswritePitch) {
273 		int ypos = y * LensOption.lenswidth;
274 		for (int x = 0; x < LensOption.lenswidth; x++) {
275 			int lenspos = ypos + x;
276 			int coffx = lens[lenspos].xoffset;
277 			int coffy = lens[lenspos].yoffset;
278 			if (oy + coffy > 0 && oy + coffy < sh && ox + coffx > 0 && ox + coffx < sw) {
279 				lensarray[lensy + x] = vScreen[(oy + coffy) * virtscPitch + ox + coffx];
280 				//vScreen[(oy + coffy) * virtscPitch + ox + coffx] = ABS(coffy);
281 			}
282 		}
283 	}
284 	/*
285 	for (int y=0, lensy = 0;y<LensOption.lenswidth;y++, lensy += lenswritePitch)
286 	{
287 	    int ypos = y*LensOption.lenswidth;
288 	    for (int x=0;x<LensOption.lenswidth;x++)
289 	    {
290 	        if (oy+y > 0 && oy+y < sh && ox+x > 0 && ox+x < sw)
291 	        {
292 	            vScreen[(oy+y) * virtscPitch + ox+x] = lensarray[lensy + x];
293 	        }
294 	    }
295 	}
296 	*/
297 	int radsq = radius * radius;
298 	for (int cy = -radius, lensy = 0; cy <= radius; cy++, lensy += lenswritePitch) { //Draw a circle around the point, for the mask.
299 		int cysq = cy * cy;
300 		for (int cx = -radius; cx <= radius; cx++) {
301 			int cxsq = cx * cx;
302 			int dx = cx + ox;
303 			int dy = cy + oy;
304 			if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0 && cy + radius < LensOption.lenswidth - 1 && cx + radius < LensOption.lenswidth - 1) {
305 				//if (cy+radius < 0 || cx+radius < 0) engine->AbortGame ("I did something wrong");
306 				vScreen[dy * virtscPitch + dx] = lensarray[lensy + cx + radius];
307 			}
308 		}
309 	}
310 
311 	engine->ReleaseBitmapSurface(lenswrite);
312 	engine->ReleaseBitmapSurface(virtsc);
313 	engine->FreeBitmap(lenswrite);
314 }
315 
SetLensPos(ScriptMethodParams & params)316 void AGSPalRender::SetLensPos(ScriptMethodParams &params) {
317 	PARAMS2(int, x, int, y);
318 	LensOption.x = x;
319 	LensOption.y = y;
320 }
321 
GetLensX(ScriptMethodParams & params)322 void AGSPalRender::GetLensX(ScriptMethodParams &params) {
323 	params._result = LensOption.x;
324 }
325 
GetLensY(ScriptMethodParams & params)326 void AGSPalRender::GetLensY(ScriptMethodParams &params) {
327 	params._result =  LensOption.y;
328 }
329 
SetLensDrawn(ScriptMethodParams & params)330 void AGSPalRender::SetLensDrawn(ScriptMethodParams &params) {
331 	PARAMS1(int, toggle);
332 	if (toggle > 0) LensOption.draw = 1;
333 	else LensOption.draw = 0;
334 }
335 
GetLensDrawn(ScriptMethodParams & params)336 void AGSPalRender::GetLensDrawn(ScriptMethodParams &params) {
337 	params._result = LensOption.draw;
338 }
339 
SetLensOffsetClamp(ScriptMethodParams & params)340 void AGSPalRender::SetLensOffsetClamp(ScriptMethodParams &params) {
341 	PARAMS1(int, clamp);
342 	if (clamp < 0) LensOption.clampoffset = LensOption.lenswidth;
343 	else LensOption.clampoffset = clamp;
344 }
345 
GetLensOffsetClamp(ScriptMethodParams & params)346 void AGSPalRender::GetLensOffsetClamp(ScriptMethodParams &params) {
347 	params._result = LensOption.clampoffset;
348 }
349 
GetLensLevel(ScriptMethodParams & params)350 void AGSPalRender::GetLensLevel(ScriptMethodParams &params) {
351 	params._result = LensOption.level;
352 }
353 
SetLensLevel(ScriptMethodParams & params)354 void AGSPalRender::SetLensLevel(ScriptMethodParams &params) {
355 	PARAMS1(int, level);
356 	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
357 	else LensOption.level = level;
358 }
359 
LensInitialize(ScriptMethodParams & params)360 void AGSPalRender::LensInitialize(ScriptMethodParams &params) {
361 	PARAMS5(int, width, int, zoom, int, lensx, int, lensy, int, level);
362 	int clamp = -1;
363 	if (params.size() > 5)
364 		clamp = (int)params[5];
365 
366 	int32 sw, sh, radius;
367 	if (width < 1) engine->AbortGame("Invalid lens dimension!");
368 	radius = width >> 1;
369 	lens = new LensDistort [width * width]();
370 	engine->GetScreenDimensions(&sw, &sh, nullptr);
371 	int radsq = radius * radius;
372 	int zoomsq = zoom * zoom;
373 	for (int y = 0; y < radius; y++) {
374 		int ysq = y * y;
375 		for (int x = 0; x < radius; x++) {
376 			int lx, ly;
377 			int xsq = x * x;
378 			if ((xsq + ysq) < (radsq)) {
379 				float shift = zoom / sqrt((float)(zoomsq - (xsq + ysq - radsq)));
380 				lx = (int)(x * shift - x);
381 				ly = (int)(y * shift - y);
382 			} else {
383 				lx = 0;
384 				ly = 0;
385 			}
386 			lens[(radius - y)*width + (radius - x)].xoffset =  lx;
387 			lens[(radius - y)*width + (radius - x)].yoffset =  ly;
388 			lens[(radius + y)*width + (radius + x)].xoffset = -lx;
389 			lens[(radius + y)*width + (radius + x)].yoffset = -ly;
390 			lens[(radius + y)*width + (radius - x)].xoffset =  lx;
391 			lens[(radius + y)*width + (radius - x)].yoffset = -ly;
392 			lens[(radius - y)*width + (radius + x)].xoffset = -lx;
393 			lens[(radius - y)*width + (radius + x)].yoffset =  ly;
394 		}
395 	}
396 	LensOption.lenswidth = width;
397 	LensOption.lenszoom = zoom;
398 	if (clamp < 0) LensOption.clampoffset = width;
399 	else LensOption.clampoffset = clamp;
400 	LensOption.x = lensx;
401 	LensOption.y = lensy;
402 	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
403 	else LensOption.level = level;
404 }
405 
ResetRemapping(ScriptMethodParams &)406 void AGSPalRender::ResetRemapping(ScriptMethodParams &) {
407 	for (int j = 0; j < 256; ++j) {
408 		cycle_remap [j] = j;
409 	}
410 }
411 
412 #define MAX_PLASMA_COMPLEXITY 4
413 int plasmatype[MAX_PLASMA_COMPLEXITY];
414 int plasmadata [MAX_PLASMA_COMPLEXITY];
415 int plasmadata2 [MAX_PLASMA_COMPLEXITY];
416 int plasmadata3 [MAX_PLASMA_COMPLEXITY];
417 int plasmaroottype;
418 
419 
SetPlasmaRootType(ScriptMethodParams & params)420 void AGSPalRender::SetPlasmaRootType(ScriptMethodParams &params) {
421 	PARAMS1(int, real);
422 	if (real) plasmaroottype = 1;
423 	else plasmaroottype = 0;
424 }
425 
GetPlasmaRootType(ScriptMethodParams & params)426 void AGSPalRender::GetPlasmaRootType(ScriptMethodParams &params) {
427 	params._result = plasmaroottype;
428 }
429 
SetPlasmaType(ScriptMethodParams & params)430 void AGSPalRender::SetPlasmaType(ScriptMethodParams &params) {
431 	PARAMS5(int, component, int, type, int, data, int, data2, int, data3);
432 	if (component >= MAX_PLASMA_COMPLEXITY) engine->AbortGame("Plasma too complex!");
433 	else {
434 		plasmatype [component] = type;
435 		plasmadata [component] = data;
436 		plasmadata2[component] = data2;
437 		plasmadata3[component] = data3;
438 	}
439 
440 	//0 = None.
441 	//1 = Horizontal Bars (data=width)
442 	//2 = Vertical Bars (data=width)
443 	//3 = Circle (data=x,data2=y,data3=width)
444 	//4 = Diagonal Bars (data=width)
445 }
446 
ResetPlasmaSettings(ScriptMethodParams &)447 void AGSPalRender::ResetPlasmaSettings(ScriptMethodParams &) {
448 	int i = 0;
449 	while (i < MAX_PLASMA_COMPLEXITY) {
450 		plasmatype [i] = 0;
451 		plasmadata [i] = 0;
452 		plasmadata2[i] = 0;
453 		plasmadata3[i] = 0;
454 		i++;
455 	}
456 }
457 
DrawPlasma(ScriptMethodParams & params)458 void AGSPalRender::DrawPlasma(ScriptMethodParams &params) {
459 	PARAMS3(int, slot, int, palstart, int, palend);
460 	BITMAP *plasmaspr = engine->GetSpriteGraphic(slot);
461 	if (!plasmaspr) engine->AbortGame("Plasma: Not a sprite I can load.");
462 	int32 w, h, basecol, range = 0;
463 	if (palend > palstart) {
464 		range = palend - palstart;
465 		basecol = palstart;
466 	} else {
467 		range = palstart - palend;
468 		basecol = palend;
469 	}
470 	engine->GetBitmapDimensions(plasmaspr, &w, &h, nullptr);
471 	uint8 *plasmarray = engine->GetRawBitmapSurface(plasmaspr);
472 	int plasmapitch = engine->GetBitmapPitch(plasmaspr);
473 	double frange = range / 2.0;
474 	int complex = 0;
475 	int color = 0;
476 	int i = 0;
477 	while (i < MAX_PLASMA_COMPLEXITY) {
478 		if (plasmatype[i] > 0) complex++;
479 		i++;
480 	}
481 	for (int x = 0; x < w; x++) {
482 		for (int y = 0, plasmay = 0; y < h; y++, plasmay += plasmapitch) {
483 			color = 0;
484 			for (int p = 0; p < MAX_PLASMA_COMPLEXITY; p++) {
485 				if (plasmatype[p] == 1) { //1 = Horizontal Bars (data=width)
486 					color += int(frange + (frange * FastSin(y / (float)plasmadata[p])));
487 				} else if (plasmatype[p] == 2) { //2 = Vertical Bars (data=width)
488 					color += int(frange + (frange * FastSin(x / (float)plasmadata[p])));
489 				} else if (plasmatype[p] == 3) { //3 = Circle (data=x,data2=y,data3=width)
490 					int cx, cy = 0;
491 					cx = plasmadata [p];
492 					cy = plasmadata2 [p];
493 					if (plasmaroottype == 1) color += int(frange + (frange * FastSin(q3sqrt((float)((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
494 					else color += int(frange + (frange * FastSin(root(((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
495 				} else if (plasmatype[p] == 4) { //4 = Diagonal Bars (data=width)
496 					color += int(frange + (frange * FastSin((x + y) / (float)plasmadata[p])));
497 				}
498 			}
499 			if (color > 0 && complex > 0) color = color / complex;
500 			plasmarray[plasmay + x] = static_cast<unsigned char>(basecol + color);
501 		}
502 	}
503 	engine->ReleaseBitmapSurface(plasmaspr);
504 	engine->NotifySpriteUpdated(slot);
505 }
506 
DoFire(ScriptMethodParams & params)507 void AGSPalRender::DoFire(ScriptMethodParams &params) {
508 	PARAMS8(int, spriteId, int, masksprite, int, palstart, int, palend, int, strength, int, seed, int, cutoff, int, windspeed);
509 	BITMAP *firespr = engine->GetSpriteGraphic(masksprite);
510 	BITMAP *firecolorspr = engine->GetSpriteGraphic(spriteId);
511 	BITMAP *seedspr;
512 	int32 w, h = 0;
513 	int range, basecol, dir = 0;
514 	if (palend > palstart) {
515 		range = palend - palstart;
516 		basecol = palstart;
517 		dir = 1;
518 	} else {
519 		range = palstart - palend;
520 		basecol = palend;
521 		dir = -1;
522 	}
523 	int divider = 256 / range;
524 	engine->GetBitmapDimensions(firespr, &w, &h, nullptr);
525 	uint8 *fire = engine->GetRawBitmapSurface(firespr);
526 	uint8 *color = engine->GetRawBitmapSurface(firecolorspr);
527 	int firePitch = engine->GetBitmapPitch(firespr);
528 	int colorPitch = engine->GetBitmapPitch(firecolorspr);
529 	int sparky = 0;
530 	//srand(time(NULL));
531 	for (int y = 0, firey = 0; y < h - 1; y++, firey += firePitch) {
532 		if ((int)::AGS::g_vm->getRandomNumber(9) > 7 - windspeed) { //Wind right
533 			for (int x = w - 1; x > 1; x--) {
534 				fire[firey + x] = fire[firey + x - 1];
535 			}
536 		} else if ((int)::AGS::g_vm->getRandomNumber(9) > 7 + windspeed) { // wind left
537 			for (int x = 0; x < w - 1; x++) {
538 				fire[firey + x] = fire[firey + x + 1];
539 			}
540 		}
541 	}
542 	for (int x = 0; x < w; x++) {
543 		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
544 		int firexy = (h - sparky) * firePitch + x;
545 		if (sparky < h && sparky > 0 && fire[firexy] > cutoff &&
546 				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
547 			fire[firexy] = 255;
548 		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
549 		firexy = (h - sparky) * firePitch + x;
550 		if (sparky < h && sparky > 0 && fire[firexy] > cutoff &&
551 				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
552 			fire[firexy] = 0;
553 	}
554 	if (seed == 0) {
555 		int firey = (h - 1) * firePitch;
556 		for (int x = 0; x < w; x++)
557 			fire[firey + x] = 255;
558 		firey = (h - 2) * firePitch;
559 		for (int x = 0; x < w; x++)
560 			fire[firey + x] = ::AGS::g_vm->getRandomNumber(255);
561 	} else if (seed > 0) {
562 		seedspr = engine->GetSpriteGraphic(seed);
563 		BITMAP *virtsc = engine->GetVirtualScreen();
564 		engine->SetVirtualScreen(firespr);
565 		engine->BlitBitmap(0, 0, seedspr, 1);
566 		engine->SetVirtualScreen(virtsc);
567 		engine->ReleaseBitmapSurface(virtsc);
568 		engine->ReleaseBitmapSurface(seedspr);
569 		engine->NotifySpriteUpdated(spriteId);
570 		engine->NotifySpriteUpdated(masksprite);
571 	}
572 
573 	for (int y = 0, firey = 0, colory = 0; y < h - 1; y++, firey += firePitch, colory += colorPitch) {
574 		for (int x = 0; x < w; x++) {
575 			fire[firey + x] =
576 			    ((fire[((y + 1) % h) * firePitch + ((x - 1 + w) % w)]
577 			      + fire[((y + 1) % h) * firePitch + ((x) % w)]
578 			      + fire[((y + 1) % h) * firePitch + ((x + 1) % w)]
579 			      + fire[((y + 2) % h) * firePitch + ((x) % w)])
580 			     * 100) / (400 + (100 - strength));
581 			if (fire[firey + x] < cutoff) fire[firey + x] = 0;
582 			//if (fire[firey + x] ==255) color [colory + x] = palend;
583 			else color [colory + x] = static_cast<uint8>(basecol + (fire[firey + x] / divider) * dir);
584 		}
585 	}
586 	engine->ReleaseBitmapSurface(firespr);
587 	engine->ReleaseBitmapSurface(firecolorspr);
588 	engine->NotifySpriteUpdated(spriteId);
589 	engine->NotifySpriteUpdated(masksprite);
590 }
591 
592 /*
593 unsigned char MixColorAlpha (unsigned char fg,unsigned char bg,unsigned char alpha)
594 {
595 	//unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
596 	//unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
597 	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
598 	//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
599 	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
600 	AGSColor *palette = engine->GetPalette ();
601 	int i=0;
602 	int out_r = (palette[fg].r>>1) * alpha + (palette[bg].r>>1) * (255 - alpha);
603 	int out_g = palette[fg].g * alpha + palette[bg].g * (255 - alpha);
604 	int out_b = (palette[fg].b>>1) * alpha + (palette[bg].b>>1) * (255 - alpha);
605 	//unsigned char ralpha = alpha>>2;
606 	//unsigned char invralpha = 64-ralpha;
607 	//if (ralpha > alpha) engine->AbortGame ("wtf");
608 	//int out_r = alphamultiply[(palette[fg].r>>1)][ralpha] + alphamultiply[(palette[bg].r>>1)][(invralpha)];
609 	//int out_g = alphamultiply[(palette[fg].g)][ralpha] + alphamultiply[(palette[bg].g)][(invralpha)];
610 	//int out_b = alphamultiply[(palette[fg].b>>1)][ralpha] + alphamultiply[(palette[bg].b>>1)][(invralpha)];
611 	out_r = (out_r + 1 + (out_r >> 8)) >> 8;
612 	out_g = (out_g + 1 + (out_g >> 8)) >> 8;
613 	out_b = (out_b + 1 + (out_b >> 8)) >> 8;
614 	i = ((out_r << 11) | (out_g << 5) | out_b);
615 	unsigned char (*clutp) = clut;
616 	//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
617 	unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
618 	//engine->ReleaseBitmapSurface (clutspr);
619 	return result;
620 }
621 
622 unsigned char MixColorAdditive (unsigned char fg,unsigned char bg,unsigned char alpha)
623 {
624 	//unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
625 	//unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
626 	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
627 	//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
628 	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
629 	AGSColor *palette = engine->GetPalette ();
630 	int i=0;
631 	int add_r,add_b,add_g = 0;
632 	char ralpha = alpha>>2;
633 	//if (ralpha > alpha) engine->AbortGame ("wtf");
634 	//add_r = (((palette[fg].r>>1) * (alpha))>>8);
635 	//add_b = (((palette[fg].b>>1) * (alpha))>>8);
636 	//add_g = (((palette[fg].g)    * (alpha))>>8);
637 	add_r = ((alphamultiply[(palette[fg].r>>1)*64+ralpha])>>6);
638 	add_b = ((alphamultiply[(palette[fg].b>>1)*64+ralpha])>>6);
639 	add_g = ((alphamultiply[(palette[fg].g   )*64+ralpha])>>6);
640 	int out_r = min(31,(palette[bg].r>>1) + add_r);
641 	int out_g = min(63, palette[bg].g     + add_g);
642 	int out_b = min(31,(palette[bg].b>>1) + add_b);
643 	i = ((out_r << 11) | (out_g << 5) | out_b);
644 	unsigned char (*clutp) = clut;
645 	unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
646 	//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
647 	//engine->ReleaseBitmapSurface (clutspr);
648 	return result;
649 }
650 */
GetColor565(ScriptMethodParams & params)651 void AGSPalRender::GetColor565(ScriptMethodParams &params) {
652 	PARAMS3(unsigned char, r, unsigned char, g, unsigned char, b);
653 	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
654 	//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
655 	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
656 	int i = ((r << 11) | (g << 5) | b);
657 	unsigned char *clutp = clut;
658 	unsigned char result = *(clutp + i);
659 	result = cycle_remap [result]; //Once again, to make sure that the palette slot used is the right one.
660 	//engine->ReleaseBitmapSurface (clutspr);
661 	params._result = (int)result;
662 }
663 
CycleRemap(ScriptMethodParams & params)664 void AGSPalRender::CycleRemap(ScriptMethodParams &params) {
665 	PARAMS2(int, start, int, end);
666 	if (end > start) {
667 		// Rotate left
668 		int wraparound = cycle_remap [start];
669 		for (; start < end; ++start) {
670 			cycle_remap [start] = cycle_remap [start + 1];
671 		}
672 		cycle_remap [end] = wraparound;
673 	} else if (end < start) {
674 		// Rotate right
675 		int wraparound = cycle_remap [start];
676 		for (; start > end; --start) {
677 			cycle_remap [start] = cycle_remap [start - 1];
678 		}
679 		cycle_remap [end] = wraparound;
680 
681 	}
682 }
683 
GetRemappedSlot(ScriptMethodParams & params)684 void AGSPalRender::GetRemappedSlot(ScriptMethodParams &params) {
685 	PARAMS1(unsigned char, slot);
686 	params._result = cycle_remap [slot];
687 }
688 
LoadCLUT(ScriptMethodParams & params)689 void AGSPalRender::LoadCLUT(ScriptMethodParams &params) {
690 	PARAMS1(int, slot);
691 	if (engine->GetSpriteWidth(slot) != 256 || engine->GetSpriteHeight(slot) != 256) {
692 		params._result = 1;
693 		return;
694 	};
695 	BITMAP *clutimage = engine->GetSpriteGraphic(slot);
696 	uint8 *clutarray = engine->GetRawBitmapSurface(clutimage);
697 	int pitch = engine->GetBitmapPitch(clutimage);
698 	for (int y = 0, arrayy = 0, cluty = 0; y < 256; y++, arrayy += pitch, cluty += 256) {
699 		for (int x = 0; x < 256; x++) {
700 			clut[cluty + x] = clutarray[arrayy + x];
701 		}
702 	}
703 	clutslot = slot;
704 	engine->ReleaseBitmapSurface(clutimage);
705 	params._result = 0;
706 }
707 
SetReflections(ScriptMethodParams & params)708 void AGSPalRender::SetReflections(ScriptMethodParams &params) {
709 	PARAMS1(int, toggle);
710 	drawreflections = toggle;
711 }
712 
IsReflectionsOn(ScriptMethodParams & params)713 void AGSPalRender::IsReflectionsOn(ScriptMethodParams &params) {
714 	params._result = drawreflections;
715 }
716 
GetLuminosityFromPalette(ScriptMethodParams & params)717 void AGSPalRender::GetLuminosityFromPalette(ScriptMethodParams &params) {
718 	PARAMS1(int, slot);
719 	AGSColor *pal = engine->GetPalette();
720 	int lum = (pal[slot].r +
721 	           pal[slot].r +
722 	           pal[slot].r +
723 	           pal[slot].g +
724 	           pal[slot].g +
725 	           pal[slot].g +
726 	           pal[slot].g +
727 	           pal[slot].b) >> 3;
728 	params._result = lum;
729 }
730 
731 
732 
SetStarsOriginPoint(ScriptMethodParams & params)733 void AGSPalRender::SetStarsOriginPoint(ScriptMethodParams &params) {
734 	PARAMS2(int, x, int, y);
735 	Starfield.originx = x;
736 	Starfield.originy = y;
737 }
InitializeStars(ScriptMethodParams & params)738 void AGSPalRender::InitializeStars(ScriptMethodParams &params) {
739 	PARAMS2(int, slot, int, maxstars);
740 	int32 sw, sh = 0;
741 	BITMAP *canvas = engine->GetSpriteGraphic(slot);
742 	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
743 	Starfield.maxstars = maxstars;
744 	Starfield.overscan = 20;
745 	stars = new starstype [Starfield.maxstars];
746 	for (int i = 0; i < Starfield.maxstars; i++) {
747 		stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
748 		if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
749 		stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
750 		if (stars[i].y < 1.0 && stars[i].y > -1.0) stars[i].y = (float)sh;
751 		stars[i].z = (float)(MAX_DEPTH);
752 		stars[i].color = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 240);
753 		stars[i].sprite = 0;
754 		stars[i].maxrad = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 5);
755 	}
756 }
757 
IterateStars(ScriptMethodParams & params)758 void AGSPalRender::IterateStars(ScriptMethodParams &params) {
759 	PARAMS1(int, slot);
760 	long sw, sh = 0;
761 	sw = engine->GetSpriteWidth(slot);
762 	sh = engine->GetSpriteHeight(slot);
763 	for (int i = 0; i < Starfield.maxstars; i++) {
764 		stars[i].z -= Starfield.speed;
765 		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
766 		float k = Starfield.depthmultiplier / stars[i].z;
767 		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
768 		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
769 		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
770 			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
771 			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
772 			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
773 			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
774 			stars[i].z = (float)MAX_DEPTH;
775 			//stars[i].color = (rand () %240);
776 		}
777 	}
778 }
GetStarfieldOverscan(ScriptMethodParams & params)779 void AGSPalRender::GetStarfieldOverscan(ScriptMethodParams &params) {
780 	params._result = Starfield.overscan;
781 }
SetStarfieldOverscan(ScriptMethodParams & params)782 void AGSPalRender::SetStarfieldOverscan(ScriptMethodParams &params) {
783 	PARAMS1(int, overscan);
784 	Starfield.overscan = overscan;
785 }
786 
GetStarfieldOriginX(ScriptMethodParams & params)787 void AGSPalRender::GetStarfieldOriginX(ScriptMethodParams &params) {
788 	params._result = Starfield.originx;
789 }
790 
GetStarfieldOriginY(ScriptMethodParams & params)791 void AGSPalRender::GetStarfieldOriginY(ScriptMethodParams &params) {
792 	params._result = Starfield.originy;
793 }
794 
SetStarfieldDepthMultiplier(ScriptMethodParams & params)795 void AGSPalRender::SetStarfieldDepthMultiplier(ScriptMethodParams &params) {
796 	PARAMS1(int, multi);
797 	Starfield.depthmultiplier = multi;
798 }
799 
GetStarfieldDepthMultiplier(ScriptMethodParams & params)800 void AGSPalRender::GetStarfieldDepthMultiplier(ScriptMethodParams &params) {
801 	params._result = Starfield.depthmultiplier;
802 }
803 
GetStarfieldMaxStars(ScriptMethodParams & params)804 void AGSPalRender::GetStarfieldMaxStars(ScriptMethodParams &params) {
805 	params._result = Starfield.maxstars;
806 }
807 
SetStarSpriteScaleBoost(ScriptMethodParams & params)808 void AGSPalRender::SetStarSpriteScaleBoost(ScriptMethodParams &params) {
809 	PARAMS2(int, star, int, boost);
810 	stars[star].scaleboost = boost;
811 }
812 
GetStarSpriteScaleBoost(ScriptMethodParams & params)813 void AGSPalRender::GetStarSpriteScaleBoost(ScriptMethodParams &params) {
814 	PARAMS1(int, star);
815 	params._result = stars[star].scaleboost;
816 }
817 
SetStarMaxRadius(ScriptMethodParams & params)818 void AGSPalRender::SetStarMaxRadius(ScriptMethodParams &params) {
819 	PARAMS2(int, star, int, radius);
820 	stars[star].maxrad = radius;
821 }
822 
GetStarMaxRadius(ScriptMethodParams & params)823 void AGSPalRender::GetStarMaxRadius(ScriptMethodParams &params) {
824 	PARAMS1(int, star);
825 	params._result = stars[star].maxrad;
826 }
827 
RotateStar(ScriptMethodParams & params)828 void AGSPalRender::RotateStar(ScriptMethodParams &params) {
829 	PARAMS4(int, star, int, angle, int, px, int, py);
830 	float rsin = rot_sine_LUT[angle];
831 	float rcos = rot_cos_LUT[angle];
832 	float fPx = (float)px;
833 	float fPy = (float)py;
834 	float x1 = 0, y1 = 0, xRot = 0, yRot = 0;
835 	int i = star;
836 	x1 = stars[i].x;
837 	y1 = stars[i].y;
838 	xRot = fPx + rcos * (x1 - fPx) - rsin * (y1 - fPy);
839 	yRot = fPy + rsin * (x1 - fPx) + rcos * (y1 - fPy);
840 	stars[i].x = xRot;
841 	stars[i].y = yRot;
842 	i++;
843 }
844 
GetStarX(ScriptMethodParams & params)845 void AGSPalRender::GetStarX(ScriptMethodParams &params) {
846 	PARAMS1(int, i);
847 	float starx = (float)stars[i].x;
848 	params._result = PARAM_FROM_FLOAT(starx);
849 }
850 
GetStarY(ScriptMethodParams & params)851 void AGSPalRender::GetStarY(ScriptMethodParams &params) {
852 	PARAMS1(int, i);
853 	float stary = (float)stars[i].y;
854 	params._result = PARAM_FROM_FLOAT(stary);
855 }
856 
GetStarZ(ScriptMethodParams & params)857 void AGSPalRender::GetStarZ(ScriptMethodParams &params) {
858 	PARAMS1(int, i);
859 	float starz = (float)stars[i].z;
860 	params._result = PARAM_FROM_FLOAT(starz);
861 }
862 
SetStarPosition(ScriptMethodParams & params)863 void AGSPalRender::SetStarPosition(ScriptMethodParams &params) {
864 	PARAMS4(int, star, int32, xi, int32, yi, int32, zi);
865 	float x = PARAM_TO_FLOAT(xi);
866 	float y = PARAM_TO_FLOAT(yi);
867 	float z = PARAM_TO_FLOAT(zi);
868 	stars[star].x = x;
869 	stars[star].y = y;
870 	stars[star].z = z;
871 }
872 
SetStarColor(ScriptMethodParams & params)873 void AGSPalRender::SetStarColor(ScriptMethodParams &params) {
874 	PARAMS2(int, star, unsigned char, color);
875 	stars[star].color = color;
876 }
877 
GetStarColor(ScriptMethodParams & params)878 void AGSPalRender::GetStarColor(ScriptMethodParams &params) {
879 	PARAMS1(int, star);
880 	params._result = (int)stars[star].color;
881 }
882 
SetStarSprite(ScriptMethodParams & params)883 void AGSPalRender::SetStarSprite(ScriptMethodParams &params) {
884 	PARAMS2(int, star, int, slot);
885 	stars[star].sprite = slot;
886 }
887 
GetStarSprite(ScriptMethodParams & params)888 void AGSPalRender::GetStarSprite(ScriptMethodParams &params) {
889 	PARAMS1(int, star);
890 	params._result = stars[star].sprite;
891 }
892 
SetStarSpriteRange(ScriptMethodParams & params)893 void AGSPalRender::SetStarSpriteRange(ScriptMethodParams &params) {
894 	PARAMS3(int, start, int, end, int, slot);
895 	int sfix = start;
896 	int efix = end;
897 	if (start > Starfield.maxstars) sfix = Starfield.maxstars - 1;
898 	if (end > Starfield.maxstars) efix = Starfield.maxstars;
899 	for (int i = sfix; i < efix; i++)
900 		stars[i].sprite = slot;
901 }
902 
DrawStars(ScriptMethodParams & params)903 void AGSPalRender::DrawStars(ScriptMethodParams &params) {
904 	PARAMS2(int, slot, int, maskslot);
905 	int32 sw, sh = 0;
906 	BITMAP *canvas = engine->GetSpriteGraphic(slot);
907 	if (!canvas) engine->AbortGame("DrawStars: Can't load sprite slot.");
908 	BITMAP *maskcanvas = engine->GetSpriteGraphic(maskslot);
909 	if (!maskcanvas) engine->AbortGame("DrawStars: Can't load mask slot.");
910 	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
911 	uint8 *screenarray = engine->GetRawBitmapSurface(canvas);
912 	uint8 *maskarray = engine->GetRawBitmapSurface(maskcanvas);
913 	int screenPitch = engine->GetBitmapPitch(canvas);
914 	int maskPitch = engine->GetBitmapPitch(maskcanvas);
915 	for (int i = 0; i < Starfield.maxstars; i++) {
916 		//stars[i].z-= 0.5;
917 		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
918 		float k = (float)Starfield.depthmultiplier / stars[i].z;
919 		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
920 		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
921 		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
922 			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
923 			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
924 			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
925 			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
926 			stars[i].z = (float)MAX_DEPTH;
927 			//stars[i].color = (rand () %240);
928 		} else if (stars[i].z > 0) {
929 			int ivalue = (63 - (int)stars[i].z);
930 			if (ivalue > 63) ivalue = 63;
931 			else if (ivalue < 0) ivalue = 0;
932 			unsigned char value = (unsigned char)(ivalue);
933 			unsigned char maskcolor = value << 2;
934 			if (stars[i].sprite > 0) {
935 				BITMAP *origspr = engine->GetSpriteGraphic(stars[i].sprite);
936 				int scale = (ivalue + 1) * 100 >> 6;
937 				//int scale = 50;
938 				if (scale < 1) scale = 1;
939 				/*
940 				if (scale != 100)
941 				{
942 				uint8 * orig = engine->GetRawBitmapSurface (origspr);
943 				int origPitch = engine->GetBitmapPitch(origspr);
944 				int32 h1,h2,w1,w2=0;
945 				double fw2,fh2;
946 				engine->GetBitmapDimensions (origspr,&w1,&h1,NULL);
947 				fh2 = h1 * (scale / 100.0);
948 				fw2 = w1 * (scale / 100.0);
949 				h2 = static_cast<int>(fh2);
950 				w2 = static_cast<int>(fw2);
951 				if (w2 < 1) w2 = 1;
952 				if (h2 < 1) h2 = 1;
953 				resizspr = engine->CreateBlankBitmap (w2,h2,8);
954 				uint8 * resized = engine->GetRawBitmapSurface (resizspr);
955 				int resizePitch = engine->GetBitmapPitch(resizspr);
956 				int x_ratio = (int)((w1<<16)/w2) +1;
957 				int y_ratio = (int)((h1<<16)/h2) +1;
958 				int x2, y2 ;
959 				for (int i=0;i<h2;i++)
960 				{
961 				    for (int j=0;j<w2;j++)
962 				   {
963 				       x2 = ((j*x_ratio)>>16) ;
964 				       y2 = ((i*y_ratio)>>16) ;
965 				       resized [i * resizePitch + j] = orig [y2 * origPitch + x2];
966 				 }
967 				}
968 				engine->ReleaseBitmapSurface (resizspr);
969 				}
970 				//resizspr = origspr;
971 				int32 w,h=0;
972 				engine->GetBitmapDimensions (resizspr,&w,&h,NULL);
973 				uint8 *imagemap = engine->GetRawBitmapSurface (resizspr);
974 				int imagePitch = engine->GetBitmapPitch(resizspr);
975 				int ox = px - (w>>1);
976 				int oy = py - (h>>1);
977 				for (int dy=0;dy<h;dy++)
978 				{
979 				for (int dx=0;dx<w;dx++)
980 				{
981 				   int ex = ox+dx;
982 				   int ey = oy+dy;
983 				   if (ex < sw && ex >= 0 && ey < sh && ey >= 0)
984 				   {
985 				       if (maskcolor > maskarray [ey * maskPitch + ex] && imagemap[dy * imagePitch + dx] > 0)
986 				       {
987 				           maskarray [ey * maskPitch + ex] = maskcolor;
988 				           screenarray [ey * screenPitch + ex] = imagemap[dy][dx];
989 				       }
990 				   }
991 				}
992 				}
993 				*/
994 
995 				uint8 *orig = engine->GetRawBitmapSurface(origspr);
996 				int origPitch = engine->GetBitmapPitch(origspr);
997 				int32 h1, h2, w1, w2 = 0;
998 				double fw2, fh2;
999 				engine->GetBitmapDimensions(origspr, &w1, &h1, nullptr);
1000 				fh2 = h1 * (scale / 100.0);
1001 				fw2 = w1 * (scale / 100.0);
1002 				h2 = static_cast<int>(fh2);
1003 				w2 = static_cast<int>(fw2);
1004 				if (w2 < 1) w2 = 1;
1005 				if (h2 < 1) h2 = 1;
1006 				int x_ratio = (int)((w1 << 16) / w2) + 1;
1007 				int y_ratio = (int)((h1 << 16) / h2) + 1;
1008 				int x2, y2 ;
1009 				int ox = px - (w2 >> 1);
1010 				int oy = py - (h2 >> 1);
1011 				for (int ii = 0; ii < h2; ii++) {
1012 					int temprzy = ii * y_ratio;
1013 					int ey = oy + ii;
1014 					for (int j = 0; j < w2; j++) {
1015 						x2 = ((j * x_ratio) >> 16);
1016 						y2 = ((temprzy) >> 16);
1017 						int ex = ox + j;
1018 						if (ex < sw && ex >= 0 && ey < sh && ey >= 0) {
1019 							if (maskcolor > maskarray [ey * maskPitch + ex] && orig[y2 * origPitch + x2] > 0) {
1020 								maskarray [ey * maskPitch + ex] = maskcolor;
1021 								screenarray [ey * screenPitch + ex] = orig[y2 * origPitch + x2];
1022 							}
1023 						}
1024 						//resized [ii][j] = orig [y2 * origPitch + x2];
1025 					}
1026 				}
1027 				engine->ReleaseBitmapSurface(origspr);
1028 			} else if (stars[i].sprite == 0) {
1029 				if (stars[i].maxrad == 1) {
1030 					if (px < sw && px >= 0 && py < sh && py >= 0) {
1031 						if (maskcolor > maskarray[py * maskPitch + px]) {
1032 							maskarray[py * maskPitch + px] = maskcolor;
1033 							screenarray[py * screenPitch + px] = stars[i].color;
1034 						}
1035 					}
1036 				} else {
1037 					int scale = ((((int)stars[i].z) * 100) / 63);
1038 					if (scale < 1) scale = 1;
1039 					int radius = (stars[i].maxrad * (100 - scale) / 100);
1040 					int radsq = radius * radius;
1041 					//unsigned char color = GetColor565 (value>>1,value,value>>1);
1042 					unsigned char color = stars[i].color;
1043 					for (int cy = -radius; cy <= radius; cy++) { //Draw a circle around the point, for the mask.
1044 						int cysq = cy * cy;
1045 						for (int cx = -radius; cx <= radius; cx++) {
1046 							int cxsq = cx * cx;
1047 							int dx = cx + px;
1048 							int dy = cy + py;
1049 							if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0) {
1050 								if (maskcolor > maskarray [dy * maskPitch + dx]) {
1051 									maskarray [dy * maskPitch + dx] = maskcolor;
1052 									screenarray [dy * screenPitch + dx] = color;
1053 								}
1054 							}
1055 						}
1056 					}
1057 					/*
1058 					for(int cy=-radius; cy<=radius; cy++) //Draw a circle around the point, for the color.
1059 					{
1060 					   int cysq = cy*cy;
1061 					for(int cx=-radius; cx<=radius; cx++)
1062 					   {
1063 					       int cxsq = cx*cx;
1064 					       int dx = cx+px;
1065 					       int dy = cy+py;
1066 					       if((cxsq+cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0)
1067 					       {
1068 					           if (maskarray [dy * maskPitch + dx] == maskcolor)screenarray [dy * screenPitch + dx] = color;
1069 					       }
1070 					   }
1071 					}
1072 					*/
1073 				}
1074 			}
1075 		}
1076 	}
1077 	engine->ReleaseBitmapSurface(canvas);
1078 	engine->ReleaseBitmapSurface(maskcanvas);
1079 	engine->NotifySpriteUpdated(slot);
1080 	engine->NotifySpriteUpdated(maskslot);
1081 }
1082 
1083 
CreateTranslucentOverlay(ScriptMethodParams & params)1084 void AGSPalRender::CreateTranslucentOverlay(ScriptMethodParams &params) {
1085 	PARAMS6(int, id, int, spriteId, int, alpha, int, level, int, ox, int, oy);
1086 	int mask = 0, blendmode = 0;
1087 	if (params.size() > 6)
1088 		mask = params[6];
1089 	if (params.size() > 7)
1090 		blendmode = params[7];
1091 	BITMAP *testspr = engine->GetSpriteGraphic(spriteId);
1092 	if (testspr) overlay[id].sprite = spriteId;
1093 	else engine->AbortGame("CreateTranslucentOverlay: Invalid spriteId.");
1094 	engine->ReleaseBitmapSurface(testspr);
1095 	overlay[id].level = MAX(0, MIN(level, 4));
1096 	overlay[id].trans = MAX(0, MIN(alpha, 255));
1097 	overlay[id].spritemask = mask;
1098 	overlay[id].x = ox;
1099 	overlay[id].y = oy;
1100 	overlay[id].enabled = true;
1101 	overlay[id].blendtype = blendmode;
1102 	params._result = 0;
1103 }
1104 
DeleteTranslucentOverlay(ScriptMethodParams & params)1105 void AGSPalRender::DeleteTranslucentOverlay(ScriptMethodParams &params) {
1106 	PARAMS1(int, id);
1107 	overlay[id].enabled = false;
1108 	overlay[id].sprite = 0;
1109 	overlay[id].x = 0;
1110 	overlay[id].y = 0;
1111 	overlay[id].level = 0;
1112 	overlay[id].trans = 0;
1113 	params._result = 0;
1114 }
1115 
MoveTranslucentOverlay(ScriptMethodParams & params)1116 void AGSPalRender::MoveTranslucentOverlay(ScriptMethodParams &params) {
1117 	PARAMS3(int, id, int, ox, int, oy);
1118 	overlay[id].x = ox;
1119 	overlay[id].y = oy;
1120 	params._result = 0;
1121 }
1122 
GetTranslucentOverlayX(ScriptMethodParams & params)1123 void AGSPalRender::GetTranslucentOverlayX(ScriptMethodParams &params) {
1124 	PARAMS1(int, id);
1125 	params._result = overlay[id].x;
1126 }
1127 
GetTranslucentOverlayY(ScriptMethodParams & params)1128 void AGSPalRender::GetTranslucentOverlayY(ScriptMethodParams &params) {
1129 	PARAMS1(int, id);
1130 	params._result = overlay[id].y;
1131 }
1132 
GetTranslucentOverlaySprite(ScriptMethodParams & params)1133 void AGSPalRender::GetTranslucentOverlaySprite(ScriptMethodParams &params) {
1134 	PARAMS1(int, id);
1135 	params._result = overlay[id].sprite;
1136 }
1137 
GetTranslucentOverlayLevel(ScriptMethodParams & params)1138 void AGSPalRender::GetTranslucentOverlayLevel(ScriptMethodParams &params) {
1139 	PARAMS1(int, id);
1140 	params._result = overlay[id].level;
1141 }
1142 
GetTranslucentOverlayEnabled(ScriptMethodParams & params)1143 void AGSPalRender::GetTranslucentOverlayEnabled(ScriptMethodParams &params) {
1144 	PARAMS1(int, id);
1145 	params._result = overlay[id].enabled;
1146 }
1147 
GetTranslucentOverlayAlpha(ScriptMethodParams & params)1148 void AGSPalRender::GetTranslucentOverlayAlpha(ScriptMethodParams &params) {
1149 	PARAMS1(int, id);
1150 	params._result = overlay[id].trans;
1151 }
1152 
SetTranslucentOverlayAlpha(ScriptMethodParams & params)1153 void AGSPalRender::SetTranslucentOverlayAlpha(ScriptMethodParams &params) {
1154 	PARAMS2(int, id, int, alpha);
1155 	if (alpha >= 0 && alpha < 256)
1156 		overlay[id].trans = alpha;
1157 	else
1158 		engine->AbortGame("CreateTranslucentOverlay: Invalid alpha selected.");
1159 	params._result = 0;
1160 }
1161 
SetTranslucentOverlayEnabled(ScriptMethodParams & params)1162 void AGSPalRender::SetTranslucentOverlayEnabled(ScriptMethodParams &params) {
1163 	PARAMS2(int, id, int, toggle);
1164 	if (toggle > 0)
1165 		overlay[id].enabled = true;
1166 	else
1167 		overlay[id].enabled = false;
1168 	params._result = 0;
1169 }
1170 
SetCharacterReflected(ScriptMethodParams & params)1171 void AGSPalRender::SetCharacterReflected(ScriptMethodParams &params) {
1172 	PARAMS2(int, id, int, refl);
1173 	if (refl > 0) Reflection.Characters[id].reflect = 1;
1174 	else Reflection.Characters[id].reflect = 0;
1175 }
1176 
SetObjectReflected(ScriptMethodParams & params)1177 void AGSPalRender::SetObjectReflected(ScriptMethodParams &params) {
1178 	PARAMS2(int, id, int, refl);
1179 	if (refl > 0)
1180 		Reflection.Objects[id].reflect = 1;
1181 	else
1182 		Reflection.Objects[id].reflect = 0;
1183 }
1184 
GetCharacterReflected(ScriptMethodParams & params)1185 void AGSPalRender::GetCharacterReflected(ScriptMethodParams &params) {
1186 	PARAMS1(int, id);
1187 	params._result = Reflection.Characters[id].reflect;
1188 }
1189 
GetObjectReflected(ScriptMethodParams & params)1190 void AGSPalRender::GetObjectReflected(ScriptMethodParams &params) {
1191 	PARAMS1(int, id);
1192 	params._result = Reflection.Objects[id].reflect;
1193 }
1194 
ReplaceCharacterReflectionView(ScriptMethodParams & params)1195 void AGSPalRender::ReplaceCharacterReflectionView(ScriptMethodParams &params) {
1196 	PARAMS2(int, id, int, view);
1197 	Reflection.Characters[id].replaceview = view - 1;
1198 }
1199 
SetObjectReflectionIgnoreScaling(ScriptMethodParams & params)1200 void AGSPalRender::SetObjectReflectionIgnoreScaling(ScriptMethodParams &params) {
1201 	PARAMS2(int, id, int, wb);
1202 	if (wb) Reflection.Objects[id].ignorescaling = 1;
1203 	else    Reflection.Objects[id].ignorescaling = 0;
1204 }
1205 
DrawReflections(int id,int charobj=0)1206 int DrawReflections(int id, int charobj = 0) {
1207 	int32 screenw, screenh;
1208 	int32 bgw, bgh;
1209 	engine->GetScreenDimensions(&screenw, &screenh, nullptr);
1210 	BITMAP *bgmask = engine->GetBackgroundScene(1);
1211 	if (bgmask == nullptr) return 1;
1212 	//BITMAP *virtsc = engine->GetVirtualScreen();
1213 	BITMAP *walkbehind = engine->GetRoomMask(MASK_WALKBEHIND);
1214 	//if (!virtsc) engine->AbortGame ("Can't load virtual screen.");
1215 	if (!walkbehind) engine->AbortGame("DrawRelfections: Can't load Walkbehind into memory.");
1216 	engine->GetBitmapDimensions(walkbehind, &bgw, &bgh, nullptr);
1217 	if (!bgmask) engine->AbortGame("DrawReflections: Can't load reflection mask.");
1218 	//unsigned char **charbuffer = engine->GetRawBitmapSurface (virtsc);
1219 	uint8 *wbarray = engine->GetRawBitmapSurface(walkbehind);
1220 	uint8 *maskarray = engine->GetRawBitmapSurface(bgmask);
1221 	int wbPitch = engine->GetBitmapPitch(walkbehind);
1222 	int maskPitch = engine->GetBitmapPitch(bgmask);
1223 	//Initialize stuff
1224 	BITMAP *charsprite = nullptr;
1225 	BITMAP *charsprite2 = nullptr;
1226 	AGSCharacter *currchar = nullptr;
1227 	AGSObject *currobj;
1228 	int cox = 0, coy = 0, coz = 0;
1229 	int scale = 0;
1230 	//Get character, and their sprite.
1231 	if (charobj == 0) {
1232 		currchar = engine->GetCharacter(id);
1233 		/*int view = 0;
1234 		if (Reflection.Characters[id].replaceview == 0) view = currchar->view + 1;
1235 		else view = Reflection.Characters[id].replaceview;
1236 		*/
1237 		AGSViewFrame *vf = engine->GetViewFrame(currchar->view + 1, currchar->loop, currchar->frame);
1238 		charsprite = engine->GetSpriteGraphic(vf->pic);
1239 		long scaling = currchar->flags & CHF_NOSCALING;
1240 		if (!scaling)scale = engine->GetAreaScaling(currchar->x, currchar->y);
1241 		else scale = 100;
1242 		cox = currchar->x;
1243 		coy = currchar->y;
1244 		coz = currchar->z;
1245 	} else if (charobj == 1) {
1246 		currobj = engine->GetObject(id);
1247 
1248 		charsprite = engine->GetSpriteGraphic(currobj->num);
1249 		if (Reflection.Objects[id].ignorescaling) scale = 100;
1250 		else scale = engine->GetAreaScaling(currobj->x, currobj->y);
1251 		cox = currobj->x;
1252 		if (currobj->baseline < 0) coy = currobj->y;
1253 		else coy = currobj->baseline;
1254 		coz = 0;
1255 	}
1256 	bool scaled = false;
1257 	int32 w, h;
1258 	engine->GetBitmapDimensions(charsprite, &w, &h, nullptr);
1259 	if (scale != 100) {
1260 		uint8 *orig = engine->GetRawBitmapSurface(charsprite);
1261 		int origPitch = engine->GetBitmapPitch(charsprite);
1262 		int h1, h2, w1, w2;
1263 		double fw2, fh2;
1264 		h1 = h;
1265 		w1 = w;
1266 		fh2 = h1 * ((double)scale / 100.0);
1267 		fw2 = w1 * ((double)scale / 100.0);
1268 		h2 = static_cast<int>(fh2);
1269 		w2 = static_cast<int>(fw2);
1270 		charsprite2 = engine->CreateBlankBitmap(w2, h2, 8);
1271 		uint8 *resized = engine->GetRawBitmapSurface(charsprite2);
1272 		int resizedPitch = engine->GetBitmapPitch(charsprite2);
1273 		int x_ratio = (int)((w1 << 16) / w2) + 1;
1274 		int y_ratio = (int)((h1 << 16) / h2) + 1;
1275 		int x2, y2 ;
1276 		for (int i = 0; i < h2; i++) {
1277 			for (int j = 0; j < w2; j++) {
1278 				x2 = ((j * x_ratio) >> 16) ;
1279 				y2 = ((i * y_ratio) >> 16) ;
1280 				resized [i * resizedPitch + j] = orig [y2 * origPitch + x2];
1281 			}
1282 		}
1283 		engine->ReleaseBitmapSurface(charsprite2);
1284 		scaled = true;
1285 		w = w2;
1286 		h = h2;
1287 	} else {
1288 		charsprite2 = charsprite;
1289 	}
1290 	int transamount = 0;
1291 	uint8 *spritearray = engine->GetRawBitmapSurface(charsprite2);
1292 	uint8 *charbuffer = engine->GetRawBitmapSurface(rcolormap);
1293 	uint8 *alphaarray = engine->GetRawBitmapSurface(ralphamap);
1294 	int spritePitch = engine->GetBitmapPitch(charsprite2);
1295 	int charPitch = engine->GetBitmapPitch(rcolormap);
1296 	int alphaPitch = engine->GetBitmapPitch(ralphamap);
1297 	int i = h - 1, j = 0;
1298 	int32 ox = cox;
1299 	if (charobj == 0) ox = ox - (w / 2);
1300 	int32 oy = coy + coz - 1;
1301 	engine->RoomToViewport(&ox, &oy);
1302 	int yoffset = 0;
1303 	int translevel = 7;
1304 	//bool dither = false;
1305 	//bool dodither = false;
1306 	int counter = 0;
1307 	int rowcount = 101 - (int)(50.0 * ((double)(scale) / 100.0));
1308 	int delay = screenh / rowcount;
1309 	int *obst;
1310 	int flipped = 0;
1311 	if (charobj == 0) {
1312 		PluginMethod sfGetGameParameter = engine->GetScriptFunctionAddress("GetGameParameter");
1313 		flipped = sfGetGameParameter(13, currchar->view + 1, currchar->loop, currchar->frame);
1314 	} else flipped = 0;
1315 	obst = new int [w];
1316 	for (int k = 0; k < w; k++) {
1317 		obst[k] = 0;
1318 	}
1319 	while (i > 0) {
1320 		//if ((counter == delay/2-1 || counter == delay-1) && yoffset < 36) dodither = (!dodither);
1321 		if (counter == delay) {
1322 			counter = 0;
1323 			if (translevel > 0) translevel--;
1324 		} else counter++;
1325 		yoffset++;
1326 		while (j < w) {
1327 			int xoffset;
1328 			if (flipped == 1) xoffset = w - j - 1;
1329 			else xoffset = j;
1330 			int32 rx = ox + xoffset, ry = oy + yoffset;
1331 			int wbb = 0;
1332 			engine->ViewportToRoom(&rx, &ry);
1333 			if (ry > 0 && ry < bgh && rx > 0 && rx < bgw) {
1334 				if (wbarray [ry * wbPitch + rx] > 0) {
1335 					wbb = engine->GetWalkbehindBaseline(wbarray[ry * wbPitch + rx]);
1336 				}
1337 				if (maskarray[ry * maskPitch + rx] == 21) obst[j] = 1;
1338 			}
1339 
1340 			//dither = (!dither);
1341 			transamount = 32 * translevel;
1342 			if (spritearray [i * spritePitch + j] != 0 && oy + yoffset < screenh && ox + xoffset < screenw && oy + yoffset >= 0 && ox + xoffset >= 0) { // If the sprite isn't transparent, and isn't drawn off the edge of the bg.
1343 				if (wbb < ry && obst[j] == 0 && (oy > reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))])) {
1344 					//charbuffer[(oy+yoffset) * charPitch + ox+xoffset] = MixColorAlpha (spritearray [i * spritePitch + j],charbuffer[(oy+yoffset) * charPitch + ox+xoffset],transamount);
1345 					charbuffer [(oy + yoffset) * charPitch + ox + xoffset] = spritearray [i * spritePitch + j];
1346 					alphaarray [(oy + yoffset) * alphaPitch + ox + xoffset] = transamount;
1347 					reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))] = oy;
1348 				}
1349 			}
1350 			j++;
1351 		}
1352 		//if (w % 2 == 0) dither = (!dither);
1353 		i--;
1354 		j = 0;
1355 	}
1356 
1357 	delete[] obst;
1358 	if (scaled == true)engine->FreeBitmap(charsprite2);
1359 	engine->ReleaseBitmapSurface(charsprite);
1360 	//engine->ReleaseBitmapSurface (virtsc);
1361 	//engine->ReleaseBitmapSurface (clutspr);
1362 	engine->ReleaseBitmapSurface(bgmask);
1363 	engine->ReleaseBitmapSurface(walkbehind);
1364 	engine->ReleaseBitmapSurface(rcolormap);
1365 	engine->ReleaseBitmapSurface(ralphamap);
1366 	engine->MarkRegionDirty(ox, oy, ox + w, oy + h);
1367 	return 0;
1368 }
1369 
1370 
DrawTransSprite(ScriptMethodParams & params)1371 void AGSPalRender::DrawTransSprite(ScriptMethodParams &params) {
1372 	PARAMS3(int, spriteId, int, bg, int, translevel);
1373 	int mask = 0, blendmode = 0, use_objpal = 0;
1374 	if (params.size() > 3)
1375 		mask = params[3];
1376 	if (params.size() > 4)
1377 		blendmode = params[4];
1378 	if (params.size() > 5)
1379 		use_objpal = params[5];
1380 
1381 	BITMAP *maskspr = nullptr;
1382 	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
1383 	if (!maskspr && mask > 0) {
1384 		char maskerr [100];
1385 		snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
1386 		engine->AbortGame(maskerr);
1387 	}
1388 	// Get a reference to the screen we'll draw onto
1389 	BITMAP *bgspr = engine->GetSpriteGraphic(bg);
1390 	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
1391 	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
1392 	if (!bgspr) engine->AbortGame("DrawTransSprite: Can't load background");
1393 	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
1394 	if (!spritespr) engine->AbortGame("DrawTransSprite: Can't load overlay spriteId into memory.");
1395 	// Get its surface
1396 	int32 sprw, sprh, coldepth;
1397 	int32 bgw, bgh;
1398 	engine->GetBitmapDimensions(bgspr, &bgw, &bgh, &coldepth);
1399 	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
1400 
1401 	uint8 *bgarray = engine->GetRawBitmapSurface(bgspr);
1402 	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
1403 	uint8 *spritearray = engine->GetRawBitmapSurface(spritespr);
1404 	int bgPitch = engine->GetBitmapPitch(bgspr);
1405 	//int clutPitch = engine->GetBitmapPitch(clutspr);
1406 	int spritePitch = engine->GetBitmapPitch(spritespr);
1407 
1408 	unsigned char *maskarray = nullptr;
1409 	int maskPitch = 0;
1410 	if (mask > 0) {
1411 		maskarray = engine->GetRawBitmapSurface(maskspr);
1412 		maskPitch = engine->GetBitmapPitch(maskspr);
1413 	}
1414 	int tloffset = 255 - translevel;
1415 	int x = 0;
1416 	int y = 0;
1417 	//int transamount = 256 * translevel; //old
1418 	while (y < sprh) {
1419 		while (x < sprw) {
1420 			if (spritearray [y * spritePitch + x] != 0 && y < bgh && x < bgw && y >= 0 && x >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the bg.
1421 				if (mask > 0) {
1422 					translevel = MAX(maskarray [y * maskPitch + x] - tloffset, 0);
1423 				}
1424 				//spritearray[y * spritePitch + x] = cycle_remap[clutarray [(cycle_remap[bgarray[y * bgPitch + x]]+transamount) * clutPitch + (cycle_remap[spritearray [y * spritePitch + x]])]; //old
1425 				if (blendmode == 0) spritearray[y * spritePitch + x] = Mix::MixColorAlpha(spritearray [y * spritePitch + x], bgarray[y * bgPitch + x], translevel, use_objpal);
1426 				else if (blendmode == 1) spritearray[y * spritePitch + x] = Mix::MixColorAdditive(spritearray [y * spritePitch + x], bgarray[y * bgPitch + x], translevel, use_objpal);
1427 			}
1428 			x++;
1429 		}
1430 		x = 0;
1431 		y++;
1432 	}
1433 
1434 	// Release the screen so that the engine can continue
1435 	engine->ReleaseBitmapSurface(bgspr);
1436 	//engine->ReleaseBitmapSurface (clutspr);
1437 	engine->ReleaseBitmapSurface(spritespr);
1438 	engine->NotifySpriteUpdated(spriteId);
1439 	params._result = 0;
1440 }
1441 
DrawTranslucentOverlay(int spriteId,int translevel,int ox,int oy,int mask=0,int blendmode=0)1442 int DrawTranslucentOverlay(int spriteId, int translevel, int ox, int oy, int mask = 0, int blendmode = 0) {
1443 	if (translevel == 0) return 0;
1444 	BITMAP *maskspr = nullptr;
1445 	// Get a reference to the screen we'll draw onto
1446 	BITMAP *virtsc = engine->GetVirtualScreen();
1447 	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
1448 	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
1449 	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
1450 	if (!virtsc) engine->AbortGame("DrawTranslucentOverlay: Can't load virtual screen.");
1451 	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
1452 	if (!spritespr) engine->AbortGame("DrawTranslucentOverlay: Can't load overlay spriteId into memory.");
1453 	// Get its surface
1454 	int32 sprw, sprh, coldepth;
1455 	int32 screenw, screenh;
1456 	engine->GetScreenDimensions(&screenw, &screenh, &coldepth);
1457 	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
1458 	uint8 *charbuffer = engine->GetRawBitmapSurface(virtsc);
1459 	uint8 *spritearray = engine->GetRawBitmapSurface(spritespr);
1460 	int charPitch = engine->GetBitmapPitch(virtsc);
1461 	int spritePitch = engine->GetBitmapPitch(spritespr);
1462 	uint8 *maskarray = nullptr;
1463 	int maskPitch = 0;
1464 	if (mask > 0) {
1465 		if (!maskspr && mask > 0) {
1466 			char maskerr [100];
1467 			snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
1468 			engine->AbortGame(maskerr);
1469 		}
1470 		maskarray = engine->GetRawBitmapSurface(maskspr);
1471 		maskPitch = engine->GetBitmapPitch(maskspr);
1472 	}
1473 	int tloffset = 255 - translevel;
1474 	int x = 0;
1475 	int y = 0;
1476 	//int transamount = 256 * translevel; //old
1477 	while (y < sprh) {
1478 		while (x < sprw) {
1479 			if (spritearray [y * spritePitch + x] != 0 && y + oy < screenh && x + ox < screenw && y + oy >= 0 && x + ox >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the screen.
1480 				//charbuffer[(y+oy) * charPitch + x+ox] = cycle_remap[clutarray ([cycle_remap[charbuffer[(y+oy) * charPitch + x+ox]]+transamount) * clutPitch + (cycle_remap[spritearray [y * spritePitch + x]])]; //old
1481 				if (mask > 0) {
1482 					translevel = MAX(maskarray [y * maskPitch + x] - tloffset, 0);
1483 				}
1484 				if (blendmode == 0) {
1485 					if (translevel == 255) {
1486 						charbuffer[(y + oy) * charPitch + x + ox] = spritearray [y * spritePitch + x];
1487 					} else charbuffer[(y + oy) * charPitch + x + ox] = Mix::MixColorAlpha(spritearray [y * spritePitch + x], charbuffer[(y + oy) * charPitch + x + ox], translevel);
1488 				} else if (blendmode == 1) charbuffer[(y + oy) * charPitch + x + ox] = Mix::MixColorAdditive(spritearray [y * spritePitch + x], charbuffer[(y + oy) * charPitch + x + ox], translevel);
1489 			}
1490 			x++;
1491 		}
1492 		x = 0;
1493 		y++;
1494 	}
1495 
1496 	// Release the screen so that the engine can continue
1497 	long dirtywidth = ox + sprw;
1498 	if (dirtywidth > screenw) dirtywidth = screenw - 1;
1499 	long dirtyheight = oy + sprh;
1500 	if (dirtyheight > screenh) dirtywidth = screenh - 1;
1501 	engine->ReleaseBitmapSurface(virtsc);
1502 	//engine->ReleaseBitmapSurface (clutspr);
1503 	engine->ReleaseBitmapSurface(spritespr);
1504 	if (mask > 0) engine->ReleaseBitmapSurface(maskspr);
1505 	engine->MarkRegionDirty(ox, oy, dirtywidth, dirtyheight);
1506 
1507 	return 0;
1508 }
1509 
1510 /*------------------------------------------------------------------*/
1511 
AGS_GetPluginName()1512 const char *AGSPalRender::AGS_GetPluginName() {
1513 	return "PALgorithms Translucent Overlay Renderer";
1514 }
1515 
AGS_EngineStartup(IAGSEngine * lpEngine)1516 void AGSPalRender::AGS_EngineStartup(IAGSEngine *lpEngine) {
1517 	PluginBase::AGS_EngineStartup(lpEngine);
1518 	engine = lpEngine;
1519 
1520 	// Make sure it's got the version with the features we need
1521 	if (engine->version < 3) {
1522 		engine->AbortGame("Engine interface is too old, need newer version of AGS.");
1523 	}
1524 
1525 	SCRIPT_METHOD(PALInternal::LoadCLUT^1, AGSPalRender::LoadCLUT);
1526 	SCRIPT_METHOD(PALInternal::CycleRemap^2, AGSPalRender::CycleRemap);
1527 	SCRIPT_METHOD(PALInternal::GetColor565^3, AGSPalRender::GetColor565);
1528 	SCRIPT_METHOD(PALInternal::GetLuminosityFromPalette^1, AGSPalRender::GetLuminosityFromPalette);
1529 	SCRIPT_METHOD(PALInternal::FastSin^1, AGSPalRender::AGSFastSin);
1530 	SCRIPT_METHOD(PALInternal::FastCos^1, AGSPalRender::AGSFastCos);
1531 	SCRIPT_METHOD(PALInternal::FastRoot^1, AGSPalRender::AGSFastRoot);
1532 	SCRIPT_METHOD(PALInternal::GetRemappedSlot^1, AGSPalRender::GetRemappedSlot);
1533 	SCRIPT_METHOD(PALInternal::ResetRemapping^0, AGSPalRender::ResetRemapping);
1534 	SCRIPT_METHOD(PALInternal::GetModifiedBackgroundImage, AGSPalRender::GetModifiedBackgroundImage);
1535 	SCRIPT_METHOD(PALInternal::WriteObjectivePalette^4, AGSPalRender::WriteObjectivePalette);
1536 	SCRIPT_METHOD(PALInternal::ReadObjectivePaletteR^1, AGSPalRender::ReadObjectivePaletteR);
1537 	SCRIPT_METHOD(PALInternal::ReadObjectivePaletteB^1, AGSPalRender::ReadObjectivePaletteB);
1538 	SCRIPT_METHOD(PALInternal::ReadObjectivePaletteG^1, AGSPalRender::ReadObjectivePaletteG);
1539 
1540 	SCRIPT_METHOD(Raycast::Render^1, AGSPalRender::Raycast_Render);
1541 	SCRIPT_METHOD(Raycast::LoadMap^4, AGSPalRender::LoadMap);
1542 	SCRIPT_METHOD(Raycast::Initialize, AGSPalRender::Init_Raycaster);
1543 	SCRIPT_METHOD(Raycast::MakeTextures^1, AGSPalRender::MakeTextures);
1544 	SCRIPT_METHOD(Raycast::MoveForward^0, AGSPalRender::MoveForward);
1545 	SCRIPT_METHOD(Raycast::MoveBackward^0, AGSPalRender::MoveBackward);
1546 	SCRIPT_METHOD(Raycast::RotateLeft^0, AGSPalRender::RotateLeft);
1547 	SCRIPT_METHOD(Raycast::RotateRight^0, AGSPalRender::RotateRight);
1548 	SCRIPT_METHOD(Raycast::SetCameraPosition^2, AGSPalRender::Ray_SetPlayerPosition);
1549 	SCRIPT_METHOD(Raycast::GetCameraX^0, AGSPalRender::Ray_GetPlayerX);
1550 	SCRIPT_METHOD(Raycast::GetCameraY^0, AGSPalRender::Ray_GetPlayerY);
1551 	SCRIPT_METHOD(Raycast::GetCameraAngle^0, AGSPalRender::Ray_GetPlayerAngle);
1552 	SCRIPT_METHOD(Raycast::SetCameraAngle^1, AGSPalRender::Ray_SetPlayerAngle);
1553 	SCRIPT_METHOD(Raycast::InitSprite^9, AGSPalRender::Ray_InitSprite);
1554 	SCRIPT_METHOD(Raycast::UnloadEngine^0, AGSPalRender::QuitCleanup);
1555 	SCRIPT_METHOD(Raycast::GetHotspotAtXY^2, AGSPalRender::Ray_GetHotspotAt);
1556 	SCRIPT_METHOD(Raycast::GetObjectAtXY^2, AGSPalRender::Ray_GetObjectAt);
1557 	SCRIPT_METHOD(Raycast::SetSpriteInteractObj^2, AGSPalRender::Ray_SetSpriteInteractObj);
1558 	SCRIPT_METHOD(Raycast::GetSpriteInteractObj^1, AGSPalRender::Ray_GetSpriteInteractObj);
1559 	SCRIPT_METHOD(Raycast::SetSpritePosition^3, AGSPalRender::Ray_SetSpritePosition);
1560 	SCRIPT_METHOD(Raycast::SetSpriteVertOffset^2, AGSPalRender::Ray_SetSpriteVertOffset);
1561 	SCRIPT_METHOD(Raycast::GetSpriteVertOffset^1, AGSPalRender::Ray_GetSpriteVertOffset);
1562 	SCRIPT_METHOD(Raycast::GetSpriteX^1, AGSPalRender::Ray_GetSpriteX);
1563 	SCRIPT_METHOD(Raycast::GetSpriteY^1, AGSPalRender::Ray_GetSpriteY);
1564 	SCRIPT_METHOD(Raycast::SetWallHotspot^2, AGSPalRender::Ray_SetWallHotspot);
1565 	SCRIPT_METHOD(Raycast::SetWallTextures^5, AGSPalRender::Ray_SetWallTextures);
1566 	SCRIPT_METHOD(Raycast::SetWallSolid^5, AGSPalRender::Ray_SetWallSolid);
1567 	SCRIPT_METHOD(Raycast::SetWallIgnoreLighting^5, AGSPalRender::Ray_SetWallIgnoreLighting);
1568 	SCRIPT_METHOD(Raycast::SetWallAlpha^5, AGSPalRender::Ray_SetWallAlpha);
1569 	SCRIPT_METHOD(Raycast::SetWallBlendType^5, AGSPalRender::Ray_SetWallBlendType);
1570 	SCRIPT_METHOD(Raycast::GetMoveSpeed^0, AGSPalRender::Ray_GetMoveSpeed);
1571 	SCRIPT_METHOD(Raycast::SetMoveSpeed^1, AGSPalRender::Ray_SetMoveSpeed);
1572 	SCRIPT_METHOD(Raycast::GetRotSpeed^0, AGSPalRender::Ray_GetRotSpeed);
1573 	SCRIPT_METHOD(Raycast::SetRotSpeed^1, AGSPalRender::Ray_SetRotSpeed);
1574 	SCRIPT_METHOD(Raycast::GetWallAt^2, AGSPalRender::Ray_GetWallAt);
1575 	SCRIPT_METHOD(Raycast::GetLightAt^2, AGSPalRender::Ray_GetLightAt);
1576 	SCRIPT_METHOD(Raycast::SetLightAt^3, AGSPalRender::Ray_SetLightAt);
1577 	SCRIPT_METHOD(Raycast::SetWallAt^3, AGSPalRender::Ray_SetWallAt);
1578 	SCRIPT_METHOD(Raycast::SetPlaneY^1, AGSPalRender::Ray_SetPlaneY);
1579 	SCRIPT_METHOD(Raycast::GetDistanceAt^2, AGSPalRender::Ray_GetDistanceAt);
1580 	SCRIPT_METHOD(Raycast::GetSpriteAngle^1, AGSPalRender::Ray_GetSpriteAngle);
1581 	SCRIPT_METHOD(Raycast::SetSpriteAngle^2, AGSPalRender::Ray_SetSpriteAngle);
1582 	SCRIPT_METHOD(Raycast::SetSpriteView^2, AGSPalRender::Ray_SetSpriteView);
1583 	SCRIPT_METHOD(Raycast::GetSpriteView^1, AGSPalRender::Ray_GetSpriteView);
1584 	SCRIPT_METHOD(Raycast::SetSpriteFrame^2, AGSPalRender::Ray_SetSpriteFrame);
1585 	SCRIPT_METHOD(Raycast::GetSpriteFrame^1, AGSPalRender::Ray_GetSpriteFrame);
1586 	SCRIPT_METHOD(Raycast::SetSpritePic^2, AGSPalRender::Ray_SetSpritePic);
1587 	SCRIPT_METHOD(Raycast::GetSpritePic^1, AGSPalRender::Ray_GetSpritePic);
1588 	SCRIPT_METHOD(Raycast::SetSkyBox^1, AGSPalRender::Ray_SetSkyBox);
1589 	SCRIPT_METHOD(Raycast::SetSpriteAlpha^2, AGSPalRender::Ray_SetSpriteAlpha);
1590 	SCRIPT_METHOD(Raycast::GetSpriteAlpha^1, AGSPalRender::Ray_GetSpriteAlpha);
1591 	SCRIPT_METHOD(Raycast::GetSkyBox^1, AGSPalRender::Ray_GetSkyBox);
1592 	SCRIPT_METHOD(Raycast::SetAmbientLight^1, AGSPalRender::Ray_SetAmbientLight);
1593 	SCRIPT_METHOD(Raycast::SetAmbientColor^2, AGSPalRender::Ray_SetAmbientColor);
1594 	SCRIPT_METHOD(Raycast::GetAmbientLight^0, AGSPalRender::Ray_GetAmbientLight);
1595 	SCRIPT_METHOD(Raycast::GetAmbientWeight^0, AGSPalRender::Ray_GetAmbientWeight);
1596 	SCRIPT_METHOD(Raycast::GetTileX_At^2, AGSPalRender::Ray_GetTileX_At);
1597 	SCRIPT_METHOD(Raycast::GetTileY_At^2, AGSPalRender::Ray_GetTileY_At);
1598 	SCRIPT_METHOD(Raycast::DrawTile^2, AGSPalRender::Ray_DrawTile);
1599 	SCRIPT_METHOD(Raycast::DrawOntoTile^2, AGSPalRender::Ray_DrawOntoTile);
1600 	SCRIPT_METHOD(Raycast::SetNoClip^1, AGSPalRender::Ray_SetNoClip);
1601 	SCRIPT_METHOD(Raycast::GetNoClip^0, AGSPalRender::Ray_GetNoClip);
1602 	SCRIPT_METHOD(Raycast::GetSpriteScaleX^1, AGSPalRender::Ray_GetSpriteScaleX);
1603 	SCRIPT_METHOD(Raycast::SetSpriteScaleX^2, AGSPalRender::Ray_SetSpriteScaleX);
1604 	SCRIPT_METHOD(Raycast::GetSpriteScaleY^1, AGSPalRender::Ray_GetSpriteScaleY);
1605 	SCRIPT_METHOD(Raycast::SetSpriteScaleY^2, AGSPalRender::Ray_SetSpriteScaleY);
1606 	SCRIPT_METHOD(Raycast::GetSpriteBlendType^1, AGSPalRender::Ray_GetSpriteBlendType);
1607 	SCRIPT_METHOD(Raycast::SetSpriteBlendType^2, AGSPalRender::Ray_SetSpriteBlendType);
1608 
1609 
1610 	SCRIPT_METHOD(Raycast::SetFloorAt^3, AGSPalRender::Ray_SetFloorAt);
1611 	SCRIPT_METHOD(Raycast::SetCeilingAt^3, AGSPalRender::Ray_SetCeilingAt);
1612 	SCRIPT_METHOD(Raycast::GetCeilingAt^2, AGSPalRender::Ray_GetCeilingAt);
1613 	SCRIPT_METHOD(Raycast::GetFloorAt^2, AGSPalRender::Ray_GetFloorAt);
1614 	SCRIPT_METHOD(Raycast::GetLightingAt^2, AGSPalRender::Ray_GetLightingAt);
1615 	SCRIPT_METHOD(Raycast::SetLightingAt^3, AGSPalRender::Ray_SetLightingAt);
1616 	SCRIPT_METHOD(Raycast::GetWallHotspot^1, AGSPalRender::Ray_GetWallHotspot);
1617 	SCRIPT_METHOD(Raycast::GetWallTexture^2, AGSPalRender::Ray_GetWallTexture);
1618 	SCRIPT_METHOD(Raycast::GetWallSolid^2, AGSPalRender::Ray_GetWallSolid);
1619 	SCRIPT_METHOD(Raycast::GetWallIgnoreLighting^2, AGSPalRender::Ray_GetWallIgnoreLighting);
1620 	SCRIPT_METHOD(Raycast::GetWallAlpha^2, AGSPalRender::Ray_GetWallAlpha);
1621 	SCRIPT_METHOD(Raycast::GetWallBlendType^2, AGSPalRender::Ray_GetWallBlendType);
1622 	SCRIPT_METHOD(Raycast::SelectTile^3, AGSPalRender::Ray_SelectTile);
1623 	SCRIPT_METHOD(Raycast::HasSeenTile^2, AGSPalRender::Ray_HasSeenTile);
1624 
1625 	SCRIPT_METHOD(LensDistort::SetPos^2, AGSPalRender::SetLensPos);
1626 	SCRIPT_METHOD(LensDistort::GetX^0, AGSPalRender::GetLensX);
1627 	SCRIPT_METHOD(LensDistort::GetY^0, AGSPalRender::GetLensY);
1628 	SCRIPT_METHOD(LensDistort::Set^1, AGSPalRender::SetLensDrawn);
1629 	SCRIPT_METHOD(LensDistort::IsDrawn^0, AGSPalRender::GetLensDrawn);
1630 	SCRIPT_METHOD(LensDistort::SetOffsetClamp^1, AGSPalRender::SetLensOffsetClamp);
1631 	SCRIPT_METHOD(LensDistort::GetOffsetClamp^0, AGSPalRender::GetLensOffsetClamp);
1632 	SCRIPT_METHOD(LensDistort::GetLevel^0, AGSPalRender::GetLensLevel);
1633 	SCRIPT_METHOD(LensDistort::SetLevel^1, AGSPalRender::SetLensLevel);
1634 	SCRIPT_METHOD(LensDistort::Initialize^6, AGSPalRender::LensInitialize);
1635 
1636 	SCRIPT_METHOD(Translucence::CreateOverlay^8, AGSPalRender::CreateTranslucentOverlay);
1637 	SCRIPT_METHOD(Translucence::DeleteOverlay^1, AGSPalRender::DeleteTranslucentOverlay);
1638 	SCRIPT_METHOD(Translucence::Move^3, AGSPalRender::MoveTranslucentOverlay);
1639 	SCRIPT_METHOD(Translucence::GetOverlayX^1, AGSPalRender::GetTranslucentOverlayX);
1640 	SCRIPT_METHOD(Translucence::GetOverlayY^1, AGSPalRender::GetTranslucentOverlayY);
1641 	SCRIPT_METHOD(Translucence::GetOverlaySprite^1, AGSPalRender::GetTranslucentOverlaySprite);
1642 	SCRIPT_METHOD(Translucence::GetOverlayLevel^1, AGSPalRender::GetTranslucentOverlayLevel);
1643 	SCRIPT_METHOD(Translucence::GetOverlayEnabled^1, AGSPalRender::GetTranslucentOverlayEnabled);
1644 	SCRIPT_METHOD(Translucence::GetOverlayAlpha^1, AGSPalRender::GetTranslucentOverlayAlpha);
1645 	SCRIPT_METHOD(Translucence::SetOverlayAlpha^2, AGSPalRender::SetTranslucentOverlayAlpha);
1646 	SCRIPT_METHOD(Translucence::SetOverlayEnabled^2, AGSPalRender::SetTranslucentOverlayEnabled);
1647 	SCRIPT_METHOD(Translucence::DrawTransSprite^6, AGSPalRender::DrawTransSprite);
1648 
1649 	SCRIPT_METHOD(Starfield::GetOverscan^0, AGSPalRender::GetStarfieldOverscan);
1650 	SCRIPT_METHOD(Starfield::SetOverscan^1, AGSPalRender::SetStarfieldOverscan);
1651 	SCRIPT_METHOD(Starfield::GetOriginX^0, AGSPalRender::GetStarfieldOriginX);
1652 	SCRIPT_METHOD(Starfield::GetOriginY^0, AGSPalRender::GetStarfieldOriginY);
1653 	SCRIPT_METHOD(Starfield::SetDepthMultiplier^1, AGSPalRender::SetStarfieldDepthMultiplier);
1654 	SCRIPT_METHOD(Starfield::GetDepthMultiplier^0, AGSPalRender::GetStarfieldDepthMultiplier);
1655 	SCRIPT_METHOD(Starfield::GetMaxStars^0, AGSPalRender::GetStarfieldMaxStars);
1656 	SCRIPT_METHOD(Starfield::SetStarSpriteScaleBoost^1, AGSPalRender::SetStarSpriteScaleBoost);
1657 	SCRIPT_METHOD(Starfield::GetStarSpriteScaleBoost^0, AGSPalRender::GetStarSpriteScaleBoost);
1658 	SCRIPT_METHOD(Starfield::SetStarMaxRadius^2, AGSPalRender::SetStarMaxRadius);
1659 	SCRIPT_METHOD(Starfield::GetStarMaxRadius^0, AGSPalRender::GetStarMaxRadius);
1660 	SCRIPT_METHOD(Starfield::GetStarX^1, AGSPalRender::GetStarX);
1661 	SCRIPT_METHOD(Starfield::GetStarY^1, AGSPalRender::GetStarY);
1662 	SCRIPT_METHOD(Starfield::GetStarZ^1, AGSPalRender::GetStarZ);
1663 	SCRIPT_METHOD(Starfield::SetStarPosition^4, AGSPalRender::SetStarPosition);
1664 	SCRIPT_METHOD(Starfield::RotateStar^4, AGSPalRender::RotateStar);
1665 	SCRIPT_METHOD(Starfield::SetStarColor^2, AGSPalRender::SetStarColor);
1666 	SCRIPT_METHOD(Starfield::GetStarColor^1, AGSPalRender::GetStarColor);
1667 	SCRIPT_METHOD(Starfield::SetStarSprite^2, AGSPalRender::SetStarSprite);
1668 	SCRIPT_METHOD(Starfield::GetStarSprite^1, AGSPalRender::GetStarSprite);
1669 	SCRIPT_METHOD(Starfield::SetStarSpriteRange^3, AGSPalRender::SetStarSpriteRange);
1670 	SCRIPT_METHOD(Starfield::Initialize^2, AGSPalRender::InitializeStars);
1671 	SCRIPT_METHOD(Starfield::Iterate^1, AGSPalRender::IterateStars);
1672 	SCRIPT_METHOD(Starfield::Draw^2, AGSPalRender::DrawStars);
1673 	SCRIPT_METHOD(Starfield::SetOriginPoint^2, AGSPalRender::SetStarsOriginPoint);
1674 
1675 	SCRIPT_METHOD(Plasma::DoFire^8, AGSPalRender::DoFire);
1676 	SCRIPT_METHOD(Plasma::SetPlasmaType^5, AGSPalRender::SetPlasmaType);
1677 	SCRIPT_METHOD(Plasma::ResetPlasmaSettings^0, AGSPalRender::ResetPlasmaSettings);
1678 	SCRIPT_METHOD(Plasma::DrawPlasma^3, AGSPalRender::DrawPlasma);
1679 	SCRIPT_METHOD(Plasma::SetRootType^1, AGSPalRender::SetPlasmaRootType);
1680 	SCRIPT_METHOD(Plasma::GetRootType^0, AGSPalRender::GetPlasmaRootType);
1681 
1682 	SCRIPT_METHOD(Reflections::Set^1, AGSPalRender::SetReflections);
1683 	SCRIPT_METHOD(Reflections::IsReflecting^0, AGSPalRender::IsReflectionsOn);
1684 	SCRIPT_METHOD(Reflections::SetCharacterReflected^2, AGSPalRender::SetCharacterReflected);
1685 	SCRIPT_METHOD(Reflections::GetCharacterReflected^1, AGSPalRender::GetCharacterReflected);
1686 	SCRIPT_METHOD(Reflections::SetObjectReflected^2, AGSPalRender::SetObjectReflected);
1687 	SCRIPT_METHOD(Reflections::GetObjectReflected^1, AGSPalRender::GetObjectReflected);
1688 	SCRIPT_METHOD(Reflections::ReplaceCharacterReflectionView^2, AGSPalRender::ReplaceCharacterReflectionView);
1689 	SCRIPT_METHOD(Reflections::SetObjectReflectionIgnoreScaling^2, AGSPalRender::SetObjectReflectionIgnoreScaling);
1690 
1691 	engine->RequestEventHook(AGSE_PRESCREENDRAW);
1692 	engine->RequestEventHook(AGSE_PREGUIDRAW);
1693 	engine->RequestEventHook(AGSE_POSTSCREENDRAW);
1694 	engine->RequestEventHook(AGSE_SAVEGAME);
1695 	engine->RequestEventHook(AGSE_RESTOREGAME);
1696 	engine->RequestEventHook(AGSE_ENTERROOM);
1697 	stars = new starstype [MAX_STARS];
1698 	Starfield.maxstars = MAX_STARS;
1699 	Starfield.depthmultiplier = 256;
1700 	Starfield.speed = 0.5;
1701 	Starfield.originx = 160;
1702 	Starfield.originy = 100;
1703 	Reflection.Characters = new charrefopt [engine->GetNumCharacters()]();
1704 	lens = new LensDistort [LENS_WIDTH * LENS_WIDTH]();
1705 	//PreMultiply_Alphas ();
1706 	plasmaroottype = 0;
1707 	Make_Sin_Lut();
1708 	ScriptMethodParams params;
1709 	Init_Raycaster(params);
1710 }
1711 
AGS_EngineShutdown()1712 void AGSPalRender::AGS_EngineShutdown() {
1713 	// no work to do here - but if we had created any dynamic sprites,
1714 	// we should delete them here
1715 	delete[] Reflection.Characters;
1716 	delete[] Reflection.Objects;
1717 	//QuitCleanup();
1718 }
1719 
AGS_EngineOnEvent(int event,NumberPtr data)1720 int64 AGSPalRender::AGS_EngineOnEvent(int event, NumberPtr data) {
1721 	if (event == AGSE_PRESCREENDRAW && clutslot > 0) {
1722 		if (drawreflections) {
1723 			int32 sh, sw = 0;
1724 			engine->GetScreenDimensions(&sw, &sh, nullptr);
1725 			reflectionmap = new long[sw * sh]();
1726 			rcolormap = engine->CreateBlankBitmap(sw, sh, 8);
1727 			ralphamap = engine->CreateBlankBitmap(sw, sh, 8);
1728 			for (int i = 0; i < engine->GetNumCharacters(); i++) {
1729 				if (Reflection.Characters[i].reflect == 0) continue;
1730 				AGSCharacter *tempchar = engine->GetCharacter(i);
1731 				if (tempchar->room != engine->GetCurrentRoom()) continue;  //if character isn't even in the room, go to next iteration.
1732 				int32 vx = tempchar->x;
1733 				int32 vy = tempchar->y;
1734 				engine->RoomToViewport(&vx, &vy);
1735 				AGSViewFrame *vf = engine->GetViewFrame(tempchar->view + 1, tempchar->loop, tempchar->frame);
1736 				int w = engine->GetSpriteWidth(vf->pic);
1737 				int h = engine->GetSpriteHeight(vf->pic);
1738 				vx = vx - (w / 2);
1739 				int32 vxmax = vx + w;
1740 				int32 vymax = vy + h;
1741 				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
1742 				DrawReflections(i, 0);
1743 			}
1744 			for (int i = 0; i < engine->GetNumObjects(); i++) {
1745 				if (Reflection.Objects[i].reflect == 0) continue;
1746 				AGSObject *tempobj = engine->GetObject(i);
1747 				if (!tempobj->on) continue;
1748 				int32 vx = tempobj->x;
1749 				int32 vy = tempobj->baseline - tempobj->y;
1750 				engine->RoomToViewport(&vx, &vy);
1751 				int32 w = engine->GetSpriteWidth(tempobj->num);
1752 				int32 h = engine->GetSpriteHeight(tempobj->num);
1753 				int32 vxmax = vx + w;
1754 				int32 vymax = vy + h;
1755 				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
1756 				DrawReflections(i, 1);
1757 			}
1758 			BITMAP *virtsc = engine->GetVirtualScreen();
1759 			uint8 *screenbuffer = engine->GetRawBitmapSurface(virtsc);
1760 			uint8 *colorbuffer = engine->GetRawBitmapSurface(rcolormap);
1761 			uint8 *alphabuffer = engine->GetRawBitmapSurface(ralphamap);
1762 			int screenPitch = engine->GetBitmapPitch(virtsc);
1763 			int colorPitch = engine->GetBitmapPitch(rcolormap);
1764 			int alphaPitch = engine->GetBitmapPitch(ralphamap);
1765 			for (int y = 0, screeny = 0, colory = 0, alphay = 0; y < sh; y++, screeny += screenPitch, colory += colorPitch, alphay += alphaPitch)
1766 				for (int x = 0; x < sw; x++)
1767 					screenbuffer[screeny+x] = Mix::MixColorAlpha(colorbuffer[colory+x], screenbuffer[screeny+x], alphabuffer[alphay+x]);
1768 			engine->ReleaseBitmapSurface(rcolormap);
1769 			engine->ReleaseBitmapSurface(ralphamap);
1770 			engine->ReleaseBitmapSurface(virtsc);
1771 			engine->FreeBitmap(rcolormap);
1772 			engine->FreeBitmap(ralphamap);
1773 			delete[] reflectionmap;
1774 		}
1775 		int i = 0;
1776 		if (LensOption.draw == 1 && LensOption.level == 0) DrawLens(LensOption.x, LensOption.y);
1777 		while (i < MAX_OVERLAYS) {
1778 			if (overlay[i].enabled && overlay[i].level == 0) {
1779 				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
1780 			}
1781 			i++;
1782 		}
1783 		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
1784 	}
1785 	if (event == AGSE_PREGUIDRAW && clutslot > 0) {
1786 		int i = 0;
1787 		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
1788 		while (i < MAX_OVERLAYS) {
1789 			if (overlay[i].enabled && overlay[i].level == 1) {
1790 				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
1791 			}
1792 			i++;
1793 		}
1794 		if (LensOption.draw == 1 && LensOption.level == 2) DrawLens(LensOption.x, LensOption.y);
1795 	}
1796 	if (event == AGSE_POSTSCREENDRAW && clutslot > 0) {
1797 		int i = 0;
1798 		if (LensOption.draw == 1 && LensOption.level == 3) DrawLens(LensOption.x, LensOption.y);
1799 		while (i < MAX_OVERLAYS) {
1800 			if (overlay[i].enabled && overlay[i].level == 2) {
1801 				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
1802 			}
1803 			i++;
1804 		}
1805 		if (LensOption.draw == 1 && LensOption.level == 4) DrawLens(LensOption.x, LensOption.y);
1806 	}
1807 	if (event == AGSE_SAVEGAME) {
1808 		Serializer s(engine, data, false);
1809 		syncGame(s);
1810 	}
1811 	if (event == AGSE_RESTOREGAME) {
1812 		Serializer s(engine, data, true);
1813 		syncGame(s);
1814 	}
1815 	if (event == AGSE_ENTERROOM) {
1816 		ScriptMethodParams params;
1817 		ResetRemapping(params);
1818 		delete[] Reflection.Objects;
1819 		Reflection.Objects = new objrefopt [engine->GetNumObjects()]();
1820 	}
1821 	return 0;
1822 }
1823 
syncGame(Serializer & s)1824 void AGSPalRender::syncGame(Serializer &s) {
1825 	for (int i = 0; i < MAX_OVERLAYS; ++i) {
1826 		s.syncAsInt(overlay[i].sprite);
1827 		s.syncAsInt(overlay[i].spritemask);
1828 		s.syncAsInt(overlay[i].x);
1829 		s.syncAsInt(overlay[i].y);
1830 		s.syncAsInt(overlay[i].level);
1831 		s.syncAsInt(overlay[i].trans);
1832 		s.syncAsInt(overlay[i].blendtype);
1833 		s.syncAsBool(overlay[i].enabled);
1834 	}
1835 	s.syncAsInt(clutslot);
1836 	s.syncAsInt(drawreflections);
1837 
1838 	for (int j = 0; j < 256; ++j)
1839 		s.syncAsByte(cycle_remap[j]);
1840 
1841 	for (int j = 0; j < 256; ++j) {
1842 		s.syncAsByte(objectivepal[j].r);
1843 		s.syncAsByte(objectivepal[j].b);
1844 		s.syncAsByte(objectivepal[j].g);
1845 	}
1846 
1847 	for (int j = 0; j < 256; ++j) {
1848 		s.syncAsDouble(sprite[j].x);
1849 		s.syncAsDouble(sprite[j].y);
1850 		s.syncAsInt(sprite[j].texture);
1851 		s.syncAsByte(sprite[j].alpha);
1852 		s.syncAsDouble(sprite[j].uDivW);
1853 		s.syncAsDouble(sprite[j].uDivH);
1854 		s.syncAsDouble(sprite[j].vMove);
1855 		s.syncAsDouble(sprite[j].hMove);
1856 		s.syncAsInt8(sprite[j].objectinteract);
1857 		s.syncAsInt(sprite[j].view);
1858 		s.syncAsInt(sprite[j].frame);
1859 		s.syncAsInt(sprite[j].angle);
1860 	}
1861 
1862 	for (int j = 0; j < 256; ++j) {
1863 		for (int k = 0; k < 4; ++k) {
1864 			s.syncAsInt(wallData[j].texture[k]);
1865 			s.syncAsInt(wallData[j].solid[k]);
1866 			s.syncAsInt(wallData[j].ignorelighting[k]);
1867 			s.syncAsInt(wallData[j].alpha[k]);
1868 			s.syncAsInt(wallData[j].blendtype[k]);
1869 			s.syncAsInt(wallData[j].mask[k]);
1870 		}
1871 
1872 		s.syncAsByte(wallData[j].hotspotinteract);
1873 	}
1874 
1875 	s.syncAsBool(raycastOn);
1876 	s.syncAsBool(heightmapOn);
1877 	s.syncAsDouble(posX);
1878 	s.syncAsDouble(posY);
1879 	s.syncAsDouble(dirX);
1880 	s.syncAsDouble(dirY);
1881 	s.syncAsDouble(planeX);
1882 	s.syncAsDouble(planeY);
1883 	s.syncAsDouble(moveSpeed);
1884 	s.syncAsDouble(rotSpeed);
1885 
1886 	if (raycastOn) { //If the raycaster is active, we have additional data to save.
1887 		for (int i = 0; i < MAP_WIDTH; ++i)
1888 			for (int j = 0; j < MAP_HEIGHT; ++j) {
1889 				s.syncAsByte(worldMap[i][j]);
1890 				s.syncAsByte(lightMap[i][j]);
1891 				s.syncAsInt(ceilingMap[i][j]);
1892 				s.syncAsInt(floorMap[i][j]);
1893 				s.syncAsInt(heightMap[i][j]);
1894 			}
1895 	}
1896 
1897 	s.syncAsInt(textureSlot);
1898 	if (s.isLoading() && textureSlot) {
1899 		ScriptMethodParams params;
1900 		params.push_back(textureSlot);
1901 		MakeTextures(params);
1902 	}
1903 
1904 	s.syncAsInt(skybox);
1905 	s.syncAsInt(ambientlight);
1906 
1907 	if (s.isLoading()) {
1908 		ScriptMethodParams params;
1909 		params.push_back(clutslot);
1910 		LoadCLUT(params);
1911 	}
1912 }
1913 
1914 } // namespace AGSPalRender
1915 } // namespace Plugins
1916 } // namespace AGS3
1917