ScummVM API documentation
debug.h
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 modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (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, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef ALCACHOFA_DEBUG_H
23 #define ALCACHOFA_DEBUG_H
24 
25 #include "alcachofa/alcachofa.h"
26 
27 using namespace Common;
28 
29 namespace Alcachofa {
30 
32 public:
33  virtual ~IDebugHandler() {}
34 
35  virtual void update() = 0;
36 };
37 
39  int32 _polygonI;
40 public:
41  ClosestFloorPointDebugHandler(int32 polygonI) : _polygonI(polygonI) {}
42 
43  void update() override {
44  auto mousePos2D = g_engine->input().debugInput().mousePos2D();
45  auto mousePos3D = g_engine->input().debugInput().mousePos3D();
46  auto floor = g_engine->player().currentRoom()->activeFloor();
47  auto renderer = dynamic_cast<IDebugRenderer *>(&g_engine->renderer());
48  if (floor == nullptr || renderer == nullptr)
49  return;
50 
51  Point target3D;
52  if (_polygonI < 0 || (uint)_polygonI >= floor->polygonCount())
53  target3D = floor->closestPointTo(mousePos3D);
54  else
55  target3D = floor->at((uint)_polygonI).closestPointTo(mousePos3D);
56  renderer->debugPolyline(mousePos2D, g_engine->camera().transform3Dto2D(target3D));
57  }
58 };
59 
61  int32 _polygonI;
62  Point _fromPos3D;
63 public:
64  FloorIntersectionsDebugHandler(int32 polygonI) : _polygonI(polygonI) {}
65 
66  void update() override {
67  auto floor = g_engine->player().currentRoom()->activeFloor();
68  auto renderer = dynamic_cast<IDebugRenderer *>(&g_engine->renderer());
69  if (floor == nullptr || renderer == nullptr) {
70  g_engine->console().attach("Either the room has no floor or the renderer is not a debug renderer");
71  g_engine->setDebugMode(DebugMode::None, 0);
72  return;
73  }
74 
75  if (g_engine->input().debugInput().wasMouseLeftPressed())
76  _fromPos3D = g_engine->input().debugInput().mousePos3D();
77  renderer->debugPolyline(
78  g_engine->camera().transform3Dto2D(_fromPos3D),
79  g_engine->input().debugInput().mousePos2D(),
80  kDebugRed);
81 
82  if (_polygonI >= 0 && (uint)_polygonI < floor->polygonCount())
83  drawIntersectionsFor(floor->at((uint)_polygonI), renderer);
84  else {
85  for (uint i = 0; i < floor->polygonCount(); i++)
86  drawIntersectionsFor(floor->at(i), renderer);
87  }
88  }
89 
90 private:
91  static constexpr float kMarkerLength = 16;
92 
93  void drawIntersectionsFor(const Polygon &polygon, IDebugRenderer *renderer) {
94  auto &camera = g_engine->camera();
95  auto mousePos3D = g_engine->input().debugInput().mousePos3D();
96  for (uint i = 0; i < polygon._points.size(); i++) {
97  if (!polygon.intersectsEdge(i, _fromPos3D, mousePos3D))
98  continue;
99  auto a = camera.transform3Dto2D(polygon._points[i]);
100  auto b = camera.transform3Dto2D(polygon._points[(i + 1) % polygon._points.size()]);
101  auto mid = (a + b) / 2;
102  auto length = sqrtf(a.sqrDist(b));
103  auto normal = a - b;
104  normal = { normal.y, (int16)-normal.x };
105  auto inner = mid + normal * (kMarkerLength / length);
106 
107  renderer->debugPolyline(a, b, kDebugGreen);
108  renderer->debugPolyline(mid, inner, kDebugGreen);
109  }
110  }
111 };
112 
114  MainCharacterKind _kind;
115 public:
116  TeleportCharacterDebugHandler(int32 kindI) : _kind((MainCharacterKind)kindI) {}
117 
118  void update() override {
119  g_engine->drawQueue().clear();
120  g_engine->player().drawCursor(true);
121  g_engine->drawQueue().draw();
122 
123  auto &input = g_engine->input().debugInput();
124  if (input.wasMouseRightPressed()) {
125  g_engine->setDebugMode(DebugMode::None, 0);
126  return;
127  }
128 
129  if (!input.wasMouseLeftPressed())
130  return;
131  auto floor = g_engine->player().currentRoom()->activeFloor();
132  if (floor == nullptr || !floor->contains(input.mousePos3D()))
133  return;
134 
135  if (_kind == MainCharacterKind::Filemon)
136  teleport(g_engine->world().filemon(), input.mousePos3D());
137  else if (_kind == MainCharacterKind::Mortadelo)
138  teleport(g_engine->world().mortadelo(), input.mousePos3D());
139  else {
140  teleport(g_engine->world().filemon(), input.mousePos3D());
141  teleport(g_engine->world().mortadelo(), input.mousePos3D());
142  }
143  g_engine->setDebugMode(DebugMode::None, 0);
144  }
145 
146 private:
147  void teleport(MainCharacter &character, Point position) {
148  auto currentRoom = g_engine->player().currentRoom();
149  if (character.room() != currentRoom) {
150  character.resetTalking();
151  character.room() = currentRoom;
152  }
153  character.setPosition(position);
154  }
155 };
156 
157 class FloorColorDebugHandler final : public IDebugHandler {
158  const FloorColorShape &_shape;
159  const bool _useColor;
160  Color _curColor = kDebugGreen;
161  bool _isOnFloor = false;
162  static constexpr size_t kBufferSize = 64;
163  char _buffer[kBufferSize] = { 0 };
164 
165  FloorColorDebugHandler(const FloorColorShape &shape, bool useColor)
166  : _shape(shape)
167  , _useColor(useColor) {}
168 public:
169  static FloorColorDebugHandler *create(int32 objectI, bool useColor) {
170  const Room *room = g_engine->player().currentRoom();
171  uint floorCount = 0;
172  for (auto itObject = room->beginObjects(); itObject != room->endObjects(); ++itObject) {
173  FloorColor *floor = dynamic_cast<FloorColor *>(*itObject);
174  if (floor == nullptr)
175  continue;
176  if (objectI <= 0)
177  // dynamic_cast is not possible due to Shape not having virtual methods
178  return new FloorColorDebugHandler(*(FloorColorShape *)(floor->shape()), useColor);
179  floorCount++;
180  objectI--;
181  }
182 
183  g_engine->console().debugPrintf("Invalid floor color index, there are %u floors in this room\n", floorCount);
184  return nullptr;
185  }
186 
187  void update() override {
188  auto &input = g_engine->input().debugInput();
189  if (input.wasMouseRightPressed()) {
190  g_engine->setDebugMode(DebugMode::None, 0);
191  return;
192  }
193 
194  if (input.isMouseLeftDown()) {
195  auto optColor = _shape.colorAt(input.mousePos3D());
196  _isOnFloor = optColor.first;
197  if (!_isOnFloor) {
198  uint8 roomAlpha = (uint)(g_engine->player().currentRoom()->characterAlphaTint() * 255 / 100);
199  optColor.second = Color { 255, 255, 255, roomAlpha };
200  }
201 
202  _curColor = _useColor
203  ? Color { optColor.second.r, optColor.second.g, optColor.second.b, 255 }
204  : Color { optColor.second.a, optColor.second.a, optColor.second.a, 255 };
205  g_engine->world().mortadelo().color() =
206  g_engine->world().filemon().color() =
207  _useColor ? optColor.second : Color { 255, 255, 255, optColor.second.a };
208  }
209 
210  snprintf(_buffer, kBufferSize, "r:%3d g:%3d b:%3d a:%3d",
211  (int)_curColor.r, (int)_curColor.g, (int)_curColor.b, (int)_curColor.a);
212 
213  auto *debugRenderer = dynamic_cast<IDebugRenderer *>(&g_engine->renderer());
214  g_engine->drawQueue().clear();
215  g_engine->player().drawCursor(true);
216  g_engine->renderer().setTexture(nullptr);
217  g_engine->renderer().quad({ 0, 0 }, { 50, 50 }, _isOnFloor ? _curColor : kDebugGreen);
218  g_engine->drawQueue().add<TextDrawRequest>(
219  g_engine->globalUI().dialogFont(), _buffer, Point { 70, 20 }, 500, false, kWhite, -kForegroundOrderCount + 1);
220  if (!_isOnFloor)
221  g_engine->renderer().quad({ 5, 5 }, { 40, 40 }, _curColor);
222  if (debugRenderer != nullptr)
223  debugRenderer->debugShape(_shape, kDebugBlue);
224  g_engine->drawQueue().draw();
225  }
226 };
227 
228 }
229 
230 #endif // ALCACHOFA_DEBUG_H
Definition: graphics.h:101
Definition: alcachofa.h:45
Definition: common.h:69
Definition: debug.h:157
Definition: graphics.h:369
Definition: shape.h:45
Engine * g_engine
Definition: shape.h:238
Definition: objects.h:588
Definition: algorithm.h:29
Definition: rect.h:144
Definition: objects.h:528
Definition: debug.h:31
Definition: rooms.h:31