MFMv2.0.10
Movable Feast Machine Simulator 2.0.10
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GridPanel.h
Go to the documentation of this file.
1 /* -*- mode:C++ -*-
2  GridPanel.h Panel for rendering a Grid
3  Copyright (C) 2014 The Regents of the University of New Mexico. All rights reserved.
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18  USA
19 */
20 
27 #ifndef GRIDPANEL_H
28 #define GRIDPANEL_H
29 
30 #include "AtomViewPanel.h"
31 #include "itype.h"
32 #include "MDist.h"
33 #include "Panel.h"
34 #include "GridRenderer.h"
35 #include "EditingTool.h"
36 #include "ToolboxPanel.h"
37 #include "Util.h"
38 #include <math.h> /* for sqrt */
39 
40 #define SCREEN_INITIAL_WIDTH 1280
41 #define SCREEN_INITIAL_HEIGHT 1024
42 
43 namespace MFM
44 {
48  template <class GC>
49  class GridPanel : public Panel
50  {
51  public:
52  // Extract short type names
53  typedef typename GC::CORE_CONFIG CC;
54  typedef typename CC::PARAM_CONFIG P;
55  typedef typename CC::ATOM_TYPE T;
56  enum { W = GC::GRID_WIDTH};
57  enum { H = GC::GRID_HEIGHT};
58  enum { R = P::EVENT_WINDOW_RADIUS};
59  enum { TILE_SIDE_CACHE_SITES = P::TILE_WIDTH};
60  enum { TILE_SIDE_LIVE_SITES = TILE_SIDE_CACHE_SITES - 2*R};
61  enum { MAX_BUCKET_FILL_DEPTH = 10000 };
62 
63  static const u32 EVENT_WINDOW_RADIUS = R;
64  static const u32 GRID_WIDTH_TILES = W;
65  static const u32 GRID_HEIGHT_TILES = H;
66 
67  static const u32 GRID_WIDTH_LIVE_SITES = W * TILE_SIDE_LIVE_SITES;
68  static const u32 GRID_HEIGHT_LIVE_TILES = H * TILE_SIDE_LIVE_SITES;
69 
70  typedef Grid<GC> OurGrid;
71 
72  private:
73  GridRenderer* m_grend;
74  OurGrid* m_mainGrid;
75  ToolboxPanel<CC>* m_toolboxPanel;
76  SPoint m_leftButtonDragStart;
77  SPoint m_leftButtonGridStart;
78  bool m_paintingEnabled;
79 
80  /* I'm making this a field because of the recursive nature of BucketFill .*/
81  u32 m_bucketFillStartType;
82 
83  SPoint m_cloneOrigin;
84  SPoint m_cloneDestination;
85 
86  AtomViewPanel<GC> m_atomViewPanel;
87 
88  public:
89  GridPanel() :
90  m_paintingEnabled(false),
91  m_bucketFillStartType(0),
92  m_cloneOrigin(-1, -1),
93  m_cloneDestination(-1, -1)
94  {
95  SetName("Grid Panel");
96  SetDimensions(SCREEN_INITIAL_WIDTH,
97  SCREEN_INITIAL_HEIGHT);
98  SetRenderPoint(SPoint(0, 0));
99  SetForeground(Drawing::BLACK);
100  SetBackground(Drawing::BLACK);
101 
102  m_grend = NULL;
103  m_mainGrid = NULL;
104 
105  m_atomViewPanel.SetName("AtomViewer");
106  m_atomViewPanel.SetRenderPoint(SPoint(326, 0));
107  m_atomViewPanel.SetBackground(Drawing::BLACK);
108  m_atomViewPanel.SetForeground(Drawing::GREY70);
109  m_atomViewPanel.SetVisibility(false);
110 
111  Panel::Insert(&m_atomViewPanel, NULL);
112  }
113 
114  AtomViewPanel<GC> * GetAtomViewPanel()
115  {
116  return &m_atomViewPanel;
117  }
118 
119  void SetGrid(OurGrid* mainGrid)
120  {
121  m_mainGrid = mainGrid;
122  m_atomViewPanel.SetGrid(m_mainGrid);
123  }
124 
125  void ToggleAtomViewPanel()
126  {
127  m_atomViewPanel.ToggleVisibility();
128  }
129 
130  void ToggleDrawAtomsAsSquares()
131  {
132  if(m_grend)
133  {
134  m_grend->ToggleDrawAtomsAsSquares();
135  }
136  }
137 
138  void SetGridRenderer(GridRenderer* grend)
139  {
140  m_grend = grend;
141  }
142 
143  void SetToolboxPanel(ToolboxPanel<CC>* toolboxPanel)
144  {
145  m_toolboxPanel = toolboxPanel;
146  m_atomViewPanel.SetToolboxPanel(m_toolboxPanel);
147  }
148 
149  void SetPaintingEnabled(bool isPaintingEnabled)
150  {
151  m_paintingEnabled = isPaintingEnabled;
152  }
153 
154  void DeselectAtomAndTile()
155  {
156  m_grend->DeselectTile();
157  m_grend->DeselectAtom();
158  m_cloneOrigin.Set(-1, -1);
159  m_grend->SetCloneOrigin(m_cloneOrigin);
160  m_atomViewPanel.SetAtom(NULL);
161  }
162 
163  protected:
164  virtual void PaintComponent(Drawing& drawing)
165  {
166  this->Panel::PaintComponent(drawing);
167 
168  m_grend->RenderGrid(drawing, *m_mainGrid, m_toolboxPanel->GetBrushSize());
169  }
170 
171  void HandleSelectorTool(MouseButtonEvent& mbe)
172  {
174  pt.Set(mbe.m_event.button.x - pt.GetX(),
175  mbe.m_event.button.y - pt.GetY());
176 
177  m_grend->SelectTile(*m_mainGrid, pt);
178  }
179 
180  void HandleAtomSelectorTool(MouseButtonEvent& mbe)
181  {
182  HandleAtomSelectorTool(mbe.m_event.button.button,
183  SPoint(mbe.m_event.button.x,
184  mbe.m_event.button.y));
185  }
186 
187  void HandlePencilTool(MouseButtonEvent& mbe)
188  {
189  HandlePencilTool(mbe.m_event.button.button,
190  SPoint(mbe.m_event.button.x,
191  mbe.m_event.button.y));
192  }
193 
194  void HandleBrushTool(MouseButtonEvent& mbe)
195  {
196  HandleBrushTool(mbe.m_event.button.button,
197  SPoint(mbe.m_event.button.x,
198  mbe.m_event.button.y));
199  }
200 
201  void HandleEraserTool(MouseButtonEvent& mbe)
202  {
203  HandleEraserTool(mbe.m_event.button.button,
204  SPoint(mbe.m_event.button.x,
205  mbe.m_event.button.y));
206  }
207 
208  void HandleBucketTool(MouseButtonEvent& mbe)
209  {
210  HandleBucketTool(mbe.m_event.button.button,
211  SPoint(mbe.m_event.button.x,
212  mbe.m_event.button.y));
213  }
214 
215  void HandleXRayTool(MouseButtonEvent& mbe)
216  {
217  HandleXRayTool(mbe.m_event.button.button,
218  SPoint(mbe.m_event.button.x,
219  mbe.m_event.button.y));
220  }
221 
222  void HandleAirbrushTool(MouseButtonEvent& mbe)
223  {
224  HandleAirbrushTool(mbe.m_event.button.button,
225  SPoint(mbe.m_event.button.x,
226  mbe.m_event.button.y));
227  }
228 
229  SPoint ClickPointToAtom(const SPoint& clickPt)
230  {
231  SPoint abs = GetAbsoluteLocation();
232  abs.Set(clickPt.GetX() - abs.GetX(),
233  clickPt.GetY() - abs.GetY());
234 
235  TileRenderer& tileRenderer = m_grend->GetTileRenderer();
236  const SPoint& offset = tileRenderer.GetWindowTL();
237 
238 
239  abs.Set(abs.GetX() - offset.GetX(),
240  abs.GetY() - offset.GetY());
241 
242  u32 atomSize = tileRenderer.GetAtomSize();
243 
244  abs.Set(abs.GetX() / atomSize,
245  abs.GetY() / atomSize);
246 
247  return abs;
248  }
249 
250  void HandleCloneTool(MouseButtonEvent& mbe)
251  {
252  if(mbe.m_event.button.button == SDL_BUTTON_LEFT)
253  {
254  m_cloneDestination = ClickPointToAtom(SPoint(mbe.m_event.button.x,
255  mbe.m_event.button.y));
256  }
257  HandleCloneTool(mbe.m_event.button.button,
258  SPoint(mbe.m_event.button.x,
259  mbe.m_event.button.y));
260  }
261 
262  void HandleAtomSelectorTool(u8 button, SPoint clickPt)
263  {
264  SPoint pt = GetAbsoluteLocation();
265  pt.Set(clickPt.GetX() - pt.GetX(),
266  clickPt.GetY() - pt.GetY());
267 
268  m_grend->SelectAtom(*m_mainGrid, pt);
269  SPoint selectedAtom = m_grend->GetSelectedAtom();
270  m_atomViewPanel.SetAtom(m_mainGrid->GetWritableAtom(selectedAtom));
271  }
272 
273  void HandlePencilTool(u8 button, SPoint clickPt)
274  {
275  T atom = (button == SDL_BUTTON_LEFT) ?
276  m_toolboxPanel->GetPrimaryElement()->GetDefaultAtom() :
277  m_toolboxPanel->GetSecondaryElement()->GetDefaultAtom();
278 
279  PaintAtom(button, clickPt, 0, atom, TOOL_PENCIL);
280  }
281 
282  void HandleBrushTool(u8 button, SPoint clickPt)
283  {
284  T atom = (button == SDL_BUTTON_LEFT) ?
285  m_toolboxPanel->GetPrimaryElement()->GetDefaultAtom() :
286  m_toolboxPanel->GetSecondaryElement()->GetDefaultAtom();
287 
288  PaintAtom(button, clickPt, (s32)m_toolboxPanel->GetBrushSize(), atom, TOOL_BRUSH);
289  }
290 
291  void HandleAirbrushTool(u8 button, SPoint clickPt)
292  {
293  T atom = (button == SDL_BUTTON_LEFT) ?
294  m_toolboxPanel->GetPrimaryElement()->GetDefaultAtom() :
295  m_toolboxPanel->GetSecondaryElement()->GetDefaultAtom();
296 
297  PaintAtom(button, clickPt, (s32)m_toolboxPanel->GetBrushSize(), atom, TOOL_AIRBRUSH);
298  }
299 
300  void HandleEraserTool(u8 button, SPoint clickPt)
301  {
302  PaintAtom(button, clickPt, (s32)m_toolboxPanel->GetBrushSize(),
303  Element_Empty<CC>::THE_INSTANCE.GetDefaultAtom(), TOOL_ERASER);
304  }
305 
306  void HandleBucketTool(u8 button, SPoint clickPt)
307  {
308  T atom = (button == SDL_BUTTON_LEFT) ?
309  m_toolboxPanel->GetPrimaryElement()->GetDefaultAtom() :
310  m_toolboxPanel->GetSecondaryElement()->GetDefaultAtom();
311 
312  PaintAtom(button, clickPt, 0, atom, TOOL_BUCKET);
313  }
314 
315  void HandleXRayTool(u8 button, SPoint clickPt)
316  {
317  PaintAtom(button, clickPt, (s32)m_toolboxPanel->GetBrushSize(),
318  Element_Empty<CC>::THE_INSTANCE.GetDefaultAtom(), TOOL_XRAY);
319  }
320 
321  void HandleCloneTool(u8 button, SPoint clickPt)
322  {
323  PaintAtom(button, clickPt, (s32)m_toolboxPanel->GetBrushSize(),
324  Element_Empty<CC>::THE_INSTANCE.GetDefaultAtom(), TOOL_CLONE);
325  }
326 
327  void PaintAtom(u8 button, SPoint& clickPt, s32 brushSize,
328  const T& atom, EditingTool tool)
329  {
330  /* Only do this when tiles are together to keep from having to
331  * deal with caches */
332  if(!m_grend->IsRenderingTilesSeparated())
333  {
334  Grid<GC>& grid = *m_mainGrid;
335  SPoint cp = ClickPointToAtom(clickPt);
336  if(brushSize > 0)
337  {
338  /* brushSize can't be templated, so let's do this by hand. */
339  SPoint tile, site;
340  brushSize--;
341  const s32 brushSqr = brushSize * brushSize;
342  s32 ysqr;
343  for(s32 y = -brushSize; y <= brushSize; y++)
344  {
345  ysqr = y * y;
346  for(s32 x = -brushSize; x <= brushSize; x++)
347  {
348  SPoint pt(cp.GetX() + x, cp.GetY() + y);
349  if(((x * x) + ysqr) <= brushSqr &&
350  grid.MapGridToTile(pt, tile, site))
351  {
352  if(tool == TOOL_XRAY)
353  {
354  grid.MaybeXRayAtom(pt);
355  }
356  else if(tool == TOOL_CLONE)
357  {
358  if(button == SDL_BUTTON_RIGHT)
359  {
360  SPoint tile, site;
361  if(grid.MapGridToTile(cp, tile, site))
362  {
363  m_cloneOrigin.Set(cp.GetX(), cp.GetY());
364  m_grend->SetCloneOrigin(m_cloneOrigin);
365  }
366  return; /* Only need to do this once. */
367  }
368  else
369  {
370  if(m_cloneOrigin.GetX() >= 0 && m_cloneOrigin.GetY() >= 0)
371  {
372  SPoint clonePt(m_cloneOrigin.GetX() +
373  (pt.GetX() - m_cloneDestination.GetX()),
374  m_cloneOrigin.GetY() +
375  (pt.GetY() - m_cloneDestination.GetY()));
376  SPoint tile, site;
377  if(grid.MapGridToTile(clonePt, tile, site))
378  {
379  const T* a = grid.GetAtom(clonePt);
380  grid.PlaceAtom(*a, pt);
381  }
382  }
383  }
384  }
385  else if((tool != TOOL_AIRBRUSH) ||
386  (m_mainGrid->GetRandom().OneIn(50)))
387  {
388  grid.PlaceAtom(atom, SPoint(cp.GetX() + x, cp.GetY() + y));
389  }
390  }
391  }
392  }
393  }
394  else if(cp.GetX() >= 0 && cp.GetY() >= 0 &&
395  cp.GetX() < TILE_SIDE_LIVE_SITES * W &&
396  cp.GetY() < TILE_SIDE_LIVE_SITES * H)
397  {
398  if(tool == TOOL_BUCKET)
399  {
400  SPoint tile, site;
401  if(grid.MapGridToTile(cp, tile, site))
402  {
403  m_bucketFillStartType = grid.GetTile(tile).GetAtom(site)->GetType();
404  if(m_bucketFillStartType != atom.GetType())
405  {
406  BucketFill(grid, atom, cp, MAX_BUCKET_FILL_DEPTH);
407  }
408  }
409  }
410  else if(tool == TOOL_CLONE)
411  {
412  if(button == SDL_BUTTON_RIGHT)
413  {
414  SPoint tile, site;
415  if(grid.MapGridToTile(cp, tile, site))
416  {
417  m_cloneOrigin.Set(cp.GetX(), cp.GetY());
418  LOG.Debug("Clone Origin Set: (%d, %d)", cp.GetX(), cp.GetY());
419  }
420  }
421  else
422  {
423  SPoint clonePt(m_cloneOrigin.GetX() +
424  (cp.GetX() - m_cloneDestination.GetX()),
425  m_cloneOrigin.GetY() +
426  (cp.GetY() - m_cloneDestination.GetY()));
427  SPoint tile, site;
428  LOG.Debug("Cloning from (%d, %d) to (%d, %d) [clone dest = (%d, %d)]",
429  clonePt.GetX(), clonePt.GetY(),
430  cp.GetX(), cp.GetY(),
431  m_cloneDestination.GetX(), m_cloneDestination.GetY());
432  if(grid.MapGridToTile(clonePt, tile, site))
433  {
434  const T* a = grid.GetAtom(clonePt);
435  grid.PlaceAtom(*a, cp);
436  }
437  }
438  }
439  else
440  {
441  grid.PlaceAtom(atom, cp);
442  }
443  }
444  }
445  }
446 
447  void BucketFill(Grid<GC>& grid, const T& atom, SPoint& pt, u32 depth)
448  {
449  grid.PlaceAtom(atom, pt);
450  SPoint npt;
451  for(u32 i = MDist<1>::get().GetFirstIndex(1); i <= MDist<1>::get().GetLastIndex(1); i++)
452  {
453  npt = MDist<1>::get().GetPoint(i);
454  npt.Add(pt.GetX(), pt.GetY());
455 
456  if(npt.GetX() >= 0 && npt.GetY() >= 0 &&
457  npt.GetX() < TILE_SIDE_LIVE_SITES * W &&
458  npt.GetY() < TILE_SIDE_LIVE_SITES * H)
459  {
460  if(Atom<CC>::IsType(*grid.GetAtom(npt),
461  m_bucketFillStartType))
462  {
463  if(depth)
464  {
465  BucketFill(grid, atom, npt, depth - 1);
466  }
467  }
468  }
469  }
470  }
471 
472  virtual bool Handle(MouseButtonEvent& mbe)
473  {
474  SDL_MouseButtonEvent & event = mbe.m_event.button;
475  if(event.type == SDL_MOUSEBUTTONDOWN)
476  {
478  pt.Set(event.x - pt.GetX(),
479  event.y - pt.GetY());
480 
481  switch (event.button)
482  {
483  case SDL_BUTTON_LEFT:
484  m_leftButtonDragStart = pt;
485  m_leftButtonGridStart = m_grend->GetDrawOrigin();
486  /* FALL THROUGH */
487  case SDL_BUTTON_MIDDLE:
488  case SDL_BUTTON_RIGHT:
489  if(!mbe.m_keyboard.CtrlHeld() && m_paintingEnabled)
490  {
491  switch(mbe.m_selectedTool)
492  {
493  case TOOL_SELECTOR:
494  HandleSelectorTool(mbe);
495  break;
496  case TOOL_ATOM_SELECTOR:
497  HandleAtomSelectorTool(mbe);
498  break;
499  case TOOL_PENCIL:
500  HandlePencilTool(mbe);
501  break;
502  case TOOL_ERASER:
503  HandleEraserTool(mbe);
504  break;
505  case TOOL_BRUSH:
506  HandleBrushTool(mbe);
507  break;
508  case TOOL_BUCKET:
509  HandleBucketTool(mbe);
510  break;
511  case TOOL_XRAY:
512  HandleXRayTool(mbe);
513  break;
514  case TOOL_CLONE:
515  HandleCloneTool(mbe);
516  break;
517  case TOOL_AIRBRUSH:
518  HandleAirbrushTool(mbe);
519  break;
520 
521  default: break; /* Do the rest later */
522  }
523  }
524  break;
525  case SDL_BUTTON_WHEELUP:
526  m_grend->IncreaseAtomSize(pt);
527  break;
528  case SDL_BUTTON_WHEELDOWN:
529  m_grend->DecreaseAtomSize(pt);
530  break;
531  }
532  }
533  return true;
534  }
535 
536  virtual bool Handle(MouseMotionEvent& mbe)
537  {
538  SDL_MouseMotionEvent & event = mbe.m_event.motion;
539  if (mbe.m_keyboard.CtrlHeld())
540  {
541  if(mbe.m_buttonMask & (1 << SDL_BUTTON_LEFT))
542  {
543  SPoint nowAt(event.x, event.y);
544  SPoint delta = nowAt - m_leftButtonDragStart;
545  m_grend->SetDrawOrigin(m_leftButtonGridStart+delta);
546  }
547  }
548  else
549  {
550  u8 mask = 0;
551  if(mbe.m_buttonMask & (1 << SDL_BUTTON_LEFT))
552  {
553  mask = SDL_BUTTON_LEFT;
554  }
555  else if(mbe.m_buttonMask & (1 << SDL_BUTTON_RIGHT))
556  {
557  mask = SDL_BUTTON_RIGHT;
558  }
559 
560  m_grend->SetHoveredAtom(*m_mainGrid, SPoint(event.x, event.y));
561 
562  if(!mask)
563  {
564  m_grend->SetHoveredAtom(*m_mainGrid, SPoint(event.x, event.y));
565  }
566  else if(mask && !mbe.m_keyboard.CtrlHeld() && m_paintingEnabled)
567  {
568  switch(mbe.m_selectedTool)
569  {
570  case TOOL_PENCIL:
571  HandlePencilTool(mask, SPoint(event.x, event.y));
572  break;
573  case TOOL_ERASER:
574  HandleEraserTool(mask, SPoint(event.x, event.y));
575  break;
576  case TOOL_BRUSH:
577  HandleBrushTool(mask, SPoint(event.x, event.y));
578  break;
579  case TOOL_XRAY:
580  HandleXRayTool(mask, SPoint(event.x, event.y));
581  break;
582  case TOOL_ATOM_SELECTOR:
583  HandleAtomSelectorTool(mask, SPoint(event.x, event.y));
584  break;
585  case TOOL_CLONE:
586  HandleCloneTool(mask, SPoint(event.x, event.y));
587  break;
588  case TOOL_AIRBRUSH:
589  HandleAirbrushTool(mask, SPoint(event.x, event.y));
590  break;
591  default:
592  /* Some tools don't need to do this */
593  break;
594  }
595  }
596  else
597  {
598  m_grend->DeselectHoveredAtom();
599  }
600  }
601  return false;
602  }
603  };
604 } /* namespace MFM */
605 
606 #endif /* GRIDPANEL_H */
Definition: Panel.h:115
Definition: Panel.h:91
Definition: Panel.h:74
u32 SetForeground(const u32 color)
Definition: Panel.h:256
virtual void PaintComponent(Drawing &drawing)
Definition: GridPanel.h:164
void Set(T x, T y)
Definition: Point.tcc:183
bool OneIn(u32 odds)
Definition: Random.h:96
T GetY() const
Definition: Point.tcc:40
Definition: GridRenderer.h:46
Definition: Grid.h:47
SPoint GetAbsoluteLocation()
Definition: Panel.cpp:173
virtual void PaintComponent(Drawing &config)
Definition: Panel.cpp:230
virtual bool Handle(MouseMotionEvent &mbe)
Definition: GridPanel.h:536
virtual bool Handle(MouseButtonEvent &mbe)
Definition: GridPanel.h:472
void Debug(const char *format,...)
Definition: Logger.h:301
static MDist< R > & get()
Definition: MDist.tcc:193
Definition: GridPanel.h:49
Definition: AtomViewPanel.h:37
Definition: ToolboxPanel.h:46
Definition: Drawing.h:44
u32 SetBackground(const u32 color)
Definition: Panel.h:220
T GetX() const
Definition: Point.tcc:34