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