forked from OpenRA/OpenRA
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFrameBuffer.cs
164 lines (140 loc) · 4.44 KB
/
FrameBuffer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Diagnostics;
using System.IO;
using OpenRA.Primitives;
namespace OpenRA.Platforms.Default
{
sealed class FrameBuffer : ThreadAffine, IFrameBuffer
{
readonly ITexture texture;
readonly Size size;
readonly Color clearColor;
uint framebuffer, depth;
bool disposed;
bool scissored;
public FrameBuffer(Size size, ITextureInternal texture, Color clearColor)
{
this.size = size;
this.clearColor = clearColor;
if (!Exts.IsPowerOf2(size.Width) || !Exts.IsPowerOf2(size.Height))
throw new InvalidDataException("Frame buffer size ({0}x{1}) must be a power of two".F(size.Width, size.Height));
OpenGL.glGenFramebuffers(1, out framebuffer);
OpenGL.CheckGLError();
OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer);
OpenGL.CheckGLError();
// Color
this.texture = texture;
texture.SetEmpty(size.Width, size.Height);
OpenGL.glFramebufferTexture2D(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_COLOR_ATTACHMENT0, OpenGL.GL_TEXTURE_2D, texture.ID, 0);
OpenGL.CheckGLError();
// Depth
OpenGL.glGenRenderbuffers(1, out depth);
OpenGL.CheckGLError();
OpenGL.glBindRenderbuffer(OpenGL.GL_RENDERBUFFER, depth);
OpenGL.CheckGLError();
var glDepth = OpenGL.Profile == GLProfile.Embedded ? OpenGL.GL_DEPTH_COMPONENT16 : OpenGL.GL_DEPTH_COMPONENT;
OpenGL.glRenderbufferStorage(OpenGL.GL_RENDERBUFFER, glDepth, size.Width, size.Height);
OpenGL.CheckGLError();
OpenGL.glFramebufferRenderbuffer(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_DEPTH_ATTACHMENT, OpenGL.GL_RENDERBUFFER, depth);
OpenGL.CheckGLError();
// Test for completeness
var status = OpenGL.glCheckFramebufferStatus(OpenGL.GL_FRAMEBUFFER);
if (status != OpenGL.GL_FRAMEBUFFER_COMPLETE)
{
var error = "Error creating framebuffer: {0}\n{1}".F(status, new StackTrace());
OpenGL.WriteGraphicsLog(error);
throw new InvalidOperationException("OpenGL Error: See graphics.log for details.");
}
// Restore default buffer
OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0);
OpenGL.CheckGLError();
}
static int[] ViewportRectangle()
{
var v = new int[4];
OpenGL.glGetIntegerv(OpenGL.GL_VIEWPORT, out v[0]);
OpenGL.CheckGLError();
return v;
}
int[] cv = new int[4];
public void Bind()
{
VerifyThreadAffinity();
// Cache viewport rect to restore when unbinding
cv = ViewportRectangle();
OpenGL.glFlush();
OpenGL.CheckGLError();
OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer);
OpenGL.CheckGLError();
OpenGL.glViewport(0, 0, size.Width, size.Height);
OpenGL.CheckGLError();
OpenGL.glClearColor(clearColor.R, clearColor.G, clearColor.B, clearColor.A);
OpenGL.CheckGLError();
OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
OpenGL.CheckGLError();
}
public void Unbind()
{
if (scissored)
throw new InvalidOperationException("Attempting to unbind FrameBuffer with an active scissor region.");
VerifyThreadAffinity();
OpenGL.glFlush();
OpenGL.CheckGLError();
OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0);
OpenGL.CheckGLError();
OpenGL.glViewport(cv[0], cv[1], cv[2], cv[3]);
OpenGL.CheckGLError();
}
public void EnableScissor(Rectangle rect)
{
VerifyThreadAffinity();
OpenGL.glScissor(rect.X, rect.Y, Math.Max(rect.Width, 0), Math.Max(rect.Height, 0));
OpenGL.CheckGLError();
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
OpenGL.CheckGLError();
scissored = true;
}
public void DisableScissor()
{
VerifyThreadAffinity();
OpenGL.glDisable(OpenGL.GL_SCISSOR_TEST);
OpenGL.CheckGLError();
scissored = false;
}
public ITexture Texture
{
get
{
VerifyThreadAffinity();
return texture;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool disposing)
{
if (disposed)
return;
disposed = true;
if (disposing)
texture.Dispose();
OpenGL.glDeleteFramebuffers(1, ref framebuffer);
OpenGL.CheckGLError();
OpenGL.glDeleteRenderbuffers(1, ref depth);
OpenGL.CheckGLError();
}
}
}