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