GLClippingPlanes.java
6.14 KB
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package com.mumfrey.liteloader.gl;
import static org.lwjgl.opengl.GL11.*;
import java.nio.DoubleBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.util.Rectangle;
/**
* OpenGL clipping plane convenience functions. We prefer to clip rectangular
* GUI regions in Minecraft using clipping rather than scissor because scissor
* is a nuisance to work with, primarily because it works in "window" (OpenGL
* window) coordinates and doesn't respect the current transformation matrix.
* Using clipping planes we can specify clipping edges in "Minecraft screen
* coordinates", can optionally clip on only one or two axes, and also don't
* need to worry about the current transform.
*
* @author Adam Mummery-Smith
*/
public final class GLClippingPlanes
{
public enum Plane
{
LEFT(GL_CLIP_PLANE0),
RIGHT(GL_CLIP_PLANE1),
TOP(GL_CLIP_PLANE2),
BOTTOM(GL_CLIP_PLANE3);
final int plane;
final int sign;
private Plane(int plane)
{
this.plane = plane;
this.sign = (plane % 2 == 0) ? -1 : 1;
}
}
private static final int STACK_DEPTH = 1;
private static final int STACK_FRAME_SIZE = 128;
private static DoubleBuffer doubleBuffer = BufferUtils.createByteBuffer(STACK_FRAME_SIZE * STACK_DEPTH).asDoubleBuffer();
private static int clippingPlaneFlags = 0;
private static int totalClippingPlanes = glGetInteger(GL_MAX_CLIP_PLANES);
// private static int frame = 0;
static
{
for (int f = 0; f < STACK_DEPTH; f++)
{
// Clipping normals
GLClippingPlanes.doubleBuffer.put(1).put(0).put(0).put(0);
GLClippingPlanes.doubleBuffer.put(-1).put(0).put(0).put(0);
GLClippingPlanes.doubleBuffer.put(0).put(1).put(0).put(0);
GLClippingPlanes.doubleBuffer.put(0).put(-1).put(0).put(0);
}
}
private GLClippingPlanes() {}
/**
* Get the total number of available clipping planes on the platform
*/
public static int glGetTotalClippingPlanes()
{
return GLClippingPlanes.totalClippingPlanes;
}
/**
* Enable OpenGL clipping planes (uses planes 0, 1, 2 and 3)
*
* @param left Left edge clip or -1 to not use this plane
* @param right Right edge clip or -1 to not use this plane
* @param top Top edge clip or -1 to not use this plane
* @param bottom Bottom edge clip or -1 to not use this plane
*/
public static void glEnableClipping(int left, int right, int top, int bottom)
{
GLClippingPlanes.clippingPlaneFlags = 0;
glEnableClipping(GL_CLIP_PLANE0, left, -1);
glEnableClipping(GL_CLIP_PLANE1, right, 1);
glEnableClipping(GL_CLIP_PLANE2, top, -1);
glEnableClipping(GL_CLIP_PLANE3, bottom, 1);
}
/**
* Enable OpenGL clipping planes (uses planes 0, 1, 2 and 3)
*
* @param rect Clipping rectangle
*/
public static void glEnableClipping(Rectangle rect)
{
GLClippingPlanes.clippingPlaneFlags = 0;
glEnableClipping(GL_CLIP_PLANE0, rect.getX(), -1);
glEnableClipping(GL_CLIP_PLANE1, rect.getX() + rect.getWidth(), 1);
glEnableClipping(GL_CLIP_PLANE2, rect.getY(), -1);
glEnableClipping(GL_CLIP_PLANE3, rect.getY() + rect.getHeight(), 1);
}
/**
* Enable horizontal clipping planes (left and right) (uses planes 0, 1)
*
* @param left Left edge clip or -1 to not use this plane
* @param right Right edge clip or -1 to not use this plane
*/
public static void glEnableHorizontalClipping(int left, int right)
{
glEnableClipping(GL_CLIP_PLANE0, left, -1);
glEnableClipping(GL_CLIP_PLANE1, right, 1);
}
/**
* Enable vertical clipping planes (top and bottom) (uses planes 2, 3)
*
* @param top Top edge clip or -1 to not use this plane
* @param bottom Bottom edge clip or -1 to not use this plane
*/
public static void glEnableVerticalClipping(int top, int bottom)
{
glEnableClipping(GL_CLIP_PLANE2, top, -1);
glEnableClipping(GL_CLIP_PLANE3, bottom, 1);
}
/**
* @param plane
* @param value
*/
public static void glEnableClipping(int plane, int value)
{
if (plane < GL_CLIP_PLANE0 || plane >= (GL_CLIP_PLANE0 + GLClippingPlanes.totalClippingPlanes))
{
throw new IllegalArgumentException("Invalid clipping plane enum specified GL_CLIP_PLANE" + (plane - GL_CLIP_PLANE0));
}
glEnableClipping(plane, value, (plane % 2 == 0) ? -1 : 1);
}
/**
* @param plane
* @param value
*/
public static void glEnableClipping(Plane plane, int value)
{
glEnableClipping(plane.plane, value, plane.sign);
}
/**
* Enable clipping on a particular axis
*
* @param plane Clipping plane to enable
* @param value Clipping plane position
* @param sign Sign of the position
*/
private static void glEnableClipping(int plane, int value, int sign)
{
if (value == -1) return;
int offset = (plane - GL_CLIP_PLANE0) << 2;
GLClippingPlanes.doubleBuffer.put(offset + 3, value * sign).position(offset);
GLClippingPlanes.clippingPlaneFlags |= plane;
glClipPlane(plane, GLClippingPlanes.doubleBuffer);
glEnable(plane);
}
/**
* Enable clipping planes which were previously enabled
*/
public static void glEnableClipping()
{
if ((GLClippingPlanes.clippingPlaneFlags & GL_CLIP_PLANE0) == GL_CLIP_PLANE0) glEnable(GL_CLIP_PLANE0);
if ((GLClippingPlanes.clippingPlaneFlags & GL_CLIP_PLANE1) == GL_CLIP_PLANE1) glEnable(GL_CLIP_PLANE1);
if ((GLClippingPlanes.clippingPlaneFlags & GL_CLIP_PLANE2) == GL_CLIP_PLANE2) glEnable(GL_CLIP_PLANE2);
if ((GLClippingPlanes.clippingPlaneFlags & GL_CLIP_PLANE3) == GL_CLIP_PLANE3) glEnable(GL_CLIP_PLANE3);
}
/**
* Disable OpenGL clipping planes (uses planes 2, 3, 4 and 5)
*/
public static void glDisableClipping()
{
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE0);
}
}