0031687: Draw Harness, ViewerTest - extend command vrenderparams with option updating...
[occt.git] / src / OpenGl / OpenGl_BackgroundArray.cxx
CommitLineData
0b0320e7 1// Created on: 2015-01-16
2// Created by: Anastasia BORISOVA
3// Copyright (c) 2015 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_BackgroundArray.hxx>
17
18#include <Aspect_FillMethod.hxx>
19#include <NCollection_AlignedAllocator.hxx>
20#include <OpenGl_Texture.hxx>
3bffef55 21#include <OpenGl_View.hxx>
c04c30b3 22#include <Graphic3d_TextureParams.hxx>
0b0320e7 23
24// =======================================================================
25// method : Constructor
26// purpose :
27// =======================================================================
28OpenGl_BackgroundArray::OpenGl_BackgroundArray (const Graphic3d_TypeOfBackground theType)
29: OpenGl_PrimitiveArray (NULL, Graphic3d_TOPA_TRIANGLESTRIPS, NULL, NULL, NULL),
0b0320e7 30 myType (theType),
3bffef55 31 myFillMethod (Aspect_FM_NONE),
0b0320e7 32 myViewWidth (0),
33 myViewHeight (0),
3bffef55 34 myToUpdate (Standard_False)
0b0320e7 35{
d5846489 36 myDrawMode = GL_TRIANGLE_STRIP;
6ef0d6f1 37 myIsFillType = true;
0b0320e7 38
39 myGradientParams.color1 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
40 myGradientParams.color2 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
41 myGradientParams.type = Aspect_GFM_NONE;
42}
43
44// =======================================================================
45// method : SetTextureParameters
46// purpose :
47// =======================================================================
48void OpenGl_BackgroundArray::SetTextureParameters (const Aspect_FillMethod theFillMethod)
49{
50 if (myType != Graphic3d_TOB_TEXTURE)
51 {
52 return;
53 }
54
55 myFillMethod = theFillMethod;
56 invalidateData();
57}
58
59// =======================================================================
60// method : SetTextureFillMethod
61// purpose :
62// =======================================================================
63void OpenGl_BackgroundArray::SetTextureFillMethod (const Aspect_FillMethod theFillMethod)
64{
65 myFillMethod = theFillMethod;
66 invalidateData();
67}
68
69// =======================================================================
70// method : SetGradientParameters
71// purpose :
72// =======================================================================
73void OpenGl_BackgroundArray::SetGradientParameters (const Quantity_Color& theColor1,
74 const Quantity_Color& theColor2,
75 const Aspect_GradientFillMethod theType)
76{
77 if (myType != Graphic3d_TOB_GRADIENT)
78 {
79 return;
80 }
81
82 Standard_Real anR, aG, aB;
83 theColor1.Values (anR, aG, aB, Quantity_TOC_RGB);
84 myGradientParams.color1 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
85
86 theColor2.Values (anR, aG, aB, Quantity_TOC_RGB);
87 myGradientParams.color2 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
88
89 myGradientParams.type = theType;
90 invalidateData();
91}
92
93// =======================================================================
94// method : SetGradientFillMethod
95// purpose :
96// =======================================================================
97void OpenGl_BackgroundArray::SetGradientFillMethod (const Aspect_GradientFillMethod theType)
98{
99 if (myType != Graphic3d_TOB_GRADIENT)
100 {
101 return;
102 }
103
104 myGradientParams.type = theType;
105 invalidateData();
106}
107
108// =======================================================================
109// method : IsDefined
110// purpose :
111// =======================================================================
112bool OpenGl_BackgroundArray::IsDefined() const
113{
114 switch (myType)
115 {
116 case Graphic3d_TOB_GRADIENT: return myGradientParams.type != Aspect_GFM_NONE;
117 case Graphic3d_TOB_TEXTURE: return myFillMethod != Aspect_FM_NONE;
077a220c 118 case Graphic3d_TOB_CUBEMAP: return Standard_True;
0b0320e7 119 case Graphic3d_TOB_NONE: return Standard_False;
120 }
121 return Standard_False;
122}
123
124// =======================================================================
125// method : invalidateData
126// purpose :
127// =======================================================================
128void OpenGl_BackgroundArray::invalidateData()
129{
130 myToUpdate = Standard_True;
131}
132
133// =======================================================================
3bffef55 134// method : init
0b0320e7 135// purpose :
136// =======================================================================
3bffef55 137Standard_Boolean OpenGl_BackgroundArray::init (const Handle(OpenGl_Workspace)& theWorkspace) const
0b0320e7 138{
ba00aab7 139 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
0b0320e7 140 switch (myType)
141 {
142 case Graphic3d_TOB_GRADIENT:
143 {
ba00aab7 144 if (!createGradientArray (aCtx))
0b0320e7 145 {
146 return Standard_False;
147 }
148 break;
149 }
150 case Graphic3d_TOB_TEXTURE:
151 {
0b0320e7 152 if (!createTextureArray (theWorkspace))
153 {
154 return Standard_False;
155 }
156 break;
157 }
077a220c 158 case Graphic3d_TOB_CUBEMAP:
159 {
160 if (!createCubeMapArray())
161 {
162 return Standard_False;
163 }
164 break;
165 }
0b0320e7 166 case Graphic3d_TOB_NONE:
167 default:
168 {
169 return Standard_False;
170 }
171 }
172
173 // Init VBO
0b0320e7 174 if (myIsVboInit)
175 {
176 clearMemoryGL (aCtx);
177 }
178 buildVBO (aCtx, Standard_True);
179 myIsVboInit = Standard_True;
180
181 // Data is up-to-date
182 myToUpdate = Standard_False;
183 return Standard_True;
184}
185
186// =======================================================================
187// method : createGradientArray
188// purpose :
189// =======================================================================
ba00aab7 190Standard_Boolean OpenGl_BackgroundArray::createGradientArray (const Handle(OpenGl_Context)& theCtx) const
0b0320e7 191{
192 // Initialize data for primitive array
193 Graphic3d_Attribute aGragientAttribInfo[] =
194 {
195 { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2 },
196 { Graphic3d_TOA_COLOR, Graphic3d_TOD_VEC3 }
197 };
198
ba00aab7 199 if (myAttribs.IsNull())
200 {
201 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
202 myAttribs = new Graphic3d_Buffer (anAlloc);
203 }
0b0320e7 204 if (!myAttribs->Init (4, aGragientAttribInfo, 2))
205 {
206 return Standard_False;
207 }
208
209 OpenGl_Vec2 aVertices[4] =
210 {
3bffef55 211 OpenGl_Vec2(float(myViewWidth), 0.0f),
212 OpenGl_Vec2(float(myViewWidth), float(myViewHeight)),
213 OpenGl_Vec2(0.0f, 0.0f),
214 OpenGl_Vec2(0.0f, float(myViewHeight))
0b0320e7 215 };
216
b6472664 217 float* aCorners[4] = {};
218 float aDiagCorner1[3] = {};
219 float aDiagCorner2[3] = {};
0b0320e7 220
221 switch (myGradientParams.type)
222 {
223 case Aspect_GFM_HOR:
224 {
bc379358 225 aCorners[0] = myGradientParams.color2.ChangeData();
226 aCorners[1] = myGradientParams.color2.ChangeData();
227 aCorners[2] = myGradientParams.color1.ChangeData();
228 aCorners[3] = myGradientParams.color1.ChangeData();
0b0320e7 229 break;
230 }
231 case Aspect_GFM_VER:
232 {
bc379358 233 aCorners[0] = myGradientParams.color2.ChangeData();
234 aCorners[1] = myGradientParams.color1.ChangeData();
235 aCorners[2] = myGradientParams.color2.ChangeData();
236 aCorners[3] = myGradientParams.color1.ChangeData();
0b0320e7 237 break;
238 }
239 case Aspect_GFM_DIAG1:
240 {
bc379358 241 aCorners[0] = myGradientParams.color2.ChangeData();
242 aCorners[3] = myGradientParams.color1.ChangeData();
d5846489 243 aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[0][0] + aCorners[3][0]);
244 aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[0][1] + aCorners[3][1]);
245 aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[0][2] + aCorners[3][2]);
246 aCorners[1] = aDiagCorner1;
0b0320e7 247 aCorners[2] = aDiagCorner2;
248 break;
249 }
250 case Aspect_GFM_DIAG2:
251 {
bc379358 252 aCorners[1] = myGradientParams.color1.ChangeData();
253 aCorners[2] = myGradientParams.color2.ChangeData();
d5846489 254 aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[1][0] + aCorners[2][0]);
255 aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[1][1] + aCorners[2][1]);
256 aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[1][2] + aCorners[2][2]);
257 aCorners[0] = aDiagCorner1;
0b0320e7 258 aCorners[3] = aDiagCorner2;
259 break;
260 }
261 case Aspect_GFM_CORNER1:
262 {
3bffef55 263 aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
264 aVertices[1] = OpenGl_Vec2(0.0f, float(myViewHeight));
265 aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
266 aVertices[3] = OpenGl_Vec2(0.0f, 0.0f);
d5846489 267
bc379358 268 aCorners[0] = myGradientParams.color2.ChangeData();
269 aCorners[1] = myGradientParams.color1.ChangeData();
270 aCorners[2] = myGradientParams.color2.ChangeData();
271 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 272 break;
273 }
274 case Aspect_GFM_CORNER2:
275 {
bc379358 276 aCorners[0] = myGradientParams.color2.ChangeData();
277 aCorners[1] = myGradientParams.color1.ChangeData();
278 aCorners[2] = myGradientParams.color2.ChangeData();
279 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 280 break;
281 }
282 case Aspect_GFM_CORNER3:
283 {
3bffef55 284 aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
285 aVertices[1] = OpenGl_Vec2(0.0f, float(myViewHeight));
286 aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
287 aVertices[3] = OpenGl_Vec2(0.0f, 0.0f);
d5846489 288
bc379358 289 aCorners[0] = myGradientParams.color2.ChangeData();
290 aCorners[1] = myGradientParams.color2.ChangeData();
291 aCorners[2] = myGradientParams.color1.ChangeData();
292 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 293 break;
294 }
295 case Aspect_GFM_CORNER4:
296 {
bc379358 297 aCorners[0] = myGradientParams.color2.ChangeData();
298 aCorners[1] = myGradientParams.color2.ChangeData();
299 aCorners[2] = myGradientParams.color1.ChangeData();
300 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 301 break;
302 }
303 case Aspect_GFM_NONE:
304 {
305 break;
306 }
307 }
308
d5846489 309 for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
0b0320e7 310 {
d5846489 311 OpenGl_Vec2* aVertData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (anIt));
312 *aVertData = aVertices[anIt];
0b0320e7 313
d5846489 314 OpenGl_Vec3* aColorData = reinterpret_cast<OpenGl_Vec3* >(myAttribs->changeValue (anIt) + myAttribs->AttributeOffset (1));
ba00aab7 315 *aColorData = theCtx->Vec4FromQuantityColor (OpenGl_Vec4(aCorners[anIt][0], aCorners[anIt][1], aCorners[anIt][2], 1.0f)).rgb();
0b0320e7 316 }
317
318 return Standard_True;
319}
320
321// =======================================================================
322// method : createTextureArray
323// purpose :
324// =======================================================================
3bffef55 325Standard_Boolean OpenGl_BackgroundArray::createTextureArray (const Handle(OpenGl_Workspace)& theWorkspace) const
0b0320e7 326{
327 Graphic3d_Attribute aTextureAttribInfo[] =
328 {
329 { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2 },
330 { Graphic3d_TOA_UV, Graphic3d_TOD_VEC2 }
331 };
332
ba00aab7 333 if (myAttribs.IsNull())
334 {
335 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
336 myAttribs = new Graphic3d_Buffer (anAlloc);
337 }
0b0320e7 338 if (!myAttribs->Init (4, aTextureAttribInfo, 2))
339 {
340 return Standard_False;
341 }
342
343 GLfloat aTexRangeX = 1.0f; // texture <s> coordinate
344 GLfloat aTexRangeY = 1.0f; // texture <t> coordinate
345
346 // Set up for stretching or tiling
3bffef55 347 GLfloat anOffsetX = 0.5f * (float )myViewWidth;
348 GLfloat anOffsetY = 0.5f * (float )myViewHeight;
0b0320e7 349
350 // Setting this coefficient to -1.0f allows to tile textures relatively to the top-left corner of the view
351 // (value 1.0f corresponds to the initial behavior - tiling from the bottom-left corner)
352 GLfloat aCoef = -1.0f;
353
354 // Get texture parameters
355 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
bf5f0ca2 356 const OpenGl_Aspects* anAspectFace = theWorkspace->Aspects();
cc8cbabe 357 GLfloat aTextureWidth = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeX();
358 GLfloat aTextureHeight = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeY();
0b0320e7 359
360 if (myFillMethod == Aspect_FM_CENTERED)
361 {
3bffef55 362 anOffsetX = 0.5f * aTextureWidth;
363 anOffsetY = 0.5f * aTextureHeight;
0b0320e7 364 }
365 else if (myFillMethod == Aspect_FM_TILED)
366 {
367 aTexRangeX = (GLfloat )myViewWidth / aTextureWidth;
368 aTexRangeY = (GLfloat )myViewHeight / aTextureHeight;
369 }
370
371 // NOTE: texture is mapped using GL_REPEAT wrapping mode so integer part
372 // is simply ignored, and negative multiplier is here for convenience only
373 // and does not result e.g. in texture mirroring
374
0b0320e7 375
d5846489 376 OpenGl_Vec2* aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (0));
0b0320e7 377 aData[0] = OpenGl_Vec2 (anOffsetX, -aCoef * anOffsetY);
378 aData[1] = OpenGl_Vec2 (aTexRangeX, 0.0f);
379
d5846489 380 aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (1));
0b0320e7 381 aData[0] = OpenGl_Vec2 (anOffsetX, aCoef * anOffsetY);
382 aData[1] = OpenGl_Vec2 (aTexRangeX, aCoef * aTexRangeY);
383
d5846489 384 aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (2));
385 aData[0] = OpenGl_Vec2 (-anOffsetX, -aCoef * anOffsetY);
386 aData[1] = OpenGl_Vec2 (0.0f, 0.0f);
387
0b0320e7 388 aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (3));
389 aData[0] = OpenGl_Vec2 (-anOffsetX, aCoef * anOffsetY);
390 aData[1] = OpenGl_Vec2 (0.0f, aCoef * aTexRangeY);
391
392 return Standard_True;
393}
3bffef55 394
395// =======================================================================
077a220c 396// method : createCubeMapArray
397// purpose :
398// =======================================================================
399Standard_Boolean OpenGl_BackgroundArray::createCubeMapArray() const
400{
cdc54fb0 401 const Graphic3d_Attribute aCubeMapAttribInfo[] =
077a220c 402 {
cdc54fb0 403 { Graphic3d_TOA_POS, Graphic3d_TOD_VEC3 }
077a220c 404 };
405
ba00aab7 406 if (myAttribs.IsNull())
407 {
408 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
409 myAttribs = new Graphic3d_Buffer (anAlloc);
cdc54fb0 410 myIndices = new Graphic3d_IndexBuffer (anAlloc);
ba00aab7 411 }
cdc54fb0 412 if (!myAttribs->Init (8, aCubeMapAttribInfo, 1)
413 || !myIndices->Init<unsigned short> (14))
077a220c 414 {
415 return Standard_False;
416 }
417
077a220c 418 {
cdc54fb0 419 OpenGl_Vec3* aData = reinterpret_cast<OpenGl_Vec3*>(myAttribs->changeValue(0));
420 aData[0].SetValues (-1.0, -1.0, 1.0);
421 aData[1].SetValues ( 1.0, -1.0, 1.0);
422 aData[2].SetValues (-1.0, 1.0, 1.0);
423 aData[3].SetValues ( 1.0, 1.0, 1.0);
424 aData[4].SetValues (-1.0, -1.0, -1.0);
425 aData[5].SetValues ( 1.0, -1.0, -1.0);
426 aData[6].SetValues (-1.0, 1.0, -1.0);
427 aData[7].SetValues ( 1.0, 1.0, -1.0);
428 }
429 {
430 const unsigned short THE_BOX_TRISTRIP[14] = { 0, 1, 2, 3, 7, 1, 5, 4, 7, 6, 2, 4, 0, 1 };
431 for (unsigned int aVertIter = 0; aVertIter < 14; ++aVertIter)
432 {
433 myIndices->SetIndex (aVertIter, THE_BOX_TRISTRIP[aVertIter]);
434 }
077a220c 435 }
436
437 return Standard_True;
438}
439
440// =======================================================================
441// method : Render
3bffef55 442// purpose :
443// =======================================================================
cdc54fb0 444void OpenGl_BackgroundArray::Render (const Handle(OpenGl_Workspace)& theWorkspace,
445 Graphic3d_Camera::Projection theProjection) const
3bffef55 446{
447 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
448 Standard_Integer aViewSizeX = aCtx->Viewport()[2];
449 Standard_Integer aViewSizeY = aCtx->Viewport()[3];
f051908e 450 Graphic3d_Vec2i aTileOffset, aTileSize;
451
3bffef55 452 if (theWorkspace->View()->Camera()->Tile().IsValid())
453 {
454 aViewSizeX = theWorkspace->View()->Camera()->Tile().TotalSize.x();
455 aViewSizeY = theWorkspace->View()->Camera()->Tile().TotalSize.y();
f051908e 456
457 aTileOffset = theWorkspace->View()->Camera()->Tile().OffsetLowerLeft();
458 aTileSize = theWorkspace->View()->Camera()->Tile().TileSize;
3bffef55 459 }
460 if (myToUpdate
461 || myViewWidth != aViewSizeX
ba00aab7 462 || myViewHeight != aViewSizeY
463 || myAttribs.IsNull()
464 || myVboAttribs.IsNull())
3bffef55 465 {
466 myViewWidth = aViewSizeX;
467 myViewHeight = aViewSizeY;
468 init (theWorkspace);
469 }
470
471 OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
472 OpenGl_Mat4 aWorldView = aCtx->WorldViewState.Current();
077a220c 473
cdc54fb0 474 if (myType == Graphic3d_TOB_CUBEMAP)
475 {
476 Graphic3d_Camera aCamera (theWorkspace->View()->Camera());
477 aCamera.SetZRange (0.01, 1.0); // is needed to avoid perspective camera exception
478
479 // cancel translation
480 aCamera.MoveEyeTo (gp_Pnt (0.0, 0.0, 0.0));
481
482 // Handle projection matrix:
483 // - Cancel any head-to-eye translation for HMD display;
484 // - Ignore stereoscopic projection in case of non-HMD 3D display
485 // (ideally, we would need a stereoscopic cubemap image; adding a parallax makes no sense);
486 // - Force perspective projection when orthographic camera is active
487 // (orthographic projection makes no sense for cubemap).
488 const bool isCustomProj = aCamera.IsCustomStereoFrustum()
489 || aCamera.IsCustomStereoProjection();
490 aCamera.SetProjectionType (theProjection == Graphic3d_Camera::Projection_Orthographic || !isCustomProj
491 ? Graphic3d_Camera::Projection_Perspective
492 : theProjection);
493
494 aProjection = aCamera.ProjectionMatrixF();
495 aWorldView = aCamera.OrientationMatrixF();
496 if (isCustomProj)
497 {
498 // get projection matrix without pre-multiplied stereoscopic head-to-eye translation
499 if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
500 {
501 Graphic3d_Mat4 aMatProjL, aMatHeadToEyeL, aMatProjR, aMatHeadToEyeR;
502 aCamera.StereoProjectionF (aMatProjL, aMatHeadToEyeL, aMatProjR, aMatHeadToEyeR);
503 aProjection = aMatProjL;
504 }
505 else if (theProjection == Graphic3d_Camera::Projection_MonoRightEye)
506 {
507 Graphic3d_Mat4 aMatProjL, aMatHeadToEyeL, aMatProjR, aMatHeadToEyeR;
508 aCamera.StereoProjectionF (aMatProjL, aMatHeadToEyeL, aMatProjR, aMatHeadToEyeR);
509 aProjection = aMatProjR;
510 }
511 }
512 }
513 else
077a220c 514 {
f051908e 515 aProjection.InitIdentity();
516 aWorldView.InitIdentity();
517 if (theWorkspace->View()->Camera()->Tile().IsValid())
518 {
519 aWorldView.SetDiagonal (OpenGl_Vec4 (2.0f / aTileSize.x(), 2.0f / aTileSize.y(), 1.0f, 1.0f));
520 if (myType == Graphic3d_TOB_GRADIENT)
521 {
522 aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f - 2.0f * aTileOffset.x() / aTileSize.x(),
523 -1.0f - 2.0f * aTileOffset.y() / aTileSize.y(), 0.0f, 1.0f));
524 }
525 else
526 {
527 aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f + (float) aViewSizeX / aTileSize.x() - 2.0f * aTileOffset.x() / aTileSize.x(),
528 -1.0f + (float) aViewSizeY / aTileSize.y() - 2.0f * aTileOffset.y() / aTileSize.y(), 0.0f, 1.0f));
529 }
530 }
531 else
532 {
533 aWorldView.SetDiagonal (OpenGl_Vec4 (2.0f / myViewWidth, 2.0f / myViewHeight, 1.0f, 1.0f));
534 if (myType == Graphic3d_TOB_GRADIENT)
535 {
536 aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f, -1.0f, 0.0f, 1.0f));
537 }
538 }
077a220c 539 }
3bffef55 540
541 aCtx->ProjectionState.Push();
542 aCtx->WorldViewState.Push();
543 aCtx->ProjectionState.SetCurrent (aProjection);
544 aCtx->WorldViewState.SetCurrent (aWorldView);
545 aCtx->ApplyProjectionMatrix();
546 aCtx->ApplyModelViewMatrix();
547
548 OpenGl_PrimitiveArray::Render (theWorkspace);
549
550 aCtx->ProjectionState.Pop();
551 aCtx->WorldViewState.Pop();
552 aCtx->ApplyProjectionMatrix();
553}