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