1 /***********************************************************
2 * AGSBlend *
3 * *
4 * Author: Steven Poulton *
5 * *
6 * Date: 09/01/2011 *
7 * *
8 * Description: An AGS Plugin to allow true Alpha Blending *
9 * *
10 ***********************************************************/
11
12 #pragma region Defines_and_Includes
13
14 #define MIN_EDITOR_VERSION 1
15 #define MIN_ENGINE_VERSION 3
16
17 #ifdef WIN32
18 #define WIN32_LEAN_AND_MEAN
19 #include <windows.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <math.h>
25
26 #if !defined(BUILTIN_PLUGINS)
27 #define THIS_IS_THE_PLUGIN
28 #endif
29
30 #include "plugin/agsplugin.h"
31
32 #if defined(BUILTIN_PLUGINS)
33 namespace agsblend {
34 #endif
35
36 typedef unsigned char uint8;
37
38 #define DEFAULT_RGB_R_SHIFT_32 16
39 #define DEFAULT_RGB_G_SHIFT_32 8
40 #define DEFAULT_RGB_B_SHIFT_32 0
41 #define DEFAULT_RGB_A_SHIFT_32 24
42
43 #if !defined(WINDOWS_VERSION)
44 #define min(x,y) (((x) < (y)) ? (x) : (y))
45 #define max(x,y) (((x) > (y)) ? (x) : (y))
46 #endif
47
48 #define abs(a) ((a)<0 ? -(a) : (a))
49 #define ChannelBlend_Normal(B,L) ((uint8)(B))
50 #define ChannelBlend_Lighten(B,L) ((uint8)((L > B) ? L:B))
51 #define ChannelBlend_Darken(B,L) ((uint8)((L > B) ? B:L))
52 #define ChannelBlend_Multiply(B,L) ((uint8)((B * L) / 255))
53 #define ChannelBlend_Average(B,L) ((uint8)((B + L) / 2))
54 #define ChannelBlend_Add(B,L) ((uint8)(min(255, (B + L))))
55 #define ChannelBlend_Subtract(B,L) ((uint8)((B + L < 255) ? 0:(B + L - 255)))
56 #define ChannelBlend_Difference(B,L) ((uint8)(abs(B - L)))
57 #define ChannelBlend_Negation(B,L) ((uint8)(255 - abs(255 - B - L)))
58 #define ChannelBlend_Screen(B,L) ((uint8)(255 - (((255 - B) * (255 - L)) >> 8)))
59 #define ChannelBlend_Exclusion(B,L) ((uint8)(B + L - 2 * B * L / 255))
60 #define ChannelBlend_Overlay(B,L) ((uint8)((L < 128) ? (2 * B * L / 255):(255 - 2 * (255 - B) * (255 - L) / 255)))
61 #define ChannelBlend_SoftLight(B,L) ((uint8)((L < 128)?(2*((B>>1)+64))*((float)L/255):(255-(2*(255-((B>>1)+64))*(float)(255-L)/255))))
62 #define ChannelBlend_HardLight(B,L) (ChannelBlend_Overlay(L,B))
63 #define ChannelBlend_ColorDodge(B,L) ((uint8)((L == 255) ? L:min(255, ((B << 8 ) / (255 - L)))))
64 #define ChannelBlend_ColorBurn(B,L) ((uint8)((L == 0) ? L:max(0, (255 - ((255 - B) << 8 ) / L))))
65 #define ChannelBlend_LinearDodge(B,L)(ChannelBlend_Add(B,L))
66 #define ChannelBlend_LinearBurn(B,L) (ChannelBlend_Subtract(B,L))
67 #define ChannelBlend_LinearLight(B,L)((uint8)(L < 128)?ChannelBlend_LinearBurn(B,(2 * L)):ChannelBlend_LinearDodge(B,(2 * (L - 128))))
68 #define ChannelBlend_VividLight(B,L) ((uint8)(L < 128)?ChannelBlend_ColorBurn(B,(2 * L)):ChannelBlend_ColorDodge(B,(2 * (L - 128))))
69 #define ChannelBlend_PinLight(B,L) ((uint8)(L < 128)?ChannelBlend_Darken(B,(2 * L)):ChannelBlend_Lighten(B,(2 * (L - 128))))
70 #define ChannelBlend_HardMix(B,L) ((uint8)((ChannelBlend_VividLight(B,L) < 128) ? 0:255))
71 #define ChannelBlend_Reflect(B,L) ((uint8)((L == 255) ? L:min(255, (B * B / (255 - L)))))
72 #define ChannelBlend_Glow(B,L) (ChannelBlend_Reflect(L,B))
73 #define ChannelBlend_Phoenix(B,L) ((uint8)(min(B,L) - max(B,L) + 255))
74 #define ChannelBlend_Alpha(B,L,O) ((uint8)(O * B + (1 - O) * L))
75 #define ChannelBlend_AlphaF(B,L,F,O) (ChannelBlend_Alpha(F(B,L),B,O))
76
77
78 #pragma endregion
79
80 #if defined(WINDOWS_VERSION)
81 // The standard Windows DLL entry point
82
DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)83 BOOL APIENTRY DllMain( HANDLE hModule,
84 DWORD ul_reason_for_call,
85 LPVOID lpReserved) {
86
87 switch (ul_reason_for_call) {
88 case DLL_PROCESS_ATTACH:
89 case DLL_THREAD_ATTACH:
90 case DLL_THREAD_DETACH:
91 case DLL_PROCESS_DETACH:
92 break;
93 }
94 return TRUE;
95 }
96 #endif
97
98 //define engine
99
100 IAGSEngine *engine;
101
102
103 #pragma region Color_Functions
104
105
getr32(int c)106 int getr32(int c)
107 {
108 return ((c >> DEFAULT_RGB_R_SHIFT_32) & 0xFF);
109 }
110
111
getg32(int c)112 int getg32 (int c)
113 {
114 return ((c >> DEFAULT_RGB_G_SHIFT_32) & 0xFF);
115 }
116
117
getb32(int c)118 int getb32 (int c)
119 {
120 return ((c >> DEFAULT_RGB_B_SHIFT_32) & 0xFF);
121 }
122
123
geta32(int c)124 int geta32 (int c)
125 {
126 return ((c >> DEFAULT_RGB_A_SHIFT_32) & 0xFF);
127 }
128
129
makeacol32(int r,int g,int b,int a)130 int makeacol32 (int r, int g, int b, int a)
131 {
132 return ((r << DEFAULT_RGB_R_SHIFT_32) |
133 (g << DEFAULT_RGB_G_SHIFT_32) |
134 (b << DEFAULT_RGB_B_SHIFT_32) |
135 (a << DEFAULT_RGB_A_SHIFT_32));
136 }
137
138 #pragma endregion
139
140 #pragma region Pixel32_Definition
141
142 struct Pixel32{
143
144 public:
145 Pixel32();
~Pixel32agsblend::Pixel32146 ~Pixel32() {}
147 int GetColorAsInt();
148 int Red;
149 int Green;
150 int Blue;
151 int Alpha;
152
153 };
154
Pixel32()155 Pixel32::Pixel32() {
156 Red = 0;
157 Blue = 0;
158 Green = 0;
159 Alpha = 0;
160 }
161
GetColorAsInt()162 int Pixel32::GetColorAsInt() {
163
164 return makeacol32(Red,Green,Blue,Alpha);
165
166 }
167
168 #pragma endregion
169
170 /// <summary>
171 /// Gets the alpha value at coords x,y
172 /// </summary>
GetAlpha(int sprite,int x,int y)173 int GetAlpha(int sprite, int x, int y){
174
175
176 BITMAP *engineSprite = engine->GetSpriteGraphic(sprite);
177
178 unsigned char **charbuffer = engine->GetRawBitmapSurface (engineSprite);
179 unsigned int **longbuffer = (unsigned int**)charbuffer;
180
181 int alpha = geta32(longbuffer[y][x]);
182
183 engine->ReleaseBitmapSurface (engineSprite);
184
185 return alpha;
186
187 }
188
189 /// <summary>
190 /// Sets the alpha value at coords x,y
191 /// </summary>
PutAlpha(int sprite,int x,int y,int alpha)192 int PutAlpha(int sprite, int x, int y, int alpha){
193
194 BITMAP *engineSprite = engine->GetSpriteGraphic(sprite);
195
196 unsigned char **charbuffer = engine->GetRawBitmapSurface (engineSprite);
197 unsigned int **longbuffer = (unsigned int**)charbuffer;
198
199
200 int r = getr32(longbuffer[y][x]);
201 int g = getg32(longbuffer[y][x]);
202 int b = getb32(longbuffer[y][x]);
203 longbuffer[y][x] = makeacol32(r,g,b,alpha);
204
205 engine->ReleaseBitmapSurface (engineSprite);
206
207 return alpha;
208
209 }
210
211
212 /// <summary>
213 /// Translates index from a 2D array to a 1D array
214 /// </summary>
xytolocale(int x,int y,int width)215 int xytolocale(int x, int y, int width){
216
217 return (y * width + x);
218
219
220 }
221
HighPass(int sprite,int threshold)222 int HighPass(int sprite, int threshold){
223
224 BITMAP* src = engine->GetSpriteGraphic(sprite);
225 int srcWidth, srcHeight;
226
227 engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, NULL);
228
229 unsigned char **srccharbuffer = engine->GetRawBitmapSurface (src);
230 unsigned int **srclongbuffer = (unsigned int**)srccharbuffer;
231
232 for (int y = 0; y<srcHeight; y++){
233
234 for (int x = 0; x<srcWidth; x++){
235
236 int srcr = getb32(srclongbuffer[y][x]);
237 int srcg = getg32(srclongbuffer[y][x]);
238 int srcb = getr32(srclongbuffer[y][x]);
239 int tempmaxim = max(srcr, srcg);
240 int maxim = max(tempmaxim, srcb);
241 int tempmin = min( srcr, srcg);
242 int minim = min( srcb, tempmin);
243 int light = (maxim + minim) /2 ;
244 if (light < threshold) srclongbuffer[y][x] = makeacol32(0,0,0,0);
245
246 }
247
248 }
249
250 return 0;
251
252 }
253
254
Blur(int sprite,int radius)255 int Blur (int sprite, int radius) {
256
257 BITMAP* src = engine->GetSpriteGraphic(sprite);
258
259 int srcWidth, srcHeight;
260 engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, NULL);
261
262 unsigned char **srccharbuffer = engine->GetRawBitmapSurface (src);
263 unsigned int **srclongbuffer = (unsigned int**)srccharbuffer;
264 int negrad = -1 * radius;
265
266 //use a 1Dimensional array since the array is on the free store, not the stack
267 Pixel32 * Pixels = new Pixel32[(srcWidth + (radius * 2)) * (srcHeight + (radius * 2))]; // this defines a copy of the individual channels in class form.
268 Pixel32 * Dest = new Pixel32[(srcWidth + (radius * 2)) * (srcHeight + (radius * 2))]; // this is the destination sprite. both have a border all the way round equal to the radius for the blurring.
269 Pixel32 * Temp = new Pixel32[(srcWidth + (radius * 2)) * (srcHeight + (radius * 2))];
270
271
272 int arraywidth = srcWidth + (radius * 2); //define the array width since its used many times in the algorithm
273
274
275 for (int y = 0; y<srcHeight; y++){ //copy the sprite to the Pixels class array
276
277 for (int x = 0; x<srcWidth; x++){
278
279 int locale = xytolocale(x + radius, y + radius, arraywidth);
280
281 Pixels[locale].Red = getr32(srclongbuffer[y][x]);
282 Pixels[locale].Green = getg32(srclongbuffer[y][x]);
283 Pixels[locale].Blue = getb32(srclongbuffer[y][x]);
284 Pixels[locale].Alpha = geta32(srclongbuffer[y][x]);
285
286
287
288 }
289
290 }
291
292
293 int numofpixels = (radius * 2 + 1);
294 for (int y = 0; y < srcHeight; y++) {
295
296 int totalr = 0;
297 int totalg = 0;
298 int totalb = 0;
299 int totala = 0;
300
301 // Process entire window for first pixel
302 for (int kx = negrad; kx <= radius; kx++){
303 int locale = xytolocale(kx + radius, y + radius, arraywidth);
304 totala += Pixels[locale].Alpha;
305 totalr += (Pixels[locale].Red * Pixels[locale].Alpha)/ 255;
306 totalg += (Pixels[locale].Green * Pixels[locale].Alpha)/ 255;
307 totalb += (Pixels[locale].Blue * Pixels[locale].Alpha)/ 255;
308 }
309
310 int locale = xytolocale(radius, y + radius, arraywidth);
311 Temp[locale].Red = totalr / numofpixels; // take an average and assign it to the destination array
312 Temp[locale].Green = totalg / numofpixels;
313 Temp[locale].Blue = totalb / numofpixels;
314 Temp[locale].Alpha = totala / numofpixels;
315
316
317 // Subsequent pixels just update window total
318 for (int x = 1; x < srcWidth; x++) {
319 // Subtract pixel leaving window
320 int locale = xytolocale(x - 1, y + radius, arraywidth);
321 totala -= Pixels[locale].Alpha;
322 totalr -= (Pixels[locale].Red * Pixels[locale].Alpha)/ 255;
323 totalg -= (Pixels[locale].Green * Pixels[locale].Alpha)/ 255;
324 totalb -= (Pixels[locale].Blue * Pixels[locale].Alpha)/ 255;
325
326
327 // Add pixel entering window
328
329 locale = xytolocale(x + radius + radius, y + radius, arraywidth);
330 totala += Pixels[locale].Alpha;
331 totalr += (Pixels[locale].Red * Pixels[locale].Alpha)/ 255;
332 totalg += (Pixels[locale].Green * Pixels[locale].Alpha)/ 255;
333 totalb += (Pixels[locale].Blue * Pixels[locale].Alpha)/ 255;
334
335
336 locale = xytolocale(x + radius, y + radius, arraywidth);
337 Temp[locale].Red = totalr / numofpixels; // take an average and assign it to the destination array
338 Temp[locale].Green = totalg / numofpixels;
339 Temp[locale].Blue = totalb / numofpixels;
340 Temp[locale].Alpha = totala / numofpixels;
341
342 }
343 }
344
345
346
347
348 for (int x = 0; x < srcWidth; x++) {
349
350 int totalr = 0;
351 int totalg = 0;
352 int totalb = 0;
353 int totala = 0;
354
355 // Process entire window for first pixel
356 for (int ky = negrad; ky <= radius; ky++){
357 int locale = xytolocale(x + radius, ky + radius, arraywidth);
358 totala += Temp[locale].Alpha;
359 totalr += (Temp[locale].Red * Temp[locale].Alpha)/ 255;
360 totalg += (Temp[locale].Green * Temp[locale].Alpha)/ 255;
361 totalb += (Temp[locale].Blue * Temp[locale].Alpha)/ 255;
362 }
363
364 int locale = xytolocale(x + radius,radius, arraywidth);
365 Dest[locale].Red = totalr / numofpixels; // take an average and assign it to the destination array
366 Dest[locale].Green = totalg / numofpixels;
367 Dest[locale].Blue = totalb / numofpixels;
368 Dest[locale].Alpha = totala / numofpixels;
369
370
371 // Subsequent pixels just update window total
372 for (int y = 1; y < srcHeight; y++) {
373 // Subtract pixel leaving window
374 int locale = xytolocale(x + radius, y - 1, arraywidth);
375 totala -= Temp[locale].Alpha;
376 totalr -= (Temp[locale].Red * Temp[locale].Alpha)/ 255;
377 totalg -= (Temp[locale].Green * Temp[locale].Alpha)/ 255;
378 totalb -= (Temp[locale].Blue * Temp[locale].Alpha)/ 255;
379
380
381 // Add pixel entering window
382
383 locale = xytolocale(x + radius, y + radius + radius, arraywidth);
384 totala += Temp[locale].Alpha;
385 totalr += (Temp[locale].Red * Temp[locale].Alpha)/ 255;
386 totalg += (Temp[locale].Green * Temp[locale].Alpha)/ 255;
387 totalb += (Temp[locale].Blue * Temp[locale].Alpha)/ 255;
388
389
390 locale = xytolocale(x + radius, y + radius, arraywidth);
391 Dest[locale].Red = totalr / numofpixels; // take an average and assign it to the destination array
392 Dest[locale].Green = totalg / numofpixels;
393 Dest[locale].Blue = totalb / numofpixels;
394 Dest[locale].Alpha = totala / numofpixels;
395
396 }
397 }
398
399
400
401 for (int y = 0; y<srcHeight; y++){
402
403 for (int x = 0; x<srcWidth; x++){
404 int locale = xytolocale(x + radius, y + radius, arraywidth);
405 srclongbuffer[y][x] = Dest[locale].GetColorAsInt(); //write the destination array to the main buffer
406
407 }
408
409 }
410 delete [] Pixels;
411 delete [] Dest;
412 delete [] Temp;
413 engine->ReleaseBitmapSurface(src);
414 delete srclongbuffer;
415 delete srccharbuffer;
416 return 0;
417 }
418
Clamp(int val,int min,int max)419 int Clamp(int val, int min, int max){
420
421 if (val < min) return min;
422 else if (val > max) return max;
423 else return val;
424
425 }
426
DrawSprite(int destination,int sprite,int x,int y,int DrawMode,int trans)427 int DrawSprite(int destination, int sprite, int x, int y, int DrawMode, int trans){
428
429 trans = 100 - trans;
430 int srcWidth, srcHeight, destWidth, destHeight;
431
432 BITMAP* src = engine->GetSpriteGraphic(sprite);
433 BITMAP* dest = engine->GetSpriteGraphic(destination);
434
435 engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, NULL);
436 engine->GetBitmapDimensions(dest, &destWidth, &destHeight, NULL);
437
438 if (x > destWidth || y > destHeight || x + srcWidth < 0 || y + srcHeight < 0) return 1; // offscreen
439
440 unsigned char **srccharbuffer = engine->GetRawBitmapSurface (src);
441 unsigned int **srclongbuffer = (unsigned int**)srccharbuffer;
442
443 unsigned char **destcharbuffer = engine->GetRawBitmapSurface (dest);
444 unsigned int **destlongbuffer = (unsigned int**)destcharbuffer;
445
446
447
448 if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
449 if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
450
451 int destx, desty;
452 int srcr, srcg, srcb, srca, destr, destg, destb, desta, finalr, finalg, finalb, finala;
453 unsigned int col;
454 int starty = 0;
455 int startx = 0;
456
457 if (x < 0) startx = -1 * x;
458 if (y < 0) starty = -1 * y;
459
460 int ycount = 0;
461 int xcount = 0;
462 for(ycount = starty; ycount<srcHeight; ycount ++){
463
464 for(xcount = startx; xcount<srcWidth; xcount ++){
465
466 destx = xcount + x;
467 desty = ycount + y;
468
469 srca = (geta32(srclongbuffer[ycount][xcount]));
470
471 if (srca != 0) {
472 srca = srca * trans / 100;
473 srcr = getr32(srclongbuffer[ycount][xcount]);
474 srcg = getg32(srclongbuffer[ycount][xcount]);
475 srcb = getb32(srclongbuffer[ycount][xcount]);
476
477 destr = getr32(destlongbuffer[desty][destx]);
478 destg = getg32(destlongbuffer[desty][destx]);
479 destb = getb32(destlongbuffer[desty][destx]);
480 desta = geta32(destlongbuffer[desty][destx]);
481
482
483
484
485 switch (DrawMode) {
486
487 case 0:
488
489 finalr = srcr;
490 finalg = srcg;
491 finalb = srcb;
492 break;
493
494 case 1:
495
496 finalr = ChannelBlend_Lighten(srcr,destr);
497 finalg = ChannelBlend_Lighten(srcg,destg);
498 finalb = ChannelBlend_Lighten(srcb,destb);
499 break;
500
501 case 2:
502
503
504 finalr = ChannelBlend_Darken(srcr,destr);
505 finalg = ChannelBlend_Darken(srcg,destg);
506 finalb = ChannelBlend_Darken(srcb,destb);
507 break;
508
509 case 3:
510
511
512 finalr = ChannelBlend_Multiply(srcr,destr);
513 finalg = ChannelBlend_Multiply(srcg,destg);
514 finalb = ChannelBlend_Multiply(srcb,destb);
515 break;
516
517 case 4:
518
519
520 finalr = ChannelBlend_Add(srcr,destr);
521 finalg = ChannelBlend_Add(srcg,destg);
522 finalb = ChannelBlend_Add(srcb,destb);
523 break;
524
525 case 5:
526
527
528 finalr = ChannelBlend_Subtract(srcr,destr);
529 finalg = ChannelBlend_Subtract(srcg,destg);
530 finalb = ChannelBlend_Subtract(srcb,destb);
531 break;
532
533 case 6:
534
535
536 finalr = ChannelBlend_Difference(srcr,destr);
537 finalg = ChannelBlend_Difference(srcg,destg);
538 finalb = ChannelBlend_Difference(srcb,destb);
539 break;
540
541 case 7:
542
543
544 finalr = ChannelBlend_Negation(srcr,destr);
545 finalg = ChannelBlend_Negation(srcg,destg);
546 finalb = ChannelBlend_Negation(srcb,destb);
547 break;
548
549 case 8:
550
551
552 finalr = ChannelBlend_Screen(srcr,destr);
553 finalg = ChannelBlend_Screen(srcg,destg);
554 finalb = ChannelBlend_Screen(srcb,destb);
555 break;
556
557
558 case 9:
559
560
561 finalr = ChannelBlend_Exclusion(srcr,destr);
562 finalg = ChannelBlend_Exclusion(srcg,destg);
563 finalb = ChannelBlend_Exclusion(srcb,destb);
564 break;
565
566
567 case 10:
568
569
570 finalr = ChannelBlend_Overlay(srcr,destr);
571 finalg = ChannelBlend_Overlay(srcg,destg);
572 finalb = ChannelBlend_Overlay(srcb,destb);
573 break;
574
575
576 case 11:
577
578
579 finalr = ChannelBlend_SoftLight(srcr,destr);
580 finalg = ChannelBlend_SoftLight(srcg,destg);
581 finalb = ChannelBlend_SoftLight(srcb,destb);
582 break;
583
584 case 12:
585
586
587 finalr = ChannelBlend_HardLight(srcr,destr);
588 finalg = ChannelBlend_HardLight(srcg,destg);
589 finalb = ChannelBlend_HardLight(srcb,destb);
590 break;
591
592 case 13:
593
594
595 finalr = ChannelBlend_ColorDodge(srcr,destr);
596 finalg = ChannelBlend_ColorDodge(srcg,destg);
597 finalb = ChannelBlend_ColorDodge(srcb,destb);
598 break;
599
600 case 14:
601
602
603 finalr = ChannelBlend_ColorBurn(srcr,destr);
604 finalg = ChannelBlend_ColorBurn(srcg,destg);
605 finalb = ChannelBlend_ColorBurn(srcb,destb);
606 break;
607
608 case 15:
609
610
611 finalr = ChannelBlend_LinearDodge(srcr,destr);
612 finalg = ChannelBlend_LinearDodge(srcg,destg);
613 finalb = ChannelBlend_LinearDodge(srcb,destb);
614 break;
615
616 case 16:
617
618
619 finalr = ChannelBlend_LinearBurn(srcr,destr);
620 finalg = ChannelBlend_LinearBurn(srcg,destg);
621 finalb = ChannelBlend_LinearBurn(srcb,destb);
622 break;
623
624
625
626 case 17:
627
628
629 finalr = ChannelBlend_LinearLight(srcr,destr);
630 finalg = ChannelBlend_LinearLight(srcg,destg);
631 finalb = ChannelBlend_LinearLight(srcb,destb);
632 break;
633
634
635
636 case 18:
637
638
639 finalr = ChannelBlend_VividLight(srcr,destr);
640 finalg = ChannelBlend_VividLight(srcg,destg);
641 finalb = ChannelBlend_VividLight(srcb,destb);
642 break;
643
644 case 19:
645
646
647 finalr = ChannelBlend_PinLight(srcr,destr);
648 finalg = ChannelBlend_PinLight(srcg,destg);
649 finalb = ChannelBlend_PinLight(srcb,destb);
650 break;
651
652 case 20:
653
654
655 finalr = ChannelBlend_HardMix(srcr,destr);
656 finalg = ChannelBlend_HardMix(srcg,destg);
657 finalb = ChannelBlend_HardMix(srcb,destb);
658 break;
659
660 case 21:
661
662
663 finalr = ChannelBlend_Reflect(srcr,destr);
664 finalg = ChannelBlend_Reflect(srcg,destg);
665 finalb = ChannelBlend_Reflect(srcb,destb);
666 break;
667
668 case 22:
669
670
671 finalr = ChannelBlend_Glow(srcr,destr);
672 finalg = ChannelBlend_Glow(srcg,destg);
673 finalb = ChannelBlend_Glow(srcb,destb);
674 break;
675
676 case 23:
677
678
679 finalr = ChannelBlend_Phoenix(srcr,destr);
680 finalg = ChannelBlend_Phoenix(srcg,destg);
681 finalb = ChannelBlend_Phoenix(srcb,destb);
682 break;
683
684 }
685
686 finala = 255-(255-srca)*(255-desta)/255;
687 finalr = srca*finalr/finala + desta*destr*(255-srca)/finala/255;
688 finalg = srca*finalg/finala + desta*destg*(255-srca)/finala/255;
689 finalb = srca*finalb/finala + desta*destb*(255-srca)/finala/255;
690 col = makeacol32(finalr, finalg, finalb, finala);
691 destlongbuffer[desty][destx] = col;
692
693 }
694
695
696 }
697
698 }
699
700 engine->ReleaseBitmapSurface(src);
701 engine->ReleaseBitmapSurface(dest);
702 engine->NotifySpriteUpdated(destination);
703 return 0;
704
705 }
706
707
DrawAdd(int destination,int sprite,int x,int y,float scale)708 int DrawAdd(int destination, int sprite, int x, int y, float scale){
709
710
711 int srcWidth, srcHeight, destWidth, destHeight;
712
713 BITMAP* src = engine->GetSpriteGraphic(sprite);
714 BITMAP* dest = engine->GetSpriteGraphic(destination);
715
716 engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, NULL);
717 engine->GetBitmapDimensions(dest, &destWidth, &destHeight, NULL);
718
719 if (x > destWidth || y > destHeight) return 1; // offscreen
720
721 unsigned char **srccharbuffer = engine->GetRawBitmapSurface (src);
722 unsigned int **srclongbuffer = (unsigned int**)srccharbuffer;
723
724 unsigned char **destcharbuffer = engine->GetRawBitmapSurface (dest);
725 unsigned int **destlongbuffer = (unsigned int**)destcharbuffer;
726
727 if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
728 if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
729
730 int destx, desty;
731 int srcr, srcg, srcb, srca, destr, destg, destb, desta, finalr, finalg, finalb, finala;
732 unsigned int col;
733 int ycount = 0;
734 int xcount = 0;
735
736 int starty = 0;
737 int startx = 0;
738
739 if (x < 0) startx = -1 * x;
740 if (y < 0) starty = -1 * y;
741
742
743
744 for(ycount = starty; ycount<srcHeight; ycount ++){
745
746 for(xcount = startx; xcount<srcWidth; xcount ++){
747
748 destx = xcount + x;
749 desty = ycount + y;
750
751 srca = (geta32(srclongbuffer[ycount][xcount]));
752
753 if (srca != 0) {
754
755
756 srcr = getr32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
757 srcg = getg32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
758 srcb = getb32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
759 desta = geta32(destlongbuffer[desty][destx]);
760
761 if (desta == 0){
762 destr = 0;
763 destg = 0;
764 destb = 0;
765
766 }
767 else {
768 destr = getr32(destlongbuffer[desty][destx]);
769 destg = getg32(destlongbuffer[desty][destx]);
770 destb = getb32(destlongbuffer[desty][destx]);
771 }
772
773 finala = 255-(255-srca)*(255-desta)/255;
774 finalr = Clamp(srcr + destr, 0, 255);
775 finalg = Clamp(srcg + destg, 0, 255);
776 finalb = Clamp(srcb + destb, 0, 255);
777 col = makeacol32(finalr, finalg, finalb, finala);
778 destlongbuffer[desty][destx] = col;
779
780 }
781
782 }
783
784 }
785
786 engine->ReleaseBitmapSurface(src);
787 engine->ReleaseBitmapSurface(dest);
788 engine->NotifySpriteUpdated(destination);
789 return 0;
790
791
792
793 }
794
795
796
DrawAlpha(int destination,int sprite,int x,int y,int trans)797 int DrawAlpha(int destination, int sprite, int x, int y, int trans)
798 {
799
800 trans = 100 - trans;
801
802 int srcWidth, srcHeight, destWidth, destHeight;
803
804 BITMAP* src = engine->GetSpriteGraphic(sprite);
805 BITMAP* dest = engine->GetSpriteGraphic(destination);
806
807 engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, NULL);
808 engine->GetBitmapDimensions(dest, &destWidth, &destHeight, NULL);
809
810 if (x > destWidth || y > destHeight) return 1; // offscreen
811
812 unsigned char **srccharbuffer = engine->GetRawBitmapSurface (src);
813 unsigned int **srclongbuffer = (unsigned int**)srccharbuffer;
814
815 unsigned char **destcharbuffer = engine->GetRawBitmapSurface (dest);
816 unsigned int **destlongbuffer = (unsigned int**)destcharbuffer;
817
818 if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
819 if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
820
821 int destx, desty;
822 int srcr, srcg, srcb, srca, destr, destg, destb, desta, finalr, finalg, finalb, finala;
823
824 int ycount = 0;
825 int xcount = 0;
826
827 int starty = 0;
828 int startx = 0;
829
830 if (x < 0) startx = -1 * x;
831 if (y < 0) starty = -1 * y;
832
833
834 for(ycount = starty; ycount<srcHeight; ycount ++){
835
836 for(xcount = startx; xcount<srcWidth; xcount ++){
837
838 destx = xcount + x;
839 desty = ycount + y;
840
841 srca = (geta32(srclongbuffer[ycount][xcount])) * trans / 100;
842
843 if (srca != 0) {
844
845 srcr = getr32(srclongbuffer[ycount][xcount]);
846 srcg = getg32(srclongbuffer[ycount][xcount]);
847 srcb = getb32(srclongbuffer[ycount][xcount]);
848
849 destr = getr32(destlongbuffer[desty][destx]);
850 destg = getg32(destlongbuffer[desty][destx]);
851 destb = getb32(destlongbuffer[desty][destx]);
852 desta = geta32(destlongbuffer[desty][destx]);
853
854 finala = 255-(255-srca)*(255-desta)/255;
855 finalr = srca*srcr/finala + desta*destr*(255-srca)/finala/255;
856 finalg = srca*srcg/finala + desta*destg*(255-srca)/finala/255;
857 finalb = srca*srcb/finala + desta*destb*(255-srca)/finala/255;
858
859 destlongbuffer[desty][destx] = makeacol32(finalr, finalg, finalb, finala);
860
861 }
862
863 }
864
865 }
866
867 engine->ReleaseBitmapSurface(src);
868 engine->ReleaseBitmapSurface(dest);
869 engine->NotifySpriteUpdated(destination);
870
871 return 0;
872 }
873
874
875 #if defined(WINDOWS_VERSION)
876
877 //==============================================================================
878
879 // ***** Design time *****
880
881 IAGSEditor *editor; // Editor interface
882
883 const char *ourScriptHeader =
884 "import int DrawAlpha(int destination, int sprite, int x, int y, int transparency);\r\n"
885 "import int GetAlpha(int sprite, int x, int y);\r\n"
886 "import int PutAlpha(int sprite, int x, int y, int alpha);\r\n"
887 "import int Blur(int sprite, int radius);\r\n"
888 "import int HighPass(int sprite, int threshold);\r\n"
889 "import int DrawAdd(int destination, int sprite, int x, int y, float scale);\r\n"
890 "import int DrawSprite(int destination, int sprite, int x, int y, int DrawMode, int trans);";
891
892
893
894
895 //------------------------------------------------------------------------------
896
AGS_GetPluginName()897 LPCSTR AGS_GetPluginName()
898 {
899 return ("AGSBlend");
900 }
901
902 //------------------------------------------------------------------------------
903
AGS_EditorStartup(IAGSEditor * lpEditor)904 int AGS_EditorStartup(IAGSEditor *lpEditor)
905 {
906 // User has checked the plugin to use it in their game
907
908 // If it's an earlier version than what we need, abort.
909 if (lpEditor->version < MIN_EDITOR_VERSION)
910 return (-1);
911
912 editor = lpEditor;
913 editor->RegisterScriptHeader(ourScriptHeader);
914
915 // Return 0 to indicate success
916 return (0);
917 }
918
919 //------------------------------------------------------------------------------
920
AGS_EditorShutdown()921 void AGS_EditorShutdown()
922 {
923 // User has un-checked the plugin from their game
924 editor->UnregisterScriptHeader(ourScriptHeader);
925 }
926
927 //------------------------------------------------------------------------------
928
AGS_EditorProperties(HWND parent)929 void AGS_EditorProperties(HWND parent) //*** optional ***
930 {
931 // User has chosen to view the Properties of the plugin
932 // We could load up an options dialog or something here instead
933 /* MessageBox(parent,
934 L"AGSBlend v1.0 By Calin Leafshade",
935 L"About",
936 MB_OK | MB_ICONINFORMATION);
937 */
938 }
939
940 //------------------------------------------------------------------------------
941
AGS_EditorSaveGame(char * buffer,int bufsize)942 int AGS_EditorSaveGame(char *buffer, int bufsize) //*** optional ***
943 {
944 // Called by the editor when the current game is saved to disk.
945 // Plugin configuration can be stored in [buffer] (max [bufsize] bytes)
946 // Return the amount of bytes written in the buffer
947 return (0);
948 }
949
950 //------------------------------------------------------------------------------
951
AGS_EditorLoadGame(char * buffer,int bufsize)952 void AGS_EditorLoadGame(char *buffer, int bufsize) //*** optional ***
953 {
954 // Called by the editor when a game is loaded from disk
955 // Previous written data can be read from [buffer] (size [bufsize]).
956 // Make a copy of the data, the buffer is freed after this function call.
957 }
958
959 //==============================================================================
960
961 #endif
962
963 // ***** Run time *****
964
965 // Engine interface
966
967 //------------------------------------------------------------------------------
968
969 #define REGISTER(x) engine->RegisterScriptFunction(#x, (void *) (x));
970 #define STRINGIFY(s) STRINGIFY_X(s)
971 #define STRINGIFY_X(s) #s
972
AGS_EngineStartup(IAGSEngine * lpEngine)973 void AGS_EngineStartup(IAGSEngine *lpEngine)
974 {
975 engine = lpEngine;
976
977 // Make sure it's got the version with the features we need
978 if (engine->version < MIN_ENGINE_VERSION)
979 engine->AbortGame("Plugin needs engine version " STRINGIFY(MIN_ENGINE_VERSION) " or newer.");
980
981 //register functions
982
983 REGISTER(GetAlpha)
984 REGISTER(PutAlpha)
985 REGISTER(DrawAlpha)
986 REGISTER(Blur)
987 REGISTER(HighPass)
988 REGISTER(DrawAdd)
989 REGISTER(DrawSprite)
990
991
992 }
993
994 //------------------------------------------------------------------------------
995
AGS_EngineShutdown()996 void AGS_EngineShutdown()
997 {
998 // Called by the game engine just before it exits.
999 // This gives you a chance to free any memory and do any cleanup
1000 // that you need to do before the engine shuts down.
1001 }
1002
1003 //------------------------------------------------------------------------------
1004
AGS_EngineOnEvent(int event,int data)1005 int AGS_EngineOnEvent(int event, int data) //*** optional ***
1006 {
1007 switch (event)
1008 {
1009 /*
1010 case AGSE_KEYPRESS:
1011 case AGSE_MOUSECLICK:
1012 case AGSE_POSTSCREENDRAW:
1013 case AGSE_PRESCREENDRAW:
1014 case AGSE_SAVEGAME:
1015 case AGSE_RESTOREGAME:
1016 case AGSE_PREGUIDRAW:
1017 case AGSE_LEAVEROOM:
1018 case AGSE_ENTERROOM:
1019 case AGSE_TRANSITIONIN:
1020 case AGSE_TRANSITIONOUT:
1021 case AGSE_FINALSCREENDRAW:
1022 case AGSE_TRANSLATETEXT:
1023 case AGSE_SCRIPTDEBUG:
1024 case AGSE_SPRITELOAD:
1025 case AGSE_PRERENDER:
1026 case AGSE_PRESAVEGAME:
1027 case AGSE_POSTRESTOREGAME:
1028 */
1029 default:
1030 break;
1031 }
1032
1033 // Return 1 to stop event from processing further (when needed)
1034 return (0);
1035 }
1036
1037 //------------------------------------------------------------------------------
1038
AGS_EngineDebugHook(const char * scriptName,int lineNum,int reserved)1039 int AGS_EngineDebugHook(const char *scriptName,
1040 int lineNum, int reserved) //*** optional ***
1041 {
1042 // Can be used to debug scripts, see documentation
1043 return 0;
1044 }
1045
1046 //------------------------------------------------------------------------------
1047
AGS_EngineInitGfx(const char * driverID,void * data)1048 void AGS_EngineInitGfx(const char *driverID, void *data) //*** optional ***
1049 {
1050 // This allows you to make changes to how the graphics driver starts up.
1051 // See documentation
1052 }
1053
1054 //..............................................................................
1055
1056
1057 #if defined(BUILTIN_PLUGINS)
1058 }
1059 #endif
1060