0029286: Visualization, TKOpenGl - do not update FFP state when OpenGl_Caps::ffpEnabl...
[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 under
8 // the terms of the GNU Lesser General Public License 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_Sampler.hxx>
23 #include <OpenGl_ShaderManager.hxx>
24 #include <OpenGl_ShaderProgram.hxx>
25 #include <OpenGl_Structure.hxx>
26 #include <OpenGl_VertexBufferCompat.hxx>
27 #include <OpenGl_Workspace.hxx>
28 #include <Graphic3d_TextureParams.hxx>
29 #include <NCollection_AlignedAllocator.hxx>
30
31 namespace
32 {
33   //! Convert data type to GL info
34   inline GLenum toGlDataType (const Graphic3d_TypeOfData theType,
35                               GLint&                     theNbComp)
36   {
37     switch (theType)
38     {
39       case Graphic3d_TOD_USHORT:
40         theNbComp = 1;
41         return GL_UNSIGNED_SHORT;
42       case Graphic3d_TOD_UINT:
43         theNbComp = 1;
44         return GL_UNSIGNED_INT;
45       case Graphic3d_TOD_VEC2:
46         theNbComp = 2;
47         return GL_FLOAT;
48       case Graphic3d_TOD_VEC3:
49         theNbComp = 3;
50         return GL_FLOAT;
51       case Graphic3d_TOD_VEC4:
52         theNbComp = 4;
53         return GL_FLOAT;
54       case Graphic3d_TOD_VEC4UB:
55         theNbComp = 4;
56         return GL_UNSIGNED_BYTE;
57       case Graphic3d_TOD_FLOAT:
58         theNbComp = 1;
59         return GL_FLOAT;
60     }
61     theNbComp = 0;
62     return GL_NONE;
63   }
64
65 }
66
67 //! Auxiliary template for VBO with interleaved attributes.
68 template<class TheBaseClass, int NbAttributes>
69 class OpenGl_VertexBufferT : public TheBaseClass
70 {
71
72 public:
73
74   //! Create uninitialized VBO.
75   OpenGl_VertexBufferT (const Graphic3d_Attribute* theAttribs,
76                         const Standard_Integer     theStride)
77   : Stride (theStride)
78   {
79     memcpy (Attribs, theAttribs, sizeof(Graphic3d_Attribute) * NbAttributes);
80   }
81
82   //! Create uninitialized VBO.
83   OpenGl_VertexBufferT (const Graphic3d_Buffer& theAttribs)
84   : Stride (theAttribs.Stride)
85   {
86     memcpy (Attribs, theAttribs.AttributesArray(), sizeof(Graphic3d_Attribute) * NbAttributes);
87   }
88
89   virtual bool HasColorAttribute() const
90   {
91     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
92     {
93       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
94       if (anAttrib.Id == Graphic3d_TOA_COLOR)
95       {
96         return true;
97       }
98     }
99     return false;
100   }
101
102   virtual bool HasNormalAttribute() const
103   {
104     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
105     {
106       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
107       if (anAttrib.Id == Graphic3d_TOA_NORM)
108       {
109         return true;
110       }
111     }
112     return false;
113   }
114
115   virtual void BindPositionAttribute (const Handle(OpenGl_Context)& theGlCtx) const
116   {
117     if (!TheBaseClass::IsValid())
118     {
119       return;
120     }
121
122     TheBaseClass::Bind (theGlCtx);
123     GLint aNbComp;
124     const GLubyte* anOffset = TheBaseClass::myOffset;
125     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
126     {
127       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
128       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
129       if (aDataType == GL_NONE)
130       {
131         continue;
132       }
133       else if (anAttrib.Id == Graphic3d_TOA_POS)
134       {
135         TheBaseClass::bindAttribute (theGlCtx, Graphic3d_TOA_POS, aNbComp, aDataType, Stride, anOffset);
136         break;
137       }
138
139       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
140     }
141   }
142
143   virtual void BindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
144   {
145     if (!TheBaseClass::IsValid())
146     {
147       return;
148     }
149
150     TheBaseClass::Bind (theGlCtx);
151     GLint aNbComp;
152     const GLubyte* anOffset = TheBaseClass::myOffset;
153     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
154     {
155       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
156       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
157       if (aDataType == GL_NONE)
158       {
159         continue;
160       }
161
162       TheBaseClass::bindAttribute (theGlCtx, anAttrib.Id, aNbComp, aDataType, Stride, anOffset);
163       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
164     }
165   }
166
167   virtual void UnbindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
168   {
169     if (!TheBaseClass::IsValid())
170     {
171       return;
172     }
173     TheBaseClass::Unbind (theGlCtx);
174
175     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
176     {
177       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
178       TheBaseClass::unbindAttribute (theGlCtx, anAttrib.Id);
179     }
180   }
181
182 public:
183
184   Graphic3d_Attribute Attribs[NbAttributes];
185   Standard_Integer    Stride;
186
187 };
188
189 // =======================================================================
190 // function : clearMemoryGL
191 // purpose  :
192 // =======================================================================
193 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
194 {
195   if (!myVboIndices.IsNull())
196   {
197     myVboIndices->Release (theGlCtx.operator->());
198     myVboIndices.Nullify();
199   }
200   if (!myVboAttribs.IsNull())
201   {
202     myVboAttribs->Release (theGlCtx.operator->());
203     myVboAttribs.Nullify();
204   }
205 }
206
207 // =======================================================================
208 // function : initNormalVbo
209 // purpose  :
210 // =======================================================================
211 Standard_Boolean OpenGl_PrimitiveArray::initNormalVbo (const Handle(OpenGl_Context)& theCtx) const
212 {
213   switch (myAttribs->NbAttributes)
214   {
215     case 1:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 1> (*myAttribs); break;
216     case 2:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 2> (*myAttribs); break;
217     case 3:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 3> (*myAttribs); break;
218     case 4:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 4> (*myAttribs); break;
219     case 5:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 5> (*myAttribs); break;
220     case 6:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 6> (*myAttribs); break;
221     case 7:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 7> (*myAttribs); break;
222     case 8:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 8> (*myAttribs); break;
223     case 9:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 9> (*myAttribs); break;
224     case 10: myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 10>(*myAttribs); break;
225   }
226
227   if (!myVboAttribs->init (theCtx, 0, myAttribs->NbElements, myAttribs->Data(), GL_NONE, myAttribs->Stride))
228   {
229     TCollection_ExtendedString aMsg;
230     aMsg += "VBO creation for Primitive Array has failed for ";
231     aMsg += myAttribs->NbElements;
232     aMsg += " vertices. Out of memory?";
233     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
234
235     clearMemoryGL (theCtx);
236     return Standard_False;
237   }
238   else if (myIndices.IsNull())
239   {
240     return Standard_True;
241   }
242
243   myVboIndices = new OpenGl_IndexBuffer();
244   bool isOk = false;
245   switch (myIndices->Stride)
246   {
247     case 2:
248     {
249       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLushort*> (myIndices->Data()));
250       break;
251     }
252     case 4:
253     {
254       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLuint*> (myIndices->Data()));
255       break;
256     }
257     default:
258     {
259       clearMemoryGL (theCtx);
260       return Standard_False;
261     }
262   }
263   if (!isOk)
264   {
265     TCollection_ExtendedString aMsg;
266     aMsg += "VBO creation for Primitive Array has failed for ";
267     aMsg += myIndices->NbElements;
268     aMsg += " indices. Out of memory?";
269     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
270     clearMemoryGL (theCtx);
271     return Standard_False;
272   }
273   return Standard_True;
274 }
275
276 // =======================================================================
277 // function : buildVBO
278 // purpose  :
279 // =======================================================================
280 Standard_Boolean OpenGl_PrimitiveArray::buildVBO (const Handle(OpenGl_Context)& theCtx,
281                                                   const Standard_Boolean        theToKeepData) const
282 {
283   bool isNormalMode = theCtx->ToUseVbo();
284   clearMemoryGL (theCtx);
285   if (myAttribs.IsNull()
286    || myAttribs->IsEmpty()
287    || myAttribs->NbElements < 1
288    || myAttribs->NbAttributes < 1
289    || myAttribs->NbAttributes > 10)
290   {
291     // vertices should be always defined - others are optional
292     return Standard_False;
293   }
294
295   if (isNormalMode
296    && initNormalVbo (theCtx))
297   {
298     if (!theCtx->caps->keepArrayData
299      && !theToKeepData)
300     {
301       myIndices.Nullify();
302       myAttribs.Nullify();
303     }
304     return Standard_True;
305   }
306
307   Handle(OpenGl_VertexBufferCompat) aVboAttribs;
308   switch (myAttribs->NbAttributes)
309   {
310     case 1:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 1> (*myAttribs); break;
311     case 2:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 2> (*myAttribs); break;
312     case 3:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 3> (*myAttribs); break;
313     case 4:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 4> (*myAttribs); break;
314     case 5:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 5> (*myAttribs); break;
315     case 6:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 6> (*myAttribs); break;
316     case 7:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 7> (*myAttribs); break;
317     case 8:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 8> (*myAttribs); break;
318     case 9:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 9> (*myAttribs); break;
319     case 10: aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 10>(*myAttribs); break;
320   }
321   aVboAttribs->initLink (myAttribs, 0, myAttribs->NbElements, GL_NONE);
322   if (!myIndices.IsNull())
323   {
324     Handle(OpenGl_VertexBufferCompat) aVboIndices = new OpenGl_VertexBufferCompat();
325     switch (myIndices->Stride)
326     {
327       case 2:
328       {
329         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_SHORT);
330         break;
331       }
332       case 4:
333       {
334         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_INT);
335         break;
336       }
337       default:
338       {
339         return Standard_False;
340       }
341     }
342     myVboIndices = aVboIndices;
343   }
344   myVboAttribs = aVboAttribs;
345   if (!theCtx->caps->keepArrayData
346    && !theToKeepData)
347   {
348     // does not make sense for compatibility mode
349     //myIndices.Nullify();
350     //myAttribs.Nullify();
351   }
352
353   return Standard_True;
354 }
355
356 // =======================================================================
357 // function : drawArray
358 // purpose  :
359 // =======================================================================
360 void OpenGl_PrimitiveArray::drawArray (const Handle(OpenGl_Workspace)& theWorkspace,
361                                        const Graphic3d_Vec4*           theFaceColors,
362                                        const Standard_Boolean          theHasVertColor) const
363 {
364   if (myVboAttribs.IsNull())
365   {
366   #if !defined(GL_ES_VERSION_2_0)
367     if (myDrawMode == GL_POINTS)
368     {
369       // extreme compatibility mode - without sprites but with markers
370       drawMarkers (theWorkspace);
371     }
372   #endif
373     return;
374   }
375
376   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
377   const bool                    toHilight  = theWorkspace->ToHighlight();
378   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
379                          && aGlContext->ActiveProgram()->HasTessellationStage()
380                          ? GL_PATCHES
381                          : myDrawMode;
382   myVboAttribs->BindAllAttributes (aGlContext);
383   if (theHasVertColor && toHilight)
384   {
385     // disable per-vertex color
386     OpenGl_VertexBuffer::unbindAttribute (aGlContext, Graphic3d_TOA_COLOR);
387   }
388   if (!myVboIndices.IsNull())
389   {
390     myVboIndices->Bind (aGlContext);
391     GLubyte* anOffset = myVboIndices->GetDataOffset();
392     if (!myBounds.IsNull())
393     {
394       // draw primitives by vertex count with the indices
395       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
396       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
397       {
398         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
399         if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
400         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
401         anOffset += aStride * aNbElemsInGroup;
402       }
403     }
404     else
405     {
406       // draw one (or sequential) primitive by the indices
407       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
408     }
409     myVboIndices->Unbind (aGlContext);
410   }
411   else if (!myBounds.IsNull())
412   {
413     GLint aFirstElem = 0;
414     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
415     {
416       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
417       if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
418       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
419       aFirstElem += aNbElemsInGroup;
420     }
421   }
422   else
423   {
424     if (myDrawMode == GL_POINTS)
425     {
426       drawMarkers (theWorkspace);
427     }
428     else
429     {
430       glDrawArrays (aDrawMode, 0, myVboAttribs->GetElemsNb());
431     }
432   }
433
434   // bind with 0
435   myVboAttribs->UnbindAllAttributes (aGlContext);
436 }
437
438 // =======================================================================
439 // function : drawEdges
440 // purpose  :
441 // =======================================================================
442 void OpenGl_PrimitiveArray::drawEdges (const OpenGl_Vec4&              theEdgeColour,
443                                        const Handle(OpenGl_Workspace)& theWorkspace) const
444 {
445   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
446   if (myVboAttribs.IsNull())
447   {
448     return;
449   }
450
451   const OpenGl_AspectLine* anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace()->AspectEdge());
452   const OpenGl_AspectLine* anAspect = theWorkspace->ApplyAspectLine();
453
454 #if !defined(GL_ES_VERSION_2_0)
455   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
456 #endif
457
458   if (aGlContext->core20fwd != NULL)
459   {
460     aGlContext->ShaderManager()->BindLineProgram (NULL,
461                                                   anAspect->Aspect()->Type() != Aspect_TOL_SOLID,
462                                                   Standard_False,
463                                                   Standard_False,
464                                                   anAspect->ShaderProgramRes (aGlContext));
465   }
466   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
467                          && aGlContext->ActiveProgram()->HasTessellationStage()
468                          ? GL_PATCHES
469                          : myDrawMode;
470 #if !defined(GL_ES_VERSION_2_0)
471   if (aGlContext->ActiveProgram().IsNull()
472    && aGlContext->core11 != NULL)
473   {
474     glDisable (GL_LIGHTING);
475   }
476 #endif
477
478   /// OCC22236 NOTE: draw edges for all situations:
479   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
480   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
481   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
482   myVboAttribs->BindPositionAttribute (aGlContext);
483
484   aGlContext->SetColor4fv   (theEdgeColour);
485   aGlContext->SetTypeOfLine (anAspect->Aspect()->Type());
486   aGlContext->SetLineWidth  (anAspect->Aspect()->Width());
487
488   if (!myVboIndices.IsNull())
489   {
490     myVboIndices->Bind (aGlContext);
491     GLubyte* anOffset = myVboIndices->GetDataOffset();
492
493     // draw primitives by vertex count with the indices
494     if (!myBounds.IsNull())
495     {
496       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
497       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
498       {
499         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
500         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
501         anOffset += aStride * aNbElemsInGroup;
502       }
503     }
504     // draw one (or sequential) primitive by the indices
505     else
506     {
507       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
508     }
509     myVboIndices->Unbind (aGlContext);
510   }
511   else if (!myBounds.IsNull())
512   {
513     GLint aFirstElem = 0;
514     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
515     {
516       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
517       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
518       aFirstElem += aNbElemsInGroup;
519     }
520   }
521   else
522   {
523     glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
524   }
525
526   // unbind buffers
527   myVboAttribs->UnbindAttribute (aGlContext, Graphic3d_TOA_POS);
528
529   // restore line context
530   theWorkspace->SetAspectLine (anAspectLineOld);
531 }
532
533 // =======================================================================
534 // function : drawMarkers
535 // purpose  :
536 // =======================================================================
537 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
538 {
539   const OpenGl_AspectMarker* anAspectMarker = theWorkspace->ApplyAspectMarker();
540   const Handle(OpenGl_Context)&     aCtx    = theWorkspace->GetGlContext();
541   const GLenum aDrawMode = !aCtx->ActiveProgram().IsNull()
542                          && aCtx->ActiveProgram()->HasTessellationStage()
543                          ? GL_PATCHES
544                          : myDrawMode;
545
546   const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
547   const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
548   if (aSpriteNorm != NULL
549   && !aSpriteNorm->IsDisplayList())
550   {
551     // Textured markers will be drawn with the point sprites
552     aCtx->SetPointSize (anAspectMarker->MarkerSize());
553     aCtx->SetPointSpriteOrigin();
554   #if !defined(GL_ES_VERSION_2_0)
555     if (aCtx->core11 != NULL)
556     {
557       aCtx->core11fwd->glEnable (GL_ALPHA_TEST);
558       aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, 0.1f);
559     }
560   #endif
561
562     aCtx->core11fwd->glEnable (GL_BLEND);
563     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
564
565     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
566
567     aCtx->core11fwd->glDisable (GL_BLEND);
568   #if !defined(GL_ES_VERSION_2_0)
569     if (aCtx->core11 != NULL)
570     {
571       aCtx->core11fwd->glDisable (GL_ALPHA_TEST);
572     }
573   #endif
574     aCtx->SetPointSize (1.0f);
575     return;
576   }
577   else if (anAspectMarker->Aspect()->Type() == Aspect_TOM_POINT)
578   {
579     aCtx->SetPointSize (anAspectMarker->MarkerSize());
580     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
581     aCtx->SetPointSize (1.0f);
582   }
583 #if !defined(GL_ES_VERSION_2_0)
584   // Textured markers will be drawn with the glBitmap
585   else if (anAspectMarker->Aspect()->Type() != Aspect_TOM_POINT
586         && aSpriteNorm != NULL)
587   {
588     /**if (!isHilight && (myPArray->vcolours != NULL))
589     {
590       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
591       {
592         glColor4ubv    (myPArray->vcolours[anIter].GetData());
593         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
594         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
595       }
596     }
597     else*/
598     {
599       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
600       {
601         aCtx->core11->glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
602         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
603       }
604     }
605   }
606 #endif
607 }
608
609 // =======================================================================
610 // function : OpenGl_PrimitiveArray
611 // purpose  :
612 // =======================================================================
613 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver)
614
615 : myDrawMode  (DRAW_MODE_NONE),
616   myIsFillType(Standard_False),
617   myIsVboInit (Standard_False)
618 {
619   if (theDriver != NULL)
620   {
621     myUID = theDriver->GetNextPrimitiveArrayUID();
622   }
623 }
624
625 // =======================================================================
626 // function : OpenGl_PrimitiveArray
627 // purpose  :
628 // =======================================================================
629 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
630                                               const Graphic3d_TypeOfPrimitiveArray theType,
631                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
632                                               const Handle(Graphic3d_Buffer)&      theAttribs,
633                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
634
635 : myIndices   (theIndices),
636   myAttribs   (theAttribs),
637   myBounds    (theBounds),
638   myDrawMode  (DRAW_MODE_NONE),
639   myIsFillType(Standard_False),
640   myIsVboInit (Standard_False)
641 {
642   if (!myIndices.IsNull()
643     && myIndices->NbElements < 1)
644   {
645     // dummy index buffer?
646     myIndices.Nullify();
647   }
648
649   if (theDriver != NULL)
650   {
651     myUID = theDriver->GetNextPrimitiveArrayUID();
652   #if defined (GL_ES_VERSION_2_0)
653     const Handle(OpenGl_Context)& aCtx = theDriver->GetSharedContext();
654     if (!aCtx.IsNull())
655     {
656       processIndices (aCtx);
657     }
658   #endif
659   }
660
661   setDrawMode (theType);
662 }
663
664 // =======================================================================
665 // function : ~OpenGl_PrimitiveArray
666 // purpose  :
667 // =======================================================================
668 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
669 {
670   //
671 }
672
673 // =======================================================================
674 // function : Release
675 // purpose  :
676 // =======================================================================
677 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
678 {
679   myIsVboInit = Standard_False;
680   if (!myVboIndices.IsNull())
681   {
682     if (theContext)
683     {
684       theContext->DelayedRelease (myVboIndices);
685     }
686     myVboIndices.Nullify();
687   }
688   if (!myVboAttribs.IsNull())
689   {
690     if (theContext)
691     {
692       theContext->DelayedRelease (myVboAttribs);
693     }
694     myVboAttribs.Nullify();
695   }
696 }
697
698 // =======================================================================
699 // function : Render
700 // purpose  :
701 // =======================================================================
702 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
703 {
704   if (myDrawMode == DRAW_MODE_NONE)
705   {
706     return;
707   }
708
709   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->ApplyAspectFace();
710   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->ApplyAspectLine();
711   const OpenGl_AspectMarker* anAspectMarker = myDrawMode == GL_POINTS
712                                             ? theWorkspace->ApplyAspectMarker()
713                                             : theWorkspace->AspectMarker();
714
715   // create VBOs on first render call
716   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
717   if (!myIsVboInit)
718   {
719     // compatibility - keep data to draw markers using display lists
720     Standard_Boolean toKeepData = Standard_False;
721     if (myDrawMode == GL_POINTS)
722     {
723       const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
724       const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
725       toKeepData = aSpriteNorm != NULL
726                &&  aSpriteNorm->IsDisplayList();
727     }
728   #if defined (GL_ES_VERSION_2_0)
729     processIndices (aCtx);
730   #endif
731     buildVBO (aCtx, toKeepData);
732     myIsVboInit = Standard_True;
733   }
734
735   const Standard_Boolean hasColorAttrib = !myVboAttribs.IsNull()
736                                         && myVboAttribs->HasColorAttribute();
737   const Standard_Boolean isLightOn = !anAspectFace->IsNoLighting()
738                                   && !myVboAttribs.IsNull()
739                                   &&  myVboAttribs->HasNormalAttribute();
740
741   // Temporarily disable environment mapping
742   Handle(OpenGl_TextureSet) aTextureBack;
743   bool toDrawArray = true;
744   if (myDrawMode > GL_LINE_STRIP)
745   {
746     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
747   }
748   else if (myDrawMode <= GL_LINE_STRIP)
749   {
750     aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
751     if (myDrawMode == GL_POINTS)
752     {
753       toDrawArray = anAspectMarker->Aspect()->Type() != Aspect_TOM_EMPTY;
754     }
755     else
756     {
757       toDrawArray = anAspectLine->Aspect()->Type() != Aspect_TOL_EMPTY;
758     }
759   }
760
761   if (toDrawArray)
762   {
763     const bool             toHilight    = theWorkspace->ToHighlight();
764     const Standard_Boolean hasVertColor = hasColorAttrib && !toHilight;
765     switch (myDrawMode)
766     {
767       case GL_POINTS:
768       {
769         const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
770         const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
771         if (aSpriteNorm != NULL
772         && !aSpriteNorm->IsDisplayList())
773         {
774           const Handle(OpenGl_TextureSet)& aSprite = toHilight && anAspectMarker->SpriteHighlightRes (aCtx)->First()->IsValid()
775                                                    ? anAspectMarker->SpriteHighlightRes (aCtx)
776                                                    : aSpriteNormRes;
777           aCtx->BindTextures (aSprite);
778           aCtx->ShaderManager()->BindMarkerProgram (aSprite, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
779         }
780         else
781         {
782           aCtx->ShaderManager()->BindMarkerProgram (Handle(OpenGl_TextureSet)(), isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
783         }
784         break;
785       }
786       case GL_LINES:
787       case GL_LINE_STRIP:
788       {
789         aCtx->ShaderManager()->BindLineProgram (NULL,
790                                                 anAspectLine->Aspect()->Type() != Aspect_TOL_SOLID,
791                                                 isLightOn,
792                                                 hasVertColor,
793                                                 anAspectLine->ShaderProgramRes (aCtx));
794         break;
795       }
796       default:
797       {
798         const Handle(OpenGl_TextureSet)& aTextures = aCtx->ActiveTextures();
799         const Standard_Boolean isLightOnFace = isLightOn
800                                             && (aTextures.IsNull()
801                                              || aTextures->IsEmpty()
802                                              || aTextures->First().IsNull()
803                                              || aTextures->First()->Sampler()->Parameters()->IsModulate());
804         const Standard_Boolean toEnableEnvMap = (!aTextures.IsNull() && (aTextures == theWorkspace->EnvironmentTexture()));
805         aCtx->ShaderManager()->BindFaceProgram (aTextures,
806                                                 isLightOnFace,
807                                                 hasVertColor,
808                                                 toEnableEnvMap,
809                                                 anAspectFace->ShaderProgramRes (aCtx));
810         break;
811       }
812     }
813
814   #if !defined(GL_ES_VERSION_2_0)
815     // manage FFP lighting
816     if (aCtx->ActiveProgram().IsNull()
817      && aCtx->core11 != NULL)
818     {
819       if (!isLightOn)
820       {
821         glDisable (GL_LIGHTING);
822       }
823       else
824       {
825         glEnable (GL_LIGHTING);
826       }
827     }
828   #endif
829
830     if (!aCtx->ActiveTextures().IsNull()
831      && !aCtx->ActiveTextures()->IsEmpty()
832      && !aCtx->ActiveTextures()->First().IsNull()
833      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
834     {
835       aCtx->SetTextureMatrix (aCtx->ActiveTextures()->First()->Sampler()->Parameters());
836     }
837
838     if (myDrawMode <= GL_LINE_STRIP)
839     {
840       const OpenGl_Vec4& aLineColor = myDrawMode == GL_POINTS ? theWorkspace->MarkerColor() : theWorkspace->LineColor();
841       aCtx->SetColor4fv (aLineColor);
842     }
843     else
844     {
845       const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
846       aCtx->SetColor4fv (anInteriorColor);
847     }
848     if (myDrawMode == GL_LINES
849      || myDrawMode == GL_LINE_STRIP)
850     {
851       aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
852       aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
853     }
854
855     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
856                                       ?  myBounds->Colors
857                                       :  NULL;
858     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
859   }
860
861   if (myDrawMode <= GL_LINE_STRIP)
862   {
863     aCtx->BindTextures (aTextureBack);
864   }
865   else
866   {
867     if (anAspectFace->Aspect()->ToDrawEdges()
868      || anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
869     {
870       const OpenGl_Vec4& anEdgeColor = theWorkspace->EdgeColor();
871       drawEdges (anEdgeColor, theWorkspace);
872
873       // restore OpenGL polygon mode if needed
874     #if !defined(GL_ES_VERSION_2_0)
875       if (anAspectFace->Aspect()->InteriorStyle() >= Aspect_IS_HATCH)
876       {
877         glPolygonMode (GL_FRONT_AND_BACK,
878           anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_POINT ? GL_POINT : GL_FILL);
879       }
880     #endif
881     }
882   }
883 }
884
885 // =======================================================================
886 // function : setDrawMode
887 // purpose  :
888 // =======================================================================
889 void OpenGl_PrimitiveArray::setDrawMode (const Graphic3d_TypeOfPrimitiveArray theType)
890 {
891   if (myAttribs.IsNull())
892   {
893     myDrawMode = DRAW_MODE_NONE;
894     myIsFillType = false;
895     return;
896   }
897
898   switch (theType)
899   {
900     case Graphic3d_TOPA_POINTS:
901       myDrawMode   = GL_POINTS;
902       myIsFillType = false;
903       break;
904     case Graphic3d_TOPA_SEGMENTS:
905       myDrawMode   = GL_LINES;
906       myIsFillType = false;
907       break;
908     case Graphic3d_TOPA_POLYLINES:
909       myDrawMode   = GL_LINE_STRIP;
910       myIsFillType = false;
911       break;
912     case Graphic3d_TOPA_TRIANGLES:
913       myDrawMode   = GL_TRIANGLES;
914       myIsFillType = true;
915       break;
916     case Graphic3d_TOPA_TRIANGLESTRIPS:
917       myDrawMode   = GL_TRIANGLE_STRIP;
918       myIsFillType = true;
919       break;
920     case Graphic3d_TOPA_TRIANGLEFANS:
921       myDrawMode   = GL_TRIANGLE_FAN;
922       myIsFillType = true;
923       break;
924     //
925     case Graphic3d_TOPA_LINES_ADJACENCY:
926       myDrawMode = GL_LINES_ADJACENCY;
927       myIsFillType = false;
928       break;
929     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
930       myDrawMode   = GL_LINE_STRIP_ADJACENCY;
931       myIsFillType = false;
932       break;
933     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
934       myDrawMode   = GL_TRIANGLES_ADJACENCY;
935       myIsFillType = true;
936       break;
937     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
938       myDrawMode   = GL_TRIANGLE_STRIP_ADJACENCY;
939       myIsFillType = true;
940       break;
941     //
942   #if !defined(GL_ES_VERSION_2_0)
943     case Graphic3d_TOPA_QUADRANGLES:
944       myDrawMode   = GL_QUADS;
945       myIsFillType = true;
946       break;
947     case Graphic3d_TOPA_QUADRANGLESTRIPS:
948       myDrawMode   = GL_QUAD_STRIP;
949       myIsFillType = true;
950       break;
951     case Graphic3d_TOPA_POLYGONS:
952       myDrawMode   = GL_POLYGON;
953       myIsFillType = true;
954       break;
955   #else
956     case Graphic3d_TOPA_QUADRANGLES:
957     case Graphic3d_TOPA_QUADRANGLESTRIPS:
958     case Graphic3d_TOPA_POLYGONS:
959   #endif
960     case Graphic3d_TOPA_UNDEFINED:
961       myDrawMode   = DRAW_MODE_NONE;
962       myIsFillType = false;
963       break;
964   }
965 }
966
967 // =======================================================================
968 // function : processIndices
969 // purpose  :
970 // =======================================================================
971 Standard_Boolean OpenGl_PrimitiveArray::processIndices (const Handle(OpenGl_Context)& theContext) const
972 {
973   if (myIndices.IsNull()
974    || myAttribs.IsNull()
975    || theContext->hasUintIndex)
976   {
977     return Standard_True;
978   }
979
980   if (myAttribs->NbElements > std::numeric_limits<GLushort>::max())
981   {
982     Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (new NCollection_AlignedAllocator (16));
983     if (!anAttribs->Init (myIndices->NbElements, myAttribs->AttributesArray(), myAttribs->NbAttributes))
984     {
985       return Standard_False; // failed to initialize attribute array
986     }
987
988     for (Standard_Integer anIdxIdx = 0; anIdxIdx < myIndices->NbElements; ++anIdxIdx)
989     {
990       const Standard_Integer anIndex = myIndices->Index (anIdxIdx);
991       memcpy (anAttribs->ChangeData() + myAttribs->Stride * anIdxIdx,
992               myAttribs->Data()       + myAttribs->Stride * anIndex,
993               myAttribs->Stride);
994     }
995
996     myIndices.Nullify();
997     myAttribs = anAttribs;
998   }
999
1000   return Standard_True;
1001 }
1002
1003 // =======================================================================
1004 // function : InitBuffers
1005 // purpose  :
1006 // =======================================================================
1007 void OpenGl_PrimitiveArray::InitBuffers (const Handle(OpenGl_Context)&        theContext,
1008                                          const Graphic3d_TypeOfPrimitiveArray theType,
1009                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
1010                                          const Handle(Graphic3d_Buffer)&      theAttribs,
1011                                          const Handle(Graphic3d_BoundBuffer)& theBounds)
1012 {
1013   // Release old graphic resources
1014   Release (theContext.operator->());
1015
1016   myIndices = theIndices;
1017   myAttribs = theAttribs;
1018   myBounds = theBounds;
1019 #if defined(GL_ES_VERSION_2_0)
1020   processIndices (theContext);
1021 #endif
1022
1023   setDrawMode (theType);
1024 }