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