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/console.h"
24 #include "ags/ags.h"
25 #include "ags/globals.h"
26 #include "ags/shared/ac/sprite_cache.h"
27 #include "ags/shared/gfx/allegro_bitmap.h"
28 #include "ags/shared/script/cc_options.h"
29 #include "image/png.h"
30
31 namespace AGS {
32
AGSConsole(AGSEngine * vm)33 AGSConsole::AGSConsole(AGSEngine *vm) : GUI::Debugger(), _vm(vm), _logOutputTarget(nullptr), _agsDebuggerOutput(nullptr) {
34 registerCmd("ags_debug_groups_list", WRAP_METHOD(AGSConsole, Cmd_listDebugGroups));
35 registerCmd("ags_debug_groups_set", WRAP_METHOD(AGSConsole, Cmd_setDebugGroupLevel));
36 registerCmd("ags_set_script_dump", WRAP_METHOD(AGSConsole, Cmd_SetScriptDump));
37 registerCmd("ags_sprite_info", WRAP_METHOD(AGSConsole, Cmd_getSpriteInfo));
38 registerCmd("ags_sprite_dump", WRAP_METHOD(AGSConsole, Cmd_dumpSprite));
39
40 _logOutputTarget = new LogOutputTarget();
41 _agsDebuggerOutput = _GP(DbgMgr).RegisterOutput("ScummVMLog", _logOutputTarget, AGS3::AGS::Shared::kDbgMsg_None);
42 }
43
~AGSConsole()44 AGSConsole::~AGSConsole() {
45 delete _logOutputTarget;
46 }
47
48 struct LevelName {
49 const char *name;
50 AGS3::AGS::Shared::MessageType level;
51 };
52
53 static const LevelName levelNames[] = {
54 {"none", AGS3::AGS::Shared::kDbgMsg_None},
55 {"alerts", AGS3::AGS::Shared::kDbgMsg_Alert},
56 {"fatal", AGS3::AGS::Shared::kDbgMsg_Fatal},
57 {"errors", AGS3::AGS::Shared::kDbgMsg_Error},
58 {"warnings", AGS3::AGS::Shared::kDbgMsg_None},
59 {"info", AGS3::AGS::Shared::kDbgMsg_Info},
60 {"debug", AGS3::AGS::Shared::kDbgMsg_Debug},
61 {nullptr, AGS3::AGS::Shared::kDbgMsg_None}
62 };
63
64 struct GroupName {
65 const char *name;
66 AGS3::uint32_t group;
67 };
68
69 static const GroupName groupNames[] = {
70 {"Main", AGS3::AGS::Shared::kDbgGroup_Main},
71 {"Game", AGS3::AGS::Shared::kDbgGroup_Game},
72 {"Script", AGS3::AGS::Shared::kDbgGroup_Script},
73 {"SpriteCache", AGS3::AGS::Shared::kDbgGroup_SprCache},
74 {"ManObj", AGS3::AGS::Shared::kDbgGroup_ManObj},
75 {nullptr, (AGS3::uint32_t)-1}
76 };
77
Cmd_listDebugGroups(int argc,const char ** argv)78 bool AGSConsole::Cmd_listDebugGroups(int argc, const char **argv) {
79 if (argc != 1) {
80 debugPrintf("Usage: %s\n", argv[0]);
81 return true;
82 }
83
84 debugPrintf("%-16s %-16s\n", "Name", "Level");
85 for (int i = 0 ; groupNames[i].name != nullptr ; ++i)
86 debugPrintf("%-16s %-16s\n", groupNames[i].name, getVerbosityLevel(groupNames[i].group));
87 return true;
88 }
89
Cmd_setDebugGroupLevel(int argc,const char ** argv)90 bool AGSConsole::Cmd_setDebugGroupLevel(int argc, const char **argv) {
91 if (argc != 3) {
92 debugPrintf("Usage: %s group level\n", argv[0]);
93 debugPrintf(" valid groups: ");
94 printGroupList();
95 debugPrintf("\n");
96 debugPrintf(" valid levels: ");
97 printLevelList();
98 debugPrintf("\n");
99 return true;
100 }
101
102 bool found = false;
103 AGS3::uint32_t group = parseGroup(argv[1], found);
104 if (!found) {
105 debugPrintf("Unknown debug group '%s'\n", argv[1]);
106 debugPrintf("Valid groups are: ");
107 printGroupList();
108 debugPrintf("\n");
109 return true;
110 }
111
112 AGS3::AGS::Shared::MessageType level = parseLevel(argv[2], found);
113 if (!found) {
114 debugPrintf("Unknown level '%s'\n", argv[2]);
115 debugPrintf("Valid levels are: ");
116 printLevelList();
117 debugPrintf("\n");
118 return true;
119 }
120
121 _agsDebuggerOutput->SetGroupFilter(group, level);
122 return true;
123 }
124
getVerbosityLevel(AGS3::uint32_t groupID) const125 const char *AGSConsole::getVerbosityLevel(AGS3::uint32_t groupID) const {
126 int i = 1;
127 while (levelNames[i].name != nullptr) {
128 if (!_agsDebuggerOutput->TestGroup(groupID, levelNames[i].level))
129 break;
130 ++i;
131 }
132 return levelNames[i - 1].name;
133 }
134
parseGroup(const char * name,bool & found) const135 AGS3::uint32_t AGSConsole::parseGroup(const char *name, bool &found) const {
136 int i = 0;
137 while (groupNames[i].name != nullptr) {
138 if (scumm_stricmp(name, groupNames[i].name) == 0) {
139 found = true;
140 return groupNames[i].group;
141 }
142 ++i;
143 }
144
145 found = false;
146 return (AGS3::uint32_t)-1;
147 }
148
parseLevel(const char * name,bool & found) const149 AGS3::AGS::Shared::MessageType AGSConsole::parseLevel(const char *name, bool &found) const {
150 int i = 0;
151 while (levelNames[i].name != nullptr) {
152 if (scumm_stricmp(name, levelNames[i].name) == 0) {
153 found = true;
154 return levelNames[i].level;
155 }
156 ++i;
157 }
158
159 found = false;
160 return AGS3::AGS::Shared::kDbgMsg_None;
161 }
162
printGroupList()163 void AGSConsole::printGroupList() {
164 debugPrintf("%s", groupNames[0].name);
165 for (int i = 1 ; groupNames[i].name != nullptr ; ++i)
166 debugPrintf(", %s", groupNames[i].name);
167 }
168
printLevelList()169 void AGSConsole::printLevelList() {
170 debugPrintf("%s", levelNames[0].name);
171 for (int i = 1 ; levelNames[i].name != nullptr ; ++i)
172 debugPrintf(", %s", levelNames[i].name);
173 }
174
Cmd_SetScriptDump(int argc,const char ** argv)175 bool AGSConsole::Cmd_SetScriptDump(int argc, const char **argv) {
176 if (argc != 2) {
177 debugPrintf("Usage: %s [on|off]\n", argv[0]);
178 return true;
179 }
180
181 if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "true") == 0)
182 AGS3::ccSetOption(SCOPT_DEBUGRUN, 1);
183 else
184 AGS3::ccSetOption(SCOPT_DEBUGRUN, 0);
185 return true;
186 }
187
Cmd_getSpriteInfo(int argc,const char ** argv)188 bool AGSConsole::Cmd_getSpriteInfo(int argc, const char **argv) {
189 if (argc != 2) {
190 debugPrintf("Usage: %s SpriteNumber\n", argv[0]);
191 return true;
192 }
193
194 int spriteId = atoi(argv[1]);
195 if (!_GP(spriteset).DoesSpriteExist(spriteId)) {
196 debugPrintf("Sprite %d does not exist\n", spriteId);
197 return true;
198 }
199
200 AGS3::Shared::Bitmap *sprite = _GP(spriteset)[spriteId];
201 if (!sprite) {
202 debugPrintf("Failed to get sprite %d\n", spriteId);
203 return true;
204 }
205
206 debugPrintf("Size: %dx%d\n", sprite->GetWidth(), sprite->GetHeight());
207 debugPrintf("Color depth: %d\n", sprite->GetColorDepth());
208 return true;
209 }
210
Cmd_dumpSprite(int argc,const char ** argv)211 bool AGSConsole::Cmd_dumpSprite(int argc, const char **argv) {
212 if (argc != 2) {
213 debugPrintf("Usage: %s SpriteNumber\n", argv[0]);
214 return true;
215 }
216
217 int spriteId = atoi(argv[1]);
218 if (!_GP(spriteset).DoesSpriteExist(spriteId)) {
219 debugPrintf("Sprite %d does not exist\n", spriteId);
220 return true;
221 }
222
223 AGS3::Shared::Bitmap *sprite = _GP(spriteset)[spriteId];
224 if (!sprite) {
225 debugPrintf("Failed to get sprite %d\n", spriteId);
226 return true;
227 }
228
229 Common::String pngFile = Common::String::format("%s-sprite%03d.png", _vm->getGameId().c_str(), spriteId);
230 Common::DumpFile df;
231 if (df.open(pngFile)) {
232 byte *palette = nullptr;
233 if (sprite->GetColorDepth() == 8) {
234 palette = new byte[256 * 3];
235 for (int c = 0, i = 0 ; c < 256 ; ++c, i += 3) {
236 palette[i] = _G(current_palette)[c].r * 255 / 63;
237 palette[i + 1] = _G(current_palette)[c].g * 255 / 63;
238 palette[i + 2] = _G(current_palette)[c].b * 255 / 63;
239 }
240 }
241 Image::writePNG(df, sprite->GetAllegroBitmap()->getSurface().rawSurface(), palette);
242 delete[] palette;
243 }
244
245 return true;
246 }
247
LogOutputTarget()248 LogOutputTarget::LogOutputTarget() {
249 }
250
~LogOutputTarget()251 LogOutputTarget::~LogOutputTarget() {
252 }
253
PrintMessage(const AGS3::AGS::Shared::DebugMessage & msg)254 void LogOutputTarget::PrintMessage(const AGS3::AGS::Shared::DebugMessage &msg) {
255 LogMessageType::Type msgType = LogMessageType::kInfo;
256 switch (msg.MT) {
257 case AGS3::AGS::Shared::kDbgMsg_None:
258 return;
259 case AGS3::AGS::Shared::kDbgMsg_Alert:
260 case AGS3::AGS::Shared::kDbgMsg_Fatal:
261 case AGS3::AGS::Shared::kDbgMsg_Error:
262 msgType = LogMessageType::kError;
263 break;
264 case AGS3::AGS::Shared::kDbgMsg_Warn:
265 msgType = LogMessageType::kWarning;
266 break;
267 case AGS3::AGS::Shared::kDbgMsg_Info:
268 msgType = LogMessageType::kInfo;
269 break;
270 case AGS3::AGS::Shared::kDbgMsg_Debug:
271 msgType = LogMessageType::kDebug;
272 break;
273 }
274 Common::String text = Common::String::format("%s\n", msg.Text.GetCStr());
275 g_system->logMessage(msgType, text.c_str());
276 }
277
278
279 } // End of namespace AGS
280