1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 
15 #include "ac/walkbehind.h"
16 #include "ac/common.h"
17 #include "ac/common_defines.h"
18 #include "ac/roomstruct.h"
19 #include "ac/gamestate.h"
20 #include "media/audio/audio.h"
21 #include "gfx/graphicsdriver.h"
22 #include "gfx/bitmap.h"
23 
24 using namespace AGS::Common;
25 using namespace AGS::Engine;
26 
27 extern roomstruct thisroom;
28 extern GameState play;
29 extern IGraphicsDriver *gfxDriver;
30 
31 
32 char *walkBehindExists = NULL;  // whether a WB area is in this column
33 int *walkBehindStartY = NULL, *walkBehindEndY = NULL;
34 char noWalkBehindsAtAll = 0;
35 int walkBehindLeft[MAX_OBJ], walkBehindTop[MAX_OBJ];
36 int walkBehindRight[MAX_OBJ], walkBehindBottom[MAX_OBJ];
37 IDriverDependantBitmap *walkBehindBitmap[MAX_OBJ];
38 int walkBehindsCachedForBgNum = 0;
39 WalkBehindMethodEnum walkBehindMethod = DrawOverCharSprite;
40 int walk_behind_baselines_changed = 0;
41 
update_walk_behind_images()42 void update_walk_behind_images()
43 {
44   int ee, rr;
45   int bpp = (thisroom.ebscene[play.bg_frame]->GetColorDepth() + 7) / 8;
46   Bitmap *wbbmp;
47   for (ee = 1; ee < MAX_OBJ; ee++)
48   {
49     update_polled_stuff_if_runtime();
50 
51     if (walkBehindRight[ee] > 0)
52     {
53       wbbmp = BitmapHelper::CreateTransparentBitmap(
54                                (walkBehindRight[ee] - walkBehindLeft[ee]) + 1,
55                                (walkBehindBottom[ee] - walkBehindTop[ee]) + 1,
56 							   thisroom.ebscene[play.bg_frame]->GetColorDepth());
57       int yy, startX = walkBehindLeft[ee], startY = walkBehindTop[ee];
58       for (rr = startX; rr <= walkBehindRight[ee]; rr++)
59       {
60         for (yy = startY; yy <= walkBehindBottom[ee]; yy++)
61         {
62           if (thisroom.object->GetScanLine(yy)[rr] == ee)
63           {
64             for (int ii = 0; ii < bpp; ii++)
65               wbbmp->GetScanLineForWriting(yy - startY)[(rr - startX) * bpp + ii] = thisroom.ebscene[play.bg_frame]->GetScanLine(yy)[rr * bpp + ii];
66           }
67         }
68       }
69 
70       update_polled_stuff_if_runtime();
71 
72       if (walkBehindBitmap[ee] != NULL)
73       {
74         gfxDriver->DestroyDDB(walkBehindBitmap[ee]);
75       }
76       walkBehindBitmap[ee] = gfxDriver->CreateDDBFromBitmap(wbbmp, false);
77       delete wbbmp;
78     }
79   }
80 
81   walkBehindsCachedForBgNum = play.bg_frame;
82 }
83 
84 
recache_walk_behinds()85 void recache_walk_behinds () {
86   if (walkBehindExists) {
87     free (walkBehindExists);
88     free (walkBehindStartY);
89     free (walkBehindEndY);
90   }
91 
92   walkBehindExists = (char*)malloc (thisroom.object->GetWidth());
93   walkBehindStartY = (int*)malloc (thisroom.object->GetWidth() * sizeof(int));
94   walkBehindEndY = (int*)malloc (thisroom.object->GetWidth() * sizeof(int));
95   noWalkBehindsAtAll = 1;
96 
97   int ee,rr,tmm;
98   const int NO_WALK_BEHIND = 100000;
99   for (ee = 0; ee < MAX_OBJ; ee++)
100   {
101     walkBehindLeft[ee] = NO_WALK_BEHIND;
102     walkBehindTop[ee] = NO_WALK_BEHIND;
103     walkBehindRight[ee] = 0;
104     walkBehindBottom[ee] = 0;
105 
106     if (walkBehindBitmap[ee] != NULL)
107     {
108       gfxDriver->DestroyDDB(walkBehindBitmap[ee]);
109       walkBehindBitmap[ee] = NULL;
110     }
111   }
112 
113   update_polled_stuff_if_runtime();
114 
115   // since this is an 8-bit memory bitmap, we can just use direct
116   // memory access
117   if ((!thisroom.object->IsLinearBitmap()) || (thisroom.object->GetColorDepth() != 8))
118     quit("Walk behinds bitmap not linear");
119 
120   for (ee=0;ee<thisroom.object->GetWidth();ee++) {
121     walkBehindExists[ee] = 0;
122     for (rr=0;rr<thisroom.object->GetHeight();rr++) {
123       tmm = thisroom.object->GetScanLine(rr)[ee];
124       //tmm = _getpixel(thisroom.object,ee,rr);
125       if ((tmm >= 1) && (tmm < MAX_OBJ)) {
126         if (!walkBehindExists[ee]) {
127           walkBehindStartY[ee] = rr;
128           walkBehindExists[ee] = tmm;
129           noWalkBehindsAtAll = 0;
130         }
131         walkBehindEndY[ee] = rr + 1;  // +1 to allow bottom line of screen to work
132 
133         if (ee < walkBehindLeft[tmm]) walkBehindLeft[tmm] = ee;
134         if (rr < walkBehindTop[tmm]) walkBehindTop[tmm] = rr;
135         if (ee > walkBehindRight[tmm]) walkBehindRight[tmm] = ee;
136         if (rr > walkBehindBottom[tmm]) walkBehindBottom[tmm] = rr;
137       }
138     }
139   }
140 
141   if (walkBehindMethod == DrawAsSeparateSprite)
142   {
143     update_walk_behind_images();
144   }
145 }
146