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