1/* 2 File: MBCBoardViewDraw.mm 3 Contains: Draw chess board 4 Copyright: � 2002-2012 by Apple Inc., all rights reserved. 5 6 Derived from glChess, Copyright © 2002 Robert Ancell and Michael Duelli 7 Permission granted to Apple to relicense under the following terms: 8 9 IMPORTANT: This Apple software is supplied to you by Apple Computer, 10 Inc. ("Apple") in consideration of your agreement to the following 11 terms, and your use, installation, modification or redistribution of 12 this Apple software constitutes acceptance of these terms. If you do 13 not agree with these terms, please do not use, install, modify or 14 redistribute this Apple software. 15 16 In consideration of your agreement to abide by the following terms, 17 and subject to these terms, Apple grants you a personal, non-exclusive 18 license, under Apple's copyrights in this original Apple software (the 19 "Apple Software"), to use, reproduce, modify and redistribute the 20 Apple Software, with or without modifications, in source and/or binary 21 forms; provided that if you redistribute the Apple Software in its 22 entirety and without modifications, you must retain this notice and 23 the following text and disclaimers in all such redistributions of the 24 Apple Software. Neither the name, trademarks, service marks or logos 25 of Apple Inc. may be used to endorse or promote products 26 derived from the Apple Software without specific prior written 27 permission from Apple. Except as expressly stated in this notice, no 28 other rights or licenses, express or implied, are granted by Apple 29 herein, including but not limited to any patent rights that may be 30 infringed by your derivative works or by other works in which the 31 Apple Software may be incorporated. 32 33 The Apple Software is provided by Apple on an "AS IS" basis. APPLE 34 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 35 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND 36 FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 37 USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 38 39 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, 40 INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 41 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 42 PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 43 REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, 44 HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING 45 NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 46 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47*/ 48 49#import "MBCBoardViewDraw.h" 50#import "MBCBoardViewModels.h" 51#import "MBCBoardViewTextures.h" 52 53#import <math.h> 54#import <OpenGL/glu.h> 55#import <algorithm> 56#import <sys/time.h> 57#import <vector> 58 59using std::min; 60 61@implementation MBCDrawStyle 62 63- (id) init 64{ 65 fTexture = 0; 66 67 return self; 68} 69 70- (id) initWithTexture:(GLuint)tex 71{ 72 fTexture = tex; 73 fDiffuse = 1.0f; 74 fSpecular = 0.2f; 75 fShininess = 5.0f; 76 fAlpha = 1.0f; 77 78 return self; 79} 80 81- (void) unloadTexture 82{ 83 if (fTexture) 84 glDeleteTextures(1, &fTexture); 85} 86 87- (void) startStyle:(float)alpha 88{ 89 GLfloat white_texture_color[4] = 90 {fDiffuse, fDiffuse, fDiffuse, fAlpha*alpha}; 91 GLfloat emission_color[4] = 92 {0.0f, 0.0f, 0.0f, fAlpha*alpha}; 93 GLfloat specular_color[4] = 94 {fSpecular, fSpecular, fSpecular, fAlpha*alpha}; 95 96 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 97 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white_texture_color); 98 glMaterialfv(GL_FRONT, GL_EMISSION, emission_color); 99 glMaterialfv(GL_FRONT, GL_SPECULAR, specular_color); 100 glMaterialf(GL_FRONT, GL_SHININESS, fShininess); 101 glBindTexture(GL_TEXTURE_2D, fTexture); 102} 103 104@end 105 106@implementation MBCBoardView ( Draw ) 107 108- (void) setupPerspective 109{ 110 NSRect bounds = [self convertRectToBacking:[self bounds]]; 111 GLint opaque = NO; 112 [[self openGLContext] setValues:&opaque 113 forParameter:NSOpenGLCPSurfaceOpacity]; 114 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 115 116 /* Stuff you can't do without */ 117 glEnable(GL_DEPTH_TEST); 118 glEnable(GL_CULL_FACE); 119 glEnable(GL_NORMALIZE); 120 121 /* Textures */ 122 glEnable(GL_TEXTURE_2D); 123 124 /* The lighting */ 125 glEnable(GL_LIGHTING); 126 127 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); 128 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); 129 glShadeModel(GL_SMOOTH); 130 131 glDisable(GL_FOG); 132 133 const float w = bounds.size.width; 134 const float h = bounds.size.height*1.1f*(fVariant==kVarCrazyhouse ? 1.15f : 1.0f); 135 const float kAspect = std::max(1.0f, h / w); 136 const float kDistance = 300.0f; 137 const float kBoardSize = kAspect*50.0f; 138 const float kDeg2Rad = M_PI / 180.0f; 139 const float kRad2Deg = 180.0f / M_PI; 140 const float kAngleOfView = 2.0f * atan2(kBoardSize, kDistance) * kRad2Deg; 141 142 glViewport(0, 0, (GLsizei)(bounds.size.width), (GLsizei)(bounds.size.height)); 143 144 glMatrixMode(GL_MODELVIEW); 145 glLoadIdentity(); 146 glMatrixMode(GL_PROJECTION); 147 glLoadIdentity(); 148 149 gluPerspective(kAngleOfView, bounds.size.width/bounds.size.height, 150 10.0, 1000.0); 151 152 glMatrixMode(GL_TEXTURE); 153 glLoadIdentity(); 154 glScalef(1.0f, -1.0f, 0.0f); 155 156 glMatrixMode(GL_MODELVIEW); 157 158 float cameraY = kDistance * sin(fElevation * kDeg2Rad); 159 float cameraXZ= kDistance * cos(fElevation * kDeg2Rad); 160 float cameraX = cameraXZ * sin(fAzimuth * kDeg2Rad); 161 float cameraZ = cameraXZ *-cos(fAzimuth * kDeg2Rad); 162 163 gluLookAt(cameraX, cameraY, cameraZ, 164 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 165 166 fNeedPerspective = false; 167} 168 169- (void) drawBoard:(BOOL)overReflection 170{ 171 int x, y, color; 172 173 // 174 // We want variation in the squares, not psychedelic effects 175 // 176 srandom(1); 177 178 glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); 179 180 // 181 // Blend edges of squares 182 // 183 if (overReflection) 184 glDisable(GL_DEPTH_TEST); 185 glEnable(GL_BLEND); 186 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 187 glEnable(GL_LINE_SMOOTH); 188 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 189 // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, !overReflection); 190 191 glNormal3f(0.0f, 1.0f, 0.0f); 192 193 for (x = 0; x < 8; x++) { 194 for (y = 0; y < 8; y++) { 195 /* Get board piece color */ 196 color = (x % 2 == y % 2); 197 198 [fBoardDrawStyle[color] 199 startStyle:overReflection 200 ? 1.0f-fBoardReflectivity 201 : 1.0f]; 202 203 float r = random()/8589934588.0f; /* 4*(2**31-1) */ 204 205 /* draw one square */ 206 glBegin(GL_TRIANGLE_STRIP); 207 glTexCoord2f(0.0f+r, 0.0f+r); 208 glVertex3f(x * 10.0f - 40.0f, 0.0f, 40.0f - y * 10.0f); 209 glTexCoord2f(0.5f+r, 0.0f+r); 210 glVertex3f(x * 10.0f - 30.0f, 0.0f, 40.0f - y * 10.0f); 211 glTexCoord2f(0.0f+r, 0.5f+r); 212 glVertex3f(x * 10.0f - 40.0f, 0.0f, 30.0f - y * 10.0f); 213 glTexCoord2f(0.5f+r, 0.5f+r); 214 glVertex3f(x * 10.0f - 30.0f, 0.0f, 30.0f - y * 10.0f); 215 glEnd(); 216 217#if 0 218 if (!overReflection) { 219 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); 220 glBegin(GL_QUADS); 221 glTexCoord2f(0.0f+r, 0.0f+r); 222 glVertex3f(x * 10.0f - 40.0f, 0.0f, 40.0f - y * 10.0f); 223 glTexCoord2f(0.5f+r, 0.0f+r); 224 glVertex3f(x * 10.0f - 30.0f, 0.0f, 40.0f - y * 10.0f); 225 glTexCoord2f(0.5f+r, 0.5f+r); 226 glVertex3f(x * 10.0f - 30.0f, 0.0f, 30.0f - y * 10.0f); 227 glTexCoord2f(0.0f+r, 0.5f+r); 228 glVertex3f(x * 10.0f - 40.0f, 0.0f, 30.0f - y * 10.0f); 229 glEnd(); 230 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); 231 } 232#endif 233 } 234 } 235 236 if (overReflection) { 237 glPopAttrib(); 238 239 return; 240 } 241 242 243 // 244 // Draw border 245 // 246 const float IB = kBoardRadius; // Inside border 247 const float OB = IB+kBorderWidth; // Outside border 248 const float DP = 5.0f; // Depth 249 const float TO = 0.5f*(1.0f - IB/OB); // Texture offset 250 251 [fBorderDrawStyle startStyle:1.0f]; 252 253 // 254 // Front 255 // 256 glBegin(GL_TRIANGLE_STRIP); 257 glNormal3f(0.0f, 1.0f, 0.0f); 258 glTexCoord2f(0.0f, 0.0f); 259 glVertex3f(-OB, 0.0f, +OB); 260 glTexCoord2f(TO, 0.0f); 261 glVertex3f(-IB, 0.0f, +OB); 262 glTexCoord2f(TO, 1.0f); 263 glVertex3f(-IB, 0.0f, +IB); 264 glTexCoord2f(1.0f-TO, 0.0f); 265 glVertex3f(+IB, 0.0f, +OB); 266 glTexCoord2f(1.0f-TO, 1.0f); 267 glVertex3f(+IB, 0.0f, +IB); 268 glTexCoord2f(1.0f, 0.0f); 269 glVertex3f(+OB, 0.0f, +OB); 270 glEnd(); 271 glBegin(GL_TRIANGLE_STRIP); 272 glNormal3f(0.0f, 0.0f, 1.0f); 273 glTexCoord2f(0.0f, 1.0f); 274 glVertex3f(-OB, 0.0f, +OB); 275 glTexCoord2f(0.0f, 0.0f); 276 glVertex3f(-OB, -DP, +OB); 277 glTexCoord2f(1.0f, 1.0f); 278 glVertex3f(+OB, 0.0f, +OB); 279 glTexCoord2f(1.0f, 0.0f); 280 glVertex3f(+OB, -DP, +OB); 281 glEnd(); 282 // 283 // Back 284 // 285 glBegin(GL_TRIANGLE_STRIP); 286 glNormal3f(0.0f, 1.0f, 0.0f); 287 glTexCoord2f(0.0f, 0.0f); 288 glVertex3f(-OB, 0.0f, -OB); 289 glTexCoord2f(TO, 1.0f); 290 glVertex3f(-IB, 0.0f, -IB); 291 glTexCoord2f(TO, 0.0f); 292 glVertex3f(-IB, 0.0f, -OB); 293 glTexCoord2f(1.0f-TO, 1.0f); 294 glVertex3f(+IB, 0.0f, -IB); 295 glTexCoord2f(1.0f-TO, 0.0f); 296 glVertex3f(+IB, 0.0f, -OB); 297 glTexCoord2f(1.0f, 0.0f); 298 glVertex3f(+OB, 0.0f, -OB); 299 glEnd(); 300 glBegin(GL_TRIANGLE_STRIP); 301 glNormal3f(0.0f, 0.0f, -1.0f); 302 glTexCoord2f(0.0f, 1.0f); 303 glVertex3f(-OB, 0.0f, -OB); 304 glTexCoord2f(1.0f, 1.0f); 305 glVertex3f(+OB, 0.0f, -OB); 306 glTexCoord2f(0.0f, 0.0f); 307 glVertex3f(-OB, -DP, -OB); 308 glTexCoord2f(1.0f, 0.0f); 309 glVertex3f(+OB, -DP, -OB); 310 glEnd(); 311 // 312 // Left 313 // 314 glBegin(GL_TRIANGLE_STRIP); 315 glNormal3f(0.0f, 1.0f, 0.0f); 316 glTexCoord2f(1.0f, 0.0f); 317 glVertex3f(-OB, 0.0f, +OB); 318 glTexCoord2f(1.0f-TO, 1.0f); 319 glVertex3f(-IB, 0.0f, +IB); 320 glTexCoord2f(1.0f-TO, 0.0f); 321 glVertex3f(-OB, 0.0f, +IB); 322 glTexCoord2f(TO, 1.0f); 323 glVertex3f(-IB, 0.0f, -IB); 324 glTexCoord2f(TO, 0.0f); 325 glVertex3f(-OB, 0.0f, -IB); 326 glTexCoord2f(0.0f, 0.0f); 327 glVertex3f(-OB, 0.0f, -OB); 328 glEnd(); 329 glBegin(GL_TRIANGLE_STRIP); 330 glNormal3f(-1.0f, 0.0f, 0.0f); 331 glTexCoord2f(1.0f, 1.0f); 332 glVertex3f(-OB, 0.0f, +OB); 333 glTexCoord2f(0.0f, 1.0f); 334 glVertex3f(-OB, 0.0f, -OB); 335 glTexCoord2f(1.0f, 0.0f); 336 glVertex3d(-OB, -DP, +OB); 337 glTexCoord2f(0.0f, 0.0f); 338 glVertex3d(-OB, -DP, -OB); 339 glEnd(); 340 // 341 // Right 342 // 343 glBegin(GL_TRIANGLE_STRIP); 344 glNormal3f(0.0f, 1.0f, 0.0f); 345 glTexCoord2f(0.0f, 0.0f); 346 glVertex3f(+OB, 0.0f, +OB); 347 glTexCoord2f(TO, 0.0f); 348 glVertex3f(+OB, 0.0f, +IB); 349 glTexCoord2f(TO, 1.0f); 350 glVertex3f(+IB, 0.0f, +IB); 351 glTexCoord2f(1.0f-TO, 0.0f); 352 glVertex3f(+OB, 0.0f, -IB); 353 glTexCoord2f(1.0f-TO, 1.0f); 354 glVertex3f(+IB, 0.0f, -IB); 355 glTexCoord2f(1.0f, 0.0f); 356 glVertex3f(+OB, 0.0f, -OB); 357 glEnd(); 358 glBegin(GL_TRIANGLE_STRIP); 359 glNormal3f(1.0f, 0.0f, 0.0f); 360 glTexCoord2f(0.0f, 1.0f); 361 glVertex3f(+OB, 0.0f, +OB); 362 glTexCoord2f(0.0f, 0.0f); 363 glVertex3d(+OB, -DP, +OB); 364 glTexCoord2f(1.0f, 1.0f); 365 glVertex3f(+OB, 0.0f, -OB); 366 glTexCoord2f(1.0f, 0.0f); 367 glVertex3d(+OB, -DP, -OB); 368 glEnd(); 369 370 glPopAttrib(); 371} 372 373/* Draws the co-ordinates around the edge of the board */ 374- (void) drawCoords 375{ 376 glPushAttrib(GL_LIGHTING | GL_TEXTURE_BIT | GL_ENABLE_BIT); 377 378 glEnable(GL_TEXTURE_2D); 379 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 380 glEnable(GL_BLEND); 381 glDisable(GL_DEPTH_TEST); 382 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 383 glDisable(GL_LIGHTING); 384 385 const float kSize = 3.5f; 386 const float kNHOff = 1.25f; 387 const float kNVOff = 3.25f; 388 const float kLHOff = 3.25f; 389 const float kLVOff = 1.00f; 390 391 /* Draw the numbers, always on the left and upright, no matter 392 which color we're playing 393 */ 394 glColor4f(1.0f, 1.0f, 1.0f, fLabelIntensity); 395 for (int rows = 0; rows < 8; rows++) { 396 glBindTexture(GL_TEXTURE_2D, fNumberTextures[rows]); 397 398 float t,l,b,r; 399 400 if ([self facingWhite]) { 401 l = -(40.0f + kNHOff + kSize); 402 r = -(40.0f + kNHOff); 403 t = 40.0f - kNVOff - rows*10.0f - kSize; 404 b = 40.0f - kNVOff - rows*10.0f; 405 } else { 406 r = -(40.0f + kNHOff + kSize); 407 l = -(40.0f + kNHOff); 408 b = 40.0f - kNVOff - rows*10.0f - kSize; 409 t = 40.0f - kNVOff - rows*10.0f; 410 } 411 glBegin(GL_QUADS); 412 glTexCoord2f(0.0f, 0.0f); 413 glVertex3f(l, 0.0f, b); 414 glTexCoord2f(1.0f, 0.0f); 415 glVertex3f(r, 0.0f, b); 416 glTexCoord2f(1.0f, 1.0f); 417 glVertex3f(r, 0.0f, t); 418 glTexCoord2f(0.0f, 1.0f); 419 glVertex3f(l, 0.0f, t); 420 glEnd(); 421 } 422 423 /* Draw the letters */ 424 for (int cols = 0; cols < 8; cols++) { 425 glBindTexture(GL_TEXTURE_2D, fLetterTextures[cols]); 426 427 float t,l,b,r; 428 429 if ([self facingWhite]) { 430 t = 40.0f + kLVOff; 431 b = 40.0f + kLVOff + kSize; 432 l = cols*10.f + kLHOff - 40.0f; 433 r = cols*10.f + kLHOff - 40.0f + kSize; 434 } else { 435 t = -(40.0f + kLVOff); 436 b = -(40.0f + kLVOff + kSize); 437 r = cols*10.f + kLHOff - 40.0f; 438 l = cols*10.f + kLHOff - 40.0f + kSize; 439 } 440 glBegin(GL_QUADS); 441 glTexCoord2f(0.0f, 0.0f); 442 glVertex3f(l, 0.0f, b); 443 glTexCoord2f(1.0f, 0.0f); 444 glVertex3f(r, 0.0f, b); 445 glTexCoord2f(1.0f, 1.0f); 446 glVertex3f(r, 0.0f, t); 447 glTexCoord2f(0.0f, 1.0f); 448 glVertex3f(l, 0.0f, t); 449 glEnd(); 450 } 451 452 glPopAttrib(); 453} 454 455- (void) setupPieceDrawing:(BOOL)white reflect:(BOOL)reflection alpha:(float)alpha 456{ 457 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 458 glEnable(GL_BLEND); 459 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 460 if (reflection) 461 alpha *= fBoardReflectivity; 462 [fPieceDrawStyle[!white] startStyle:alpha]; 463 glDepthMask(alpha > 0.5f); 464} 465 466- (void) endPieceDrawing 467{ 468 glPopAttrib(); 469} 470 471/* Draws a single piece */ 472- (void) simplyDrawPiece:(MBCPiece)piece at:(MBCPosition)pos scale:(float)scale 473{ 474 bool wkr = false; /* white knight rotate flag */ 475 int color = Color(piece) != 0; 476 piece = Piece(piece); 477 478 if (!color) /* white */ 479 if (piece == KNIGHT) /* white knight */ 480 wkr = true; /* white knight */ 481 482 glPushMatrix(); 483 glTranslatef(pos[0], pos[1], pos[2]); 484 if (wkr) /* is white knight */ 485 glRotatef(180.0f, 0.0f, 1.0f, 0.0f); 486 glScalef(scale, scale, scale); 487 glCallList(piece); 488 glPopMatrix(); 489 490 fLastPieceDrawn = piece; 491} 492 493- (void) drawPiece:(MBCPiece)piece at:(MBCPosition)pos scale:(float)scale reflect:(BOOL)reflection alpha:(float)alpha 494{ 495 [self setupPieceDrawing:!Color(piece) reflect:reflection alpha:alpha]; 496 [self simplyDrawPiece:piece at:pos scale:scale]; 497 [self endPieceDrawing]; 498} 499 500- (void) drawPiece:(MBCPiece)piece at:(MBCPosition)pos reflect:(BOOL)reflection alpha:(float)alpha 501{ 502 [self setupPieceDrawing:!Color(piece) reflect:reflection alpha:alpha]; 503 [self simplyDrawPiece:piece at:pos scale:1.0f]; 504 [self endPieceDrawing]; 505} 506 507- (void) drawPiece:(MBCPiece)piece at:(MBCPosition)pos reflect:(BOOL)reflection 508{ 509 [self setupPieceDrawing:!Color(piece) reflect:reflection alpha:1.0f]; 510 [self simplyDrawPiece:piece at:pos scale:1.0f]; 511 [self endPieceDrawing]; 512} 513 514- (void) drawPiece:(MBCPiece)piece at:(MBCPosition)pos scale:(float)scale 515{ 516 [self setupPieceDrawing:!Color(piece) reflect:NO alpha:1.0f]; 517 [self simplyDrawPiece:piece at:pos scale:scale]; 518 [self endPieceDrawing]; 519} 520 521/* Draws the pieces */ 522- (void) drawPieces:(BOOL)reflection 523{ 524 for (MBCSquare square = 0; square<64; ++square) { 525 MBCPiece piece = fInAnimation 526 ? [fBoard oldContents:square] 527 : [fBoard curContents:square]; 528 if (fSelectedPiece && square == fSelectedSquare) 529 continue; // Skip original position of selected piece 530 if (piece) { 531 const MBCPosition pos = [self squareToPosition:square]; 532 float dist = 533 fSelectedPiece && (!fInAnimation || square == fSelectedDest) 534 ? fSelectedPos.FlatDistance(pos) 535 : 100.0f; 536 const float kProximity = 5.0f; 537 if (dist < kProximity) 538 [self drawPiece:piece at:pos reflect:reflection 539 alpha:pow(dist/kProximity, 4.0)]; 540 else 541 [self drawPiece:piece at:pos reflect:reflection]; 542 } 543 } 544} 545 546 547/* Draw the selected piece (may be off grid) */ 548- (void) drawSelectedPiece:(BOOL)reflection 549{ 550 [self drawPiece:fSelectedPiece at:fSelectedPos reflect:reflection]; 551} 552 553/* Draw the promotion piece (transparent) */ 554- (void) drawPromotionPiece 555{ 556 MBCPiece piece = EMPTY; 557 MBCPosition pos; 558 559 fPromotionSide = kNeitherSide; 560 561 if (fSide == kWhiteSide || fSide == kBothSides) 562 if ([fBoard canPromote:kWhiteSide]) { 563 piece = [fBoard defaultPromotion:YES]; 564 fPromotionSide = kWhiteSide; 565 pos[0] = -kPromotionPieceX; 566 pos[1] = 0.0f; 567 pos[2] = -kPromotionPieceZ; 568 } 569 if (fSide == kBlackSide || fSide == kBothSides) 570 if ([fBoard canPromote:kBlackSide]) { 571 piece = [fBoard defaultPromotion:NO]; 572 fPromotionSide = kBlackSide; 573 pos[0] = kPromotionPieceX; 574 pos[1] = 0.0f; 575 pos[2] = kPromotionPieceZ; 576 } 577 if (fPromotionSide == kNeitherSide) 578 return; 579 580 bool wkr = (fPromotionSide == kWhiteSide && piece == KNIGHT); 581 582 glPushAttrib(GL_ENABLE_BIT|GL_TEXTURE_BIT); 583 584 [fSelectedPieceDrawStyle startStyle:1.0f]; 585 586 glEnable(GL_BLEND); 587 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 588 589 glPushMatrix(); 590 glTranslatef(pos[0], pos[1], pos[2]); 591 if (wkr) /* is white knight */ 592 glRotatef(180.0f, 0.0f, 1.0f, 0.0f); 593 glCallList(Piece(piece)); 594 glPopMatrix(); 595 596 glPopAttrib(); 597} 598 599- (void) placeLights 600{ 601 const float kDiffuse = 0.75; 602 GLfloat l_diffuse[4] = { kDiffuse, kDiffuse, kDiffuse, 1.0 }; 603 GLfloat l_ambient[4] = { fAmbient, fAmbient, fAmbient, 0.0 }; 604 605 glEnable(GL_LIGHT0); 606 glLightfv(GL_LIGHT0, GL_DIFFUSE, l_diffuse); 607 glLightfv(GL_LIGHT0, GL_AMBIENT, l_ambient); 608 glLightfv(GL_LIGHT0, GL_SPECULAR, l_diffuse); 609 glLightfv(GL_LIGHT0, GL_POSITION, fLightPos); 610 611 if (fPickedSquare != kInvalidSquare) { 612 GLfloat spot_color[4] = { 1.0, 1.0, 1.0, 1.0 }; 613 GLfloat spot_pos[4] = { 0.0, 100.0, 0.0, 1.0}; 614 GLfloat spot_direction[3] = { 0.0, -1.0, 0.0 }; 615 616 MBCPosition pickedPos = [self squareToPosition:fPickedSquare]; 617 618 spot_pos[0] = pickedPos[0]; 619 spot_pos[2] = pickedPos[2]; 620 621 glEnable(GL_LIGHT1); 622 glLightfv(GL_LIGHT1, GL_DIFFUSE, spot_color); 623 glLightfv(GL_LIGHT1, GL_SPECULAR, spot_color); 624 glLightfv(GL_LIGHT1, GL_POSITION, spot_pos); 625 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); 626 glLighti(GL_LIGHT1, GL_SPOT_EXPONENT, 100); 627 glLighti(GL_LIGHT1, GL_SPOT_CUTOFF, 5); 628 glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.0f); 629 glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0001f); 630 } else 631 glDisable(GL_LIGHT1); 632} 633 634MBCPieceCode gInHandOrder[] = {PAWN, BISHOP, KNIGHT, ROOK, QUEEN}; 635 636- (void) drawPiecesInHand 637{ 638 const float kLabelX = 42.0f; 639 const float kLabelSize = 3.0f; 640 const float kLabelLeft = kLabelX; 641 const float kLabelRight = kLabelX+kLabelSize; 642 const float kSpacing = kInHandPieceSize; 643 const float kLabelZ = 6.0f; 644 const float kPieceX = kInHandPieceX; 645 const float kPieceZ = kInHandPieceZOffset+kInHandPieceSize/2.0f; 646 const float kScale = 0.95f; 647 const bool kFlip = fAzimuth < 90.0f || fAzimuth >= 270.0f; 648 const float kTexLeft = kFlip ? 1.0f : 0.0f; 649 const float kTexRight = 1.0f-kTexLeft; 650 const float kTexBottom = kFlip ? 1.0f : 0.0f; 651 const float kTexTop = 1.0f-kTexBottom; 652 653 glPushAttrib(GL_LIGHTING | GL_ENABLE_BIT | GL_TEXTURE_BIT); 654 655 glEnable(GL_TEXTURE_2D); 656 glEnable(GL_BLEND); 657 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 658 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 659 glDisable(GL_LIGHTING); 660 glDisable(GL_DEPTH_TEST); 661 662 /* Draw the numbers */ 663 glColor4f(1.0f, 1.0f, 1.0f, fLabelIntensity); 664 665 for (int p = 0; p<5; ++p) { 666 MBCPiece piece = White(gInHandOrder[p]); 667 int numInHand = fInAnimation 668 ? [fBoard oldInHand:piece] 669 : [fBoard curInHand:piece]; 670 numInHand -= (piece+kInHandSquare == fSelectedSquare); 671 if (numInHand > 1) { 672 glBindTexture(GL_TEXTURE_2D, fNumberTextures[min(numInHand,8)-1]); 673 674 float z = p * kSpacing; 675 676 glBegin(GL_QUADS); 677 glTexCoord2f(kTexLeft, kTexBottom); 678 glVertex3f(kLabelLeft, 0.0f, kLabelZ+z+kLabelSize); 679 glTexCoord2f(kTexRight, kTexBottom); 680 glVertex3f(kLabelRight, 0.0f, kLabelZ+z+kLabelSize); 681 glTexCoord2f(kTexRight, kTexTop); 682 glVertex3f(kLabelRight, 0.0f, kLabelZ+z); 683 glTexCoord2f(kTexLeft, kTexTop); 684 glVertex3f(kLabelLeft, 0.0f, kLabelZ+z); 685 glEnd(); 686 } 687 } 688 689 for (int p = 0; p<5; ++p) { 690 MBCPiece piece = Black(gInHandOrder[p]); 691 int numInHand = fInAnimation 692 ? [fBoard oldInHand:piece] 693 : [fBoard curInHand:piece]; 694 numInHand -= (piece+kInHandSquare == fSelectedSquare); 695 if (numInHand > 1) { 696 glBindTexture(GL_TEXTURE_2D, fNumberTextures[min(numInHand,8)-1]); 697 698 float z = p * kSpacing; 699 700 glBegin(GL_QUADS); 701 glTexCoord2f(kTexLeft, kTexBottom); 702 glVertex3f(kLabelLeft, 0.0f, -kLabelZ-z); 703 glTexCoord2f(kTexRight, kTexBottom); 704 glVertex3f(kLabelRight, 0.0f, -kLabelZ-z); 705 glTexCoord2f(kTexRight, kTexTop); 706 glVertex3f(kLabelRight, 0.0f, -kLabelZ-z-kLabelSize); 707 glTexCoord2f(kTexLeft, kTexTop); 708 glVertex3f(kLabelLeft, 0.0f, -kLabelZ-z-kLabelSize); 709 glEnd(); 710 } 711 } 712 713 glDisable(GL_BLEND); 714 715 glPopAttrib(); 716 717 [self placeLights]; 718 719 for (int p = 0; p<5; ++p) { 720 MBCPiece piece = White(gInHandOrder[p]); 721 int numInHand = fInAnimation 722 ? [fBoard oldInHand:piece] 723 : [fBoard curInHand:piece]; 724 numInHand -= (piece+kInHandSquare == fSelectedSquare); 725 if (numInHand) { 726 MBCPosition pos = {{kPieceX, 0.0f, kPieceZ}}; 727 pos[2] += p*kSpacing; 728 729 [self drawPiece:piece at:pos scale:kScale]; 730 } 731 } 732 733 for (int p = 0; p<5; ++p) { 734 MBCPiece piece = Black(gInHandOrder[p]); 735 int numInHand = fInAnimation 736 ? [fBoard oldInHand:piece] 737 : [fBoard curInHand:piece]; 738 numInHand -= (piece+kInHandSquare == fSelectedSquare); 739 if (numInHand) { 740 MBCPosition pos = {{kPieceX, 0.0f, -kPieceZ}}; 741 pos[2] -= p*kSpacing; 742 743 [self drawPiece:piece at:pos scale:kScale]; 744 } 745 } 746 glPopMatrix(); 747} 748 749- (void) drawArrowFrom:(MBCPosition)fromPos to:(MBCPosition)toPos width:(float)w 750{ 751 glPushAttrib(GL_ENABLE_BIT); /* Save states */ 752 glDisable(GL_DEPTH_TEST); 753 glDisable(GL_TEXTURE_2D); 754 glDisable(GL_LIGHTING); 755 glEnable(GL_BLEND); 756 glDisable(GL_CULL_FACE); /* Too lazy to figure out winding */ 757 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 758 759 const float kStemW = w; 760 const float kPointW = 2.00f*w; 761 const float kPointH = 1.50f*w; 762 const float kHeight = 0.01f; 763 764 const float len = 765 hypot(toPos[0]-fromPos[0], toPos[2]-fromPos[2]); 766 const float alpha = 767 atan2(toPos[2]-fromPos[2], toPos[0]-fromPos[0]); 768 const float sinAlpha = sin(alpha); 769 const float cosAlpha = cos(alpha); 770 771 MBCPosition p1 = fromPos; 772 p1.pos[0] -= kStemW*sinAlpha; 773 p1.pos[1] = kHeight; 774 p1.pos[2] += kStemW*cosAlpha; 775 MBCPosition p2 = fromPos; 776 p2.pos[0] += kStemW*sinAlpha; 777 p2.pos[1] = kHeight; 778 p2.pos[2] -= kStemW*cosAlpha; 779 MBCPosition p3 = p1; 780 p3.pos[0] += (len-kPointH)*cosAlpha; 781 p3.pos[2] += (len-kPointH)*sinAlpha; 782 MBCPosition p4 = p2; 783 p4.pos[0] += (len-kPointH)*cosAlpha; 784 p4.pos[2] += (len-kPointH)*sinAlpha; 785 MBCPosition p5 = p3; 786 p5.pos[0] -= (kPointW-kStemW)*sinAlpha; 787 p5.pos[2] += (kPointW-kStemW)*cosAlpha; 788 MBCPosition p6 = p4; 789 p6.pos[0] += (kPointW-kStemW)*sinAlpha; 790 p6.pos[2] -= (kPointW-kStemW)*cosAlpha; 791 MBCPosition p7 = toPos; 792 p7.pos[1] = kHeight; 793 794 glBegin(GL_TRIANGLES); 795 glVertex3fv(p1); 796 glVertex3fv(p2); 797 glVertex3fv(p4); 798 glVertex3fv(p4); 799 glVertex3fv(p3); 800 glVertex3fv(p1); 801 glVertex3fv(p5); 802 glVertex3fv(p6); 803 glVertex3fv(p7); 804 glEnd(); 805 806 glPopAttrib(); 807} 808 809- (void) drawMove:(MBCMove *)move asHint:(BOOL)hint 810{ 811 if (!move) 812 return; 813 814 MBCPosition fromPos = [self squareToPosition: move->fFromSquare]; 815 MBCPosition toPos = [self squareToPosition: move->fToSquare]; 816 817 if (hint) 818 glColor4f(1.0f, 0.0f, 0.0f, 0.5f); 819 else 820 glColor4f(0.0f, 0.0f, 1.0f, 0.5f); 821 822 [self drawArrowFrom:fromPos to:toPos width:2.0f]; 823} 824 825- (void) drawManipulator 826{ 827 // 828 // Save normal projection and superimpose an Ortho projection 829 // 830 glPushMatrix(); 831 glLoadIdentity(); 832 glMatrixMode(GL_PROJECTION); 833 glPushMatrix(); 834 glLoadIdentity(); 835 NSRect b = [self bounds]; 836 gluOrtho2D(NSMinX(b), NSMaxX(b), NSMinY(b), NSMaxY(b)); 837 glMatrixMode(GL_MODELVIEW); 838 glRotatef(-90.0, 1.0, 0.0, 0.0); 839 // 840 // Draw navigation aid 841 // 842 bool horizontal = 843 fabs(fCurMouse.x-fOrigMouse.x) > fabs(fCurMouse.y-fOrigMouse.y); 844 const float kScale = 1.0f; 845 const float kCircleSize = 10.0f*kScale; 846 const float kArrowClearance = 15.0f*kScale; 847 const float kArrowLength = 30.0f*kScale; 848 const float kArrowWidth = 10.0f*kScale; 849 const float kThreshold = 10.0f*kScale; 850 const float kWellSize = 55.0f*kScale; 851 const float kWellRound = 20.0f*kScale; 852 853 GLfloat on_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; 854 GLfloat off_color[4] = {1.0f, 1.0f, 1.0f, 0.4f}; 855 GLfloat well_color[4] = {0.5f, 0.5f, 0.5f, 0.6f}; 856 // 857 // Well & Circle 858 // 859 glPushAttrib(GL_ENABLE_BIT); /* Save states */ 860 glDisable(GL_DEPTH_TEST); 861 glDisable(GL_TEXTURE_2D); 862 glDisable(GL_LIGHTING); 863 glEnable(GL_BLEND); 864 glDisable(GL_CULL_FACE); /* Too lazy to figure out winding */ 865 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 866 867 GLUquadricObj * q = gluNewQuadric(); 868 869 glPushMatrix(); 870 glRotatef(90.0, 1.0, 0.0, 0.0); 871 glTranslatef(fOrigMouse.x, fOrigMouse.y, 0.01f); 872 873 glColor4fv(well_color); 874 glBegin(GL_QUADS); 875 glVertex3f(-kWellSize+kWellRound, -kWellSize, 0.0f); 876 glVertex3f( kWellSize-kWellRound, -kWellSize, 0.0f); 877 glVertex3f( kWellSize-kWellRound, -kWellSize+kWellRound, 0.0f); 878 glVertex3f(-kWellSize+kWellRound, -kWellSize+kWellRound, 0.0f); 879 glVertex3f(-kWellSize, -kWellSize+kWellRound, 0.0f); 880 glVertex3f( kWellSize, -kWellSize+kWellRound, 0.0f); 881 glVertex3f( kWellSize, kWellSize-kWellRound, 0.0f); 882 glVertex3f(-kWellSize, kWellSize-kWellRound, 0.0f); 883 glVertex3f(-kWellSize+kWellRound, kWellSize-kWellRound, 0.0f); 884 glVertex3f( kWellSize-kWellRound, kWellSize-kWellRound, 0.0f); 885 glVertex3f( kWellSize-kWellRound, kWellSize, 0.0f); 886 glVertex3f(-kWellSize+kWellRound, kWellSize, 0.0f); 887 glEnd(); 888 glTranslatef(-kWellSize+kWellRound, -kWellSize+kWellRound, 0.0f); 889 gluPartialDisk(q, 0.0, kWellRound, 10, 1, 180.0, 90.0); 890 glTranslatef(2.0*(kWellSize-kWellRound), 0.0f, 0.0f); 891 gluPartialDisk(q, 0.0, kWellRound, 10, 1, 90.0, 90.0); 892 glTranslatef(0.0, 2.0*(kWellSize-kWellRound), 0.0f); 893 gluPartialDisk(q, 0.0, kWellRound, 10, 1, 0.0, 90.0); 894 glTranslatef(-2.0*(kWellSize-kWellRound), 0.0f, 0.0f); 895 gluPartialDisk(q, 0.0, kWellRound, 10, 1, 270.0, 90.0); 896 glTranslatef( kWellSize-kWellRound, -kWellSize+kWellRound, 0.0f); 897 898 glColor4fv(fabs(fCurMouse.x-fOrigMouse.x)<kThreshold 899 && fabs(fCurMouse.y-fOrigMouse.y)<kThreshold 900 ? on_color : off_color); 901 gluDisk(q, 0.0, kCircleSize, 40, 1); 902 glPopMatrix(); 903 gluDeleteQuadric(q); 904 905 MBCPosition fromPos, toPos; 906 907 // 908 // Up 909 // 910 fromPos[0] = fOrigMouse.x; 911 fromPos[1] = 0; 912 fromPos[2] = fOrigMouse.y+kArrowClearance; 913 toPos = fromPos; 914 toPos[2] += kArrowLength; 915 glColor4fv((!horizontal && (fCurMouse.y > fOrigMouse.y+kThreshold)) 916 ? on_color : off_color); 917 [self drawArrowFrom:fromPos to:toPos width:kArrowWidth]; 918 919 // 920 // Down 921 // 922 fromPos[0] = fOrigMouse.x; 923 fromPos[1] = 0; 924 fromPos[2] = fOrigMouse.y-kArrowClearance; 925 toPos = fromPos; 926 toPos[2] -= kArrowLength; 927 glColor4fv((!horizontal && (fCurMouse.y < fOrigMouse.y-kThreshold)) 928 ? on_color : off_color); 929 [self drawArrowFrom:fromPos to:toPos width:kArrowWidth]; 930 931 // 932 // Right 933 // 934 fromPos[0] = fOrigMouse.x+kArrowClearance; 935 fromPos[1] = 0; 936 fromPos[2] = fOrigMouse.y; 937 toPos = fromPos; 938 toPos[0] += kArrowLength; 939 glColor4fv((horizontal && (fCurMouse.x > fOrigMouse.x+kThreshold)) 940 ? on_color : off_color); 941 [self drawArrowFrom:fromPos to:toPos width:kArrowWidth]; 942 943 // 944 // Left 945 // 946 fromPos[0] = fOrigMouse.x-kArrowClearance; 947 fromPos[1] = 0; 948 fromPos[2] = fOrigMouse.y; 949 toPos = fromPos; 950 toPos[0] -= kArrowLength; 951 glColor4fv((horizontal && (fCurMouse.x < fOrigMouse.x-kThreshold)) 952 ? on_color : off_color); 953 [self drawArrowFrom:fromPos to:toPos width:kArrowWidth]; 954 955 glPopAttrib(); 956 // 957 // Restore projection 958 // 959 glPopMatrix(); 960 glMatrixMode(GL_PROJECTION); 961 glPopMatrix(); 962 glMatrixMode(GL_MODELVIEW); 963} 964 965- (void) makeBoardSolid 966{ 967 // 968 // If we're in a transparent window, we have to make sure that the 969 // board itself always remains opaque, no matter what blending we've 970 // done with it 971 // 972 const float IB = kBoardRadius; // Inside border 973 const float OB = IB+kBorderWidth; // Outside border 974 const float DP = 5.0f; // Depth 975 976 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT); 977 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); 978 glDisable(GL_BLEND); 979 glDisable(GL_LIGHTING); 980 glDisable(GL_CULL_FACE); /* Too lazy to figure out winding */ 981 glDisable(GL_DEPTH_TEST); 982 glColor4f(0.0f, 0.0f, 0.0f, 1.0f); 983 glBegin(GL_QUADS); 984 glVertex3f(-OB, 0.0f, OB); 985 glVertex3f( OB, 0.0f, OB); 986 glVertex3f( OB, 0.0f, -OB); 987 glVertex3f(-OB, 0.0f, -OB); 988 glEnd(); 989 glBegin(GL_QUAD_STRIP); 990 glVertex3f(-OB, -DP, OB); 991 glVertex3f(-OB, 0.0f, OB); 992 glVertex3f( OB, -DP, OB); 993 glVertex3f( OB, 0.0f, OB); 994 glVertex3f( OB, -DP, -OB); 995 glVertex3f( OB, 0.0f, -OB); 996 glVertex3f(-OB, -DP, -OB); 997 glVertex3f(-OB, 0.0f, -OB); 998 glEnd(); 999 glPopAttrib(); 1000} 1001 1002- (void) drawGloss 1003{ 1004 // 1005 // Save normal projection and superimpose an Ortho projection 1006 // 1007 glPushMatrix(); 1008 glLoadIdentity(); 1009 glMatrixMode(GL_PROJECTION); 1010 glPushMatrix(); 1011 glLoadIdentity(); 1012 NSRect b = [self bounds]; 1013 gluOrtho2D(NSMinX(b), NSMaxX(b), NSMinY(b), NSMaxY(b)); 1014 glMatrixMode(GL_MODELVIEW); 1015 1016 glPushAttrib(GL_ENABLE_BIT); /* Save states */ 1017 glDisable(GL_DEPTH_TEST); 1018 glDisable(GL_TEXTURE_2D); 1019 glDisable(GL_LIGHTING); 1020 glDisable(GL_CULL_FACE); 1021 glDisable(GL_BLEND); 1022 1023 GLfloat kBaseColor[3] = {0.25f, 0.25f, 0.25f}; 1024 GLfloat kTopColor[3] = {0.6f, 0.6f, 0.6f}; 1025 GLfloat kMidColor[3] = {0.3f, 0.3f, 0.3f}; 1026 const int kSegments = 32; 1027 GLfloat kAspectRatio = b.size.width/b.size.height; 1028 GLfloat kMidX = b.size.width*0.5f; 1029 GLfloat kMidY = b.size.height*3.0f*kAspectRatio; 1030 GLfloat kSecY = b.size.height*0.55f; 1031 GLfloat kRadius = hypotf(kMidX, kMidY-kSecY); 1032 GLfloat kRadius2 = kRadius*kRadius; 1033 1034 glColor3fv(kBaseColor); 1035 glBegin(GL_QUADS); 1036 glVertex3f(NSMinX(b), NSMinY(b), 0.0f); 1037 glVertex3f(NSMaxX(b), NSMinY(b), 0.0f); 1038 glVertex3f(NSMaxX(b), NSMaxY(b), 0.0f); 1039 glVertex3f(NSMinX(b), NSMaxY(b), 0.0f); 1040 glEnd(); 1041 1042 glBegin(GL_TRIANGLE_STRIP); 1043 for (int i=0; i<=kSegments; ++i) { 1044 GLfloat x = b.origin.x+b.size.width*i/kSegments; 1045 GLfloat dx = kMidX-x; 1046 GLfloat y0 = kMidY-sqrtf(kRadius2-dx*dx); 1047 GLfloat y1 = b.origin.y+b.size.height; 1048 1049 glColor3fv(kMidColor); 1050 glVertex3f(x, y0, 0.0f); 1051 glColor3fv(kTopColor); 1052 glVertex3f(x, y1, 0.0f); 1053 } 1054 glEnd(); 1055 1056 // 1057 // Restore projection 1058 // 1059 glPopAttrib(); 1060 glPopMatrix(); 1061 glMatrixMode(GL_PROJECTION); 1062 glPopMatrix(); 1063 glMatrixMode(GL_MODELVIEW); 1064} 1065 1066- (void) update 1067{ 1068 [super update]; 1069 if (![[self openGLContext] view]) { 1070 // 1071 // Fall back to a less memory hungry format. 1072 // 1073 [self pickPixelFormat:YES]; 1074 fNeedPerspective = true; 1075 } 1076} 1077 1078/* Draw the scene for a game */ 1079- (void) drawPosition 1080{ 1081 if (![[self openGLContext] view]) { 1082 // 1083 // Fall back to a less memory hungry format. 1084 // 1085 [self pickPixelFormat:YES]; 1086 fNeedPerspective = true; 1087 } 1088 1089 if (fIsFloating) { 1090 [[NSColor clearColor] set]; 1091 NSRectFill([self bounds]); 1092 } 1093 1094 if (fNeedStaticModels) { 1095 fNeedStaticModels = false; 1096 [self loadColors]; 1097 [self generateModelLists]; 1098 } 1099 if (fNeedPerspective) 1100 [self setupPerspective]; 1101 1102 /* Clear the buffers */ 1103 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 1104 if (fBoardReflectivity) 1105 glClear(GL_STENCIL_BUFFER_BIT); 1106 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1107 1108 [self drawGloss]; 1109 1110 /* Place lights */ 1111 [self placeLights]; 1112 1113 /* Draw the board */ 1114 [self drawBoard:NO]; 1115 1116 /* Make a stencil of the floor if reflections are done */ 1117 if (fBoardReflectivity) { 1118 /* Save the old scene attributes */ 1119 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT); 1120 1121 /* Disable stuff */ 1122 glDisable(GL_DEPTH_TEST); 1123 glDisable(GL_LIGHTING); 1124 glDisable(GL_BLEND); 1125 1126 /* Don't draw to the screen or the depth buffer at this moment */ 1127 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1128 glDepthMask(GL_FALSE); 1129 1130 /* Write to the stencil buffer */ 1131 glEnable(GL_STENCIL_TEST); 1132 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 1133 glStencilFunc(GL_ALWAYS, 1, 0xffffffff); 1134 1135 glBegin(GL_QUADS); 1136 glVertex3f(-40.0f, 0.0f, 40.0f); 1137 glVertex3f( 40.0f, 0.0f, 40.0f); 1138 glVertex3f( 40.0f, 0.0f, -40.0f); 1139 glVertex3f(-40.0f, 0.0f, -40.0f); 1140 glEnd(); 1141 1142 // 1143 // Re-enable writing to the depth buffer and to the color channels 1144 // but NOT to the alpha channel in case we have a translucent window 1145 // 1146 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); 1147 glDepthMask(GL_TRUE); 1148 1149 /* Draw only if stencil is set to 1 */ 1150 glStencilFunc(GL_EQUAL, 1, 0xffffffff); 1151 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 1152 1153 /* draw the reflected pieces */ 1154 1155 /* Reflect in floor */ 1156 glPushMatrix(); { 1157 glScalef(1.0f, -1.0f, 1.0f); 1158 1159 glEnable(GL_LIGHTING); 1160 [self placeLights]; 1161 1162 glCullFace(GL_FRONT); { 1163 [self drawPieces:YES]; 1164 1165 if (fSelectedPiece) 1166 [self drawSelectedPiece:YES]; 1167 } glCullFace(GL_BACK); 1168 } glPopMatrix(); 1169 1170 /* Restore the scene attributes */ 1171 glPopAttrib(); 1172 1173 /* Now blend board back into the reflections */ 1174 [self drawBoard:YES]; 1175 } 1176 1177 /* Draw the co-ordinates [1-8] [a-h] */ 1178 [self drawCoords]; 1179 1180 /* Draw hint and last move */ 1181 [self drawMove:fHintMove asHint:YES]; 1182 [self drawMove:fLastMove asHint:NO]; 1183 1184 glDisable(GL_BLEND); 1185 1186 /* Draw the pieces */ 1187 if (fVariant == kVarCrazyhouse) 1188 [self drawPiecesInHand]; 1189 [self drawPieces:NO]; 1190 1191 if (fSelectedPiece) 1192 [self drawSelectedPiece:NO]; 1193 1194 [self drawPromotionPiece]; 1195 1196#if 0 1197 // 1198 // Some graphics cards seem to mess up the lighting when the knight 1199 // or king model were the last ones drawn 1200 // 1201 if (fLastPieceDrawn == KING || fLastPieceDrawn == KNIGHT) { 1202 MBCPosition pos = {{0.0f, 0.0f, 0.0f}}; 1203 [self drawPiece:PAWN at:pos reflect:NO alpha:0.0f]; 1204 } 1205#endif 1206 1207 if (fInBoardManipulation) 1208 [self drawManipulator]; 1209 1210 [self makeBoardSolid]; 1211 1212 // 1213 // Work around OpenGL driver issue 1214 // 1215#ifdef __LP64__ 1216 glFlush(); 1217#endif 1218 1219 [[self openGLContext] flushBuffer]; 1220} 1221 1222@end 1223 1224// Local Variables: 1225// mode:ObjC 1226// End: 1227