0024428: Implementation of LGPL license
[occt.git] / src / OpenGl / OpenGl_PrimitiveArray.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and / or modify it
8 // under the terms of the GNU Lesser General Public version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_AspectFace.hxx>
17 #include <OpenGl_Context.hxx>
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_IndexBuffer.hxx>
20 #include <OpenGl_PointSprite.hxx>
21 #include <OpenGl_PrimitiveArray.hxx>
22 #include <OpenGl_ShaderManager.hxx>
23 #include <OpenGl_ShaderProgram.hxx>
24 #include <OpenGl_Structure.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 #include <InterfaceGraphic_PrimitiveArray.hxx>
28
29 namespace
30 {
31   template<class T>
32   void BindProgramWithMaterial (const Handle(OpenGl_Workspace)& theWS,
33                                 const T*                      theAspect)
34   {
35     const Handle(OpenGl_Context)& aCtx = theWS->GetGlContext();
36     const Handle(OpenGl_ShaderProgram)& aProgram = theAspect->ShaderProgramRes (theWS);
37     if (aProgram.IsNull())
38     {
39       OpenGl_ShaderProgram::Unbind (aCtx);
40       return;
41     }
42     aProgram->BindWithVariables (aCtx);
43
44     const OpenGl_MaterialState* aMaterialState = aCtx->ShaderManager()->MaterialState (aProgram);
45     if (aMaterialState == NULL || aMaterialState->Aspect() != theAspect)
46     {
47       aCtx->ShaderManager()->UpdateMaterialStateTo (aProgram, theAspect);
48     }
49
50     aCtx->ShaderManager()->PushState (aProgram);
51   }
52 }
53
54 // =======================================================================
55 // function : clearMemoryOwn
56 // purpose  :
57 // =======================================================================
58 void OpenGl_PrimitiveArray::clearMemoryOwn() const
59 {
60   Standard::Free ((Standard_Address& )myPArray->edges);
61   Standard::Free ((Standard_Address& )myPArray->vertices);
62   Standard::Free ((Standard_Address& )myPArray->vcolours);
63   Standard::Free ((Standard_Address& )myPArray->vnormals);
64   Standard::Free ((Standard_Address& )myPArray->vtexels);
65   Standard::Free ((Standard_Address& )myPArray->edge_vis); /// ???
66
67   myPArray->edges    = NULL;
68   myPArray->vertices = NULL;
69   myPArray->vcolours = NULL;
70   myPArray->vnormals = NULL;
71   myPArray->vtexels  = NULL;
72   myPArray->edge_vis = NULL;
73 }
74
75 // =======================================================================
76 // function : clearMemoryGL
77 // purpose  :
78 // =======================================================================
79 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
80 {
81   for (Standard_Integer anIter = 0; anIter < VBOMaxType; ++anIter)
82   {
83     if (!myVbos[anIter].IsNull())
84     {
85       myVbos[anIter]->Release (theGlCtx.operator->());
86       myVbos[anIter].Nullify();
87     }
88   }
89 }
90
91 // =======================================================================
92 // function : BuildVBO
93 // purpose  :
94 // =======================================================================
95 Standard_Boolean OpenGl_PrimitiveArray::BuildVBO (const Handle(OpenGl_Workspace)& theWorkspace) const
96 {
97   const Handle(OpenGl_Context)& aGlCtx = theWorkspace->GetGlContext();
98   if (myPArray->vertices == NULL)
99   {
100     // vertices should be always defined - others are optional
101     return Standard_False;
102   }
103   myVbos[VBOVertices] = new OpenGl_VertexBuffer();
104   if (!myVbos[VBOVertices]->Init (aGlCtx, 3, myPArray->num_vertexs, &myPArray->vertices[0].xyz[0]))
105   {
106     clearMemoryGL (aGlCtx);
107     return Standard_False;
108   }
109
110   if (myPArray->edges != NULL
111    && myPArray->num_edges > 0)
112   {
113     myVbos[VBOEdges] = new OpenGl_IndexBuffer();
114     if (!myVbos[VBOEdges]->Init (aGlCtx, 1, myPArray->num_edges, (GLuint* )myPArray->edges))
115     {
116       clearMemoryGL (aGlCtx);
117       return Standard_False;
118     }
119   }
120   if (myPArray->vcolours != NULL)
121   {
122     myVbos[VBOVcolours] = new OpenGl_VertexBuffer();
123     if (!myVbos[VBOVcolours]->Init (aGlCtx, 4, myPArray->num_vertexs, (GLubyte* )myPArray->vcolours))
124     {
125       clearMemoryGL (aGlCtx);
126       return Standard_False;
127     }
128   }
129   if (myPArray->vnormals != NULL)
130   {
131     myVbos[VBOVnormals] = new OpenGl_VertexBuffer();
132     if (!myVbos[VBOVnormals]->Init (aGlCtx, 3, myPArray->num_vertexs, &myPArray->vnormals[0].xyz[0]))
133     {
134       clearMemoryGL (aGlCtx);
135       return Standard_False;
136     }
137   }
138   if (myPArray->vtexels)
139   {
140     myVbos[VBOVtexels] = new OpenGl_VertexBuffer();
141     if (!myVbos[VBOVtexels]->Init (aGlCtx, 2, myPArray->num_vertexs, &myPArray->vtexels[0].xy[0]))
142     {
143       clearMemoryGL (aGlCtx);
144       return Standard_False;
145     }
146   }
147
148   if (!aGlCtx->caps->keepArrayData)
149   {
150     clearMemoryOwn();
151   }
152   
153   return Standard_True;
154 }
155
156 // =======================================================================
157 // function : DrawArray
158 // purpose  :
159 // =======================================================================
160 void OpenGl_PrimitiveArray::DrawArray (Tint theLightingModel,
161                                        const Aspect_InteriorStyle theInteriorStyle,
162                                        Tint theEdgeFlag,
163                                        const TEL_COLOUR* theInteriorColour,
164                                        const TEL_COLOUR* theLineColour,
165                                        const TEL_COLOUR* theEdgeColour,
166                                        const OPENGL_SURF_PROP* theFaceProp,
167                                        const Handle(OpenGl_Workspace)& theWorkspace) const
168 {
169   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
170
171   Tint i,n;
172   Tint transp = 0;
173   // Following pointers have been provided for performance improvement
174   tel_colour pfc = myPArray->fcolours;
175   Tint* pvc = myPArray->vcolours;
176   if (pvc != NULL)
177   {
178     for (i = 0; i < myPArray->num_vertexs; ++i)
179     {
180       transp = int(theFaceProp->trans * 255.0f);
181     #if defined (sparc) || defined (__sparc__) || defined (__sparc)
182       pvc[i] = (pvc[i] & 0xffffff00);
183       pvc[i] += transp;
184     #else
185       pvc[i] = (pvc[i] & 0x00ffffff);
186       pvc[i] += transp << 24;
187     #endif
188     }
189   }
190
191   switch (myPArray->type)
192   {
193     case TelPointsArrayType:
194     case TelPolylinesArrayType:
195     case TelSegmentsArrayType:
196       glColor3fv (theLineColour->rgb);
197       break;
198     case TelPolygonsArrayType:
199     case TelTrianglesArrayType:
200     case TelQuadranglesArrayType:
201     case TelTriangleStripsArrayType:
202     case TelQuadrangleStripsArrayType:
203     case TelTriangleFansArrayType:
204       glColor3fv (theInteriorColour->rgb);
205       break;
206     case TelUnknownArrayType:
207       break;
208   }
209
210   // Temporarily disable environment mapping
211   if (myDrawMode <= GL_LINE_STRIP)
212   {
213     glPushAttrib (GL_ENABLE_BIT);
214     glDisable (GL_TEXTURE_1D);
215     glDisable (GL_TEXTURE_2D);
216   }
217
218   if ((myDrawMode >  GL_LINE_STRIP && theInteriorStyle != Aspect_IS_EMPTY) ||
219       (myDrawMode <= GL_LINE_STRIP))
220   {
221     if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
222     {
223       pfc = NULL;
224       pvc = NULL;
225     }
226
227     if (theInteriorStyle == Aspect_IS_HIDDENLINE)
228     {
229       theEdgeFlag = 1;
230       pfc = NULL;
231       pvc = NULL;
232     }
233
234     // Sometimes the GL_LIGHTING mode is activated here
235     // without glEnable(GL_LIGHTING) call for an unknown reason, so it is necessary
236     // to call glEnable(GL_LIGHTING) to synchronize Light On/Off mechanism*
237     if (theLightingModel == 0 || myDrawMode <= GL_LINE_STRIP)
238       glDisable (GL_LIGHTING);
239     else
240       glEnable (GL_LIGHTING);
241
242     if (!toDrawVbo())
243     {
244       if (myPArray->vertices != NULL)
245       {
246         glVertexPointer (3, GL_FLOAT, 0, myPArray->vertices); // array of vertices
247         glEnableClientState (GL_VERTEX_ARRAY);
248       }
249       if (myPArray->vnormals != NULL)
250       {
251         glNormalPointer (GL_FLOAT, 0, myPArray->vnormals); // array of normals
252         glEnableClientState (GL_NORMAL_ARRAY);
253       }
254       if (myPArray->vtexels != NULL)
255       {
256         glTexCoordPointer (2, GL_FLOAT, 0, myPArray->vtexels); // array of texture coordinates
257         glEnableClientState (GL_TEXTURE_COORD_ARRAY);
258       }
259
260       if ((pvc != NULL) && (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT) == 0)
261       {
262         glColorPointer (4, GL_UNSIGNED_BYTE, 0, pvc);  // array of colors
263         glEnableClientState (GL_COLOR_ARRAY);
264         glColorMaterial (GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
265         glEnable (GL_COLOR_MATERIAL);
266       }
267     }
268     else
269     {
270       // Bindings concrete pointer in accordance with VBO buffer
271       myVbos[VBOVertices]->BindFixed (aGlContext, GL_VERTEX_ARRAY);
272       if (!myVbos[VBOVnormals].IsNull())
273       {
274         myVbos[VBOVnormals]->BindFixed (aGlContext, GL_NORMAL_ARRAY);
275       }
276       if (!myVbos[VBOVtexels].IsNull() && (theWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
277       {
278         myVbos[VBOVtexels]->BindFixed (aGlContext, GL_TEXTURE_COORD_ARRAY);
279       }
280       if (!myVbos[VBOVcolours].IsNull() && (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT) == 0)
281       {
282         myVbos[VBOVcolours]->BindFixed (aGlContext, GL_COLOR_ARRAY);
283         glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
284         glEnable (GL_COLOR_MATERIAL);
285       }
286     }
287
288     /// OCC22236 NOTE: draw for all situations:
289     /// 1) draw elements from myPArray->bufferVBO[VBOEdges] indicies array
290     /// 2) draw elements from vertice array, when bounds defines count of primitive's verts.
291     /// 3) draw primitive by vertexes if no edges and bounds array is specified
292     if (toDrawVbo())
293     {
294       if (!myVbos[VBOEdges].IsNull())
295       {
296         myVbos[VBOEdges]->Bind (aGlContext);
297         if (myPArray->num_bounds > 0)
298         {
299           // draw primitives by vertex count with the indicies
300           Tint* anOffset = NULL;
301           for (i = 0; i < myPArray->num_bounds; ++i)
302           {
303             if (pfc != NULL) glColor3fv (pfc[i].rgb);
304             glDrawElements (myDrawMode, myPArray->bounds[i], myVbos[VBOEdges]->GetDataType(), anOffset);
305             anOffset += myPArray->bounds[i];
306           }
307         }
308         else
309         {
310           // draw one (or sequential) primitive by the indicies
311           glDrawElements (myDrawMode, myPArray->num_edges, myVbos[VBOEdges]->GetDataType(), NULL);
312         }
313         myVbos[VBOEdges]->Unbind (aGlContext);
314       }
315       else if (myPArray->num_bounds > 0)
316       {
317         for (i = n = 0; i < myPArray->num_bounds; ++i)
318         {
319           if (pfc != NULL) glColor3fv (pfc[i].rgb);
320           glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
321           n += myPArray->bounds[i];
322         }
323       }
324       else
325       {
326         if (myDrawMode == GL_POINTS)
327         {
328           DrawMarkers (theWorkspace);
329         }
330         else
331         {
332           glDrawArrays (myDrawMode, 0, myVbos[VBOVertices]->GetElemsNb());
333         }
334       }
335
336       // bind with 0
337       myVbos[VBOVertices]->UnbindFixed (aGlContext, GL_VERTEX_ARRAY);
338       if (!myVbos[VBOVnormals].IsNull())
339       {
340         myVbos[VBOVnormals]->UnbindFixed (aGlContext, GL_NORMAL_ARRAY);
341       }
342       if (!myVbos[VBOVtexels].IsNull() && (theWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
343       {
344         myVbos[VBOVtexels]->UnbindFixed (aGlContext, GL_TEXTURE_COORD_ARRAY);
345       }
346       if (!myVbos[VBOVcolours].IsNull())
347       {
348         myVbos[VBOVcolours]->UnbindFixed (aGlContext, GL_COLOR_ARRAY);
349         glDisable (GL_COLOR_MATERIAL);
350         theWorkspace->NamedStatus |= OPENGL_NS_RESMAT; // Reset material
351       }
352     }
353     else
354     {
355       if (myPArray->num_bounds > 0)
356       {
357         if (myPArray->num_edges > 0)
358         {
359           for (i = n = 0; i < myPArray->num_bounds; ++i)
360           {
361             if (pfc != NULL) glColor3fv (pfc[i].rgb);
362             glDrawElements (myDrawMode, myPArray->bounds[i], GL_UNSIGNED_INT, (GLenum* )&myPArray->edges[n]);
363             n += myPArray->bounds[i];
364           }
365         }
366         else
367         {
368           for (i = n = 0; i < myPArray->num_bounds; ++i)
369           {
370             if (pfc != NULL) glColor3fv (pfc[i].rgb);
371             glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
372             n += myPArray->bounds[i];
373           }
374         }
375       }
376       else if (myPArray->num_edges > 0)
377       {
378         glDrawElements (myDrawMode, myPArray->num_edges, GL_UNSIGNED_INT, (GLenum* )myPArray->edges);
379       }
380       else
381       {
382         if (myDrawMode == GL_POINTS)
383         {
384           DrawMarkers (theWorkspace);
385         }
386         else
387         {
388           glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
389         }
390       }
391
392       if (pvc != NULL)
393       {
394         glDisable (GL_COLOR_MATERIAL);
395         theWorkspace->NamedStatus |= OPENGL_NS_RESMAT; // Reset material
396       }
397
398       glDisableClientState (GL_VERTEX_ARRAY);
399       if (myPArray->vcolours != NULL)
400         glDisableClientState (GL_COLOR_ARRAY);
401       if (myPArray->vnormals != NULL)
402         glDisableClientState (GL_NORMAL_ARRAY);
403       if (myPArray->vtexels != NULL)
404         glDisableClientState (GL_TEXTURE_COORD_ARRAY);
405     }
406   }
407
408   // On some NVIDIA graphic cards, using glEdgeFlagPointer() in
409   // combination with VBO (edge flag data put into a VBO buffer)
410   // leads to a crash in a driver. Therefore, edge flags are simply
411   // igonored when VBOs are enabled, so all the edges are drawn if
412   // edge visibility is turned on. In order to draw edges selectively,
413   // either disable VBO or turn off edge visibilty in the current
414   // primitive array and create a separate primitive array (segments)
415   // and put edges to be drawn into it.
416   if (theEdgeFlag && myDrawMode > GL_LINE_STRIP)
417   {
418     DrawEdges (theEdgeColour, theWorkspace);
419   }
420
421   if (myDrawMode <= GL_LINE_STRIP)
422     glPopAttrib();
423 }
424
425 // =======================================================================
426 // function : DrawEdges
427 // purpose  :
428 // =======================================================================
429 void OpenGl_PrimitiveArray::DrawEdges (const TEL_COLOUR*               theEdgeColour,
430                                        const Handle(OpenGl_Workspace)& theWorkspace) const
431 {
432   glDisable (GL_LIGHTING);
433
434   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
435   const OpenGl_AspectLine* anAspectLineOld = NULL;
436   if (myDrawMode > GL_LINE_STRIP)
437   {
438     anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace (Standard_True)->AspectEdge());
439     const OpenGl_AspectLine* anAspect = theWorkspace->AspectLine (Standard_True);
440
441     glPushAttrib (GL_POLYGON_BIT);
442     glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
443
444     if (aGlContext->IsGlGreaterEqual (2, 0))
445     {
446       BindProgramWithMaterial (theWorkspace, anAspect);
447     }
448   }
449
450   Tint i, j, n;
451
452   /// OCC22236 NOTE: draw edges for all situations:
453   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indicies array
454   /// 2) draw elements from vertice array, when bounds defines count of primitive's verts.
455   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
456   if (toDrawVbo())
457   {
458     myVbos[VBOVertices]->BindFixed (aGlContext, GL_VERTEX_ARRAY);
459     glColor3fv (theEdgeColour->rgb);
460     if (!myVbos[VBOEdges].IsNull())
461     {
462       myVbos[VBOEdges]->Bind (aGlContext);
463
464       // draw primitives by vertex count with the indicies
465       if (myPArray->num_bounds > 0)
466       {
467         Tint* offset = 0;
468         for (i = 0, offset = 0; i < myPArray->num_bounds; ++i)
469         {
470           glDrawElements (myDrawMode, myPArray->bounds[i], myVbos[VBOEdges]->GetDataType(), offset);
471           offset += myPArray->bounds[i];
472         }
473       }
474       // draw one (or sequential) primitive by the indicies
475       else
476       {
477         glDrawElements (myDrawMode, myVbos[VBOEdges]->GetElemsNb(), myVbos[VBOEdges]->GetDataType(), NULL);
478       }
479       myVbos[VBOEdges]->Unbind (aGlContext);
480     }
481     else if (myPArray->num_bounds > 0)
482     {
483       for (i = n = 0; i < myPArray->num_bounds; ++i)
484       {
485         glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
486         n += myPArray->bounds[i];
487       }
488     }
489     else
490     {
491       glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
492     }
493
494     // unbind buffers
495     myVbos[VBOVertices]->UnbindFixed (aGlContext, GL_VERTEX_ARRAY);
496   }
497   else
498   {
499     glEnableClientState (GL_VERTEX_ARRAY);
500     glVertexPointer (3, GL_FLOAT, 0, myPArray->vertices); // array of vertices
501
502     glColor3fv (theEdgeColour->rgb);
503     if (myPArray->num_bounds > 0)
504     {
505       if (myPArray->num_edges > 0)
506       {
507         for (i = n = 0; i < myPArray->num_bounds; ++i)
508         {
509           if (myPArray->edge_vis)
510           {
511             glBegin (myDrawMode);
512             for (j = 0; j < myPArray->bounds[i]; ++j)
513             {
514               glEdgeFlag (myPArray->edge_vis[n+j]);
515               glVertex3fv (&myPArray->vertices[myPArray->edges[n+j]].xyz[0]);
516             }
517             glEnd();
518           }
519           else
520           {
521             glDrawElements (myDrawMode, myPArray->bounds[i], GL_UNSIGNED_INT, (GLenum* )&myPArray->edges[n]);
522           }
523           n += myPArray->bounds[i];
524         }
525       }
526       else
527       {
528         for (i = n = 0 ; i < myPArray->num_bounds; ++i)
529         {
530           glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
531           n += myPArray->bounds[i];
532         }
533       }
534     }
535     else if (myPArray->num_edges > 0)
536     {
537       if (myPArray->edge_vis)
538       {
539         glBegin (myDrawMode);
540         for (i = 0; i < myPArray->num_edges; ++i)
541         {
542           glEdgeFlag (myPArray->edge_vis[i]);
543           glVertex3fv (&myPArray->vertices[myPArray->edges[i]].xyz[0]);
544         }
545         glEnd();
546       }
547       else
548       {
549         glDrawElements (myDrawMode, myPArray->num_edges, GL_UNSIGNED_INT, (GLenum* )myPArray->edges);
550       }
551     }
552     else
553     {
554       glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
555     }
556   }
557
558   if (myDrawMode > GL_LINE_STRIP)
559   {
560     // Restore line context
561     theWorkspace->SetAspectLine (anAspectLineOld);
562     glPopAttrib();
563   }
564 }
565
566 // =======================================================================
567 // function : DrawMarkers
568 // purpose  :
569 // =======================================================================
570 void OpenGl_PrimitiveArray::DrawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
571 {
572   const OpenGl_AspectMarker* anAspectMarker     = theWorkspace->AspectMarker (Standard_True);
573   const Handle(OpenGl_Context)&     aCtx        = theWorkspace->GetGlContext();
574   const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (theWorkspace);
575   const Standard_Boolean            isHilight   = (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT);
576   if (aCtx->IsGlGreaterEqual (2, 0)
577    && !aSpriteNorm.IsNull() && !aSpriteNorm->IsDisplayList())
578   {
579     // Textured markers will be drawn with the point sprites
580     glPointSize (anAspectMarker->MarkerSize());
581
582     Handle(OpenGl_Texture) aTextureBack;
583     if (anAspectMarker->Type() != Aspect_TOM_POINT)
584     {
585       const Handle(OpenGl_PointSprite)& aSprite = (isHilight && anAspectMarker->SpriteHighlightRes (theWorkspace)->IsValid())
586                                                 ? anAspectMarker->SpriteHighlightRes (theWorkspace)
587                                                 : aSpriteNorm;
588       aTextureBack = theWorkspace->EnableTexture (aSprite);
589
590       glEnable (GL_ALPHA_TEST);
591       glAlphaFunc (GL_GEQUAL, 0.1f);
592
593       glEnable (GL_BLEND);
594       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
595     }
596
597     glDrawArrays (myDrawMode, 0, toDrawVbo() ? myVbos[VBOVertices]->GetElemsNb() : myPArray->num_vertexs);
598
599     glDisable (GL_BLEND);
600     glDisable (GL_ALPHA_TEST);
601     if (anAspectMarker->Type() != Aspect_TOM_POINT)
602     {
603       theWorkspace->EnableTexture (aTextureBack);
604     }
605     glPointSize (1.0f);
606     return;
607   }
608
609   // Textured markers will be drawn with the glBitmap
610   if (anAspectMarker->Type() == Aspect_TOM_POINT
611    || anAspectMarker->Type() == Aspect_TOM_O_POINT)
612   {
613     const GLfloat aPntSize = anAspectMarker->Type() == Aspect_TOM_POINT
614                            ? anAspectMarker->MarkerSize()
615                            : 0.0f;
616     if (aPntSize > 0.0f)
617     {
618       glPointSize (aPntSize);
619     }
620     glDrawArrays (myDrawMode, 0, toDrawVbo() ? myVbos[VBOVertices]->GetElemsNb() : myPArray->num_vertexs);
621     if (aPntSize > 0.0f)
622     {
623       glPointSize (1.0f);
624     }
625   }
626
627   if (anAspectMarker->Type() != Aspect_TOM_POINT
628    && !aSpriteNorm.IsNull())
629   {
630     if (!isHilight && (myPArray->vcolours != NULL))
631     {
632       for (Standard_Integer anIter = 0; anIter < myPArray->num_vertexs; anIter++)
633       {
634         glColor4ubv ((GLubyte* )&myPArray->vcolours[anIter]);
635         glRasterPos3fv (myPArray->vertices[anIter].xyz);
636         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
637       }
638     }
639     else
640     {
641       for (Standard_Integer anIter = 0; anIter < myPArray->num_vertexs; anIter++)
642       {
643         glRasterPos3fv (myPArray->vertices[anIter].xyz);
644         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
645       }
646     }
647   }
648 }
649
650 // =======================================================================
651 // function : OpenGl_PrimitiveArray
652 // purpose  :
653 // =======================================================================
654 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (CALL_DEF_PARRAY* thePArray)
655 : myPArray (thePArray),
656   myDrawMode (DRAW_MODE_NONE),
657   myIsVboInit (Standard_False)
658 {
659   switch (myPArray->type)
660   {
661     case TelPointsArrayType:
662       myDrawMode = GL_POINTS;
663       break;
664     case TelPolylinesArrayType:
665       myDrawMode = GL_LINE_STRIP;
666       break;
667     case TelSegmentsArrayType:
668       myDrawMode = GL_LINES;
669       break;
670     case TelPolygonsArrayType:
671       myDrawMode = GL_POLYGON;
672       break;
673     case TelTrianglesArrayType:
674       myDrawMode = GL_TRIANGLES;
675       break;
676     case TelQuadranglesArrayType:
677       myDrawMode = GL_QUADS;
678       break;
679     case TelTriangleStripsArrayType:
680       myDrawMode = GL_TRIANGLE_STRIP;
681       break;
682     case TelQuadrangleStripsArrayType:
683       myDrawMode = GL_QUAD_STRIP;
684       break;
685     case TelTriangleFansArrayType:
686       myDrawMode = GL_TRIANGLE_FAN;
687       break;
688     case TelUnknownArrayType:
689       break;
690   }
691 }
692
693 // =======================================================================
694 // function : ~OpenGl_PrimitiveArray
695 // purpose  :
696 // =======================================================================
697 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
698 {
699   //
700 }
701
702 // =======================================================================
703 // function : Release
704 // purpose  :
705 // =======================================================================
706 void OpenGl_PrimitiveArray::Release (const Handle(OpenGl_Context)& theContext)
707 {
708   for (Standard_Integer anIter = 0; anIter < VBOMaxType; ++anIter)
709   {
710     if (!myVbos[anIter].IsNull())
711     {
712       if (!theContext.IsNull())
713       {
714         theContext->DelayedRelease (myVbos[anIter]);
715       }
716       myVbos[anIter].Nullify();
717     }
718   }
719 }
720
721 // =======================================================================
722 // function : Render
723 // purpose  :
724 // =======================================================================
725 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
726 {
727   if (myPArray == NULL || myDrawMode == DRAW_MODE_NONE || myPArray->num_vertexs <= 0)
728   {
729     return;
730   }
731
732   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->AspectFace   (Standard_True);
733   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->AspectLine   (Standard_True);
734   const OpenGl_AspectMarker* anAspectMarker = theWorkspace->AspectMarker (myDrawMode == GL_POINTS);
735
736   // create VBOs on first render call
737   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
738   if (!myIsVboInit
739    && !aCtx->caps->vboDisable
740    && aCtx->core15 != NULL
741    && (myDrawMode != GL_POINTS || anAspectMarker->SpriteRes (theWorkspace).IsNull() || !anAspectMarker->SpriteRes (theWorkspace)->IsDisplayList()))
742   {
743     if (!BuildVBO (theWorkspace))
744     {
745       TCollection_ExtendedString aMsg;
746       aMsg += "VBO creation for Primitive Array has failed for ";
747       aMsg += myPArray->num_vertexs;
748       aMsg += " vertices. Out of memory?";
749       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_PERFORMANCE_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMsg);
750     }
751     myIsVboInit = Standard_True;
752   }
753
754   switch (myPArray->type)
755   {
756     case TelPointsArrayType:
757     case TelPolylinesArrayType:
758     case TelSegmentsArrayType:
759     {
760       glDisable (GL_LIGHTING);
761       break;
762     }
763     default:
764       break;
765   }
766
767   Tint aFrontLightingModel = anAspectFace->IntFront().color_mask;
768   const TEL_COLOUR* anInteriorColor = &anAspectFace->IntFront().matcol;
769   const TEL_COLOUR* anEdgeColor = &anAspectFace->AspectEdge()->Color();
770   const TEL_COLOUR* aLineColor = (myPArray->type == TelPointsArrayType) ? &anAspectMarker->Color() : &anAspectLine->Color();
771
772   // Use highlight colors
773   if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
774   {
775     anEdgeColor = anInteriorColor = aLineColor = theWorkspace->HighlightColor;
776     aFrontLightingModel = 0;
777   }
778
779   if (aCtx->IsGlGreaterEqual (2, 0))
780   {
781     switch (myPArray->type)
782     {
783       case TelPointsArrayType:
784       {
785         BindProgramWithMaterial (theWorkspace, anAspectMarker);
786         break;
787       }
788       case TelSegmentsArrayType:
789       case TelPolylinesArrayType:
790       {
791         BindProgramWithMaterial (theWorkspace, anAspectLine);
792         break;
793       }
794       default: // polygonal array
795       {
796         BindProgramWithMaterial (theWorkspace, anAspectFace);
797         break;
798       }
799     }
800   }
801
802   DrawArray (aFrontLightingModel,
803              anAspectFace->InteriorStyle(),
804              anAspectFace->Edge(),
805              anInteriorColor,
806              aLineColor,
807              anEdgeColor,
808              &anAspectFace->IntFront(),
809              theWorkspace);
810 }