0023012: Detection gives incorrect results
[occt.git] / src / OpenGl / OpenGl_Polygon.cxx
CommitLineData
b311480e 1// Created on: 2011-07-13
2// Created by: Sergey ZERCHANINOV
3// Copyright (c) 2011-2012 OPEN CASCADE SAS
4//
5// The content of this file is subject to the Open CASCADE Technology Public
6// License Version 6.5 (the "License"). You may not use the content of this file
7// except in compliance with the License. Please obtain a copy of the License
8// at http://www.opencascade.org and read it completely before using this file.
9//
10// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12//
13// The Original Code and all software distributed under the License is
14// distributed on an "AS IS" basis, without warranty of any kind, and the
15// Initial Developer hereby disclaims all such warranties, including without
16// limitation, any warranties of merchantability, fitness for a particular
17// purpose or non-infringement. Please see the License for the specific terms
18// and conditions governing the rights and limitations under the License.
19
2166f0fa 20
5f8b738e 21#include <OpenGl_GlCore11.hxx>
2166f0fa
SK
22
23#include <OpenGl_Polygon.hxx>
24
2166f0fa
SK
25#include <OpenGl_telem_util.hxx>
26#include <OpenGl_TextureBox.hxx>
27#include <OpenGl_Memory.hxx>
28
29#include <OpenGl_AspectFace.hxx>
30#include <OpenGl_Structure.hxx>
31
32#include <GL/glu.h>
33
34#if (defined(_WIN32) || defined(__WIN32__))
35 #define STATIC
36#else
37 #define STATIC static
38#endif
39
40struct EXTRA_VERTEX
41{
42 GLfloat vert[3];
43 int ind;
1c35b92f 44 DEFINE_STANDARD_ALLOC
2166f0fa
SK
45};
46typedef EXTRA_VERTEX* extra_vertex;
47
48struct SEQ_
49{
50 Tint ts_num, ts_alloc;
51 void **tmesh_sequence;
52 GLenum triangle_type; /* FSXXX OPTI */
1c35b92f 53 DEFINE_STANDARD_ALLOC
2166f0fa
SK
54};
55
56struct OPENGL_DISPLAY_PGN
57{
58 Tint num_of_seq;
59 Tint num_alloc;
60 SEQ_ *seq;
1c35b92f 61 DEFINE_STANDARD_ALLOC
2166f0fa
SK
62};
63
64static void bgntriangulate( const TEL_POLYGON_DATA *, void (APIENTRY*)() );
65static void endtriangulate(void);
66
67#ifndef GLU_VERSION_1_2
68 #define GLUtesselator GLUtriangulatorObj
69 void gluTessBeginContour();
70 void gluTessBeginPolygon();
71 void gluTessEndPolygon();
72 void gluTessEndContour();
73 #define GLU_TESS_BEGIN 100100
74 #define GLU_TESS_VERTEX 100101
75 #define GLU_TESS_END 100102
76 #define GLU_TESS_ERROR 100103
77 #define GLU_TESS_COMBINE 100105
78#endif
79
80/*----------------------------------------------------------------------*/
81
82void OpenGl_Polygon::draw_polygon (const Handle(OpenGl_Workspace) &AWorkspace, Tint front_lighting_model) const
83{
84 Tint i;
85
86 tel_point ptr;
87 tel_point pvn;
88 tel_colour pfc, pvc;
89 tel_texture_coord pvt;
90
91 pfc = myData.fcolour;
92 pvc = myData.vcolours;
93 pvn = myData.vnormals;
94 pvt = myData.vtexturecoord;
95
96 if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
97 pvc = pfc = NULL;
98
99 ptr = myData.vertices;
100 if ( pfc )
101 glColor3fv( pfc->rgb );
102 if ( front_lighting_model )
103 glNormal3fv( myData.fnormal.xyz );
104
105 if( myData.reverse_order ) glFrontFace( GL_CW );
106
107 if (myData.num_vertices == 3) glBegin(GL_TRIANGLES);
108 else if(myData.num_vertices == 4) glBegin(GL_QUADS);
109 else glBegin(GL_POLYGON);
110 if( front_lighting_model )
111 {
112 if( pvn )
113 {
114 if (pvt && (AWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
115 for( i=0; i<myData.num_vertices; i++, ptr++ )
116 {
117 glNormal3fv( pvn[i].xyz );
118 glTexCoord2fv( pvt[i].xy );
119 glVertex3fv( ptr->xyz );
120 }
121 else
122 for( i=0; i<myData.num_vertices; i++, ptr++ )
123 {
124 glNormal3fv( pvn[i].xyz );
125 glVertex3fv( ptr->xyz );
126 }
127 }
128 else
129 {
130 for( i=0; i<myData.num_vertices; i++, ptr++ )
131 {
132 glVertex3fv( ptr->xyz );
133 }
134 }
135 }
136 else
137 {
138 if( pvc )
139 {
140 for( i=0; i<myData.num_vertices; i++, ptr++ )
141 {
142 glColor3fv( pvc[i].rgb );
143 glVertex3fv( ptr->xyz );
144 }
145 }
146 else
147 {
148 for( i=0; i<myData.num_vertices; i++, ptr++ )
149 {
150 glVertex3fv( ptr->xyz );
151 }
152 }
153 }
154 glEnd();
155 if( myData.reverse_order ) glFrontFace( GL_CCW );
156
157}
158
159/*----------------------------------------------------------------------*/
160
161/* JWR - allow varying the size */
162
163#define INCREMENT 8
164
165static int seq_increment = INCREMENT;
166
167static const TEL_POLYGON_DATA *DaTa;
168static GLUtesselator *tripak = 0;
169
170STATIC void APIENTRY
171out_bgntmesh( GLenum triangle_type )
172{
173 OPENGL_DISPLAY_PGN *dis = DaTa->dsply;
174
175 dis->num_of_seq++;
176 if( dis->num_alloc < dis->num_of_seq )
177 {
178 dis->num_alloc += seq_increment;
179
180 if( dis->seq == 0 )
181 {
182 dis->seq = new SEQ_[dis->num_alloc];
183 }
184 else
185 {
186#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
187 dis->seq = (SEQ_*)realloc( dis->seq, dis->num_alloc*sizeof(SEQ_) );
188#else
189 dis->seq = cmn_resizemem<SEQ_>( dis->seq, dis->num_alloc );
190#endif
191 }
192 }
193 dis->seq[ dis->num_of_seq - 1 ].ts_num = 0;
194 dis->seq[ dis->num_of_seq - 1 ].ts_alloc = 0;
195 dis->seq[ dis->num_of_seq - 1 ].tmesh_sequence = 0;
196
197#ifdef JWR_DEC_TRIFAN_BUG
198 dis->seq[ dis->num_of_seq - 1 ].triangle_type = GL_POLYGON;
199 glBegin(GL_POLYGON);
200#else
201 dis->seq[ dis->num_of_seq - 1 ].triangle_type = triangle_type;
202 glBegin(triangle_type);
203#endif
204}
205
206/*----------------------------------------------------------------------*/
207
208STATIC void APIENTRY
209out_vert1( void *data )
210{
211 SEQ_ *s = &( DaTa->dsply->seq[ DaTa->dsply->num_of_seq - 1 ] );
212
213 s->ts_num++;
214 if( s->ts_alloc < s->ts_num )
215 {
216 s->ts_alloc += seq_increment;
217
218 if( s->tmesh_sequence == 0 )
219 {
220 s->tmesh_sequence = new void*[s->ts_alloc];
221 }
222 else
223 {
224#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
225 s->tmesh_sequence = (void**)realloc( s->tmesh_sequence, s->ts_alloc*sizeof(void*));
226#else
227 s->tmesh_sequence = cmn_resizemem<void*>( s->tmesh_sequence, s->ts_alloc);
228#endif
229 }
230 }
231 s->tmesh_sequence[ s->ts_num - 1 ] = data;
232
233
234 if ( data < (void *)0xffff ) {
235 long a = (long)data;
236
237 glVertex3fv( DaTa->vertices[a].xyz );
238 }
239 else {
240 extra_vertex b = (extra_vertex) data;
241
242 glVertex3fv( b->vert );
243 }
244
245}
246
247/*----------------------------------------------------------------------*/
248
249STATIC void APIENTRY
250out_vert2( void *data )
251{
252 SEQ_ *s = &( DaTa->dsply->seq[ DaTa->dsply->num_of_seq - 1 ] );
253
254 s->ts_num++;
255 if( s->ts_alloc < s->ts_num )
256 {
257 s->ts_alloc += seq_increment;
258
259 if( s->tmesh_sequence == 0 )
260 {
261 s->tmesh_sequence = new void*[s->ts_alloc];
262 }
263 else
264 {
265#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
266 s->tmesh_sequence = (void**)( s->tmesh_sequence, s->ts_alloc*sizeof(void*) );
267#else
268 s->tmesh_sequence = cmn_resizemem<void*>( s->tmesh_sequence, s->ts_alloc );
269#endif
270 }
271 }
272 s->tmesh_sequence[ s->ts_num - 1 ] = data;
273
274 if ( data < (void *)0xffff ) {
275 long a = (long)data;
276
277 glColor3fv( DaTa->vcolours[a].rgb );
278 glVertex3fv( DaTa->vertices[a].xyz );
279 }
280 else {
281 extra_vertex b = (extra_vertex) data;
282
283 glColor3fv( DaTa->vcolours[(b->ind)].rgb );
284 glVertex3fv( b->vert );
285 }
286}
287
288/*----------------------------------------------------------------------*/
289
290STATIC void APIENTRY
291out_vert3( void *data )
292{
293 SEQ_ *s = &( DaTa->dsply->seq[ DaTa->dsply->num_of_seq - 1 ] );
294
295 s->ts_num++;
296 if( s->ts_alloc < s->ts_num )
297 {
298 s->ts_alloc += seq_increment;
299
300 if( s->tmesh_sequence == 0 )
301 {
302 s->tmesh_sequence = new void*[s->ts_alloc];
303 }
304 else
305 {
306#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
307 s->tmesh_sequence = (void**)realloc( s->tmesh_sequence, s->ts_alloc*sizeof(void*) );
308#else
309 s->tmesh_sequence = cmn_resizemem<void*>( s->tmesh_sequence, s->ts_alloc );
310#endif
311 }
312 }
313 s->tmesh_sequence[ s->ts_num - 1 ] = data;
314
315 if ( data <= (void *)0xffff ) {
316 long a = (long)data;
317
318 glNormal3fv( DaTa->vnormals[a].xyz );
319 glVertex3fv( DaTa->vertices[a].xyz);
320 }
321 else {
322 extra_vertex b = (extra_vertex) data;
323
324 glNormal3fv( DaTa->vnormals[(b->ind)].xyz );
325 glVertex3fv( b->vert );
326 }
327}
328
329/*----------------------------------------------------------------------*/
330
331STATIC void APIENTRY
332mycombine( GLdouble coords[3], int *data, GLfloat w[4], void **dataout)
333{
334 extra_vertex new_vertex = (extra_vertex) malloc(sizeof(EXTRA_VERTEX));
335
336 new_vertex->vert[0] = ( float )coords[0];
337 new_vertex->vert[1] = ( float )coords[1];
338 new_vertex->vert[2] = ( float )coords[2];
339 new_vertex->ind = *data;
340 *dataout = new_vertex;
341}
342
343/*----------------------------------------------------------------------*/
344
345STATIC void APIENTRY
346out_endtmesh( void )
347{
348 glEnd();
349}
350
351/*----------------------------------------------------------------------*/
352
353STATIC void APIENTRY
354out_error( GLenum error )
355{
356 printf( "POLYGON : %s\n", (char *) gluErrorString(error) );
357}
358
359/*----------------------------------------------------------------------*/
360
361static void
362bgntriangulate(const TEL_POLYGON_DATA *d, void ( APIENTRY * out_ver)() )
363{
364 DaTa = d;
365
366 tripak = gluNewTess();
367
368#if defined(linux) && !defined(NOGLUfuncptr)
369 gluTessCallback( tripak, GLU_TESS_BEGIN, (_GLUfuncptr)(out_bgntmesh) );
370 gluTessCallback( tripak, GLU_TESS_VERTEX, out_ver );
371 gluTessCallback( tripak, GLU_TESS_END, out_endtmesh );
372 gluTessCallback( tripak, GLU_TESS_ERROR, (_GLUfuncptr)(out_error) );
373 gluTessCallback( tripak, GLU_TESS_COMBINE, (_GLUfuncptr)(mycombine) );
374#else
375 gluTessCallback( tripak, GLU_TESS_BEGIN, (void (APIENTRY*)())out_bgntmesh );
376 gluTessCallback( tripak, GLU_TESS_VERTEX, (void (APIENTRY*)())out_ver );
377 gluTessCallback( tripak, GLU_TESS_END, (void (APIENTRY*)())out_endtmesh );
378 gluTessCallback( tripak, GLU_TESS_ERROR, (void (APIENTRY*)())out_error );
379 gluTessCallback( tripak, GLU_TESS_COMBINE, (void (APIENTRY*)())mycombine );
380#endif
381}
382
383/*----------------------------------------------------------------------*/
384
385static void
386endtriangulate()
387{
388 DaTa = 0;
389 gluDeleteTess(tripak);
390}
391
392/*----------------------------------------------------------------------*/
393
394void OpenGl_Polygon::draw_polygon_concav (const Handle(OpenGl_Workspace) &AWorkspace, Tint front_lighting_model) const
395{
396 long i;
397
398 tel_point pvn;
399 tel_point ptr;
400 tel_colour pfc, pvc;
401 GLdouble xyz[3];
402
403 pfc = myData.fcolour;
404 pvc = myData.vcolours;
405 pvn = myData.vnormals;
406
407 if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
408 pvc = pfc = NULL;
409
410 ptr = myData.vertices;
411 DaTa = &myData;
412
413 if ( pfc )
414 glColor3fv( pfc->rgb );
415 if ( front_lighting_model )
416 glNormal3fv( myData.fnormal.xyz );
417
418 if( myData.reverse_order ) glFrontFace( GL_CW );
419
420 if( !myData.dsply )
421 {
422 if( front_lighting_model )
423 {
424 if( pvn )
425 {
426 bgntriangulate(&myData, (void (APIENTRY*)())out_vert3);
427 }
428 else
429 {
430 bgntriangulate(&myData, (void (APIENTRY*)())out_vert1);
431 }
432 }
433 else
434 {
435 if( pvc )
436 {
437 bgntriangulate(&myData, (void (APIENTRY*)())out_vert2);
438 }
439 else
440 {
441 bgntriangulate(&myData, (void (APIENTRY*)())out_vert1);
442 }
443 }
444 gluTessBeginPolygon( tripak, NULL );
445 gluTessBeginContour( tripak);
446
447 for( i=0; i<myData.num_vertices; i++, ptr++ )
448 {
449 xyz[0] = ptr->xyz[0];
450 xyz[1] = ptr->xyz[1];
451 xyz[2] = ptr->xyz[2];
452#ifndef WNT
453 gluTessVertex( tripak, xyz,(void * ) i );
454#else
455 {
456 double v[ 3 ] = {ptr -> xyz[ 0 ], ptr -> xyz[ 1 ], ptr -> xyz[ 2 ]};
457 gluTessVertex ( tripak, v, ( void* )i );
458 }
459#endif /* WNT */
460 }
461 gluTessEndContour( tripak );
462 gluTessEndPolygon( tripak );
463 endtriangulate();
464 }
465 else
466 {
467 if( front_lighting_model )
468 {
469 draw_tmesh( pvn? 3 : 1 );
470 }
471 else
472 {
473 draw_tmesh( pvc? 2 : 1 );
474 }
475 }
476
477 if( myData.reverse_order ) glFrontFace( GL_CCW );
478}
479
480/*----------------------------------------------------------------------*/
481
482void OpenGl_Polygon::draw_edges (const TEL_COLOUR *edge_colour, const Aspect_InteriorStyle interior_style, const Handle(OpenGl_Workspace) &AWorkspace) const
483{
484 const OpenGl_AspectFace *aspect_face = AWorkspace->AspectFace( Standard_True );
485
486 if ( interior_style != Aspect_IS_HIDDENLINE && aspect_face->Context().Edge == TOff )
487 return;
488
489 glDisable(GL_LIGHTING);
490 const GLboolean texture_on = IsTextureEnabled();
491 if (texture_on) DisableTexture();
492
493 // Setup line aspect
494 const OpenGl_AspectLine *aspect_line_old = AWorkspace->SetAspectLine( aspect_face->AspectEdge() );
495 AWorkspace->AspectLine( Standard_True );
496
497 Tint i;
498 tel_point ptr = myData.vertices;
499
500 glColor3fv( edge_colour->rgb );
501
502 glBegin(GL_LINE_LOOP);
503 for( i=0; i<myData.num_vertices; i++, ptr++ )
504 {
505 glVertex3fv( ptr->xyz );
506 }
507 glEnd();
508
509 // Restore line context
510 AWorkspace->SetAspectLine( aspect_line_old );
511
512 if (texture_on) EnableTexture();
513}
514
515/*----------------------------------------------------------------------*/
516
517void OpenGl_Polygon::draw_tmesh ( Tint v ) const
518{
519 Tint i, j, k;
520 SEQ_ *s;
521 extra_vertex b;
522
523 OPENGL_DISPLAY_PGN *dis = myData.dsply;
524 for( i = 0; i < dis->num_of_seq; i++ )
525 {
526 s = &(dis->seq[i]);
527
528 glBegin(s->triangle_type);
529 switch( v )
530 {
531 case 1:
532 {
533 for( j = 0, k = 0; j < s->ts_num; j++ )
534 {
535 if ( s->tmesh_sequence[j] < (void *)0xffff )
536 glVertex3fv( myData.vertices[ (long)s->tmesh_sequence[ j ] ].xyz );
537 else {
538 extra_vertex b = (extra_vertex)s->tmesh_sequence[j];
539 glVertex3fv( b->vert );
540 }
541
542 }
543 break;
544 }
545 case 2:
546 {
547 for( j = 0, k = 0; j < s->ts_num; j++ )
548 {
549 if ( s->tmesh_sequence[j] < (void *)0xffff ) {
550 glColor3fv( myData.vcolours[ (long) s->tmesh_sequence[ j ] ].rgb );
551 glVertex3fv( myData.vertices[ (long) s->tmesh_sequence[ j ] ].xyz );
552 } else {
553 b = (extra_vertex) s->tmesh_sequence[j];
554 glColor3fv( myData.vcolours[(b->ind)].rgb);
555 glVertex3fv( b->vert );
556 }
557 }
558 break;
559 }
560 case 3:
561 {
562 for( j = 0, k = 0; j < s->ts_num; j++ )
563 {
564 if ( s->tmesh_sequence[j] < (void *)0xffff ) {
565 glNormal3fv( myData.vnormals[ (long) s->tmesh_sequence[ j ] ].xyz);
566 glVertex3fv( myData.vertices[ (long) s->tmesh_sequence[ j ] ].xyz);
567 } else {
568 b = (extra_vertex) s->tmesh_sequence[j];
569 glNormal3fv( myData.vnormals[(b->ind)].xyz);
570 glVertex3fv( b->vert );
571 }
572 }
573 break;
574 }
575 }
576 glEnd();
577 }
578}
579
580/*----------------------------------------------------------------------*/
581
582OpenGl_Polygon::OpenGl_Polygon (const Graphic3d_Array1OfVertex& AListVertex,
583 const Graphic3d_TypeOfPolygon AType)
584{
585 const Standard_Integer nv = AListVertex.Length();
586
587 myData.num_vertices = nv;
588
589 myData.vertices = new TEL_POINT[nv];
590 memcpy( myData.vertices, &AListVertex(AListVertex.Lower()), nv*sizeof(TEL_POINT) );
591
592 myData.vertex_flag = TEL_VT_NONE;
593 myData.vnormals = NULL;
594
595 myData.vcolours = NULL;
596
597 myData.vtexturecoord = NULL;
598
599 myData.reverse_order = 0;
600
601 myData.facet_flag = TEL_FA_NONE;
602 TelGetPolygonNormal( myData.vertices, NULL, nv, myData.fnormal.xyz );
603
604 myData.fcolour = NULL;
605
606#if defined(__sgi) || defined(IRIX)
607 // Pb with tesselator on sgi
608 myData.shape_flag = TEL_SHAPE_CONVEX;
609#else
610 switch (AType)
611 {
612 case Graphic3d_TOP_UNKNOWN :
613 myData.shape_flag = TEL_SHAPE_UNKNOWN;
614 break;
615 case Graphic3d_TOP_COMPLEX :
616 myData.shape_flag = TEL_SHAPE_COMPLEX;
617 break;
618 case Graphic3d_TOP_CONCAVE :
619 myData.shape_flag = TEL_SHAPE_CONCAVE;
620 break;
621 //case Graphic3d_TOP_CONVEX :
622 default :
623 myData.shape_flag = TEL_SHAPE_CONVEX;
624 break;
625 }
626#endif
627
628 myData.dsply = new OPENGL_DISPLAY_PGN();
629 myData.dsply->num_of_seq = 0;
630 myData.dsply->num_alloc = 0;
631 myData.dsply->seq = NULL;
632}
633
634/*----------------------------------------------------------------------*/
635
636OpenGl_Polygon::~OpenGl_Polygon ()
637{
638 if( myData.fcolour )
639 delete myData.fcolour;
640 if( myData.vertices )
641 delete[] myData.vertices;
642 if( myData.vcolours )
643 delete[] myData.vcolours;
644 if( myData.vnormals )
645 delete[] myData.vnormals;
646 if ( myData.vtexturecoord )
647 delete myData.vtexturecoord;
648
649 if ( myData.dsply )
650 {
651 Tint i, j;
652
653 for( i = 0; i < myData.dsply->num_of_seq; i++ )
654 {
655 if(myData.dsply->seq[i].tmesh_sequence) {
656 for ( j = 0; j < myData.dsply->seq[i].ts_num ; j++ ) {
657 if ( myData.dsply->seq[i].tmesh_sequence[j] >= (void *)0xffff )
658 free(myData.dsply->seq[i].tmesh_sequence[j]);
659 }
660 }
661 delete[] myData.dsply->seq[i].tmesh_sequence;
662 }
663 delete[] myData.dsply->seq;
664 delete myData.dsply;
665 }
666}
667
668/*----------------------------------------------------------------------*/
669
670void OpenGl_Polygon::Render (const Handle(OpenGl_Workspace) &AWorkspace) const
671{
672 const OpenGl_AspectFace *aspect_face = AWorkspace->AspectFace( Standard_True );
673
674 Tint front_lighting_model = aspect_face->Context().IntFront.color_mask;
675 const Aspect_InteriorStyle interior_style = aspect_face->Context().InteriorStyle;
676 const TEL_COLOUR *interior_colour = &aspect_face->Context().IntFront.matcol;
677 const TEL_COLOUR *edge_colour = &aspect_face->AspectEdge()->Color();
678
679 // Use highlight colous
680 if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
681 {
682 edge_colour = interior_colour = AWorkspace->HighlightColor;
683 front_lighting_model = 0;
684 }
685
686 if( interior_style != Aspect_IS_EMPTY && AWorkspace->DegenerateModel < 2 )
687 {
688 if ( front_lighting_model )
689 glEnable(GL_LIGHTING);
690 else
691 glDisable(GL_LIGHTING);
692
693 glColor3fv( interior_colour->rgb );
694
695 if( myData.shape_flag != TEL_SHAPE_CONVEX )
696 draw_polygon_concav( AWorkspace, front_lighting_model );
697 else
698 draw_polygon( AWorkspace, front_lighting_model );
699 }
700
701 /* OCC11904 -- Temporarily disable environment mapping */
702 glPushAttrib(GL_ENABLE_BIT);
703 glDisable(GL_TEXTURE_1D);
704 glDisable(GL_TEXTURE_2D);
705
706 switch ( AWorkspace->DegenerateModel )
707 {
708 default:
709 draw_edges ( edge_colour, interior_style, AWorkspace );
710 break;
711 case 3: /* marker degeneration */
712 break;
713 }
714
715 glPopAttrib(); /* skt: GL_ENABLE_BIT*/
716}
717
718/*----------------------------------------------------------------------*/