stencil.c revision a9754793dab4b24c09cae21c29f902ce0e53319a
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * \file stencil.c 28 * Stencil operations. 29 * 30 * Note: There's some conflict between GL_EXT_stencil_two_side and 31 * OpenGL 2.0's two-sided stencil feature. 32 * 33 * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the 34 * front OR back face state (as set by glActiveStencilFaceEXT) is set. 35 * 36 * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the 37 * front AND back state. 38 * 39 * Also, note that GL_ATI_separate_stencil is different as well: 40 * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. 41 * glStencilFuncSeparate(GLenum face, GLenum func, ...). 42 * 43 * This problem is solved by keeping three sets of stencil state: 44 * state[0] = GL_FRONT state. 45 * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. 46 * state[2] = GL_EXT_stencil_two_side GL_BACK state. 47 */ 48 49 50#include "glheader.h" 51#include "imports.h" 52#include "context.h" 53#include "macros.h" 54#include "stencil.h" 55#include "mtypes.h" 56 57 58static GLboolean 59validate_stencil_op(struct gl_context *ctx, GLenum op) 60{ 61 switch (op) { 62 case GL_KEEP: 63 case GL_ZERO: 64 case GL_REPLACE: 65 case GL_INCR: 66 case GL_DECR: 67 case GL_INVERT: 68 case GL_INCR_WRAP: 69 case GL_DECR_WRAP: 70 return GL_TRUE; 71 default: 72 return GL_FALSE; 73 } 74} 75 76 77static GLboolean 78validate_stencil_func(struct gl_context *ctx, GLenum func) 79{ 80 switch (func) { 81 case GL_NEVER: 82 case GL_LESS: 83 case GL_LEQUAL: 84 case GL_GREATER: 85 case GL_GEQUAL: 86 case GL_EQUAL: 87 case GL_NOTEQUAL: 88 case GL_ALWAYS: 89 return GL_TRUE; 90 default: 91 return GL_FALSE; 92 } 93} 94 95 96/** 97 * Set the clear value for the stencil buffer. 98 * 99 * \param s clear value. 100 * 101 * \sa glClearStencil(). 102 * 103 * Updates gl_stencil_attrib::Clear. On change 104 * flushes the vertices and notifies the driver via 105 * the dd_function_table::ClearStencil callback. 106 */ 107void GLAPIENTRY 108_mesa_ClearStencil( GLint s ) 109{ 110 GET_CURRENT_CONTEXT(ctx); 111 112 if (ctx->Stencil.Clear == (GLuint) s) 113 return; 114 115 FLUSH_VERTICES(ctx, _NEW_STENCIL); 116 ctx->Stencil.Clear = (GLuint) s; 117} 118 119 120/** 121 * Set the function and reference value for stencil testing. 122 * 123 * \param frontfunc front test function. 124 * \param backfunc back test function. 125 * \param ref front and back reference value. 126 * \param mask front and back bitmask. 127 * 128 * \sa glStencilFunc(). 129 * 130 * Verifies the parameters and updates the respective values in 131 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 132 * driver via the dd_function_table::StencilFunc callback. 133 */ 134void GLAPIENTRY 135_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 136{ 137 GET_CURRENT_CONTEXT(ctx); 138 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; 139 140 if (MESA_VERBOSE & VERBOSE_API) 141 _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 142 143 if (!validate_stencil_func(ctx, frontfunc)) { 144 _mesa_error(ctx, GL_INVALID_ENUM, 145 "glStencilFuncSeparateATI(frontfunc)"); 146 return; 147 } 148 if (!validate_stencil_func(ctx, backfunc)) { 149 _mesa_error(ctx, GL_INVALID_ENUM, 150 "glStencilFuncSeparateATI(backfunc)"); 151 return; 152 } 153 154 ref = CLAMP( ref, 0, stencilMax ); 155 156 /* set both front and back state */ 157 if (ctx->Stencil.Function[0] == frontfunc && 158 ctx->Stencil.Function[1] == backfunc && 159 ctx->Stencil.ValueMask[0] == mask && 160 ctx->Stencil.ValueMask[1] == mask && 161 ctx->Stencil.Ref[0] == ref && 162 ctx->Stencil.Ref[1] == ref) 163 return; 164 FLUSH_VERTICES(ctx, _NEW_STENCIL); 165 ctx->Stencil.Function[0] = frontfunc; 166 ctx->Stencil.Function[1] = backfunc; 167 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 168 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 169 if (ctx->Driver.StencilFuncSeparate) { 170 ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 171 frontfunc, ref, mask); 172 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 173 backfunc, ref, mask); 174 } 175} 176 177 178/** 179 * Set the function and reference value for stencil testing. 180 * 181 * \param func test function. 182 * \param ref reference value. 183 * \param mask bitmask. 184 * 185 * \sa glStencilFunc(). 186 * 187 * Verifies the parameters and updates the respective values in 188 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 189 * driver via the dd_function_table::StencilFunc callback. 190 */ 191void GLAPIENTRY 192_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) 193{ 194 GET_CURRENT_CONTEXT(ctx); 195 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; 196 const GLint face = ctx->Stencil.ActiveFace; 197 198 if (MESA_VERBOSE & VERBOSE_API) 199 _mesa_debug(ctx, "glStencilFunc()\n"); 200 201 if (!validate_stencil_func(ctx, func)) { 202 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 203 return; 204 } 205 206 ref = CLAMP( ref, 0, stencilMax ); 207 208 if (face != 0) { 209 if (ctx->Stencil.Function[face] == func && 210 ctx->Stencil.ValueMask[face] == mask && 211 ctx->Stencil.Ref[face] == ref) 212 return; 213 FLUSH_VERTICES(ctx, _NEW_STENCIL); 214 ctx->Stencil.Function[face] = func; 215 ctx->Stencil.Ref[face] = ref; 216 ctx->Stencil.ValueMask[face] = mask; 217 218 /* Only propagate the change to the driver if EXT_stencil_two_side 219 * is enabled. 220 */ 221 if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 222 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 223 } 224 } 225 else { 226 /* set both front and back state */ 227 if (ctx->Stencil.Function[0] == func && 228 ctx->Stencil.Function[1] == func && 229 ctx->Stencil.ValueMask[0] == mask && 230 ctx->Stencil.ValueMask[1] == mask && 231 ctx->Stencil.Ref[0] == ref && 232 ctx->Stencil.Ref[1] == ref) 233 return; 234 FLUSH_VERTICES(ctx, _NEW_STENCIL); 235 ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 236 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 237 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 238 if (ctx->Driver.StencilFuncSeparate) { 239 ctx->Driver.StencilFuncSeparate(ctx, 240 ((ctx->Stencil.TestTwoSide) 241 ? GL_FRONT : GL_FRONT_AND_BACK), 242 func, ref, mask); 243 } 244 } 245} 246 247 248/** 249 * Set the stencil writing mask. 250 * 251 * \param mask bit-mask to enable/disable writing of individual bits in the 252 * stencil planes. 253 * 254 * \sa glStencilMask(). 255 * 256 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 257 * notifies the driver via the dd_function_table::StencilMask callback. 258 */ 259void GLAPIENTRY 260_mesa_StencilMask( GLuint mask ) 261{ 262 GET_CURRENT_CONTEXT(ctx); 263 const GLint face = ctx->Stencil.ActiveFace; 264 265 if (MESA_VERBOSE & VERBOSE_API) 266 _mesa_debug(ctx, "glStencilMask()\n"); 267 268 if (face != 0) { 269 /* Only modify the EXT_stencil_two_side back-face state. 270 */ 271 if (ctx->Stencil.WriteMask[face] == mask) 272 return; 273 FLUSH_VERTICES(ctx, _NEW_STENCIL); 274 ctx->Stencil.WriteMask[face] = mask; 275 276 /* Only propagate the change to the driver if EXT_stencil_two_side 277 * is enabled. 278 */ 279 if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 280 ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 281 } 282 } 283 else { 284 /* set both front and back state */ 285 if (ctx->Stencil.WriteMask[0] == mask && 286 ctx->Stencil.WriteMask[1] == mask) 287 return; 288 FLUSH_VERTICES(ctx, _NEW_STENCIL); 289 ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 290 if (ctx->Driver.StencilMaskSeparate) { 291 ctx->Driver.StencilMaskSeparate(ctx, 292 ((ctx->Stencil.TestTwoSide) 293 ? GL_FRONT : GL_FRONT_AND_BACK), 294 mask); 295 } 296 } 297} 298 299 300/** 301 * Set the stencil test actions. 302 * 303 * \param fail action to take when stencil test fails. 304 * \param zfail action to take when stencil test passes, but depth test fails. 305 * \param zpass action to take when stencil test passes and the depth test 306 * passes (or depth testing is not enabled). 307 * 308 * \sa glStencilOp(). 309 * 310 * Verifies the parameters and updates the respective fields in 311 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 312 * driver via the dd_function_table::StencilOp callback. 313 */ 314void GLAPIENTRY 315_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 const GLint face = ctx->Stencil.ActiveFace; 319 320 if (MESA_VERBOSE & VERBOSE_API) 321 _mesa_debug(ctx, "glStencilOp()\n"); 322 323 if (!validate_stencil_op(ctx, fail)) { 324 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 325 return; 326 } 327 if (!validate_stencil_op(ctx, zfail)) { 328 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 329 return; 330 } 331 if (!validate_stencil_op(ctx, zpass)) { 332 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 333 return; 334 } 335 336 if (face != 0) { 337 /* only set active face state */ 338 if (ctx->Stencil.ZFailFunc[face] == zfail && 339 ctx->Stencil.ZPassFunc[face] == zpass && 340 ctx->Stencil.FailFunc[face] == fail) 341 return; 342 FLUSH_VERTICES(ctx, _NEW_STENCIL); 343 ctx->Stencil.ZFailFunc[face] = zfail; 344 ctx->Stencil.ZPassFunc[face] = zpass; 345 ctx->Stencil.FailFunc[face] = fail; 346 347 /* Only propagate the change to the driver if EXT_stencil_two_side 348 * is enabled. 349 */ 350 if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 351 ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 352 } 353 } 354 else { 355 /* set both front and back state */ 356 if (ctx->Stencil.ZFailFunc[0] == zfail && 357 ctx->Stencil.ZFailFunc[1] == zfail && 358 ctx->Stencil.ZPassFunc[0] == zpass && 359 ctx->Stencil.ZPassFunc[1] == zpass && 360 ctx->Stencil.FailFunc[0] == fail && 361 ctx->Stencil.FailFunc[1] == fail) 362 return; 363 FLUSH_VERTICES(ctx, _NEW_STENCIL); 364 ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 365 ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 366 ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 367 if (ctx->Driver.StencilOpSeparate) { 368 ctx->Driver.StencilOpSeparate(ctx, 369 ((ctx->Stencil.TestTwoSide) 370 ? GL_FRONT : GL_FRONT_AND_BACK), 371 fail, zfail, zpass); 372 } 373 } 374} 375 376 377 378/* GL_EXT_stencil_two_side */ 379void GLAPIENTRY 380_mesa_ActiveStencilFaceEXT(GLenum face) 381{ 382 GET_CURRENT_CONTEXT(ctx); 383 384 if (MESA_VERBOSE & VERBOSE_API) 385 _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 386 387 if (!ctx->Extensions.EXT_stencil_two_side) { 388 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 389 return; 390 } 391 392 if (face == GL_FRONT || face == GL_BACK) { 393 FLUSH_VERTICES(ctx, _NEW_STENCIL); 394 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 395 } 396 else { 397 _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 398 } 399} 400 401 402 403/** 404 * OpenGL 2.0 function. 405 * \todo Make StencilOp() call this function. And eventually remove the 406 * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate 407 * instead. 408 */ 409void GLAPIENTRY 410_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 411{ 412 GLboolean set = GL_FALSE; 413 GET_CURRENT_CONTEXT(ctx); 414 415 if (MESA_VERBOSE & VERBOSE_API) 416 _mesa_debug(ctx, "glStencilOpSeparate()\n"); 417 418 if (!validate_stencil_op(ctx, sfail)) { 419 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 420 return; 421 } 422 if (!validate_stencil_op(ctx, zfail)) { 423 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 424 return; 425 } 426 if (!validate_stencil_op(ctx, zpass)) { 427 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 428 return; 429 } 430 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 431 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 432 return; 433 } 434 435 if (face != GL_BACK) { 436 /* set front */ 437 if (ctx->Stencil.ZFailFunc[0] != zfail || 438 ctx->Stencil.ZPassFunc[0] != zpass || 439 ctx->Stencil.FailFunc[0] != sfail){ 440 FLUSH_VERTICES(ctx, _NEW_STENCIL); 441 ctx->Stencil.ZFailFunc[0] = zfail; 442 ctx->Stencil.ZPassFunc[0] = zpass; 443 ctx->Stencil.FailFunc[0] = sfail; 444 set = GL_TRUE; 445 } 446 } 447 if (face != GL_FRONT) { 448 /* set back */ 449 if (ctx->Stencil.ZFailFunc[1] != zfail || 450 ctx->Stencil.ZPassFunc[1] != zpass || 451 ctx->Stencil.FailFunc[1] != sfail) { 452 FLUSH_VERTICES(ctx, _NEW_STENCIL); 453 ctx->Stencil.ZFailFunc[1] = zfail; 454 ctx->Stencil.ZPassFunc[1] = zpass; 455 ctx->Stencil.FailFunc[1] = sfail; 456 set = GL_TRUE; 457 } 458 } 459 if (set && ctx->Driver.StencilOpSeparate) { 460 ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 461 } 462} 463 464 465/* OpenGL 2.0 */ 466void GLAPIENTRY 467_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 468{ 469 GET_CURRENT_CONTEXT(ctx); 470 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; 471 472 if (MESA_VERBOSE & VERBOSE_API) 473 _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 474 475 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 476 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 477 return; 478 } 479 if (!validate_stencil_func(ctx, func)) { 480 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 481 return; 482 } 483 484 ref = CLAMP(ref, 0, stencilMax); 485 486 FLUSH_VERTICES(ctx, _NEW_STENCIL); 487 488 if (face != GL_BACK) { 489 /* set front */ 490 ctx->Stencil.Function[0] = func; 491 ctx->Stencil.Ref[0] = ref; 492 ctx->Stencil.ValueMask[0] = mask; 493 } 494 if (face != GL_FRONT) { 495 /* set back */ 496 ctx->Stencil.Function[1] = func; 497 ctx->Stencil.Ref[1] = ref; 498 ctx->Stencil.ValueMask[1] = mask; 499 } 500 if (ctx->Driver.StencilFuncSeparate) { 501 ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 502 } 503} 504 505 506/* OpenGL 2.0 */ 507void GLAPIENTRY 508_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 509{ 510 GET_CURRENT_CONTEXT(ctx); 511 512 if (MESA_VERBOSE & VERBOSE_API) 513 _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 514 515 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 516 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 517 return; 518 } 519 520 FLUSH_VERTICES(ctx, _NEW_STENCIL); 521 522 if (face != GL_BACK) { 523 ctx->Stencil.WriteMask[0] = mask; 524 } 525 if (face != GL_FRONT) { 526 ctx->Stencil.WriteMask[1] = mask; 527 } 528 if (ctx->Driver.StencilMaskSeparate) { 529 ctx->Driver.StencilMaskSeparate(ctx, face, mask); 530 } 531} 532 533 534/** 535 * Update derived stencil state. 536 */ 537void 538_mesa_update_stencil(struct gl_context *ctx) 539{ 540 const GLint face = ctx->Stencil._BackFace; 541 542 ctx->Stencil._Enabled = (ctx->Stencil.Enabled && 543 ctx->DrawBuffer->Visual.stencilBits > 0); 544 545 ctx->Stencil._TestTwoSide = 546 ctx->Stencil._Enabled && 547 (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || 548 ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || 549 ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || 550 ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || 551 ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || 552 ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || 553 ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); 554} 555 556 557/** 558 * Initialize the context stipple state. 559 * 560 * \param ctx GL context. 561 * 562 * Initializes __struct gl_contextRec::Stencil attribute group. 563 */ 564void 565_mesa_init_stencil(struct gl_context *ctx) 566{ 567 ctx->Stencil.Enabled = GL_FALSE; 568 ctx->Stencil.TestTwoSide = GL_FALSE; 569 ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 570 ctx->Stencil.Function[0] = GL_ALWAYS; 571 ctx->Stencil.Function[1] = GL_ALWAYS; 572 ctx->Stencil.Function[2] = GL_ALWAYS; 573 ctx->Stencil.FailFunc[0] = GL_KEEP; 574 ctx->Stencil.FailFunc[1] = GL_KEEP; 575 ctx->Stencil.FailFunc[2] = GL_KEEP; 576 ctx->Stencil.ZPassFunc[0] = GL_KEEP; 577 ctx->Stencil.ZPassFunc[1] = GL_KEEP; 578 ctx->Stencil.ZPassFunc[2] = GL_KEEP; 579 ctx->Stencil.ZFailFunc[0] = GL_KEEP; 580 ctx->Stencil.ZFailFunc[1] = GL_KEEP; 581 ctx->Stencil.ZFailFunc[2] = GL_KEEP; 582 ctx->Stencil.Ref[0] = 0; 583 ctx->Stencil.Ref[1] = 0; 584 ctx->Stencil.Ref[2] = 0; 585 ctx->Stencil.ValueMask[0] = ~0U; 586 ctx->Stencil.ValueMask[1] = ~0U; 587 ctx->Stencil.ValueMask[2] = ~0U; 588 ctx->Stencil.WriteMask[0] = ~0U; 589 ctx->Stencil.WriteMask[1] = ~0U; 590 ctx->Stencil.WriteMask[2] = ~0U; 591 ctx->Stencil.Clear = 0; 592 ctx->Stencil._BackFace = 1; 593} 594