1 /****************************************************************************
2
3 Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
4
5 This file is part of the QGLViewer library version 2.7.2.
6
7 http://www.libqglviewer.com - contact@libqglviewer.com
8
9 This file may be used under the terms of the GNU General Public License
10 versions 2.0 or 3.0 as published by the Free Software Foundation and
11 appearing in the LICENSE file included in the packaging of this file.
12 In addition, as a special exception, Gilles Debunne gives you certain
13 additional rights, described in the file GPL_EXCEPTION in this package.
14
15 libQGLViewer uses dual licensing. Commercial/proprietary software must
16 purchase a libQGLViewer Commercial License.
17
18 This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19 WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20
21 *****************************************************************************/
22
23 #include "drawer.h"
24 #include <QGLViewer/qglviewer.h>
25 #include <qimage.h>
26 #include <qmessagebox.h>
27 #include <qstringlist.h>
28
29 using namespace std;
30 using namespace dvonn;
31 using namespace qglviewer;
32
33 namespace {
34 static const float whiteColor[3] = {1.0f, 1.0f, 1.0f};
35 static const float blackColor[3] = {0.2f, 0.2f, 0.2f};
36 static const float redColor[3] = {1.0f, 0.0f, 0.0f};
37 static const float boardColor[3] = {1.0f, 1.0f, 1.0f};
38 static const float boardBorderColor[3] = {0.0f, 0.0f, 0.0f};
39 // Dimension (D=widht=height) of a case and of the inner border of the
40 // case (B)
41 const float caseD = 1.0f;
42 const float caseB = 0.2f;
43 // Dimension of a piece
44 const float pieceRMax = (caseD - 2.0f * caseB) / sqrtf(2.0f);
45 const float pieceRMin = pieceRMax / 3.0f;
46 const float pieceH = 0.14f;
47 const float pieceC = 0.25f; // curvature of normal on vring part
48 // Dimension of the label case
49 float hLabelW = caseD; // must be caseD
50 float hLabelH = caseD / 3.0f;
51 float vLabelW = caseD / 3.0f;
52 float vLabelH = caseD; // must be caseD
53 // Dimension of the board
54 const float boardB = 0.1f;
55 const float boardW =
56 Board::nbSpacesMaxOnRow() * caseD + 2 * boardB + 2 * vLabelW;
57 const float boardH = Board::nbRows() * caseD + 2 * boardB + 2 * hLabelH;
58 const float poolB = 0.1f;
tessAndTexture(float x0,float y0,float x2,float y2,float u0=0.0f,float v0=0.0f,float u2=1.0f,float v2=1.0f)59 void tessAndTexture(float x0, float y0, float x2, float y2, float u0 = 0.0f,
60 float v0 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) {
61 if (x0 > x2)
62 swap(x0, x2);
63 if (y0 > y2)
64 swap(y0, y2);
65 if (x2 - x0 > caseD) {
66 float x1 = (x0 + x2) / 2.0f;
67 float u1 = (u0 + u2) / 2.0f;
68 tessAndTexture(x0, y0, x1, y2, u0, v0, u1, v2);
69 tessAndTexture(x1, y0, x2, y2, u1, v0, u2, v2);
70 } else if (y2 - y0 > caseD) {
71 float y1 = (y0 + y2) / 2.0f;
72 float v1 = (v0 + v2) / 2.0f;
73 tessAndTexture(x0, y0, x2, y1, u0, v0, u2, v1);
74 tessAndTexture(x0, y1, x2, y2, u0, v1, u2, v2);
75 } else {
76 glMultiTexCoord2f(GL_TEXTURE0, x0 / caseD, y0 / caseD);
77 glMultiTexCoord2f(GL_TEXTURE1, u0, v0);
78 glVertex2f(x0, y0);
79 glMultiTexCoord2f(GL_TEXTURE0, x2 / caseD, y0 / caseD);
80 glMultiTexCoord2f(GL_TEXTURE1, u2, v0);
81 glVertex2f(x2, y0);
82 glMultiTexCoord2f(GL_TEXTURE0, x2 / caseD, y2 / caseD);
83 glMultiTexCoord2f(GL_TEXTURE1, u2, v2);
84 glVertex2f(x2, y2);
85 glMultiTexCoord2f(GL_TEXTURE0, x0 / caseD, y2 / caseD);
86 glMultiTexCoord2f(GL_TEXTURE1, u0, v2);
87 glVertex2f(x0, y2);
88 }
89 }
90 const Vec normal[5] = {Vec(-1.0, 0.0, 0.0), Vec(0.0, 1.0, 0.0),
91 Vec(1.0, 0.0, 0.0), Vec(0.0, -1.0, 0.0),
92 Vec(-1.0, 0.0, 0.0)};
drawHRing(const float rMin,const float rMax,const float height)93 void drawHRing(const float rMin, const float rMax, const float height) {
94 // TODO : tabulate the cos and sin tables
95 const int nbSteps = 24;
96
97 glNormal3f(0.0, 0.0, 1.0);
98 glBegin(GL_QUAD_STRIP);
99 glVertex3f(rMin, 0.0, height);
100 glVertex3f(rMax, 0.0, height);
101 for (int i = 1; i <= nbSteps; ++i) {
102 const float angle = i * 2.0 * M_PI / nbSteps;
103 const float cosine = cos(angle);
104 const float sine = sin(angle);
105 glVertex3f(rMin * cosine, rMin * sine, height);
106 glVertex3f(rMax * cosine, rMax * sine, height);
107 }
108 glEnd();
109 }
drawVRing(const float hMin,const float hMax,const float r,bool in)110 void drawVRing(const float hMin, const float hMax, const float r, bool in) {
111 const int nbSteps = 24;
112 const float normalSign = (in ? -1.0 : 1.0);
113 float thMin = hMin;
114 float thMax = hMax;
115 if (in)
116 swap(thMax, thMin);
117 glBegin(GL_QUAD_STRIP);
118 glNormal3f(normalSign, 0.0, 0.0);
119 for (int i = 0; i <= nbSteps; ++i) {
120 const float angle = i * 2.0 * M_PI / nbSteps;
121 const float cosine = cos(angle);
122 const float sine = sin(angle);
123 glNormal3fv(Vec(normalSign * cosine, normalSign * sine, +pieceC).unit());
124 glVertex3f(r * cosine, r * sine, thMax);
125 glNormal3fv(Vec(normalSign * cosine, normalSign * sine, -pieceC).unit());
126 glVertex3f(r * cosine, r * sine, thMin);
127 }
128 glEnd();
129 }
drawPiece(const Color & p,float a=1.0f)130 void drawPiece(const Color &p, float a = 1.0f) {
131 static const float *colors[3] = {redColor, whiteColor, blackColor};
132 const float *c = colors[static_cast<int>(p)];
133 glColor4f(c[0] * a, c[1] * a, c[2] * a, a);
134 drawHRing(pieceRMin, pieceRMax, pieceH);
135 drawVRing(0.0f, pieceH, pieceRMax, false);
136 drawVRing(0.0f, pieceH, pieceRMin, true);
137 }
drawHLabel(unsigned int i)138 void drawHLabel(unsigned int i) {
139 glBegin(GL_QUADS);
140 unsigned int d = Board::nbRows() / 2;
141 if (i < Board::nbSpacesMaxOnRow() - d) // Bottom
142 {
143 float x = boardB + vLabelW + (d + 1) * (caseD / 2.0f) + i * hLabelW;
144 float y = boardB;
145 tessAndTexture(x, y, x + hLabelH, y + hLabelH, 0.0f, 0.0f, 1.0f, 1.0f);
146 tessAndTexture(x + hLabelH, y, x + hLabelW, y + hLabelH, 2.0f, 2.0f, 2.0f,
147 2.0f);
148 }
149 if (i >= d) {
150 float x = boardB + vLabelW - (d + 1) * (caseD / 2.0f) + i * hLabelW;
151 float y = boardB + hLabelH + Board::nbRows() * caseD;
152 tessAndTexture(x, y, x + hLabelW - hLabelH, y + hLabelH, 2.0f, 2.0f, 2.0f,
153 2.0f);
154 tessAndTexture(x + hLabelW - hLabelH, y, x + hLabelW, y + hLabelH, 0.0f,
155 0.0f, 1.0f, 1.0f);
156 }
157 glEnd();
158 }
drawVLabel(int i)159 void drawVLabel(int i) {
160 glBegin(GL_QUADS);
161 int d = static_cast<int>(Board::nbRows() / 2);
162 int e = abs(d - i);
163 float shift = e * caseD / 2.0f;
164 float x = boardB + shift;
165 float y = boardB + hLabelH + i * vLabelH;
166 tessAndTexture(x, y, x + vLabelW, y + vLabelH / 3.0f, 2.0f, 2.0f, 2.0f, 2.0f);
167 tessAndTexture(x, y + vLabelH / 3.0f, x + vLabelW, y + 2.0f * vLabelH / 3.0f,
168 0.0f, 0.0f, 1.0f, 1.0f);
169 tessAndTexture(x, y + 2.0f * vLabelH / 3.0f, x + vLabelW, y + vLabelH, 2.0f,
170 2.0f, 2.0f, 2.0f);
171 x = boardB + shift + vLabelW + (Board::nbSpacesMaxOnRow() - e) * caseD;
172 y = boardB + hLabelH + i * vLabelH;
173 tessAndTexture(x, y, x + vLabelW, y + vLabelH / 3.0f, 2.0f, 2.0f, 2.0f, 2.0f);
174 tessAndTexture(x, y + vLabelH / 3.0f, x + vLabelW, y + 2.0f * vLabelH / 3.0f,
175 0.0f, 0.0f, 1.0f, 1.0f);
176 tessAndTexture(x, y + 2.0f * vLabelH / 3.0f, x + vLabelW, y + vLabelH, 2.0f,
177 2.0f, 2.0f, 2.0f);
178 glEnd();
179 }
loadTexture(const QString fileName)180 GLuint loadTexture(const QString fileName) {
181 QImage img("images/" + fileName);
182 if (img.isNull()) {
183 QMessageBox::critical(NULL, "Image not found",
184 "Unable to load texture from " + fileName);
185 exit(1); // TODO: be nicer!
186 }
187 // 1E-3 needed. Just try with width=128 and see !
188 if ((img.width() != 1 << (int)(1 + log(img.width() - 1 + 1E-3) / log(2.0))) ||
189 (img.height() !=
190 1 << (int)(1 + log(img.height() - 1 + 1E-3) / log(2.0)))) {
191 QMessageBox::critical(NULL, "Wrong image dimensions",
192 "Texture dimensions are not powers of 2 in " +
193 fileName);
194 exit(1); // TODO: be nicer!
195 }
196 // cout << "Loaded "<<fileName<<endl;
197 QImage glImg = QGLWidget::convertToGLFormat(img); // flipped 32bit RGBA
198 // Create a texture object
199 GLuint to;
200 glGenTextures(1, &to);
201 glBindTexture(GL_TEXTURE_2D, to);
202 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, glImg.width(), glImg.height(),
203 GL_RGBA, GL_UNSIGNED_BYTE, glImg.bits());
204 return to;
205 }
206 } // namespace
207 //************************************************************
208 // Implementation of Drawer
209 //************************************************************
Drawer()210 Drawer::Drawer() : showTextures_(true) {}
toggleTexture(bool b)211 void Drawer::toggleTexture(bool b) { showTextures_ = b; }
~Drawer()212 Drawer::~Drawer() {}
init()213 void Drawer::init() {
214 static const QStringList texFilenames = QStringList() << "board.png"
215 << "case.png";
216 for (QStringList::const_iterator it = texFilenames.begin();
217 it != texFilenames.end(); ++it) {
218 textures_[*it] = loadTexture(*it);
219 }
220 for (unsigned int i = 0; i < Board::nbSpacesMaxOnRow(); ++i) {
221 static const char *letter = "ABCDEFGHIJK";
222 hLabels_.push_back(loadTexture(QString("label%1.png").arg(letter[i])));
223 }
224 for (unsigned int i = 0; i < Board::nbRows(); ++i) {
225 vLabels_.push_back(loadTexture(QString("label%1.png").arg(i + 1)));
226 }
227 glActiveTexture(GL_TEXTURE0);
228 glEnable(GL_TEXTURE_2D);
229 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
230 glActiveTexture(GL_TEXTURE1);
231 glEnable(GL_TEXTURE_2D);
232 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
233 }
startTexture(const QString & t) const234 void Drawer::startTexture(const QString &t) const {
235 glPushAttrib(GL_ENABLE_BIT);
236 glActiveTexture(GL_TEXTURE0);
237 map<QString, GLuint>::const_iterator fter = textures_.find(t);
238 if (showTextures_ && fter != textures_.end()) {
239 glEnable(GL_TEXTURE_2D);
240 glBindTexture(GL_TEXTURE_2D, fter->second);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
243 } else {
244 glDisable(GL_TEXTURE_2D);
245 }
246 glActiveTexture(GL_TEXTURE1);
247 glDisable(GL_TEXTURE_2D);
248 }
startTexture(const QString & t,GLuint to) const249 void Drawer::startTexture(const QString &t, GLuint to) const {
250 glPushAttrib(GL_ENABLE_BIT);
251 glActiveTexture(GL_TEXTURE0);
252 map<QString, GLuint>::const_iterator fter = textures_.find(t);
253 if (showTextures_ && fter != textures_.end()) {
254 glEnable(GL_TEXTURE_2D);
255 glBindTexture(GL_TEXTURE_2D, fter->second);
256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
258 } else {
259 glDisable(GL_TEXTURE_2D);
260 }
261 glActiveTexture(GL_TEXTURE1);
262 if (showTextures_) {
263 glBindTexture(GL_TEXTURE_2D, to);
264 glEnable(GL_TEXTURE_2D);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
267 } else {
268 glDisable(GL_TEXTURE_2D);
269 }
270 }
startTexture() const271 void Drawer::startTexture() const {
272 glPushAttrib(GL_ENABLE_BIT);
273 glActiveTexture(GL_TEXTURE0);
274 glDisable(GL_TEXTURE_2D);
275 glActiveTexture(GL_TEXTURE1);
276 glDisable(GL_TEXTURE_2D);
277 }
endTexture() const278 void Drawer::endTexture() const { glPopAttrib(); }
translateTo(Board::Coord c,float h=0.0f)279 void translateTo(Board::Coord c, float h = 0.0f) {
280 static const float shifts[5] = {1.0f, 0.5f, 0.0f, -0.5f, -1.0f};
281 glTranslatef(boardB + vLabelW + c.x() * caseD + shifts[c.y()] * caseD,
282 boardB + hLabelH + c.y() * caseD, h);
283 }
drawPieces(const Board::ConstStackHandle & s) const284 void Drawer::drawPieces(const Board::ConstStackHandle &s) const {
285 startTexture();
286 glPushMatrix();
287 translateTo(s.stackCoord());
288 glTranslatef(0.5f * caseD, 0.5f * caseD, 0.0f);
289 for (Stack::const_iterator iter = s->begin(), istop = s->end(); iter != istop;
290 ++iter) {
291 drawPiece((*iter)->color());
292 glTranslatef(0.0f, 0.0f, pieceH);
293 }
294 glPopMatrix();
295 endTexture();
296 }
drawStatus(const Board::ConstStackHandle & s,QGLViewer * v) const297 void Drawer::drawStatus(const Board::ConstStackHandle &s, QGLViewer *v) const {
298 startTexture();
299 glPushMatrix();
300 translateTo(s.stackCoord(), s->height() * pieceH + pieceH / 2.0f);
301 glColor3f(1.0f, 1.0f, 0.0f);
302 v->renderText(0.5f * caseD, 0.5f * caseD, QString("%1").arg(s.stackStatus()),
303 QFont());
304 glPopMatrix();
305 endTexture();
306 }
drawTransparentPiece(Color col,const Board::ConstStackHandle & c,float a) const307 void Drawer::drawTransparentPiece(Color col, const Board::ConstStackHandle &c,
308 float a) const {
309 startTexture();
310 glPushMatrix();
311 translateTo(c.stackCoord(), c->height() * pieceH);
312 glTranslatef(0.5f * caseD, 0.5f * caseD, 0.0f);
313 drawPiece(col, a);
314 glPopMatrix();
315 endTexture();
316 }
drawTransparentPieces(Stack::const_iterator first,Stack::const_iterator last,const Board::Coord & c,float h,float a) const317 void Drawer::drawTransparentPieces(Stack::const_iterator first,
318 Stack::const_iterator last,
319 const Board::Coord &c, float h,
320 float a) const {
321 startTexture();
322 glPushMatrix();
323 translateTo(c, h * pieceH);
324 glTranslatef(0.5f * caseD, 0.5f * caseD, 0.0f);
325 while (first != last) {
326 drawPiece((*first++)->color(), a);
327 glTranslatef(0.0f, 0.0f, pieceH);
328 }
329 glPopMatrix();
330 endTexture();
331 }
draw(const Board::ConstStackHandle & c) const332 void Drawer::draw(const Board::ConstStackHandle &c) const {
333 glPushMatrix();
334 translateTo(c.stackCoord());
335 startTexture("case.png");
336 glColor3fv(boardColor);
337 glNormal3fv(boardUpVector());
338 glBegin(GL_QUADS);
339 tessAndTexture(0.0f, 0.0f, caseD, caseD);
340 glEnd();
341 endTexture();
342 glPopMatrix();
343 }
drawComplement(bool showLabels) const344 void Drawer::drawComplement(bool showLabels) const {
345 glPushAttrib(GL_ALL_ATTRIB_BITS);
346 glNormal3fv(boardUpVector());
347 glColor3fv(boardColor);
348 for (unsigned int i = 0; i < Board::nbSpacesMaxOnRow(); ++i) {
349 if (showLabels)
350 startTexture("board.png", hLabels_[i]);
351 else
352 startTexture("board.png");
353 drawHLabel(i);
354 endTexture();
355 }
356 glColor3fv(boardColor);
357 for (unsigned int i = 0; i < Board::nbRows(); ++i) {
358 if (showLabels)
359 startTexture("board.png", vLabels_[i]);
360 else
361 startTexture("board.png");
362 drawVLabel(i);
363 endTexture();
364 }
365 startTexture("board.png");
366 glBegin(GL_QUADS);
367 if (boardB > 0.0f) {
368 glColor3fv(boardBorderColor);
369 tessAndTexture(0.0f, 0.0f, boardW, boardB);
370 tessAndTexture(0.0f, boardH - boardB, boardW, boardH);
371 tessAndTexture(0.0f, boardB, boardB, boardH - boardB);
372 tessAndTexture(boardW - boardB, boardB, boardW, boardH - boardB);
373 }
374 glColor3fv(boardColor);
375 int d = Board::nbRows() / 2;
376 tessAndTexture(boardB, boardB, boardB + vLabelW + (d + 1) * caseD / 2.0f,
377 boardB + hLabelH);
378 tessAndTexture(boardB, boardH - boardB - hLabelH,
379 boardB + vLabelW + (d + 1) * caseD / 2.0f - hLabelW,
380 boardH - boardB);
381 tessAndTexture(boardW - (boardB + vLabelW + (d + 1) * caseD / 2.0f) + hLabelW,
382 boardB, boardW - boardB, boardB + hLabelH);
383 tessAndTexture(boardW - (boardB + vLabelW + (d + 1) * caseD / 2.0f),
384 boardH - boardB - hLabelH, boardW - boardB, boardH - boardB);
385 for (int i = 0; i < d; ++i) {
386 tessAndTexture(boardB, boardB + hLabelH + i * vLabelH,
387 boardB + (d - i) * caseD / 2.0f,
388 boardB + hLabelH + i * vLabelH + vLabelH);
389 tessAndTexture(boardB, boardH - (boardB + hLabelH + i * vLabelH + vLabelH),
390 boardB + (d - i) * caseD / 2.0f,
391 boardH - (boardB + hLabelH + i * vLabelH));
392 tessAndTexture(boardW - (boardB + (d - i) * caseD / 2.0f),
393 boardB + hLabelH + i * vLabelH, boardW - boardB,
394 boardB + hLabelH + i * vLabelH + vLabelH);
395 tessAndTexture(boardW - (boardB + (d - i) * caseD / 2.0f),
396 boardH - (boardB + hLabelH + i * vLabelH + vLabelH),
397 boardW - boardB, boardH - (boardB + hLabelH + i * vLabelH));
398 }
399 glEnd();
400 endTexture();
401 glPopAttrib();
402 }
drawWhitePiecePools(const Board & b,bool lastTransparent) const403 void Drawer::drawWhitePiecePools(const Board &b, bool lastTransparent) const {
404 unsigned int d = Board::nbRows() / 2;
405 unsigned int e = Board::nbSpacesMaxOnRow() - d;
406 startTexture();
407 // Draw the whites and its up to two reds
408 unsigned int nbR = b.nbUnplacedPieces(Red);
409 unsigned int nbW = b.nbUnplacedPieces(White);
410 unsigned int nbRed4White = nbR / 2 + nbR % 2;
411 for (unsigned int istop = nbW + nbRed4White, i = 0; i < istop; ++i) {
412 const float x = boardB + vLabelW + (d + 1) * caseD / 2.0f + (i % e) * caseD;
413 static const float y = -poolB - caseD / 2.0f;
414 const float z = (i / e) * pieceH;
415 glPushMatrix();
416 glTranslatef(x, y, z);
417 drawPiece((i < nbW) ? White : Red,
418 (lastTransparent && i == nbW + nbRed4White - 1) ? 0.5f : 1.0f);
419 glPopMatrix();
420 }
421 endTexture();
422 }
drawBlackPiecePools(const Board & b,bool lastTransparent) const423 void Drawer::drawBlackPiecePools(const Board &b, bool lastTransparent) const {
424 unsigned int d = Board::nbRows() / 2;
425 unsigned int e = Board::nbSpacesMaxOnRow() - d;
426 startTexture();
427 // Draw the blacks and its up to one red
428 unsigned int nbR = b.nbUnplacedPieces(Red);
429 unsigned int nbB = b.nbUnplacedPieces(Black);
430 unsigned int nbRed4Black = nbR / 2;
431 for (unsigned int istop = nbB + nbRed4Black, i = 0; i < istop; ++i) {
432 const float x =
433 boardW - (boardB + vLabelW + (d + 1) * caseD / 2.0f + (i % e) * caseD);
434 static const float y = boardH + poolB + caseD / 2.0f;
435 const float z = (i / e) * pieceH;
436 glPushMatrix();
437 glTranslatef(x, y, z);
438 drawPiece((i < nbB) ? Black : Red,
439 (lastTransparent && i == nbB + nbRed4Black - 1) ? 0.4f : 1.0f);
440 glPopMatrix();
441 }
442 endTexture();
443 }
highlight(const Board::ConstStackHandle & c) const444 void Drawer::highlight(const Board::ConstStackHandle &c) const {
445 glPushAttrib(GL_ENABLE_BIT);
446 glDisable(GL_LIGHTING);
447 startTexture();
448 glPushMatrix();
449 translateTo(c.stackCoord(), 0.05f * pieceH + pieceH / 2.0f);
450 glScalef(caseD, caseD, pieceH);
451 // glutWireCube(1.0f);
452 glPopMatrix();
453 endTexture();
454 glPopAttrib();
455 }
highlightPieces(const Board::ConstStackHandle & c) const456 void Drawer::highlightPieces(const Board::ConstStackHandle &c) const {
457 glPushAttrib(GL_ENABLE_BIT);
458 glDisable(GL_LIGHTING);
459 startTexture();
460 glPushMatrix();
461 translateTo(c.stackCoord(), 0.01f);
462 glTranslatef(0.5f * caseD, 0.5f * caseD, 0.0f);
463 glColor4f(0.0f, 0.0f, 0.3f, 0.3f);
464 drawHRing(pieceRMin, 1.2f * pieceRMax, 0.0f);
465 glPopMatrix();
466 endTexture();
467 glPopAttrib();
468 }
drawMove(const Board & b,const Game::Move m,float t) const469 void Drawer::drawMove(const Board &b, const Game::Move m, float t) const {
470 const float L = caseD * estimateDrawMoveLength(b, m);
471 const float t0 =
472 (b.heightMax() + 1 - b.stackAt(m.src)->height()) * pieceH / L;
473 const float t1 =
474 1.0f - (b.heightMax() + 1 - b.stackAt(m.dst)->height()) * pieceH / L;
475 Board::ConstStackHandle src = b.stackAt(m.src);
476 glPushMatrix();
477 startTexture();
478 if (t <= t0) {
479 t /= t0;
480 float srcH = src->height() * pieceH;
481 float dstH = b.heightMax() * pieceH + pieceH;
482 translateTo(m.src);
483 glTranslatef(0.5f * caseD, 0.5f * caseD, (1 - t) * srcH + t * dstH);
484 for (Stack::const_iterator iter = src->begin(), istop = src->end();
485 iter != istop; ++iter) {
486 drawPiece((*iter)->color());
487 glTranslatef(0.0f, 0.0f, pieceH);
488 }
489 } else if (t <= t1) {
490 t = (t - t0) / (t1 - t0);
491 static const float shifts[5] = {1.0f, 0.5f, 0.0f, -0.5f, -1.0f};
492 float srcX =
493 boardB + vLabelW + m.src.x() * caseD + shifts[m.src.y()] * caseD;
494 float srcY = boardB + hLabelH + m.src.y() * caseD;
495 float dstX =
496 boardB + vLabelW + m.dst.x() * caseD + shifts[m.dst.y()] * caseD;
497 float dstY = boardB + hLabelH + m.dst.y() * caseD;
498 glTranslatef((1.0f - t) * srcX + t * dstX + 0.5f * caseD,
499 (1.0f - t) * srcY + t * dstY + 0.5f * caseD,
500 b.heightMax() * pieceH + pieceH);
501 for (Stack::const_iterator iter = src->begin(), istop = src->end();
502 iter != istop; ++iter) {
503 drawPiece((*iter)->color());
504 glTranslatef(0.0f, 0.0f, pieceH);
505 }
506 } else {
507 t = (t - t1) / (1.0f - t1);
508 float srcH = b.heightMax() * pieceH + pieceH;
509 float dstH = b.stackAt(m.dst)->height() * pieceH;
510 translateTo(m.dst);
511 glTranslatef(0.5f * caseD, 0.5f * caseD, (1 - t) * srcH + t * dstH);
512 for (Stack::const_iterator iter = src->begin(), istop = src->end();
513 iter != istop; ++iter) {
514 drawPiece((*iter)->color());
515 glTranslatef(0.0f, 0.0f, pieceH);
516 }
517 }
518 endTexture();
519 glPopMatrix();
520 }
estimateDrawMoveLength(const Board & b,const Game::Move m) const521 float Drawer::estimateDrawMoveLength(const Board &b, const Game::Move m) const {
522 static const float shifts[5] = {1.0f, 0.5f, 0.0f, -0.5f, -1.0f};
523 float srcX = boardB + vLabelW + m.src.x() * caseD + shifts[m.src.y()] * caseD;
524 float srcY = boardB + hLabelH + m.src.y() * caseD;
525 float dstX = boardB + vLabelW + m.dst.x() * caseD + shifts[m.dst.y()] * caseD;
526 float dstY = boardB + hLabelH + m.dst.y() * caseD;
527 return (Vec(dstX - srcX, dstY - srcY, 0.0f).norm() +
528 (b.heightMax() + 1 - b.stackAt(m.src)->height()) * pieceH +
529 (b.heightMax() + 1 - b.stackAt(m.dst)->height()) * pieceH) /
530 caseD;
531 }
boardCenter() const532 Vec Drawer::boardCenter() const {
533 return Vec(boardW / 2.0f, boardH / 2.0f, 0.0f);
534 }
boardUpVector() const535 Vec Drawer::boardUpVector() const { return Vec(0.0f, 0.0f, 1.0f); }
boardRadius() const536 float Drawer::boardRadius() const {
537 return Vec(boardW / 2.0f, boardH / 2.0f, 0.0).norm();
538 }
defaultEyePosition() const539 Vec Drawer::defaultEyePosition() const {
540 return boardCenter() + boardRadius() * Vec(0.0, -1.7f, 1.0);
541 }
542