-
Notifications
You must be signed in to change notification settings - Fork 13
/
ShaderTransition.java
199 lines (174 loc) · 6.29 KB
/
ShaderTransition.java
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
194
195
196
197
198
199
/*
* Copyright 2020 damios
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.eskalon.commons.screen.transition.impl;
import org.jspecify.annotations.Nullable;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.utils.DefaultTextureBinder;
import com.badlogic.gdx.graphics.g3d.utils.RenderContext;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import de.damios.guacamole.Preconditions;
import de.damios.guacamole.annotations.Beta;
import de.damios.guacamole.gdx.graphics.QuadMeshGenerator;
import de.damios.guacamole.gdx.graphics.ShaderCompatibilityHelper;
import de.damios.guacamole.gdx.graphics.ShaderProgramFactory;
import de.eskalon.commons.screen.transition.TimedTransition;
/**
* A transition that is using a shader to render the two transitioning screens.
* Can be reused.
* <p>
* The following uniforms are set before rendering and thus have to be specified
* in the shader code:
* <ul>
* <li>vertex shader:</li>
* <ul>
* <li>{@code uniform mat4 u_projTrans}</li>
* </ul>
* <li>fragment shader:</li>
* <ul>
* <li>{@code uniform sampler2D lastScreen}</li>
* <li>{@code uniform sampler2D currScreen}</li>
* <li>{@code uniform float progress}</li>
* </ul>
* </ul>
*
* @version 0.4.0
* @author damios
*
* @see GLTransitionsShaderTransition
*/
public class ShaderTransition extends TimedTransition {
protected ShaderProgram program;
protected Viewport viewport;
private RenderContext renderContext;
/**
* A screen filling quad.
*/
private Mesh screenQuad;
private int projTransLoc;
private int lastScreenLoc, currScreenLoc;
private int progressLoc;
/**
* Creates a shader transition. Please note that this entails the shader
* being compiled which needs to happen on the rendering thread!
*
* @param vert
* the vertex shader code
* @param frag
* the fragment shader code
* @param ignorePrepend
* whether to ignore the code in
* {@link ShaderProgram#prependFragmentCode} and
* {@link ShaderProgram#prependVertexCode}
* @param duration
* the transition's duration in seconds
*
* @see #ShaderTransition(OrthographicCamera, float, Interpolation)
*/
public ShaderTransition(String vert, String frag, boolean ignorePrepend,
float duration) {
this(vert, frag, ignorePrepend, duration, null);
}
/**
* Creates a shader transition. Please note that this entails the shader
* being compiled which needs to happen on the rendering thread!
*
* @param vert
* the vertex shader code
* @param frag
* the fragment shader code
* @param ignorePrepend
* whether to ignore the code in
* {@link ShaderProgram#prependFragmentCode} and
* {@link ShaderProgram#prependVertexCode}
* @param duration
* the transition's duration in seconds
* @param interpolation
* the interpolation to use
*/
public ShaderTransition(String vert, String frag, boolean ignorePrepend,
float duration, @Nullable Interpolation interpolation) {
this(vert, frag, ignorePrepend, duration, interpolation, false);
}
@Beta
public ShaderTransition(String vert, String frag, boolean ignorePrepend,
float duration, @Nullable Interpolation interpolation,
boolean useCompatibilityHandler) {
super(duration, interpolation);
Preconditions.checkNotNull(vert, "The vertex shader cannot be null.");
Preconditions.checkNotNull(frag, "The fragment shader cannot be null.");
this.viewport = new ScreenViewport(); // Takes care of rendering the
// transition over the whole
// screen
// Compile the shader; this needs to happen on the rendering thread!
if (useCompatibilityHandler)
this.program = ShaderCompatibilityHelper.fromString(vert, frag); // ignorePrepend
// is
// ignored
else
this.program = ShaderProgramFactory.fromString(vert, frag, true,
ignorePrepend);
this.projTransLoc = this.program.getUniformLocation("u_projTrans");
this.lastScreenLoc = this.program.getUniformLocation("lastScreen");
this.currScreenLoc = this.program.getUniformLocation("currScreen");
this.progressLoc = this.program.getUniformLocation("progress");
this.renderContext = new RenderContext(
new DefaultTextureBinder(DefaultTextureBinder.ROUNDROBIN));
}
@Override
public void render(float delta, TextureRegion lastScreen,
TextureRegion currScreen, float progress) {
viewport.apply();
this.renderContext.begin();
this.program.bind();
// Set uniforms
this.program.setUniformMatrix(this.projTransLoc,
viewport.getCamera().combined);
this.program.setUniformf(this.progressLoc, progress);
this.program.setUniformi(this.lastScreenLoc,
renderContext.textureBinder.bind(lastScreen.getTexture()));
this.program.setUniformi(this.currScreenLoc,
renderContext.textureBinder.bind(currScreen.getTexture()));
// Render the screens using the shader
this.screenQuad.render(this.program, GL20.GL_TRIANGLE_STRIP);
this.renderContext.end();
}
@Override
public void resize(int width, int height) {
viewport.update(width, height, true);
if (this.screenQuad != null)
this.screenQuad.dispose();
this.screenQuad = QuadMeshGenerator.createFullScreenQuad(width, height,
true);
}
@Override
public void dispose() {
if (this.program != null)
this.program.dispose();
if (this.screenQuad != null)
this.screenQuad.dispose();
}
/**
* @return the shader used by this transition
*/
public ShaderProgram getProgram() {
return program;
}
}