1 /*
2  * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 #include "View.h"
10 
11 #include "PhaseLocker.h"
12 #include "ModelList.h"
13 #include "Decor.h"
14 
15 #include "Cube.h"
16 #include "Anim.h"
17 #include "Dir.h"
18 #include "minmax.h"
19 
20 //-----------------------------------------------------------------
21 /**
22  * Create new view.
23  * @param models wrapper arount models
24  */
View(const ModelList & models)25 View::View(const ModelList &models)
26      : m_models(models), m_screenShift(0, 0)
27 {
28     m_animShift = 0;
29     m_shiftSize = SCALE;
30     m_screen = NULL;
31 }
32 //-----------------------------------------------------------------
~View()33 View::~View()
34 {
35     removeDecors();
36 }
37 //-----------------------------------------------------------------
38 void
removeDecors()39 View::removeDecors()
40 {
41     t_decors::iterator end = m_decors.end();
42     for (t_decors::iterator i = m_decors.begin(); i != end; ++i) {
43         delete *i;
44     }
45     m_decors.clear();
46 }
47 //-----------------------------------------------------------------
48 void
drawDecors()49 View::drawDecors()
50 {
51     t_decors::iterator end = m_decors.end();
52     for (t_decors::iterator i = m_decors.begin(); i != end; ++i) {
53         (*i)->drawOnScreen(this, m_screen);
54     }
55 }
56 
57 //-----------------------------------------------------------------
58 /**
59  * Prepare new anim.
60  */
61     void
noteNewRound(int phases)62 View::noteNewRound(int phases)
63 {
64     m_animShift = 0;
65     computeShiftSize(phases);
66 }
67 //-----------------------------------------------------------------
68 void
drawOn(SDL_Surface * screen)69 View::drawOn(SDL_Surface *screen)
70 {
71     m_screen = screen;
72     m_animShift = min(SCALE, m_animShift + m_shiftSize);
73     m_models.drawOn(this);
74     drawDecors();
75 }
76 //-----------------------------------------------------------------
77 /**
78  * Draw model.
79  * Care about model shift during move.
80  */
81     void
drawModel(Cube * model)82 View::drawModel(Cube *model)
83 {
84     if (!model->isLost()) {
85         V2 screenPos = getScreenPos(model);
86 
87         Anim::eSide side = Anim::SIDE_LEFT;
88         if (!model->isLeft()) {
89             side = Anim::SIDE_RIGHT;
90         }
91         model->anim()->drawAt(m_screen,
92                 screenPos.getX(), screenPos.getY(), side);
93     }
94 }
95 //-----------------------------------------------------------------
96 /**
97  * Split move in a few phases.
98  */
99     void
computeShiftSize(int phases)100 View::computeShiftSize(int phases)
101 {
102     if (phases > 0) {
103         m_shiftSize = SCALE / phases;
104     }
105     else {
106         m_shiftSize = SCALE;
107     }
108 }
109 //-----------------------------------------------------------------
110 /**
111  * Returns position on screen when model will be drawn.
112  */
113 V2
getScreenPos(const Cube * model) const114 View::getScreenPos(const Cube *model) const
115 {
116     V2 shift(0, 0);
117     Dir::eDir dir = model->getLastMoveDir();
118     if (dir != Dir::DIR_NO) {
119         shift = Dir::dir2xy(dir);
120         shift = shift.scale(m_animShift);
121     }
122     shift = shift.plus(m_screenShift);
123 
124     V2 anim_shift = model->const_anim()->getViewShift();
125     return model->getLocation().plus(anim_shift).scale(SCALE).plus(shift);
126 }
127 //-----------------------------------------------------------------
128 /**
129  * Returns position of tile under cursor.
130  */
131 V2
getFieldPos(const V2 & cursor) const132 View::getFieldPos(const V2 &cursor) const
133 {
134     return cursor.minus(m_screenShift).shrink(SCALE);
135 }
136 
137