0023457: Slow text rendering
[occt.git] / src / OpenGl / OpenGl_Polygon.cxx
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
20 #include <OpenGl_GlCore11.hxx>
21
22 #include <OpenGl_Polygon.hxx>
23
24 #include <OpenGl_telem_util.hxx>
25
26 #include <OpenGl_AspectFace.hxx>
27 #include <OpenGl_Structure.hxx>
28 #include <OpenGl_Workspace.hxx>
29
30 #if (defined(_WIN32) || defined(__WIN32__))
31   #define STATIC
32 #else
33   #define STATIC static
34 #endif
35
36 struct EXTRA_VERTEX
37 {
38   GLfloat vert[3];
39   int ind;
40   DEFINE_STANDARD_ALLOC
41 };
42 typedef EXTRA_VERTEX* extra_vertex;
43
44 struct SEQ_
45 {
46   NCollection_Vector<void *> tmesh_sequence;
47   GLenum triangle_type; /* FSXXX OPTI */
48   DEFINE_STANDARD_ALLOC
49 };
50
51 static void bgntriangulate( const TEL_POLYGON_DATA *, void (APIENTRY*)() );
52 static void endtriangulate(void);
53
54 #ifndef GLU_VERSION_1_2
55   #define GLUtesselator GLUtriangulatorObj
56   void gluTessBeginContour();
57   void gluTessBeginPolygon();
58   void gluTessEndPolygon();
59   void gluTessEndContour();
60   #define GLU_TESS_BEGIN   100100
61   #define GLU_TESS_VERTEX  100101
62   #define GLU_TESS_END     100102
63   #define GLU_TESS_ERROR   100103
64   #define GLU_TESS_COMBINE 100105
65 #endif
66
67 /*----------------------------------------------------------------------*/
68
69 void OpenGl_Polygon::draw_polygon (const Handle(OpenGl_Workspace) &AWorkspace, Tint front_lighting_model) const
70 {
71   Tint      i;
72
73   tel_point ptr;
74   tel_point  pvn;
75   tel_colour pfc, pvc;
76   tel_texture_coord pvt;
77
78   pfc = myData.fcolour;
79   pvc = myData.vcolours;
80   pvn = myData.vnormals;
81   pvt = myData.vtexturecoord;
82
83   if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
84     pvc = pfc = NULL;
85
86   ptr = myData.vertices;
87   if ( pfc )
88     glColor3fv( pfc->rgb );
89   if ( front_lighting_model )
90     glNormal3fv( myData.fnormal.xyz );
91
92   if( myData.reverse_order ) glFrontFace( GL_CW );
93
94   if (myData.num_vertices == 3) glBegin(GL_TRIANGLES);
95   else if(myData.num_vertices == 4) glBegin(GL_QUADS);
96   else glBegin(GL_POLYGON);
97   if( front_lighting_model )
98   {
99     if( pvn )
100     {
101       if (pvt && (AWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
102         for( i=0; i<myData.num_vertices; i++, ptr++ )
103         {
104           glNormal3fv( pvn[i].xyz );
105           glTexCoord2fv( pvt[i].xy );
106           glVertex3fv( ptr->xyz );
107         }
108       else
109         for( i=0; i<myData.num_vertices; i++, ptr++ )
110         {
111           glNormal3fv( pvn[i].xyz );
112           glVertex3fv( ptr->xyz );
113         }
114     }
115     else
116     {
117       for( i=0; i<myData.num_vertices; i++, ptr++ )
118       {
119         glVertex3fv( ptr->xyz );
120       }
121     }
122   }
123   else
124   {
125     if( pvc )
126     {
127       for( i=0; i<myData.num_vertices; i++, ptr++ )
128       {
129         glColor3fv( pvc[i].rgb );
130         glVertex3fv( ptr->xyz );
131       }
132     }
133     else
134     {
135       for( i=0; i<myData.num_vertices; i++, ptr++ )
136       {
137         glVertex3fv( ptr->xyz );
138       }
139     }
140   }
141   glEnd();
142   if( myData.reverse_order ) glFrontFace( GL_CCW );
143
144 }
145
146 /*----------------------------------------------------------------------*/
147
148 /* JWR - allow varying the size */
149
150 static const TEL_POLYGON_DATA *DaTa;
151 static GLUtesselator *tripak = 0;
152
153 STATIC void APIENTRY
154 out_bgntmesh( GLenum triangle_type )
155 {
156   NCollection_Vector<SEQ_> *dis = DaTa->dsply;
157
158   SEQ_ aSeq;
159 #ifdef JWR_DEC_TRIFAN_BUG
160   aSeq.triangle_type = GL_POLYGON;
161   dis->Append(aSeq);
162   glBegin(GL_POLYGON);
163 #else
164   aSeq.triangle_type = triangle_type;
165   dis->Append(aSeq);
166   glBegin(triangle_type);
167 #endif
168 }
169
170 /*----------------------------------------------------------------------*/
171
172 STATIC void APIENTRY
173 out_vert1( void *data )
174 {
175   SEQ_ &s = DaTa->dsply->ChangeValue(DaTa->dsply->Length() - 1);
176
177   s.tmesh_sequence.Append(data);
178
179   if ( data < (void *)0xffff ) {
180     long a = (long)data;
181
182     glVertex3fv( DaTa->vertices[a].xyz );
183   }
184   else {
185     extra_vertex b = (extra_vertex) data;
186
187     glVertex3fv( b->vert );
188   }
189
190 }
191
192 /*----------------------------------------------------------------------*/
193
194 STATIC void APIENTRY
195 out_vert2( void *data )
196 {
197   SEQ_ &s = DaTa->dsply->ChangeValue(DaTa->dsply->Length() - 1);
198
199   s.tmesh_sequence.Append(data);
200
201   if ( data < (void *)0xffff ) {
202     long a = (long)data;
203
204     glColor3fv( DaTa->vcolours[a].rgb );
205     glVertex3fv(  DaTa->vertices[a].xyz );
206   }
207   else {
208     extra_vertex b = (extra_vertex) data;
209
210     glColor3fv( DaTa->vcolours[(b->ind)].rgb );
211     glVertex3fv( b->vert );
212   }
213 }
214
215 /*----------------------------------------------------------------------*/
216
217 STATIC void APIENTRY
218 out_vert3( void *data )
219 {
220   SEQ_ &s = DaTa->dsply->ChangeValue(DaTa->dsply->Length() - 1);
221
222   s.tmesh_sequence.Append(data);
223
224   if ( data <= (void *)0xffff ) {
225     long a = (long)data;
226
227     glNormal3fv(  DaTa->vnormals[a].xyz );
228     glVertex3fv(  DaTa->vertices[a].xyz);
229   }
230   else {
231     extra_vertex b = (extra_vertex) data;
232
233     glNormal3fv(  DaTa->vnormals[(b->ind)].xyz );
234     glVertex3fv( b->vert );
235   }
236 }
237
238 /*----------------------------------------------------------------------*/
239
240 STATIC void APIENTRY
241 mycombine( GLdouble coords[3], int *data, GLfloat w[4], void **dataout)
242 {
243   extra_vertex new_vertex = new EXTRA_VERTEX();
244
245   new_vertex->vert[0] = ( float )coords[0];
246   new_vertex->vert[1] = ( float )coords[1];
247   new_vertex->vert[2] = ( float )coords[2];
248   new_vertex->ind =   *data;
249   *dataout = new_vertex;
250 }
251
252 /*----------------------------------------------------------------------*/
253
254 STATIC void APIENTRY
255 out_endtmesh( void )
256 {
257   glEnd();
258 }
259
260 /*----------------------------------------------------------------------*/
261
262 STATIC void APIENTRY
263 out_error( GLenum error )
264 {
265   printf( "POLYGON : %s\n", (char *) gluErrorString(error) );
266 }
267
268 /*----------------------------------------------------------------------*/
269
270 static void
271 bgntriangulate(const TEL_POLYGON_DATA *d, void ( APIENTRY * out_ver)() )
272 {
273   DaTa = d;
274
275   tripak = gluNewTess();
276
277 #if defined(linux) && !defined(NOGLUfuncptr)
278   gluTessCallback( tripak, GLU_TESS_BEGIN, (_GLUfuncptr)(out_bgntmesh) );
279   gluTessCallback( tripak, GLU_TESS_VERTEX, out_ver );
280   gluTessCallback( tripak, GLU_TESS_END, out_endtmesh );
281   gluTessCallback( tripak, GLU_TESS_ERROR, (_GLUfuncptr)(out_error) );
282   gluTessCallback( tripak, GLU_TESS_COMBINE, (_GLUfuncptr)(mycombine) );
283 #else
284   gluTessCallback( tripak, GLU_TESS_BEGIN, (void (APIENTRY*)())out_bgntmesh );
285   gluTessCallback( tripak, GLU_TESS_VERTEX, (void (APIENTRY*)())out_ver );
286   gluTessCallback( tripak, GLU_TESS_END, (void (APIENTRY*)())out_endtmesh );
287   gluTessCallback( tripak, GLU_TESS_ERROR, (void (APIENTRY*)())out_error );
288   gluTessCallback( tripak, GLU_TESS_COMBINE, (void (APIENTRY*)())mycombine );
289 #endif
290 }
291
292 /*----------------------------------------------------------------------*/
293
294 static void
295 endtriangulate()
296 {
297   DaTa = 0;
298   gluDeleteTess(tripak);
299 }
300
301 /*----------------------------------------------------------------------*/
302
303 void OpenGl_Polygon::draw_polygon_concav (const Handle(OpenGl_Workspace) &AWorkspace, Tint front_lighting_model) const
304 {
305   long       i;
306
307   tel_point  pvn;
308   tel_point  ptr;
309   tel_colour pfc, pvc;
310   GLdouble  xyz[3];
311
312   pfc = myData.fcolour;
313   pvc = myData.vcolours;
314   pvn = myData.vnormals;
315
316   if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
317     pvc = pfc = NULL;
318
319   ptr = myData.vertices;
320   DaTa = &myData;
321
322   if ( pfc )
323     glColor3fv( pfc->rgb );
324   if ( front_lighting_model )
325     glNormal3fv( myData.fnormal.xyz );
326
327   if( myData.reverse_order ) glFrontFace( GL_CW );
328
329   if( !myData.dsply )
330   {
331     if( front_lighting_model )
332     {
333       if( pvn )
334       {
335         bgntriangulate(&myData, (void (APIENTRY*)())out_vert3);
336       }
337       else
338       {
339         bgntriangulate(&myData, (void (APIENTRY*)())out_vert1);
340       }
341     }
342     else
343     {
344       if( pvc )
345       {
346         bgntriangulate(&myData, (void (APIENTRY*)())out_vert2);
347       }
348       else
349       {
350         bgntriangulate(&myData, (void (APIENTRY*)())out_vert1);
351       }
352     }
353     gluTessBeginPolygon( tripak, NULL );
354     gluTessBeginContour( tripak);
355
356     for( i=0; i<myData.num_vertices; i++, ptr++ )
357     {
358       xyz[0] = ptr->xyz[0];
359       xyz[1] = ptr->xyz[1];
360       xyz[2] = ptr->xyz[2];
361 #ifndef WNT
362       gluTessVertex( tripak, xyz,(void * ) i );
363 #else
364       {
365         double v[ 3 ] = {ptr -> xyz[ 0 ], ptr -> xyz[ 1 ], ptr -> xyz[ 2 ]};
366         gluTessVertex (  tripak,  v, ( void* )i  );
367       }
368 #endif  /* WNT */
369     }
370     gluTessEndContour( tripak );
371     gluTessEndPolygon( tripak );
372     endtriangulate();
373   }
374   else
375   {
376     if( front_lighting_model )
377     {
378       draw_tmesh( pvn? 3 : 1 );
379     }
380     else
381     {
382       draw_tmesh( pvc? 2 : 1 );
383     }
384   }
385
386   if( myData.reverse_order ) glFrontFace( GL_CCW );
387 }
388
389 /*----------------------------------------------------------------------*/
390
391 void OpenGl_Polygon::draw_edges (const TEL_COLOUR*               theEdgeColor,
392                                  const Aspect_InteriorStyle      theInteriorStyle,
393                                  const Handle(OpenGl_Workspace)& theWorkspace) const
394 {
395   const OpenGl_AspectFace* anAspectFace = theWorkspace->AspectFace (Standard_True);
396
397   if (theInteriorStyle != Aspect_IS_HIDDENLINE
398    && anAspectFace->Edge == TOff)
399   {
400     return;
401   }
402
403   glDisable (GL_LIGHTING);
404   const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
405
406   // Setup line aspect
407   const OpenGl_AspectLine* aPrevAspectLine = theWorkspace->SetAspectLine (anAspectFace->AspectEdge());
408   theWorkspace->AspectLine (Standard_True);
409
410   glColor3fv (theEdgeColor->rgb);
411
412   glBegin (GL_LINE_LOOP);
413   tel_point ptr = myData.vertices;
414   for (Tint i = 0; i < myData.num_vertices; i++, ptr++)
415   {
416     glVertex3fv (ptr->xyz);
417   }
418   glEnd();
419
420   // Restore line context
421   theWorkspace->SetAspectLine (aPrevAspectLine);
422
423   theWorkspace->EnableTexture (aPrevTexture);
424 }
425
426 /*----------------------------------------------------------------------*/
427
428 void OpenGl_Polygon::draw_tmesh ( Tint v ) const
429 {
430   Tint      i, j, k;
431   SEQ_     *s;
432   extra_vertex b;
433
434   NCollection_Vector<SEQ_> *dis = myData.dsply;
435   for( i = 0; i < dis->Length(); i++ )
436   {
437     s = &(dis->ChangeValue(i));
438
439     glBegin(s->triangle_type);
440     switch( v )
441     {
442     case 1:
443       {
444         for( j = 0, k = 0; j < s->tmesh_sequence.Length(); j++ )
445         {
446           if ( s->tmesh_sequence(j) < (void *)0xffff )
447             glVertex3fv( myData.vertices[ (long)s->tmesh_sequence.Value(j) ].xyz );
448           else {
449             b = (extra_vertex) s->tmesh_sequence(j);
450             glVertex3fv( b->vert );
451           }
452
453         }
454         break;
455       }
456     case 2:
457       {
458         for( j = 0, k = 0; j < s->tmesh_sequence.Length(); j++ )
459         {
460           if ( s->tmesh_sequence(j) < (void *)0xffff ) {
461             glColor3fv( myData.vcolours[ (long) s->tmesh_sequence(j) ].rgb );
462             glVertex3fv( myData.vertices[ (long) s->tmesh_sequence(j) ].xyz );
463           } else {
464             b = (extra_vertex) s->tmesh_sequence(j);
465             glColor3fv( myData.vcolours[(b->ind)].rgb);
466             glVertex3fv( b->vert );
467           }
468         }
469         break;
470       }
471     case 3:
472       {
473         for( j = 0, k = 0; j < s->tmesh_sequence.Length(); j++ )
474         {
475           if ( s->tmesh_sequence(j) < (void *)0xffff ) {
476             glNormal3fv( myData.vnormals[ (long) s->tmesh_sequence(j) ].xyz);
477             glVertex3fv( myData.vertices[ (long) s->tmesh_sequence(j) ].xyz);
478           } else {
479             b = (extra_vertex) s->tmesh_sequence(j);
480             glNormal3fv( myData.vnormals[(b->ind)].xyz);
481             glVertex3fv( b->vert );
482           }
483         }
484         break;
485       }
486     }
487     glEnd();
488   }
489 }
490
491 /*----------------------------------------------------------------------*/
492
493 OpenGl_Polygon::OpenGl_Polygon (const Graphic3d_Array1OfVertex& AListVertex,
494                               const Graphic3d_TypeOfPolygon AType)
495 {
496   const Standard_Integer nv = AListVertex.Length();
497
498   myData.num_vertices = nv;
499
500   myData.vertices = new TEL_POINT[nv];
501   memcpy( myData.vertices, &AListVertex(AListVertex.Lower()), nv*sizeof(TEL_POINT) );
502
503   myData.vertex_flag = TEL_VT_NONE;
504   myData.vnormals = NULL;
505
506   myData.vcolours = NULL;
507
508   myData.vtexturecoord = NULL;
509
510   myData.reverse_order = 0;
511
512   myData.facet_flag = TEL_FA_NONE;
513   TelGetPolygonNormal( myData.vertices, NULL, nv, myData.fnormal.xyz );
514
515   myData.fcolour = NULL;
516
517 #if defined(__sgi) || defined(IRIX)
518   // Pb with tesselator on sgi
519   myData.shape_flag = TEL_SHAPE_CONVEX;
520 #else
521   switch (AType)
522   {
523     case Graphic3d_TOP_UNKNOWN :
524       myData.shape_flag = TEL_SHAPE_UNKNOWN;
525       break;
526     case Graphic3d_TOP_COMPLEX :
527       myData.shape_flag = TEL_SHAPE_COMPLEX;
528       break;
529     case Graphic3d_TOP_CONCAVE :
530       myData.shape_flag = TEL_SHAPE_CONCAVE;
531       break;
532     //case Graphic3d_TOP_CONVEX :
533     default :
534       myData.shape_flag = TEL_SHAPE_CONVEX;
535       break;
536   }
537 #endif
538
539   myData.dsply = new NCollection_Vector<SEQ_>();
540 }
541
542 /*----------------------------------------------------------------------*/
543
544 OpenGl_Polygon::~OpenGl_Polygon ()
545 {
546   if( myData.fcolour )
547     delete myData.fcolour;
548   if( myData.vertices )
549     delete[] myData.vertices;
550   if( myData.vcolours )
551     delete[] myData.vcolours;
552   if( myData.vnormals )
553     delete[] myData.vnormals;
554   if ( myData.vtexturecoord )
555     delete myData.vtexturecoord;
556
557   if ( myData.dsply )
558   {
559     Tint i, j;
560
561     for( i = 0; i <  myData.dsply->Length(); i++ )
562     {
563       for ( j = 0; j < myData.dsply->Value(i).tmesh_sequence.Length() ; j++ )
564       {
565         if ( myData.dsply->Value(i).tmesh_sequence(j) >= (void *)0xffff )
566           delete myData.dsply->Value(i).tmesh_sequence(j);
567       }
568     }
569
570     delete myData.dsply;
571   }
572 }
573
574 /*----------------------------------------------------------------------*/
575
576 void OpenGl_Polygon::Render (const Handle(OpenGl_Workspace) &AWorkspace) const
577 {
578   const OpenGl_AspectFace *aspect_face = AWorkspace->AspectFace( Standard_True );
579
580   Tint front_lighting_model = aspect_face->IntFront.color_mask;
581   const Aspect_InteriorStyle interior_style = aspect_face->InteriorStyle;
582   const TEL_COLOUR *interior_colour = &aspect_face->IntFront.matcol;
583   const TEL_COLOUR *edge_colour = &aspect_face->AspectEdge()->Color();
584
585   // Use highlight colous
586   if ( AWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT )
587   {
588     edge_colour = interior_colour = AWorkspace->HighlightColor;
589     front_lighting_model = 0;
590   }
591
592   if( interior_style != Aspect_IS_EMPTY && AWorkspace->DegenerateModel < 2 )
593   {
594     if ( front_lighting_model )
595       glEnable(GL_LIGHTING);
596     else
597       glDisable(GL_LIGHTING);
598
599     glColor3fv( interior_colour->rgb );
600
601     if( myData.shape_flag != TEL_SHAPE_CONVEX )
602       draw_polygon_concav( AWorkspace, front_lighting_model );
603     else
604       draw_polygon( AWorkspace, front_lighting_model );
605   }
606
607   /* OCC11904 -- Temporarily disable environment mapping */
608   glPushAttrib(GL_ENABLE_BIT);
609   glDisable(GL_TEXTURE_1D);
610   glDisable(GL_TEXTURE_2D);
611
612   switch ( AWorkspace->DegenerateModel )
613   {
614     default:
615       draw_edges ( edge_colour, interior_style, AWorkspace );
616       break;
617     case 3:  /* marker degeneration */
618       break;
619   }
620
621   glPopAttrib(); /* skt: GL_ENABLE_BIT*/
622 }
623
624 void OpenGl_Polygon::Release (const Handle(OpenGl_Context)& theContext)
625 {
626   //
627 }