public Bitmap ReadFramebufferTest() { Size bmpSize = new Size(Width, Height);; if (GL.IsFramebuffer(frameBuffer[isCore, 1])) { bmpSize = _videoSize; } if ((bmpSize.Height <= 0) || (bmpSize.Width <= 0)) { return(null); } Bitmap testBmp = new Bitmap(bmpSize.Width, bmpSize.Height); //Graphics gr = Graphics.FromImage(testBmp); //gr.Clear(Color.Red); var testData = testBmp.LockBits( new Rectangle(0, 0, testBmp.Width, testBmp.Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); RenderControl.GLError("A"); GL.ReadPixels(0, 0, testBmp.Width, testBmp.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, testData.Scan0); RenderControl.GLInfo("B"); // SetRenderTarget(RenderControl.RenderTarget.ScreenDirect); // GL.DrawPixels(Width, Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, testData.Scan0); testBmp.UnlockBits(testData); // testBmp.Dispose(); return(testBmp); }
/// <summary> /// Recursive rendering function /// </summary> /// <param name="node">Current node</param> /// <param name="visibleMeshesByNode"> </param> /// <param name="flags">Rendering flags</param> /// <param name="animated">Play animation?</param> /// <returns>whether there is any need to do a second render pass with alpha blending enabled</returns> protected bool RecursiveRender(Node node, Dictionary <Node, List <Mesh> > visibleMeshesByNode, RenderFlags flags, bool animated, int currDispList) { var needAlpha = false; Matrix4 m; if (animated) { Owner.SceneAnimator.GetLocalTransform(node, out m); } else { m = AssimpToOpenTk.FromMatrix(node.Transform); } // TODO for some reason, all OpenTk matrices need a ^T - we should clarify our conventions somewhere RenderControl.GLError("A11"); m.Transpose(); PushWorld(ref m); RenderControl.GLError("B11"); if ((node.HasMeshes) && (currDispList == GetDispList(node.Name))) { needAlpha = DrawOpaqueMeshes(node, visibleMeshesByNode, flags, animated); } for (var i = 0; i < node.ChildCount; i++) { needAlpha = RecursiveRender(node.Children[i], visibleMeshesByNode, flags, animated, currDispList) || needAlpha; } RenderControl.GLError("C11"); PopWorld(); return(needAlpha); }
/// <summary> /// Switches between all available targets. /// </summary> /// <returns></returns> public void SetRenderTarget(RenderTarget rt) { RenderControl.GLError("BeforeTargetChange"); switch (rt) { case RenderTarget.ScreenDirect: this.MakeCurrent(); // GL.Viewport(Left, Top, Width, Height); isCore = 0; GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); break; case RenderTarget.ScreenCompat: this.MakeCurrent(); // GL.Viewport(Left, Top, Width, Height); isCore = 0; GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 0]); break; case RenderTarget.ScreenCore: glCore.MakeCurrent(); // GL.Viewport(Left, Top, Width, Height); isCore = 1; GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 0]); break; case RenderTarget.VideoCompat: this.MakeCurrent(); GL.Viewport(0, 0, _videoSize.Width, _videoSize.Height); isCore = 0; GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 1]); break; case RenderTarget.VideoCore: glCore.MakeCurrent(); GL.Viewport(0, 0, _videoSize.Width, _videoSize.Height); isCore = 1; GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 1]); break; case RenderTarget.VideoSSCompat: this.MakeCurrent(); GL.Viewport(0, 0, _videoSize.Width, _videoSize.Height); isCore = 0; GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 2]); break; case RenderTarget.VideoSSCore: glCore.MakeCurrent(); isCore = 1; GL.Viewport(0, 0, _videoSize.Width, _videoSize.Height); GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer[isCore, 2]); break; } RenderControl.GLError("AfterTargetChange"); }
/// <summary> /// Draws the mesh geometry given the current pipeline state. /// /// The pipeline is restored afterwards. /// </summary> /// <param name="flags">Rendering mode</param> public void Render(RenderFlags flags) { Debug.Assert(_vbo.VertexBufferId != 0); Debug.Assert(_vbo.ElementBufferId != 0); GL.BindVertexArray(_vbo.VertexArray); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo.VertexBufferId); // primitives GL.BindBuffer(BufferTarget.ElementArrayBuffer, _vbo.ElementBufferId); GL.DrawElements(OpenTK.Graphics.OpenGL.PrimitiveType.Triangles, _vbo.NumIndices, _vbo.Is32BitIndices ? DrawElementsType.UnsignedInt : DrawElementsType.UnsignedShort, IntPtr.Zero); RenderControl.GLError("EndModernRender"); }
/// <summary> /// <see cref="ISceneRenderer.Render"/> /// </summary> /// </summary> public void Render(ICameraController cam, Dictionary <Node, List <Mesh> > visibleMeshesByNode, bool visibleSetChanged, bool texturesChanged, RenderFlags flags, Renderer renderer) { RenderControl.GLError("ModernRenderStart"); GL.Enable(EnableCap.DepthTest); GL.FrontFace(FrontFaceDirection.Ccw); if (flags.HasFlag(RenderFlags.Wireframe)) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } var view = cam == null?Matrix4.LookAt(0, 10, 5, 0, 0, 0, 0, 1, 0) : cam.GetView(); var tmp = InitposeMax.X - InitposeMin.X; tmp = Math.Max(InitposeMax.Y - InitposeMin.Y, tmp); tmp = Math.Max(InitposeMax.Z - InitposeMin.Z, tmp); int logScale = (int)Math.Truncate(Math.Log10(tmp * 10 / 50)); // Up to 50units max size = 50m: keep scale (for smaller scenes). float scale = 1; for (int i = 0; i < logScale; i++) { scale = scale / 10; } Owner.Scale = scale; Matrix4 world = Matrix4.Identity;//want to keep unity in our world // set a proper perspective matrix for rendering int[] CurrentViewport = new int[4]; GL.GetInteger(GetPName.Viewport, CurrentViewport); var aspectRatio = (float)CurrentViewport[2] / CurrentViewport[3]; Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(cam.GetFOV(), aspectRatio, renderer.zNear, renderer.zFar); Owner.MaterialMapper.SetMatrices(world, view, perspective); PushWorld(ref world); Owner.MaterialMapper.BeginScene(renderer, flags.HasFlag(RenderFlags.UseSceneLights)); //here we switch on lights // If textures changed, we may need to upload some of them to VRAM. if (texturesChanged) { UploadTextures(); } var animated = Owner.SceneAnimator.IsAnimationActive; int currDispList = 0; int count = 1; switch (cam.GetScenePartMode()) { case ScenePartMode.Background: currDispList = 0; break; case ScenePartMode.Foreground: currDispList = 2; break; case ScenePartMode.Others: currDispList = 1; break; case ScenePartMode.GreenScreen: currDispList = 3; break; case ScenePartMode.All: currDispList = 0; count = 4; break; default: break; //at other modes we do not render anything } for (int countDispList = 0; countDispList < count; countDispList++) { var needAlpha = RecursiveRender(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList); var needAlphaAnim = RecursiveRender(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList + 4); if (flags.HasFlag(RenderFlags.ShowSkeleton) || flags.HasFlag(RenderFlags.ShowNormals)) { //RecursiveRenderNoScale(Owner.Raw.RootNode, visibleMeshesByNode, flags, 1.0f / tmp, animated); } if (needAlpha) { // handle semi-transparent geometry RecursiveRenderWithAlpha(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList); } if (needAlphaAnim) { // handle semi-transparent geometry RecursiveRenderWithAlpha(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList + 4); } currDispList++; /* RenderFlags application: * Wireframe = 0x1, - Scene renderer,OK * Shaded = 0x2, - MaterialMapper.ApplyMaterial, OK * ShowBoundingBoxes = 0x4, * ShowNormals = 0x8, - Scene renderer, unused in GL4 * ShowSkeleton = 0x10, - Scene renderer, unused in GL4 * Textured = 0x20, - MaterialMapper.ApplyMaterial, OK * ShowGhosts = 0x40, unused, always ON, InternDrawMesh applies own showGhost to MaterialMapper.Apply(Ghost)Material, * UseSceneLights = 0x80, - MaterialMapper.BeginScene, OK */ } PopWorld(); // always switch back to FILL GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.Disable(EnableCap.DepthTest); RenderControl.GLError("SceneRendererModernGLEnd"); }
/// <summary> /// Upload the texture to video RAM. /// /// This requires that State == TextureState.WinFormsImageCreated, i.e. the /// RAM texture image must be ready for use and the Gl object may not have /// been created yet. /// /// Must be called on a thread that is allowed to use Gl APIs. /// </summary> public void Upload() { if (State == TextureState.GlTextureCreated) { return; } Debug.Assert(State == TextureState.WinFormsImageCreated); // this may be required if ReleaseUpload() has been called before if (_gl != 0) { GL.DeleteTexture(_gl); _gl = 0; } lock (_lock) { // this is a long CS, but at this time we don't expect concurrent action, i.e. updating texture by loader. // http://www.opentk.com/node/259 Bitmap textureBitmap = null; var shouldDisposeBitmap = false; // in order to LockBits(), we need to create a Bitmap. In case the given Image // *is* already a Bitmap however, we can directly re-use it. try { if (_image is Bitmap) { textureBitmap = (Bitmap)_image; } else { textureBitmap = new Bitmap(_image); shouldDisposeBitmap = true; } RenderControl.GLError("StartUploadTex"); // apply texture resolution bias? (i.e. low quality textures) if (GraphicsSettings.Default.TexQualityBias > 0) { var b = ApplyResolutionBias(textureBitmap, GraphicsSettings.Default.TexQualityBias); if (shouldDisposeBitmap) { textureBitmap.Dispose(); } textureBitmap = b; shouldDisposeBitmap = true; } var textureData = textureBitmap.LockBits( new Rectangle(0, 0, textureBitmap.Width, textureBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb ); // determine alpha pixels if this has not been done before if (_alphaState == AlphaState.NotKnownYet) { _alphaState = LookForAlphaBits(textureData) ? AlphaState.HasAlpha : AlphaState.Opaque; } int tex; GL.GenTextures(1, out tex); GL.Arb.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, tex); // upload { RenderControl.GLError("BeforeUploadTex"); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, textureBitmap.Width, textureBitmap.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, textureData.Scan0); RenderControl.GLError("EndUploadTex"); } textureBitmap.UnlockBits(textureData); // set final state only if the Gl texture object has been filled successfully if (GL.GetError() == ErrorCode.NoError) { _gl = tex; State = TextureState.GlTextureCreated; } ConfigureFilters(); //Contains Generate mipmaps, texture must be uploaded and GlTextureCreated; } finally { if (shouldDisposeBitmap) { textureBitmap.Dispose(); } } } /* check upload is OK * { * GL.BindTexture(TextureTarget.Texture2D, _gl); * Bitmap xtestBmp = new Bitmap(1080, 1080); * var testData = xtestBmp.LockBits(new Rectangle(0, 0, xtestBmp.Width, xtestBmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); * GL.GetTexImage(TextureTarget.Texture2D, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, testData.Scan0); * xtestBmp.UnlockBits(testData); * xtestBmp.Dispose(); * } */ }
public override void ApplyMaterial(Mesh mesh, Material mat, bool textured, bool shaded, bool twoSided) { RenderControl.GLError("StartMaterialMapper"); ShaderGen.GenFlags flags = 0; var hasAlpha = false; var hasTexture = false; // note: keep this up-to-date with the code in MaterialMapper.UploadTextures() for (int i = 0; i < Renderer.modernGLUsedTextureTypeCount; i++) { TextureType currTextureType = (TextureType)((int)TextureType.Diffuse + i); GL.ActiveTexture((TextureUnit)((int)TextureUnit.Texture0 + i)); GL.BindTexture(TextureTarget.Texture2D, Renderer.modernGLTextureType[i]); //we use own texture always, even when textures off to supply preset values if (textured && mat.GetMaterialTextureCount(currTextureType) > 0) { hasTexture = true; //flags |= ShaderGen.GenFlags.Texture; flag not used, we always have some texture TextureSlot tex; mat.GetMaterialTexture(currTextureType, 0, out tex); var gtex = _scene.TextureSet.GetOriginalOrReplacement(tex.FilePath); hasAlpha = hasAlpha || gtex.HasAlpha == Texture.AlphaState.HasAlpha; if (gtex.State == Texture.TextureState.GlTextureCreated) { gtex.BindGlTexture(); } } } GL.ActiveTexture(TextureUnit.Texture0); RenderControl.GLError("EndTextureSettings"); if (shaded) { flags |= ShaderGen.GenFlags.Lighting; } var hasColors = mesh != null && mesh.HasVertexColors(0); if (hasColors) { flags |= ShaderGen.GenFlags.VertexColor; } if (_UseSceneLights) { flags |= ShaderGen.GenFlags.PhongSpecularShading; } if ((mat.IsTwoSided) || (twoSided)) { flags |= ShaderGen.GenFlags.TwoSide; } Shader shader = _shaderGen.GenerateOrGetFromCache(flags, _LightCount > 0 ? _LightCount : 1); shader.BindIfNecessary(); Matrix4 curView = Matrix4.CreateScale(_scene.Scale) * _View; shader.SetMat4("WorldViewProjection", _World * curView * _Perspective); Matrix4 cameraPos = _View.ClearRotation(); Matrix4 cameraRotation = _View.ClearTranslation(); Matrix4 cam = Matrix4.Identity; cam = cameraPos * cameraRotation; Vector3 cameraPosition = -cam.ExtractTranslation() / _scene.Scale;//does not work for orbitcontroller // cameraPosition = new Vector3(200,100,-100); //1m = 100units and positive cameraPosition.Z = -cameraPosition.Z; shader.SetVec3("CameraPosition", -cameraPosition); shader.SetMat4("World", _World); shader.SetMat4("WorldView", _World * curView); //_world* curView keeps light source at "fixed" position during rotating of the model shader.SetFloat("SceneBrightness", _SceneBrightness); shader.SetFloat("Material.diffuse", 0); shader.SetFloat("Material.ambient", 1); shader.SetFloat("Material.specular", 2); shader.SetFloat("Material.emissive", 3); shader.SetFloat("Material.height", 4); shader.SetFloat("Material.normal", 5); shader.SetLights(_GLLights, _LightCount); RenderControl.GLError("UniformSettings"); // note: keep semantics of hasAlpha consistent with IsAlphaMaterial() var alpha = 1.0f; if (mat.HasOpacity) { alpha = mat.Opacity; if (alpha < AlphaSuppressionThreshold) // suppress zero opacity, this is likely wrong input data { alpha = 1.0f; } } var color = new Color4(.8f, .8f, .8f, 1.0f); if (mat.HasColorDiffuse) { color = AssimpToOpenTk.FromColor(mat.ColorDiffuse); if (color.A < AlphaSuppressionThreshold) // s.a. { color.A = 1.0f; } } color.A *= alpha; hasAlpha = hasAlpha || color.A < 1.0f; if (shaded) { // if the material has a texture but the diffuse color texture is all black, // then heuristically assume that this is an import/export flaw and substitute // white. if (hasTexture && color.R < 1e-3f && color.G < 1e-3f && color.B < 1e-3f) { color = Color4.White; } shader.SetCol4("MaterialDiffuse_Alpha", color); color = new Color4(0, 0, 0, 1.0f); if (mat.HasColorSpecular) { color = AssimpToOpenTk.FromColor(mat.ColorSpecular); } shader.SetCol4("MaterialSpecular", color); color = new Color4(.2f, .2f, .2f, 1.0f); if (mat.HasColorAmbient) { color = AssimpToOpenTk.FromColor(mat.ColorAmbient); } shader.SetCol4("MaterialAmbient", color); color = new Color4(0, 0, 0, 1.0f); if (mat.HasColorEmissive) { color = AssimpToOpenTk.FromColor(mat.ColorEmissive); } shader.SetCol4("MaterialEmissive", color); float shininess = 1; float strength = 1; if (mat.HasShininess) { shininess = mat.Shininess; } // todo: I don't even remember how shininess strength was supposed to be handled in assimp .. Scales the specular color of the material.Not implemented here. if (mat.HasShininessStrength) { strength = mat.ShininessStrength; } var exp = shininess; if (exp >= 128.0f) // 128 is the maximum exponent as per the Gl spec { exp = 128.0f; } shader.SetFloat("MaterialShininess", exp); //Shininess may be at mat.ColorSpecular.a too..?? but in FBX is } else if (!hasColors) { shader.SetCol4("MaterialDiffuse_Alpha", color); } if (hasAlpha) { GL.Enable(EnableCap.Blend); GL.BlendFuncSeparate(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha, BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One); GL.DepthMask(false); } else { GL.DepthMask(true); GL.Disable(EnableCap.Blend); } RenderControl.GLError("EndMaterialMapper"); }
public override void Dispose() { _shaderGen.Dispose(); GC.SuppressFinalize(this); RenderControl.GLError("MaterialNewDispose"); }
public override void BeginScene(Renderer renderer, bool useSceneLights = true) { _UseSceneLights = useSceneLights; if (useSceneLights) { var lightNodes = GenerateLightNodes(); var Lights = GenerateLights(); _LightCount = LightCount(); _GLLights = new GLLight[_LightCount]; for (var i = 0; i < _LightCount; i++) { Node node = lightNodes[i]; if ((node != null) && ((node == _scene.ActiveLight) || (null == _scene.ActiveLight))) { var mat1 = Matrix4x4.Identity; var cur = node; while (cur != null) { var trafo = cur.Transform; trafo.Transpose(); mat1 = trafo * mat1; cur = cur.Parent; } mat1.Transpose(); var mat = renderer.LightRotation; //here move position info into lights[] _GLLights[i].lightType = (int)Lights[i].LightType; Vector3 lposTemp = new Vector3(mat1.A4, mat1.B4, mat1.C4); Vector3 ldirTemp = new Vector3(mat1.B1, -mat1.B2, mat1.B3); //partially a guess, needed verification _GLLights[i].position = lposTemp; _GLLights[i].direction = -ldirTemp; float baseBrightness = 0.01f; float lightScale = _GLLights[i].lightType == 1 ? baseBrightness : 1.0f; _GLLights[i].ambient = Colo3DToVector3(Lights[i].ColorAmbient) * lightScale; _GLLights[i].specular = Colo3DToVector3(Lights[i].ColorSpecular) * lightScale * 2; _GLLights[i].diffuse = Colo3DToVector3(Lights[i].ColorDiffuse) * lightScale; _GLLights[i].constant = Lights[i].AttenuationConstant; _GLLights[i].linear = Lights[i].AttenuationLinear * _scene.Scale; _GLLights[i].quadratic = Lights[i].AttenuationQuadratic * _scene.Scale * _scene.Scale; _GLLights[i].outerCutOff = Lights[i].AngleOuterCone; _GLLights[i].cutOff = Lights[i].AngleInnerCone; } } _SceneBrightness = (0.25f + 1.5f * GraphicsSettings.Default.OutputBrightness / 100.0f) * 1.5f; int neededUniformComponents = 21 * 4 * _LightCount + 15 * 4 * 4;//approximately if (neededUniformComponents > GL.GetInteger(GetPName.MaxFragmentUniformComponents)) { throw new Exception("Too many lights"); } } else { _LightCount = 1; // light direction var dir = new Vector3(0, 0, 1); var mat = renderer.LightRotation; Vector3.TransformNormal(ref dir, ref mat, out dir); // light color var col = new Vector3(1, 1, 1); _SceneBrightness = (0.00f + 5f * GraphicsSettings.Default.OutputBrightness / 100.0f); _GLLights = new GLLight[_LightCount]; _GLLights[0].lightType = 1; _GLLights[0].direction = dir; _GLLights[0].specular = col; _GLLights[0].diffuse = col; } RenderControl.GLError("BeginSceneEnd"); }
/// <summary> /// Sets up initiate values and buffers. /// </summary> /// <returns></returns> public void InitGlControl(int videoSizeX, int videoSizeY) { ErrorCode err = GL.GetError();//nVidia does not like something at real beginning RenderControl.GLError("InitializeGLControl"); _videoSize.Width = videoSizeX; _videoSize.Height = videoSizeY; GL.GenRenderbuffers(numBuffers, renderBuffer); GL.GenRenderbuffers(numBuffers, depthBuffer); GL.GenBuffers(numBuffers, pixelPackBuffer); GL.GenBuffers(numBuffers, pixelUnpackBuffer); GL.Enable(EnableCap.Multisample); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer[0]); GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, samples, RenderbufferStorage.Rgba8, Width, Height); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer[0]); GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, samples, RenderbufferStorage.Depth24Stencil8, Width, Height); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer[1]); GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, samples, RenderbufferStorage.Rgba8, videoSizeX, videoSizeY); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer[1]); GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, samples, RenderbufferStorage.Depth24Stencil8, videoSizeX, videoSizeY); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBuffer[2]); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgba8, videoSizeX, videoSizeY); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer[2]); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, videoSizeX, videoSizeY); this.MakeCurrent(); VSync = false; isCore = 0; int[] frameBufferCompat = new int[numBuffers]; GL.GenFramebuffers(numBuffers, frameBufferCompat); frameBuffer[isCore, 0] = frameBufferCompat[0]; frameBuffer[isCore, 1] = frameBufferCompat[1]; frameBuffer[isCore, 2] = frameBufferCompat[2]; BindBuffers(); GL.BindBuffer(BufferTarget.PixelPackBuffer, pixelPackBuffer[0]); GL.BufferData(BufferTarget.PixelPackBuffer, (IntPtr)(Width * Height * bytePerPixel), (IntPtr)0, BufferUsageHint.DynamicCopy); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, pixelUnpackBuffer[0]); GL.BufferData(BufferTarget.PixelUnpackBuffer, (IntPtr)(Width * Height * bytePerPixel), (IntPtr)0, BufferUsageHint.DynamicCopy); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); glCore.MakeCurrent(); glCore.VSync = false; isCore = 1; int[] frameBufferCore = new int[numBuffers]; GL.GenFramebuffers(numBuffers, frameBufferCore); frameBuffer[isCore, 0] = frameBufferCore[0]; frameBuffer[isCore, 1] = frameBufferCore[1]; frameBuffer[isCore, 2] = frameBufferCore[2]; BindBuffers(); GL.BindBuffer(BufferTarget.PixelPackBuffer, pixelPackBuffer[1]); GL.BufferData(BufferTarget.PixelPackBuffer, (IntPtr)(videoSizeX * videoSizeY * bytePerPixel), (IntPtr)0, BufferUsageHint.DynamicRead); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, pixelUnpackBuffer[1]); GL.BufferData(BufferTarget.PixelUnpackBuffer, (IntPtr)(videoSizeX * videoSizeY * bytePerPixel), (IntPtr)0, BufferUsageHint.DynamicDraw); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); initialized = true; RenderControl.GLError("AfterInit"); }