├── .classpath
├── .gitignore
├── .project
├── AUTHORS.txt
├── PT Free Font License_eng_1.2.txt
├── lib
├── PNGDecoder.jar
├── jinput.jar
├── lwjgl.jar
└── lwjgl_util.jar
├── native
├── OpenAL32.dll
├── OpenAL64.dll
├── jinput-dx8.dll
├── jinput-dx8_64.dll
├── jinput-raw.dll
├── jinput-raw_64.dll
├── libjinput-linux.so
├── libjinput-linux64.so
├── libjinput-osx.jnilib
├── liblwjgl.jnilib
├── liblwjgl.so
├── liblwjgl64.so
├── libopenal.so
├── libopenal64.so
├── lwjgl.dll
├── lwjgl64.dll
└── solaris
│ ├── liblwjgl.so
│ ├── liblwjgl64.so
│ ├── libopenal.so
│ └── libopenal64.so
├── readme.md
├── src
└── mdesl
│ ├── graphics
│ ├── Color.java
│ ├── ITexture.java
│ ├── Pixmap.java
│ ├── SpriteBatch.java
│ ├── Texture.java
│ ├── TextureRegion.java
│ ├── glutils
│ │ ├── FrameBuffer.java
│ │ ├── ShaderProgram.java
│ │ ├── VertexArray.java
│ │ ├── VertexAttrib.java
│ │ └── VertexData.java
│ └── text
│ │ └── BitmapFont.java
│ └── util
│ └── MathUtil.java
├── test
├── mdesl
│ └── test
│ │ ├── FBOTest.java
│ │ ├── FileDrop.java
│ │ ├── FontTest.java
│ │ ├── Game.java
│ │ ├── RectTest.java
│ │ ├── SimpleGame.java
│ │ ├── SpriteBatchTest.java
│ │ ├── TextureBlendTest.java
│ │ ├── TextureRepeat.java
│ │ ├── Util.java
│ │ └── shadertut
│ │ ├── ShaderLesson1.java
│ │ ├── ShaderLesson2.java
│ │ ├── ShaderLesson3.java
│ │ ├── ShaderLesson4.java
│ │ ├── ShaderLesson4B.java
│ │ ├── ShaderLesson5.java
│ │ └── ShaderLesson6.java
└── res
│ ├── dirt.png
│ ├── grass.png
│ ├── heart.png
│ ├── height.png
│ ├── mask.png
│ ├── ptsans.fnt
│ ├── ptsans_00.png
│ ├── ptsans_00_atlas.png
│ ├── rock.png
│ ├── rock_n.png
│ ├── scene.png
│ ├── shadertut
│ ├── lesson1.frag
│ ├── lesson1.vert
│ ├── lesson2.frag
│ ├── lesson2.vert
│ ├── lesson3.frag
│ ├── lesson3.vert
│ ├── lesson4.frag
│ ├── lesson4.vert
│ ├── lesson4b.frag
│ ├── lesson5.frag
│ ├── lesson5.vert
│ ├── lesson5_horiz.frag
│ ├── lesson5_vert.frag
│ ├── lesson6.frag
│ ├── lesson6.vert
│ └── lesson6a.frag
│ ├── slider.png
│ ├── slider_opaque.png
│ ├── suzanne.png
│ ├── suzanne_n.png
│ └── tiles.png
└── tools
└── blender-normals
├── normals_template.blend
├── readme.md
├── suzanne.png
└── suzanne_n.png
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Java specific
2 | *.class
3 |
4 | # generic files to ignore
5 | *~
6 | *.lock
7 | *.DS_Store
8 | *.swp
9 | *.out
10 |
11 | # Eclipse ignores
12 | *.pydevproject
13 | .metadata
14 | bin/**
15 | tmp/**
16 | tmp/**/*
17 | *.tmp
18 | *.bak
19 | *.swp
20 | *~.nib
21 | local.properties
22 | .settings/
23 | .loadpath
24 |
25 | # External tool builders
26 | .externalToolBuilders/
27 |
28 | # Locally stored "Eclipse launch configurations"
29 | *.launch
30 |
31 | # CDT-specific
32 | .cproject
33 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | lwjgl-basics
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AUTHORS.txt:
--------------------------------------------------------------------------------
1 | SOURCE AUTHORS
2 | --------------
3 |
4 | LWJGL / JInput:
5 | http://lwjgl.org/
6 |
7 | Matthias Mann's PNGDecoder:
8 | http://hg.l33tlabs.org/twl/file/tip/src/de/matthiasmann/twl/utils/PNGDecoder.java
9 |
10 | LibGDX et al - TextureRegion source and plenty of other inspiration
11 | http://libgdx.badlogicgames.com/
12 |
13 | Unless otherwise stated, source code & tutorials written by Matt DesLauriers (aka mattdesl, davedes)
--------------------------------------------------------------------------------
/PT Free Font License_eng_1.2.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/PT Free Font License_eng_1.2.txt
--------------------------------------------------------------------------------
/lib/PNGDecoder.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/lib/PNGDecoder.jar
--------------------------------------------------------------------------------
/lib/jinput.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/lib/jinput.jar
--------------------------------------------------------------------------------
/lib/lwjgl.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/lib/lwjgl.jar
--------------------------------------------------------------------------------
/lib/lwjgl_util.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/lib/lwjgl_util.jar
--------------------------------------------------------------------------------
/native/OpenAL32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/OpenAL32.dll
--------------------------------------------------------------------------------
/native/OpenAL64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/OpenAL64.dll
--------------------------------------------------------------------------------
/native/jinput-dx8.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/jinput-dx8.dll
--------------------------------------------------------------------------------
/native/jinput-dx8_64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/jinput-dx8_64.dll
--------------------------------------------------------------------------------
/native/jinput-raw.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/jinput-raw.dll
--------------------------------------------------------------------------------
/native/jinput-raw_64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/jinput-raw_64.dll
--------------------------------------------------------------------------------
/native/libjinput-linux.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/libjinput-linux.so
--------------------------------------------------------------------------------
/native/libjinput-linux64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/libjinput-linux64.so
--------------------------------------------------------------------------------
/native/libjinput-osx.jnilib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/libjinput-osx.jnilib
--------------------------------------------------------------------------------
/native/liblwjgl.jnilib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/liblwjgl.jnilib
--------------------------------------------------------------------------------
/native/liblwjgl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/liblwjgl.so
--------------------------------------------------------------------------------
/native/liblwjgl64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/liblwjgl64.so
--------------------------------------------------------------------------------
/native/libopenal.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/libopenal.so
--------------------------------------------------------------------------------
/native/libopenal64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/libopenal64.so
--------------------------------------------------------------------------------
/native/lwjgl.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/lwjgl.dll
--------------------------------------------------------------------------------
/native/lwjgl64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/lwjgl64.dll
--------------------------------------------------------------------------------
/native/solaris/liblwjgl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/solaris/liblwjgl.so
--------------------------------------------------------------------------------
/native/solaris/liblwjgl64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/solaris/liblwjgl64.so
--------------------------------------------------------------------------------
/native/solaris/libopenal.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/solaris/libopenal.so
--------------------------------------------------------------------------------
/native/solaris/libopenal64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/native/solaris/libopenal64.so
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | _lwjgl-basics_ is a minimal shader-based library for 2D LWJGL sprite games. It provides essential utilities for handling textures, shaders, and sprite rendering.
2 |
3 | For a large game project, a platform like [LibGDX](http://libgdx.badlogicgames.com/) may be more suitable.
4 |
5 | The [source code](https://github.com/mattdesl/lwjgl-basics) is hosted on GitHub.
6 |
7 | ### OpenGL & Shader Tutorials
8 |
9 | The Wiki also hosts various OpenGL and GLSL tutorials:
10 | https://github.com/mattdesl/lwjgl-basics/wiki
11 |
12 | ### Installing the API
13 |
14 | The best way to install the API is to use Eclipse and EGit (or another IDE with Git support) to pull the most recent source code. Included in the `lib` and `native` folder is a distribution of LWJGL 2.8.5, as well as an Eclipse project with class path set up for you. You can download newer versions of LWJGL from their [downloads page](http://lwjgl.org/download.php).
15 |
16 | Alternatively, you can download the full library as a ZIP:
17 |
18 | 
19 |
20 | Then, simply open the Eclipse project to start testing. Ensure your LWJGL JARs and natives have been set correctly in [Eclipse](http://www.lwjgl.org/wiki/index.php?title=Setting_Up_LWJGL_with_Eclipse), [NetBeans](http://www.lwjgl.org/wiki/index.php?title=Setting_Up_LWJGL_with_NetBeans) or [IntelliJ](http://www.lwjgl.org/wiki/index.php?title=Setting_Up_LWJGL_with_IntelliJ_IDEA), and include lwjgl-basics as a class library. lwjgl-basics also uses PNGDecoder.jar as a dependency, which can be downloaded [here](http://twl.l33tlabs.org/textureloader/).
21 |
22 | See the [tests](https://github.com/mattdesl/lwjgl-basics/tree/master/test/mdesl/test) package to get started with some basic examples.
23 |
24 |
25 | ### Credits
26 |
27 | - PNG decoder by Matthias Mann
28 | - [PT Font](http://www.fontsquirrel.com/fonts/PT-Sans)
29 | - [Grass & Water Tileset](http://opengameart.org/content/grass-and-water-tiles)
30 | - [Tiling textures](http://opengameart.org/content/tilling-textures-pack-33)
31 | - [2D Game Scene](http://opengameart.org/content/grassland-tileset)
32 | - Code written by Matt DesLauriers (aka: davedes or mattdesl) unless otherwise stated.
--------------------------------------------------------------------------------
/src/mdesl/graphics/Color.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics;
32 |
33 | /** A minimal Color utility, which holds four float values representing RGBA.
34 | *
35 | * @author davedes */
36 | public class Color {
37 |
38 | /** The fixed color transparent */
39 | public static final Color TRANSPARENT = new Color(0.0f, 0.0f, 0.0f, 0.0f);
40 | /** The fixed colour white */
41 | public static final Color WHITE = new Color(1.0f, 1.0f, 1.0f, 1.0f);
42 | /** The fixed colour yellow */
43 | public static final Color YELLOW = new Color(1.0f, 1.0f, 0, 1.0f);
44 | /** The fixed colour red */
45 | public static final Color RED = new Color(1.0f, 0, 0, 1.0f);
46 | /** The fixed colour blue */
47 | public static final Color BLUE = new Color(0, 0, 1.0f, 1.0f);
48 | /** The fixed colour green */
49 | public static final Color GREEN = new Color(0, 1.0f, 0, 1.0f);
50 | /** The fixed colour black */
51 | public static final Color BLACK = new Color(0, 0, 0, 1.0f);
52 | /** The fixed colour gray */
53 | public static final Color GRAY = new Color(0.5f, 0.5f, 0.5f, 1.0f);
54 | /** The fixed colour cyan */
55 | public static final Color CYAN = new Color(0, 1.0f, 1.0f, 1.0f);
56 | /** The fixed colour dark gray */
57 | public static final Color DARK_GRAY = new Color(0.3f, 0.3f, 0.3f, 1.0f);
58 | /** The fixed colour light gray */
59 | public static final Color LIGHT_GRAY = new Color(0.7f, 0.7f, 0.7f, 1.0f);
60 | /** The fixed colour dark pink */
61 | public final static Color PINK = new Color(255, 175, 175, 255);
62 | /** The fixed colour dark orange */
63 | public final static Color ORANGE = new Color(255, 200, 0, 255);
64 | /** The fixed colour dark magenta */
65 | public final static Color MAGENTA = new Color(255, 0, 255, 255);
66 |
67 | /** The red component [0.0 - 1.0]. */
68 | public float r;
69 | /** The green component [0.0 - 1.0]. */
70 | public float g;
71 | /** The blue component [0.0 - 1.0]. */
72 | public float b;
73 | /** The alpha component [0.0 - 1.0]. */
74 | public float a;
75 |
76 | /** Create a 4 component colour
77 | *
78 | * @param r The red component of the colour (0.0 -> 1.0)
79 | * @param g The green component of the colour (0.0 -> 1.0)
80 | * @param b The blue component of the colour (0.0 -> 1.0)
81 | * @param a The alpha component of the colour (0.0 -> 1.0) */
82 | public Color(float r, float g, float b, float a) {
83 | this.r = r;
84 | this.g = g;
85 | this.b = b;
86 | this.a = a;
87 | }
88 |
89 | /** Create a 3 component colour; alpha is passed as 1.0 (255).
90 | *
91 | * @param r The red component of the colour (0.0 -> 1.0)
92 | * @param g The green component of the colour (0.0 -> 1.0)
93 | * @param b The blue component of the colour (0.0 -> 1.0) */
94 | public Color(float r, float g, float b) {
95 | this(r, g, b, 1f);
96 | }
97 |
98 | /** Create a 4 component colour
99 | *
100 | * @param r The red component of the colour (0 -> 255)
101 | * @param g The green component of the colour (0 -> 255)
102 | * @param b The blue component of the colour (0 -> 255)
103 | * @param a The alpha component of the colour (0 -> 255) */
104 | public Color(int r, int g, int b, int a) {
105 | this(r / 255f, g / 255f, b / 255f, a / 255f);
106 | }
107 |
108 | /** Create a 3 component colour; alpha is passed as 255 (1.0).
109 | *
110 | * @param r The red component of the colour (0 -> 255)
111 | * @param g The green component of the colour (0 -> 255)
112 | * @param b The blue component of the colour (0 -> 255) */
113 | public Color(int r, int g, int b) {
114 | this(r, g, b, 255);
115 | }
116 |
117 | /** Creates a WHITE color. */
118 | public Color() {
119 | this(Color.WHITE);
120 | }
121 |
122 | /** Copy constructor
123 | *
124 | * @param color The color to copy into the new instance */
125 | public Color(Color color) {
126 | this(color.r, color.g, color.b, color.a);
127 | }
128 |
129 | /** Create a colour from an integer packed 0xAARRGGBB. If AA is specified as
130 | * zero then it will be interpreted as unspecified and hence a value of 255
131 | * will be recorded.
132 | *
133 | * @param value The value to interpret for the colour */
134 | public Color(int value) {
135 | int r = (value & 0x00FF0000) >> 16;
136 | int g = (value & 0x0000FF00) >> 8;
137 | int b = (value & 0x000000FF);
138 | int a = (value & 0xFF000000) >> 24;
139 | if (a < 0)
140 | a += 256;
141 | if (a == 0)
142 | a = 255;
143 | this.r = r / 255.0f;
144 | this.g = g / 255.0f;
145 | this.b = b / 255.0f;
146 | this.a = a / 255.0f;
147 | }
148 |
149 | /** Decode a number in a string and process it as a colour.
150 | *
151 | * @param nm The number string to decode
152 | * @return The color created from the number read
153 | * @throws NumberFormatException if the string was invalid */
154 | public static Color decode(String nm) {
155 | return new Color(Integer.decode(nm).intValue());
156 | }
157 |
158 | /** Get the red byte component of this colour
159 | *
160 | * @return The red component (range 0-255) */
161 | public int red() {
162 | return (int) (r * 255);
163 | }
164 |
165 | /** Get the green byte component of this colour
166 | *
167 | * @return The green component (range 0-255) */
168 | public int green() {
169 | return (int) (g * 255);
170 | }
171 |
172 | /** Get the blue byte component of this colour
173 | *
174 | * @return The blue component (range 0-255) */
175 | public int blue() {
176 | return (int) (b * 255);
177 | }
178 |
179 | /** Get the alpha byte component of this colour
180 | *
181 | * @return The alpha component (range 0-255) */
182 | public int alpha() {
183 | return (int) (a * 255);
184 | }
185 |
186 | public void set(Color color) {
187 | set(color.r, color.g, color.b, color.a);
188 | }
189 |
190 | public void set(float r, float g, float b, float a) {
191 | set(r, g, b);
192 | this.a = a;
193 | }
194 |
195 | public void set(float r, float g, float b) {
196 | this.r = r;
197 | this.g = g;
198 | this.b = b;
199 | }
200 |
201 | /** Packs the 4 components of this color into a 32-bit int.
202 | *
203 | * @return the packed color as a 32-bit int. */
204 | public int toIntBits() {
205 | int color = ((int) (255 * a) << 24) | ((int) (255 * b) << 16) | ((int) (255 * g) << 8)
206 | | ((int) (255 * r));
207 | return color;
208 | }
209 |
210 | /** @see java.lang.Object#hashCode() */
211 | public int hashCode() {
212 | return ((int) (r + g + b + a) * 255);
213 | }
214 |
215 | /** @see java.lang.Object#equals(java.lang.Object) */
216 | public boolean equals(Object other) {
217 | if (other instanceof Color) {
218 | Color o = (Color) other;
219 | return ((o.r == r) && (o.g == g) && (o.b == b) && (o.a == a));
220 | }
221 | return false;
222 | }
223 |
224 | /** @see java.lang.Object#toString() */
225 | public String toString() {
226 | return "Color (" + r + "," + g + "," + b + "," + a + ")";
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/mdesl/graphics/ITexture.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics;
32 |
33 | /**
34 | * An Image is a base type which Texture and TextureRegion implement. To create
35 | * an image, you would initialize a new Texture. To render the image, you would
36 | * then use a SpriteBatch.
37 | *
38 | * @author davedes
39 | */
40 | public interface ITexture {
41 |
42 | public Texture getTexture();
43 | public int getWidth();
44 | public int getHeight();
45 | public float getU();
46 | public float getV();
47 | public float getU2();
48 | public float getV2();
49 | }
--------------------------------------------------------------------------------
/src/mdesl/graphics/Pixmap.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics;
32 |
33 | import java.nio.ByteBuffer;
34 |
35 | import org.lwjgl.BufferUtils;
36 |
37 | /**
38 | * A simple wrapper around an array of RGBA pixel colors, which can then be passed to a GL texture.
39 | * @author davedes
40 | */
41 | public class Pixmap {
42 |
43 | //if we were targeting Android, we might prefer to use byte[] arrays for performance
44 | /** The RGBA bytes backing this pixmap. */
45 | protected ByteBuffer pixels;
46 |
47 | public static final int BYTES_PER_PIXEL = 4;
48 |
49 | public Pixmap(int width, int height) {
50 | pixels = BufferUtils.createByteBuffer(width * height * BYTES_PER_PIXEL);
51 | }
52 |
53 | /**
54 | * Sets the pixel data to the given array, which should be less
55 | * than the size of length(), then flips the buffer.
56 | *
57 | * @param rgbaData the new pixel data
58 | * @return this object, for chaining
59 | */
60 | public Pixmap set(byte[] rgbaData) {
61 | pixels.clear();
62 | pixels.put(rgbaData);
63 | pixels.flip();
64 | return this;
65 | }
66 |
67 | /**
68 | * Clears the pixel array to transparent black.
69 | * @return this object, for chaining
70 | */
71 | public Pixmap clear() {
72 | return clear(0, 0, 0, 0);
73 | }
74 |
75 | /**
76 | * Clears the pixel array to the specified color, then flips the buffer.
77 | *
78 | * @param r the red byte
79 | * @param g the green byte
80 | * @param b the blue byte
81 | * @param a the alpha byte
82 | * @return this object, for chaining
83 | */
84 | public Pixmap clear(int r, int g, int b, int a) {
85 | pixels.clear();
86 | for (int i=0; i ATTRIBUTES = Arrays.asList(new VertexAttrib(0,
72 | ATTR_POSITION, 2), new VertexAttrib(1, ATTR_COLOR, 4), new VertexAttrib(2,
73 | ATTR_TEXCOORD, 2));
74 |
75 | static ShaderProgram defaultShader;
76 | public static int renderCalls = 0;
77 |
78 | protected FloatBuffer buf16;
79 | protected Matrix4f projMatrix = new Matrix4f();
80 | protected Matrix4f viewMatrix = new Matrix4f();
81 | protected Matrix4f transpositionPool = new Matrix4f();
82 | private Matrix4f projViewMatrix = new Matrix4f(); //only for re-using Matrix4f objects
83 |
84 | protected Texture texture;
85 | protected ShaderProgram program;
86 |
87 | protected VertexData data;
88 |
89 | private int idx;
90 | private int maxIndex;
91 |
92 | private Color color = new Color();
93 | private boolean drawing = false;
94 |
95 | public static ShaderProgram getDefaultShader() throws LWJGLException {
96 | return defaultShader == null ? (defaultShader = new ShaderProgram(DEFAULT_VERT_SHADER, DEFAULT_FRAG_SHADER,
97 | ATTRIBUTES)) : defaultShader;
98 | }
99 |
100 | public SpriteBatch(ShaderProgram program) {
101 | this(program, 1000);
102 | }
103 |
104 | public SpriteBatch(ShaderProgram program, int size) {
105 | this(program, 1000, true);
106 | }
107 |
108 | public SpriteBatch(ShaderProgram program, int size, boolean updateUniforms) {
109 | this.program = program;
110 |
111 | // later we can do some abstraction to replace this with VBOs...
112 | this.data = new VertexArray(size * 6, ATTRIBUTES);
113 |
114 | // max indices before we need to flush the renderer
115 | maxIndex = size * 6;
116 |
117 | // default size
118 | resize(Display.getWidth(), Display.getHeight());
119 | }
120 |
121 | /**
122 | * Creates a sprite batch with a default shader, shared across all sprite batches.
123 | * @param size
124 | * @throws LWJGLException
125 | */
126 | public SpriteBatch(int size) throws LWJGLException {
127 | this(getDefaultShader(), size);
128 | }
129 |
130 | public SpriteBatch() throws LWJGLException {
131 | this(1000);
132 | }
133 |
134 | public Matrix4f getViewMatrix() {
135 | return viewMatrix;
136 | }
137 |
138 | public Matrix4f getProjectionMatrix() {
139 | return projMatrix;
140 | }
141 |
142 | public Matrix4f getCombinedMatrix() {
143 | Matrix4f.mul(Matrix4f.transpose(projMatrix, transpositionPool),
144 | viewMatrix, projViewMatrix);
145 | return projViewMatrix;
146 | }
147 |
148 | /** A convenience method to resize the projection matrix to the given
149 | * dimensions, using y-down ortho 2D. This will invoke a call to
150 | * updateMatrices.
151 | *
152 | * @param width
153 | * @param height */
154 | public void resize(int width, int height) {
155 | projMatrix = MathUtil.toOrtho2D(projMatrix, 0, 0, width, height);
156 | updateUniforms();
157 | }
158 |
159 | /** Sets this SpriteBatch's color to the RGBA values of the given color
160 | * object.
161 | *
162 | * @param color the RGBA values to use */
163 | public void setColor(Color color) {
164 | setColor(color.r, color.g, color.b, color.a);
165 | }
166 |
167 | /** Sets this SpriteBatch's color to the given RGBA values.
168 | *
169 | * @param r the red value
170 | * @param g the green value
171 | * @param b the blue value
172 | * @param a the alpha value */
173 | public void setColor(float r, float g, float b, float a) {
174 | color.set(r, g, b, a);
175 | }
176 |
177 | /** Call to multiply the the projection with the view matrix and save the
178 | * result in the uniform mat4 {@value #U_PROJ_VIEW}, as well as update the
179 | * {@value #U_TEXTURE} uniform. */
180 | public void updateUniforms() {
181 | updateUniforms(program);
182 | }
183 |
184 | /** Call to multiply the the projection with the view matrix and save the
185 | * result in the uniform mat4 {@value #U_PROJ_VIEW}, as well as update the
186 | * {@value #U_TEXTURE} uniform. */
187 | public void updateUniforms(ShaderProgram program) {
188 | projViewMatrix = getCombinedMatrix();
189 |
190 | // bind the program before sending uniforms
191 | program.use();
192 |
193 | boolean oldStrict = ShaderProgram.isStrictMode();
194 |
195 | //disable strict mode so we don't run into any problems
196 | ShaderProgram.setStrictMode(false);
197 |
198 | // we can now utilize ShaderProgram's hash map which may be better than
199 | // glGetUniformLocation
200 |
201 | // Store the the multiplied matrix in the "projViewMatrix"-uniform:
202 | program.setUniformMatrix(U_PROJ_VIEW, false, projViewMatrix);
203 |
204 | // upload texcoord 0
205 | program.setUniformi(U_TEXTURE, 0);
206 |
207 | //reset strict mode
208 | ShaderProgram.setStrictMode(oldStrict);
209 | }
210 |
211 | /** An advanced call that allows you to change the shader without uploading
212 | * shader uniforms. This will flush the batch if we are within begin().
213 | *
214 | * @param program
215 | * @param updateUniforms whether to call updateUniforms after changing the
216 | * programs */
217 | public void setShader(ShaderProgram program, boolean updateUniforms) {
218 | if (program==null)
219 | throw new NullPointerException("shader cannot be null; use getDefaultShader instead");
220 | if (drawing) //if we are already drawing, flush the batch before switching shaders
221 | flush();
222 | this.program = program; //now switch the shader
223 | if (updateUniforms) //send uniform data to shader
224 | updateUniforms();
225 | else if (drawing) //if we don't want to update, then just start the program if we are drawing
226 | program.use();
227 | }
228 |
229 | /** Changes the shader and updates it with the current texture and projView
230 | * uniforms. This will flush the batch if we are within begin().
231 | *
232 | * @param program the new program to use */
233 | public void setShader(ShaderProgram program) {
234 | setShader(program, true);
235 | }
236 |
237 | public ShaderProgram getShader() {
238 | return program;
239 | }
240 |
241 | public void begin() {
242 | if (drawing)
243 | throw new IllegalStateException("must not be drawing before calling begin()");
244 | drawing = true;
245 | program.use();
246 | idx = 0;
247 | renderCalls = 0;
248 | texture = null;
249 | }
250 |
251 | public void end() {
252 | if (!drawing)
253 | throw new IllegalStateException("must be drawing before calling end()");
254 | drawing = false;
255 | flush();
256 | }
257 |
258 | public void flush() {
259 | if (idx > 0) {
260 | data.flip();
261 | render();
262 | idx = 0;
263 | data.clear();
264 | }
265 | }
266 |
267 | public void drawRegion(Texture tex, float srcX, float srcY, float srcWidth, float srcHeight,
268 | float dstX, float dstY) {
269 | drawRegion(tex, srcX, srcY, srcWidth, srcHeight, dstX, dstY, srcWidth, srcHeight);
270 | }
271 |
272 | public void drawRegion(Texture tex, float srcX, float srcY, float srcWidth, float srcHeight,
273 | float dstX, float dstY, float dstWidth, float dstHeight) {
274 | float u = srcX / tex.getWidth();
275 | float v = srcY / tex.getHeight();
276 | float u2 = (srcX + srcWidth) / tex.getWidth();
277 | float v2 = (srcY + srcHeight) / tex.getHeight();
278 | draw(tex, dstX, dstY, dstWidth, dstHeight, u, v, u2, v2);
279 | }
280 |
281 | public void drawRegion(TextureRegion region, float srcX, float srcY, float srcWidth, float srcHeight, float dstX, float dstY) {
282 | drawRegion(region, srcX, srcY, srcWidth, srcHeight, dstX, dstY, srcWidth, srcHeight);
283 | }
284 |
285 | public void drawRegion(TextureRegion region, float srcX, float srcY, float srcWidth, float srcHeight,
286 | float dstX, float dstY, float dstWidth, float dstHeight) {
287 | drawRegion(region.getTexture(), region.getRegionX() + srcX, region.getRegionY() + srcY,
288 | srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight);
289 | }
290 |
291 | public void draw(ITexture tex, float x, float y) {
292 | draw(tex, x, y, tex.getWidth(), tex.getHeight());
293 | }
294 |
295 | public void draw(ITexture tex, float x, float y, float width, float height) {
296 | draw(tex, x, y, width, height, tex.getU(), tex.getV(), tex.getU2(), tex.getV2());
297 | }
298 |
299 |
300 | public void draw(ITexture tex, float x, float y, float originX, float originY, float rotationRadians) {
301 | draw(tex, x, y, tex.getWidth(), tex.getHeight(), originX, originY, rotationRadians);
302 | }
303 |
304 | public void draw(ITexture tex, float x, float y, float width, float height,
305 | float originX, float originY, float rotationRadians) {
306 | draw(tex, x, y, width, height, originX, originY, rotationRadians, tex.getU(), tex.getV(), tex.getU2(), tex.getV2());
307 | }
308 |
309 | public void draw(ITexture tex, float x, float y, float width, float height,
310 | float originX, float originY, float rotationRadians,
311 | float u, float v,
312 | float u2, float v2) {
313 | checkFlush(tex);
314 | final float r = color.r;
315 | final float g = color.g;
316 | final float b = color.b;
317 | final float a = color.a;
318 |
319 |
320 | float x1,y1, x2,y2, x3,y3, x4,y4;
321 |
322 | if (rotationRadians != 0) {
323 | float scaleX = 1f;//width/tex.getWidth();
324 | float scaleY = 1f;//height/tex.getHeight();
325 |
326 | float cx = originX*scaleX;
327 | float cy = originY*scaleY;
328 |
329 | float p1x = -cx;
330 | float p1y = -cy;
331 | float p2x = width - cx;
332 | float p2y = -cy;
333 | float p3x = width - cx;
334 | float p3y = height - cy;
335 | float p4x = -cx;
336 | float p4y = height - cy;
337 |
338 | final float cos = (float) Math.cos(rotationRadians);
339 | final float sin = (float) Math.sin(rotationRadians);
340 |
341 | x1 = x + (cos * p1x - sin * p1y) + cx; // TOP LEFT
342 | y1 = y + (sin * p1x + cos * p1y) + cy;
343 | x2 = x + (cos * p2x - sin * p2y) + cx; // TOP RIGHT
344 | y2 = y + (sin * p2x + cos * p2y) + cy;
345 | x3 = x + (cos * p3x - sin * p3y) + cx; // BOTTOM RIGHT
346 | y3 = y + (sin * p3x + cos * p3y) + cy;
347 | x4 = x + (cos * p4x - sin * p4y) + cx; // BOTTOM LEFT
348 | y4 = y + (sin * p4x + cos * p4y) + cy;
349 | } else {
350 | x1 = x;
351 | y1 = y;
352 |
353 | x2 = x+width;
354 | y2 = y;
355 |
356 | x3 = x+width;
357 | y3 = y+height;
358 |
359 | x4 = x;
360 | y4 = y+height;
361 | }
362 |
363 | // top left, top right, bottom left
364 | vertex(x1, y1, r, g, b, a, u, v);
365 | vertex(x2, y2, r, g, b, a, u2, v);
366 | vertex(x4, y4, r, g, b, a, u, v2);
367 |
368 | // top right, bottom right, bottom left
369 | vertex(x2, y2, r, g, b, a, u2, v);
370 | vertex(x3, y3, r, g, b, a, u2, v2);
371 | vertex(x4, y4, r, g, b, a, u, v2);
372 | }
373 |
374 | public void draw(ITexture tex, float x, float y, float width, float height, float u, float v,
375 | float u2, float v2) {
376 | draw(tex, x, y, width, height, x, y, 0f, u, v, u2, v2);
377 | }
378 |
379 | /** Renders a texture using custom vertex attributes; e.g. for different
380 | * vertex colours. This will ignore the current batch color and "x/y translation",
381 | * as well as the U/V coordinates of the given ITexture.
382 | *
383 | * @param tex the texture to use
384 | * @param vertices an array of 6 vertices, each holding 8 attributes (total
385 | * = 48 elements)
386 | * @param offset the offset from the vertices array to start from */
387 | public void draw(ITexture tex, float[] vertices, int offset) {
388 | checkFlush(tex);
389 | data.put(vertices, offset, data.getTotalNumComponents() * 6);
390 | idx += 6;
391 | }
392 |
393 | VertexData vertex(float x, float y, float r, float g, float b, float a, float u, float v) {
394 | data.put(x).put(y).put(r).put(g).put(b).put(a).put(u).put(v);
395 | idx++;
396 | return data;
397 | }
398 |
399 | protected void checkFlush(ITexture sprite) {
400 | if (sprite == null || sprite.getTexture()==null)
401 | throw new NullPointerException("null texture");
402 |
403 | // we need to bind a different texture/type. this is
404 | // for convenience; ideally the user should order
405 | // their rendering wisely to minimize texture binds
406 | if (sprite.getTexture() != this.texture || idx >= maxIndex) {
407 | // apply the last texture
408 | flush();
409 | this.texture = sprite.getTexture();
410 | }
411 | }
412 |
413 | private void render() {
414 | if (texture != null)
415 | texture.bind();
416 | data.bind();
417 | data.draw(GL_TRIANGLES, 0, idx);
418 | data.unbind();
419 | renderCalls++;
420 | }
421 | }
422 |
--------------------------------------------------------------------------------
/src/mdesl/graphics/Texture.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics;
32 |
33 | import static org.lwjgl.opengl.GL11.GL_CLAMP;
34 | import static org.lwjgl.opengl.GL11.GL_LINEAR;
35 | import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_LINEAR;
36 | import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_NEAREST;
37 | import static org.lwjgl.opengl.GL11.GL_NEAREST;
38 | import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_LINEAR;
39 | import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_NEAREST;
40 | import static org.lwjgl.opengl.GL11.GL_PACK_ALIGNMENT;
41 | import static org.lwjgl.opengl.GL11.GL_REPEAT;
42 | import static org.lwjgl.opengl.GL11.GL_RGBA;
43 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
44 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
45 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
46 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
47 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
48 | import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
49 | import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
50 | import static org.lwjgl.opengl.GL11.glBindTexture;
51 | import static org.lwjgl.opengl.GL11.glDeleteTextures;
52 | import static org.lwjgl.opengl.GL11.glEnable;
53 | import static org.lwjgl.opengl.GL11.glGenTextures;
54 | import static org.lwjgl.opengl.GL11.glPixelStorei;
55 | import static org.lwjgl.opengl.GL11.glTexImage2D;
56 | import static org.lwjgl.opengl.GL11.glTexParameteri;
57 | import static org.lwjgl.opengl.GL11.glTexSubImage2D;
58 | import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE;
59 |
60 | import java.io.IOException;
61 | import java.io.InputStream;
62 | import java.net.URL;
63 | import java.nio.ByteBuffer;
64 |
65 | import org.lwjgl.BufferUtils;
66 | import org.lwjgl.opengl.EXTFramebufferObject;
67 | import org.lwjgl.opengl.GL11;
68 | import org.lwjgl.opengl.GLContext;
69 |
70 | import de.matthiasmann.twl.utils.PNGDecoder;
71 |
72 | /** This is a minimal implementation of an OpenGL texture loader. A more complete
73 | * implementation would support multiple filetypes (JPEG, BMP, TGA, etc), allow
74 | * for parameters such as width/height to be changed (by uploading new texture
75 | * data), allow for different internal formats, async loading, different targets
76 | * (i.e. for GL_TEXTURE_3D or array textures), mipmaps, compression, etc.
77 | *
78 | * @author davedes */
79 | public class Texture implements ITexture {
80 |
81 | protected int id;
82 | protected int width;
83 | protected int height;
84 |
85 | public static int toPowerOfTwo(int n) {
86 | return 1 << (32 - Integer.numberOfLeadingZeros(n-1));
87 | }
88 |
89 | public static boolean isPowerOfTwo(int n) {
90 | return (n & -n) == n;
91 | }
92 |
93 | public static boolean isNPOTSupported() {
94 | return GLContext.getCapabilities().GL_ARB_texture_non_power_of_two;
95 | }
96 |
97 | // Some filters, included here for convenience
98 | public static final int LINEAR = GL_LINEAR;
99 | public static final int NEAREST = GL_NEAREST;
100 | public static final int LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR;
101 | public static final int LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST;
102 | public static final int NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST;
103 | public static final int NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR;
104 |
105 | // Some wrap modes, included here for convenience
106 | public static final int CLAMP = GL_CLAMP;
107 | public static final int CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE;
108 | public static final int REPEAT = GL_REPEAT;
109 |
110 | public static final int DEFAULT_FILTER = NEAREST;
111 | public static final int DEFAULT_WRAP = REPEAT;
112 |
113 | protected Texture() {
114 | //does nothing... for subclasses
115 | }
116 |
117 | /** Creates an empty OpenGL texture with the given width and height, where
118 | * each pixel is transparent black (0, 0, 0, 0) and the wrap mode is
119 | * CLAMP_TO_EDGE and the filter is NEAREST.
120 | *
121 | * @param width the width of the texture
122 | * @param height the height of the texture */
123 | public Texture(int width, int height) {
124 | this(width, height, DEFAULT_FILTER);
125 | }
126 |
127 | /** Creates an empty OpenGL texture with the given width and height, where
128 | * each pixel is transparent black (0, 0, 0, 0) and the wrap mode is
129 | * CLAMP_TO_EDGE.
130 | *
131 | * @param width the width of the texture
132 | * @param height the height of the texture
133 | * @param filter the filter to use */
134 | public Texture(int width, int height, int filter) {
135 | this(width, height, filter, DEFAULT_WRAP);
136 | }
137 |
138 | /** Creates an empty OpenGL texture with the given width and height, where
139 | * each pixel is transparent black (0, 0, 0, 0).
140 | *
141 | * @param width the width of the texture
142 | * @param height the height of the texture
143 | * @param minFilter the minification filter to use
144 | * @param magFilter the magnification filter to use
145 | * @param wrap the wrap mode to use
146 | * @param genMipmaps - whether to generate mipmaps, which requires
147 | * GL_EXT_framebuffer_object (or GL3+) */
148 | public Texture(int width, int height, int filter, int wrap) {
149 | glEnable(getTarget());
150 | id = glGenTextures();
151 | this.width = width;
152 | this.height = height;
153 | bind();
154 |
155 | setFilter(filter);
156 | setWrap(wrap);
157 |
158 | ByteBuffer buf = BufferUtils.createByteBuffer(width * height * 4);
159 | upload(GL_RGBA, buf);
160 | }
161 |
162 | public Texture(URL pngRef) throws IOException {
163 | this(pngRef, DEFAULT_FILTER);
164 | }
165 |
166 | public Texture(URL pngRef, int filter) throws IOException {
167 | this(pngRef, filter, DEFAULT_WRAP);
168 | }
169 |
170 | public Texture(URL pngRef, int filter, int wrap) throws IOException {
171 | this(pngRef, filter, filter, wrap, false);
172 | }
173 |
174 | public Texture(URL pngRef, int filter, boolean genMipmap) throws IOException {
175 | this(pngRef, filter, filter, DEFAULT_WRAP, genMipmap);
176 | }
177 |
178 | public Texture(URL pngRef, int minFilter, int magFilter, int wrap,
179 | boolean genMipmap) throws IOException {
180 | //TODO: npot check
181 | InputStream input = null;
182 | try {
183 | input = pngRef.openStream();
184 | PNGDecoder dec = new PNGDecoder(input);
185 |
186 | width = dec.getWidth();
187 | height = dec.getHeight();
188 | ByteBuffer buf = BufferUtils.createByteBuffer(4 * width * height);
189 | dec.decode(buf, width * 4, PNGDecoder.Format.RGBA);
190 | buf.flip();
191 |
192 | glEnable(getTarget());
193 | id = glGenTextures();
194 |
195 | bind();
196 | setFilter(minFilter, magFilter);
197 | setWrap(wrap);
198 | upload(GL_RGBA, buf);
199 |
200 | //use EXT since we are targeting 2.0+
201 | if (genMipmap) {
202 | EXTFramebufferObject.glGenerateMipmapEXT(getTarget());
203 | }
204 | } finally {
205 | if (input != null) {
206 | try {
207 | input.close();
208 | } catch (IOException e) {
209 | }
210 | }
211 | }
212 | }
213 |
214 | public int getTarget() {
215 | return GL_TEXTURE_2D;
216 | }
217 |
218 | public int getID() {
219 | return id;
220 | }
221 |
222 | protected void setUnpackAlignment() {
223 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
224 | glPixelStorei(GL_PACK_ALIGNMENT, 1);
225 | }
226 |
227 | /** Uploads image data with the dimensions of this Texture.
228 | *
229 | * @param dataFormat the format, e.g. GL_RGBA
230 | * @param data the byte data */
231 | public void upload(int dataFormat, ByteBuffer data) {
232 | bind();
233 | setUnpackAlignment();
234 | glTexImage2D(getTarget(), 0, GL_RGBA, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, data);
235 | }
236 |
237 | /** Uploads a sub-image within this texture.
238 | *
239 | * @param x the destination x offset
240 | * @param y the destination y offset, with lower-left origin
241 | * @param width the width of the sub image data
242 | * @param height the height of the sub image data
243 | * @param dataFormat the format of the sub image data, e.g. GL_RGBA
244 | * @param data the sub image data */
245 | public void upload(int x, int y, int width, int height, int dataFormat, ByteBuffer data) {
246 | bind();
247 | setUnpackAlignment();
248 | glTexSubImage2D(getTarget(), 0, x, y, width, height, dataFormat, GL_UNSIGNED_BYTE, data);
249 | }
250 |
251 | public void setFilter(int filter) {
252 | setFilter(filter, filter);
253 | }
254 |
255 | public void setFilter(int minFilter, int magFilter) {
256 | bind();
257 | glTexParameteri(getTarget(), GL_TEXTURE_MIN_FILTER, minFilter);
258 | glTexParameteri(getTarget(), GL_TEXTURE_MAG_FILTER, magFilter);
259 | }
260 |
261 | public void setWrap(int wrap) {
262 | bind();
263 | glTexParameteri(getTarget(), GL_TEXTURE_WRAP_S, wrap);
264 | glTexParameteri(getTarget(), GL_TEXTURE_WRAP_T, wrap);
265 | }
266 |
267 | public void bind() {
268 | if (!valid())
269 | throw new IllegalStateException("trying to bind a texture that was disposed");
270 | glBindTexture(getTarget(), id);
271 | }
272 |
273 | public void dispose() {
274 | if (valid()) {
275 | glDeleteTextures(id);
276 | id = 0;
277 | }
278 | }
279 |
280 | /**
281 | * Returns true if this texture is valid, aka it has not been disposed.
282 | * @return true if id!=0
283 | */
284 | public boolean valid() {
285 | return id!=0;
286 | }
287 |
288 | public int getWidth() {
289 | return width;
290 | }
291 |
292 | public int getHeight() {
293 | return height;
294 | }
295 |
296 | /** Returns this object; used for abstraction with SpriteBatch.
297 | * @return this texture object */
298 | public Texture getTexture() {
299 | return this;
300 | }
301 |
302 | @Override
303 | public float getU() {
304 | return 0f;
305 | }
306 |
307 | @Override
308 | public float getV() {
309 | return 0f;
310 | }
311 |
312 | @Override
313 | public float getU2() {
314 | return 1f;
315 | }
316 |
317 | @Override
318 | public float getV2() {
319 | return 1f;
320 | }
321 | }
--------------------------------------------------------------------------------
/src/mdesl/graphics/TextureRegion.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011 See AUTHORS file.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package mdesl.graphics;
17 |
18 | /** A trimmed down version of TextureRegion from LibGDX.
19 | * Defines a rectangular area of a texture. The coordinate system used has its origin in the upper left corner with the x-axis
20 | * pointing to the right and the y axis pointing downwards.
21 | * @author mzechner
22 | * @author Nathan Sweet */
23 | public class TextureRegion implements ITexture {
24 |
25 | protected Texture texture;
26 | protected float u;
27 | protected float v;
28 | protected float u2;
29 | protected float v2;
30 |
31 | protected int regionWidth;
32 | protected int regionHeight;
33 |
34 | public TextureRegion(Texture texture) {
35 | this(texture, 0, 0);
36 | }
37 |
38 | public TextureRegion(Texture texture, int x, int y) {
39 | this(texture, x, y, texture.getWidth(), texture.getHeight());
40 | }
41 |
42 | public TextureRegion(Texture texture, int x, int y, int width, int height) {
43 | set(texture, x, y, width, height);
44 | }
45 |
46 | public TextureRegion(Texture texture, float u, float v, float u2, float v2) {
47 | set(texture, u, v, u2, v2);
48 | }
49 |
50 | public TextureRegion(TextureRegion region, int x, int y, int width, int height) {
51 | set(region, x, y, width, height);
52 | }
53 |
54 | public void set(Texture texture, int x, int y, int width, int height) {
55 | set(texture, x / (float)texture.getWidth(),
56 | y / (float)texture.getHeight(),
57 | (x + width) / (float)texture.getWidth(),
58 | (y + height) / (float)texture.getHeight());
59 | regionWidth = Math.round(width);
60 | regionHeight = Math.round(height);
61 | }
62 |
63 | public void set(Texture texture, float u, float v, float u2, float v2) {
64 | this.texture = texture;
65 | this.u = u;
66 | this.v = v;
67 | this.u2 = u2;
68 | this.v2 = v2;
69 | regionWidth = Math.round(Math.abs(u2 - u) * texture.getWidth());
70 | regionHeight = Math.round(Math.abs(v2 - v) * texture.getHeight());
71 | }
72 |
73 | public void set(TextureRegion region, int x, int y, int width, int height) {
74 | set(region.texture, x + region.getRegionX(), y + region.getRegionY(), width, height);
75 | }
76 |
77 | public int getRegionX () {
78 | return Math.round(u * texture.getWidth());
79 | }
80 |
81 | public int getRegionY () {
82 | return Math.round(v * texture.getHeight());
83 | }
84 |
85 | public void flip (boolean x, boolean y) {
86 | if (x) {
87 | float temp = u;
88 | u = u2;
89 | u2 = temp;
90 | }
91 | if (y) {
92 | float temp = v;
93 | v = v2;
94 | v2 = temp;
95 | }
96 | }
97 |
98 | /**
99 | * @return the texture
100 | */
101 | public Texture getTexture() {
102 | return texture;
103 | }
104 |
105 | /**
106 | * @param texture the texture to set
107 | */
108 | public void setTexture(Texture texture) {
109 | this.texture = texture;
110 | }
111 |
112 | /**
113 | * @return the u
114 | */
115 | public float getU() {
116 | return u;
117 | }
118 |
119 | /**
120 | * @param u the u to set
121 | */
122 | public void setU(float u) {
123 | this.u = u;
124 | }
125 |
126 | /**
127 | * @return the v
128 | */
129 | public float getV() {
130 | return v;
131 | }
132 |
133 | /**
134 | * @param v the v to set
135 | */
136 | public void setV(float v) {
137 | this.v = v;
138 | }
139 |
140 | /**
141 | * @return the u2
142 | */
143 | public float getU2() {
144 | return u2;
145 | }
146 |
147 | /**
148 | * @param u2 the u2 to set
149 | */
150 | public void setU2(float u2) {
151 | this.u2 = u2;
152 | }
153 |
154 | /**
155 | * @return the v2
156 | */
157 | public float getV2() {
158 | return v2;
159 | }
160 |
161 | /**
162 | * @param v2 the v2 to set
163 | */
164 | public void setV2(float v2) {
165 | this.v2 = v2;
166 | }
167 |
168 | /**
169 | * Returns the width (in pixels) of this region.
170 | * @return the width of this region
171 | */
172 | @Override
173 | public int getWidth() {
174 | return regionWidth;
175 | }
176 |
177 | /**
178 | * Returns the height (in pixels) of this region.
179 | * @return the height of this region
180 | */
181 | @Override
182 | public int getHeight() {
183 | return regionHeight;
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/src/mdesl/graphics/glutils/FrameBuffer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics.glutils;
32 |
33 | import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT;
34 | import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT;
35 | import static org.lwjgl.opengl.EXTFramebufferObject.glCheckFramebufferStatusEXT;
36 | import static org.lwjgl.opengl.EXTFramebufferObject.glDeleteFramebuffersEXT;
37 | import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT;
38 | import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT;
39 | import static org.lwjgl.opengl.GL11.glViewport;
40 | import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
41 | import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
42 | import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_COMPLETE;
43 | import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
44 |
45 | import mdesl.graphics.ITexture;
46 | import mdesl.graphics.Texture;
47 |
48 | import org.lwjgl.LWJGLException;
49 | import org.lwjgl.opengl.Display;
50 | import org.lwjgl.opengl.GLContext;
51 |
52 | /**
53 | * A very thin wrapper around OpenGL Frame Buffer Objects, intended for
54 | * 2D purposes. This uses GL_FRAMEBUFFER_EXT for GL 2.1 compatibility.
55 | *
56 | * @author davedes
57 | */
58 | public class FrameBuffer implements ITexture {
59 |
60 | public static boolean isSupported() {
61 | return GLContext.getCapabilities().GL_EXT_framebuffer_object;
62 | }
63 |
64 | /** The ID of the FBO in use */
65 | protected int id;
66 | protected Texture texture;
67 | protected boolean ownsTexture;
68 |
69 | FrameBuffer(Texture texture, boolean ownsTexture) throws LWJGLException {
70 | this.texture = texture;
71 | this.ownsTexture = ownsTexture;
72 | if (!isSupported()) {
73 | throw new LWJGLException("FBO extension not supported in hardware");
74 | }
75 | texture.bind();
76 | id = glGenFramebuffersEXT();
77 | glBindFramebufferEXT(GL_FRAMEBUFFER, id);
78 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
79 | texture.getTarget(), texture.getID(), 0);
80 | int result = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
81 | if (result!=GL_FRAMEBUFFER_COMPLETE) {
82 | glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
83 | glDeleteFramebuffers(id);
84 | throw new LWJGLException("exception "+result+" when checking FBO status");
85 | }
86 | glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
87 | }
88 |
89 | /**
90 | * Advanced constructor which creates a frame buffer from a texture; the framebuffer
91 | * does not "own" the texture and thus calling dispose() on this framebuffer will not
92 | * destroy the texture.
93 | *
94 | * @param texture the texture to use
95 | * @throws LWJGLException if the framebuffer was not initialized correctly
96 | */
97 | public FrameBuffer(Texture texture) throws LWJGLException {
98 | this(texture, false);
99 | }
100 |
101 | /**
102 | *
103 | * @param width
104 | * @param height
105 | * @param filter
106 | * @param wrap
107 | * @throws LWJGLException
108 | */
109 | public FrameBuffer(int width, int height, int filter, int wrap) throws LWJGLException {
110 | this(new Texture(width, height, filter, wrap), true);
111 | }
112 |
113 | public FrameBuffer(int width, int height, int filter) throws LWJGLException {
114 | this(width, height, filter, Texture.DEFAULT_WRAP);
115 | }
116 |
117 | public FrameBuffer(int width, int height) throws LWJGLException {
118 | this(width, height, Texture.DEFAULT_FILTER, Texture.DEFAULT_WRAP);
119 | }
120 |
121 | public int getID() {
122 | return id;
123 | }
124 |
125 | public int getWidth() {
126 | return texture.getWidth();
127 | }
128 |
129 | public int getHeight() {
130 | return texture.getHeight();
131 | }
132 |
133 | public Texture getTexture() {
134 | return texture;
135 | }
136 |
137 | /**
138 | * Binds the FBO and sets glViewport to the texture region width/height.
139 | */
140 | public void begin() {
141 | if (id == 0)
142 | throw new IllegalStateException("can't use FBO as it has been destroyed..");
143 | glViewport(0, 0, getWidth(), getHeight());
144 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
145 | //glReadBuffer(GL_COLOR_ATTACHMENT0);
146 | }
147 |
148 | /**
149 | * Unbinds the FBO and resets glViewport to the display size.
150 | */
151 | public void end() {
152 | if (id==0)
153 | return;
154 | glViewport(0, 0, Display.getWidth(), Display.getHeight());
155 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
156 | }
157 |
158 | /**
159 | * Disposes this FBO without destroying the texture.
160 | */
161 | public void dispose() {
162 | if (id==0)
163 | return;
164 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
165 | glDeleteFramebuffersEXT(id);
166 | if (ownsTexture)
167 | texture.dispose();
168 | id = 0;
169 | //glReadBuffer(GL_BACK);
170 | }
171 |
172 | @Override
173 | public float getU() {
174 | return 0;
175 | }
176 |
177 | @Override
178 | public float getV() {
179 | return 1f;
180 | }
181 |
182 | @Override
183 | public float getU2() {
184 | return 1f;
185 | }
186 |
187 | @Override
188 | public float getV2() {
189 | return 0;
190 | }
191 | }
--------------------------------------------------------------------------------
/src/mdesl/graphics/glutils/VertexArray.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.graphics.glutils;
32 |
33 | import static org.lwjgl.opengl.GL11.glDrawArrays;
34 | import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray;
35 | import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
36 | import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
37 |
38 | import java.nio.FloatBuffer;
39 | import java.util.List;
40 |
41 | import org.lwjgl.BufferUtils;
42 |
43 | public class VertexArray implements VertexData {
44 |
45 | protected VertexAttrib[] attributes;
46 |
47 | private int totalNumComponents;
48 | private int stride;
49 | private FloatBuffer buffer;
50 | private int vertCount;
51 |
52 | /**
53 | *
54 | * @param vertCount the number of VERTICES; e.g. 3 verts to make a triangle, regardless of number of attributes
55 | * @param attributes a list of attributes per vertex
56 | */
57 | public VertexArray(int vertCount, VertexAttrib ... attributes) {
58 | this.attributes = attributes;
59 | for (VertexAttrib a : attributes)
60 | totalNumComponents += a.numComponents;
61 | this.vertCount = vertCount;
62 |
63 | //our buffer which holds our data
64 | this.buffer = BufferUtils.createFloatBuffer(vertCount * totalNumComponents);
65 | }
66 |
67 | public VertexArray(int vertCount, List attributes) {
68 | this(vertCount, attributes.toArray(new VertexAttrib[attributes.size()]));
69 | }
70 |
71 | public VertexArray flip() {
72 | buffer.flip();
73 | return this;
74 | }
75 |
76 | public VertexArray clear() {
77 | buffer.clear();
78 | return this;
79 | }
80 |
81 | public VertexArray put(float[] verts, int offset, int length) {
82 | buffer.put(verts, offset, length);
83 | return this;
84 | }
85 |
86 | public VertexArray put(float f) {
87 | buffer.put(f);
88 | return this;
89 | }
90 |
91 | public FloatBuffer buffer() {
92 | return buffer;
93 | }
94 |
95 | public int getTotalNumComponents() {
96 | return totalNumComponents;
97 | }
98 |
99 | public int getVertexCount() {
100 | return vertCount;
101 | }
102 |
103 | public void bind() {
104 | int offset = 0;
105 | //4 bytes per float
106 | int stride = totalNumComponents * 4;
107 |
108 | for (int i=0; i glyphs.length || c < 0)
131 | continue;
132 | Glyph g = glyphs[c];
133 | if (g==null)
134 | continue;
135 |
136 | if (lastGlyph!=null)
137 | x += lastGlyph.getKerning(c);
138 |
139 | lastGlyph = g;
140 | batch.draw(g.region, x + g.xoffset, y + g.yoffset, g.width, g.height);
141 | x += g.xadvance;
142 | }
143 | }
144 |
145 | public int getBaseline() {
146 | return baseLine;
147 | }
148 |
149 | public int getWidth(CharSequence text) {
150 | return getWidth(text, 0, text.length());
151 | }
152 |
153 | public int getWidth(CharSequence text, int start, int end) {
154 | Glyph lastGlyph = null;
155 | int width = 0;
156 | for (int i=start; i glyphs.length || c < 0)
160 | continue;
161 | Glyph g = glyphs[c];
162 | if (g==null)
163 | continue;
164 |
165 | if (lastGlyph!=null)
166 | width += lastGlyph.getKerning(c);
167 |
168 | lastGlyph = g;
169 | // width += g.width + g.xoffset;
170 |
171 | // width += g.width + g.xoffset;
172 | width += g.xadvance;
173 | }
174 | return width;
175 | }
176 |
177 | private static String parse(String line, String tag) {
178 | tag += "=";
179 | int start = line.indexOf(tag);
180 | if (start==-1)
181 | return "";
182 | int end = line.indexOf(' ', start+tag.length());
183 | if (end==-1)
184 | end = line.length();
185 | return line.substring(start+tag.length(), end);
186 | }
187 |
188 | private static int parseInt(String line, String tag) throws IOException {
189 | try {
190 | return Integer.parseInt(parse(line, tag));
191 | } catch (NumberFormatException e) {
192 | throw new IOException("data for "+tag+" is corrupt/missing: "+parse(line, tag));
193 | }
194 | }
195 |
196 | protected void parseFont(InputStream fontFile, Charset charset) throws IOException {
197 | BufferedReader br = new BufferedReader(new InputStreamReader(fontFile, charset), 512);
198 | String info = br.readLine();
199 | String common = br.readLine();
200 | lineHeight = parseInt(common, "lineHeight");
201 | baseLine = parseInt(common, "base");
202 | pages = parseInt(common, "pages");
203 |
204 | //ignore file name, let user specify texture ...
205 |
206 | String line = "";
207 |
208 | ArrayList glyphsList = null;
209 |
210 | int maxCodePoint = 0;
211 |
212 | while (true) {
213 | line = br.readLine();
214 | if (line == null) break;
215 | if (line.startsWith("chars")) {
216 | // System.out.println(line);
217 | int count = parseInt(line, "count");
218 | glyphsList = new ArrayList(count);
219 | continue;
220 | }
221 | if (line.startsWith("kernings "))
222 | break;
223 | if (!line.startsWith("char "))
224 | continue;
225 |
226 | Glyph glyph = new Glyph();
227 |
228 | StringTokenizer tokens = new StringTokenizer(line, " =");
229 | tokens.nextToken();
230 | tokens.nextToken();
231 | int ch = Integer.parseInt(tokens.nextToken());
232 | if (ch > Character.MAX_VALUE)
233 | continue;
234 | if (glyphsList==null) //incase some doofus deleted a line in the font def
235 | glyphsList = new ArrayList();
236 | glyphsList.add(glyph);
237 | glyph.chr = ch;
238 | if (ch > maxCodePoint)
239 | maxCodePoint = ch;
240 | tokens.nextToken();
241 | glyph.x = Integer.parseInt(tokens.nextToken());
242 | tokens.nextToken();
243 | glyph.y = Integer.parseInt(tokens.nextToken());
244 | tokens.nextToken();
245 | glyph.width = Integer.parseInt(tokens.nextToken());
246 | tokens.nextToken();
247 | glyph.height = Integer.parseInt(tokens.nextToken());
248 | tokens.nextToken();
249 | glyph.xoffset = Integer.parseInt(tokens.nextToken());
250 | tokens.nextToken();
251 | glyph.yoffset = Integer.parseInt(tokens.nextToken());
252 | tokens.nextToken();
253 | glyph.xadvance = Integer.parseInt(tokens.nextToken());
254 | //page ID
255 | tokens.nextToken();
256 | glyph.page = Integer.parseInt(tokens.nextToken());
257 |
258 | if (glyph.page > texturePages.length)
259 | throw new IOException("not enough texturePages supplied; glyph "+glyph.chr+" expects page index "+glyph.page);
260 | glyph.updateRegion(texturePages[glyph.page]);
261 |
262 | if (glyph.width > 0 && glyph.height > 0)
263 | descent = Math.min(baseLine + glyph.yoffset, descent);
264 | }
265 |
266 | glyphs = new Glyph[maxCodePoint + 1];
267 | for (Glyph g : glyphsList)
268 | glyphs[g.chr] = g;
269 |
270 | int kernCount = parseInt(line, "count");
271 | while (true) {
272 | line = br.readLine();
273 | if (line == null) break;
274 | if (!line.startsWith("kerning ")) break;
275 |
276 | StringTokenizer tokens = new StringTokenizer(line, " =");
277 | tokens.nextToken();
278 | tokens.nextToken();
279 | int first = Integer.parseInt(tokens.nextToken());
280 | tokens.nextToken();
281 | int second = Integer.parseInt(tokens.nextToken());
282 | if (first < 0 || first > Character.MAX_VALUE || second < 0 || second > Character.MAX_VALUE)
283 | continue;
284 |
285 | Glyph glyph = glyphs[first];
286 | tokens.nextToken();
287 | int offset = Integer.parseInt(tokens.nextToken());
288 |
289 | if (glyph.kerning==null) {
290 | glyph.kerning = new int[maxCodePoint + 1];
291 | }
292 | glyph.kerning[second] = offset;
293 |
294 | }
295 | try {
296 | fontFile.close();
297 | br.close();
298 | } catch (IOException e) {
299 | //silent
300 | }
301 | }
302 |
303 | /**
304 | * Disposes all texture pages associated with this font.
305 | */
306 | public void dispose() {
307 | for (TextureRegion t : getTexturePages())
308 | t.getTexture().dispose();
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/src/mdesl/util/MathUtil.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.util;
32 |
33 | import org.lwjgl.util.vector.Matrix4f;
34 |
35 | /**
36 | * Math utilities; adapted from LibGDX's vector classes for use with LWJGL Vector utilities
37 | */
38 | public class MathUtil {
39 |
40 | /**
41 | * Sets the given matrix to an orthographic 2D projection matrix, and returns it. If the given matrix
42 | * is null, a new one will be created and returned.
43 | *
44 | * @param m the matrix to re-use, or null to create a new matrix
45 | * @param x
46 | * @param y
47 | * @param width
48 | * @param height
49 | * @return the given matrix, or a newly created matrix if none was specified
50 | */
51 | public static Matrix4f toOrtho2D(Matrix4f m, float x, float y, float width, float height) {
52 | return toOrtho(m, x, x + width, y + height, y, 1, -1);
53 | }
54 |
55 | /**
56 | * Sets the given matrix to an orthographic 2D projection matrix, and returns it. If the given matrix
57 | * is null, a new one will be created and returned.
58 | *
59 | * @param m the matrix to re-use, or null to create a new matrix
60 | * @param x
61 | * @param y
62 | * @param width
63 | * @param height
64 | * @param near near clipping plane
65 | * @param far far clipping plane
66 | * @return the given matrix, or a newly created matrix if none was specified
67 | */
68 | public static Matrix4f toOrtho2D(Matrix4f m, float x, float y, float width, float height, float near, float far) {
69 | return toOrtho(m, x, x + width, y, y + height, near, far);
70 | }
71 |
72 | /**
73 | * Sets the given matrix to an orthographic projection matrix, and returns it. If the given matrix
74 | * is null, a new one will be created and returned.
75 | *
76 | * @param m the matrix to re-use, or null to create a new matrix
77 | * @param left
78 | * @param right
79 | * @param bottom
80 | * @param top
81 | * @param near near clipping plane
82 | * @param far far clipping plane
83 | * @return the given matrix, or a newly created matrix if none was specified
84 | */
85 | public static Matrix4f toOrtho(Matrix4f m, float left, float right, float bottom, float top,
86 | float near, float far) {
87 | if (m==null)
88 | m = new Matrix4f();
89 | float x_orth = 2 / (right - left);
90 | float y_orth = 2 / (top - bottom);
91 | float z_orth = -2 / (far - near);
92 |
93 | float tx = -(right + left) / (right - left);
94 | float ty = -(top + bottom) / (top - bottom);
95 | float tz = -(far + near) / (far - near);
96 |
97 | m.m00 = x_orth;
98 | m.m10 = 0;
99 | m.m20 = 0;
100 | m.m30 = 0;
101 | m.m01 = 0;
102 | m.m11 = y_orth;
103 | m.m21 = 0;
104 | m.m31 = 0;
105 | m.m02 = 0;
106 | m.m12 = 0;
107 | m.m22 = z_orth;
108 | m.m32 = 0;
109 | m.m03 = tx;
110 | m.m13 = ty;
111 | m.m23 = tz;
112 | m.m33 = 1;
113 | return m;
114 | }
115 |
116 |
117 | /** Sets the matrix to a projection matrix with a near- and far plane, a field of view in degrees and an aspect ratio.
118 | *
119 | * @param near The near plane
120 | * @param far The far plane
121 | * @param fov The field of view in degrees
122 | * @param aspectRatio The aspect ratio
123 | * @return This matrix for the purpose of chaining methods together. */
124 | public static Matrix4f setToProjection (Matrix4f m, float near, float far, float fov, float aspectRatio) {
125 | if (m==null)
126 | m = new Matrix4f();
127 | m.setIdentity();
128 | float l_fd = (float)(1.0 / Math.tan((fov * (Math.PI / 180)) / 2.0));
129 | float l_a1 = (far + near) / (near - far);
130 | float l_a2 = (2 * far * near) / (near - far);
131 | m.m00 = l_fd / aspectRatio;
132 | m.m10 = 0;
133 | m.m20 = 0;
134 | m.m30 = 0;
135 | m.m01 = 0;
136 | m.m11 = l_fd;
137 | m.m21 = 0;
138 | m.m31 = 0;
139 | m.m02 = 0;
140 | m.m12 = 0;
141 | m.m22 = l_a1;
142 | m.m32 = -1;
143 | m.m03 = 0;
144 | m.m13 = 0;
145 | m.m23 = l_a2;
146 | m.m33 = 0;
147 | return m;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/test/mdesl/test/FBOTest.java:
--------------------------------------------------------------------------------
1 | package mdesl.test;
2 |
3 | import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
4 | import static org.lwjgl.opengl.GL11.GL_ONE;
5 | import static org.lwjgl.opengl.GL11.*;
6 | import static org.lwjgl.opengl.GL11.GL_RGBA;
7 | import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
8 | import static org.lwjgl.opengl.GL11.glBlendFunc;
9 | import static org.lwjgl.opengl.GL11.glClear;
10 | import static org.lwjgl.opengl.GL11.glClearColor;
11 | import static org.lwjgl.opengl.GL14.glBlendFuncSeparate;
12 | import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
13 |
14 | import java.awt.image.BufferedImage;
15 | import java.io.File;
16 | import java.io.IOException;
17 | import java.nio.ByteBuffer;
18 |
19 | import javax.imageio.ImageIO;
20 |
21 | import mdesl.graphics.Color;
22 | import mdesl.graphics.SpriteBatch;
23 | import mdesl.graphics.Texture;
24 | import mdesl.graphics.TextureRegion;
25 | import mdesl.graphics.glutils.FrameBuffer;
26 |
27 | import org.lwjgl.BufferUtils;
28 | import org.lwjgl.LWJGLException;
29 | import org.lwjgl.opengl.Display;
30 | import org.lwjgl.opengl.GL11;
31 |
32 | public class FBOTest extends SimpleGame {
33 |
34 | public static void main(String[] args) throws LWJGLException {
35 | Game game = new FBOTest();
36 | game.setDisplayMode(640, 480, false);
37 | game.start();
38 | }
39 |
40 | final int FBO_SIZE = 512;
41 |
42 | //our sprite batch
43 | SpriteBatch batch;
44 |
45 | Texture atlas;
46 | TextureRegion track, thumb;
47 |
48 | FrameBuffer fbo;
49 | TextureRegion fboRegion;
50 |
51 | protected void create() throws LWJGLException {
52 | super.create();
53 | //create our font
54 | try {
55 | atlas = new Texture(Util.getResource("res/slider.png"), Texture.NEAREST);
56 |
57 | //ideally you would use a texture packer like in LibGDX
58 | track = new TextureRegion(atlas, 0, 0, 64, 256);
59 | thumb = new TextureRegion(atlas, 65, 0, 64, 128);
60 |
61 | int width = track.getWidth();
62 | int height = track.getHeight();
63 |
64 | //create a new FBO with the width and height of our track
65 | if (Texture.isNPOTSupported()) {
66 | fbo = new FrameBuffer(width, height);
67 | fboRegion = new TextureRegion(fbo.getTexture());
68 | } else {
69 | int texWidth = Texture.toPowerOfTwo(width);
70 | int texHeight = Texture.toPowerOfTwo(height);
71 | fbo = new FrameBuffer(texWidth, texHeight);
72 | fboRegion = new TextureRegion(fbo.getTexture(), 0, texHeight-height, width, height);
73 | }
74 | fboRegion.flip(false, true);
75 | //GL uses lower left coords... we use upper-left for textures, so we need to flip Y
76 |
77 | } catch (IOException e) {
78 | throw new RuntimeException("couldn't decode textures");
79 | }
80 | batch = new SpriteBatch();
81 |
82 | renderSlider();
83 | }
84 |
85 | protected void renderSlider() {
86 | //make our offscreen FBO the current buffer
87 | fbo.begin();
88 |
89 | //we need to first clear our FBO with transparent black
90 | glClearColor(0f,0f,0f,0f);
91 | glClear(GL_COLOR_BUFFER_BIT);
92 |
93 | //since our FBO is a different size than our Display,
94 | //we need to resize our SpriteBatch in order for it to render correctly
95 | System.out.println(fbo.getWidth()+" "+fbo.getTexture().getWidth());
96 |
97 | batch.resize(fbo.getWidth(), fbo.getHeight());
98 |
99 | //setup our alpha blending to avoid blending twice
100 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
101 |
102 | //start our batch
103 | batch.begin();
104 |
105 | //render some sprites to our offscreen FBO
106 | float x = 0;
107 | float y = 0;
108 | int val = 40; //example value amount
109 |
110 | //draw sprites
111 | batch.draw(track, x, y);
112 | batch.draw(thumb, x, y + val);
113 |
114 | //end (flush) our batch
115 | batch.end();
116 |
117 | //unbind the FBO
118 | fbo.end();
119 |
120 | //now we are back to screen aka "back buffer" rendering
121 | //so we should resize our SpriteBatch to the Display size
122 | batch.resize(Display.getWidth(), Display.getHeight());
123 |
124 | //now let's re-set blending to the default...
125 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
126 | }
127 |
128 | protected void render() throws LWJGLException {
129 | //nice smooth background color
130 | float L = 233/255f;
131 | glClearColor(L, L, L, 1f);
132 | glClear(GL_COLOR_BUFFER_BIT);
133 |
134 | //we don't need super.render() since it just clears the screen, and we have that above
135 |
136 | //whenever the slider moves we will need to call renderSlider() to update the offscreen texture
137 |
138 |
139 | //render the offscreen texture with "premultiplied alpha" blending
140 | glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
141 |
142 | batch.begin();
143 |
144 | //due to our different blend funcs we need to use RGBA to specify opacity
145 | //tinting becomes unavailable with this solution
146 | float a = .5f;
147 | batch.setColor(a, a, a, a);
148 |
149 | batch.draw(fboRegion, 0, 0);
150 |
151 | batch.flush();
152 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
153 | batch.draw(track, 200, 200);
154 | batch.draw(thumb, 200, 250);
155 |
156 | batch.end();
157 | }
158 |
159 | // called to resize the display
160 | protected void resize() throws LWJGLException {
161 | super.resize();
162 | // resize our batch with the new screen size
163 | batch.resize(Display.getWidth(), Display.getHeight());
164 | }
165 | }
--------------------------------------------------------------------------------
/test/mdesl/test/FontTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.test;
32 |
33 | import java.io.IOException;
34 |
35 | import mdesl.graphics.Color;
36 | import mdesl.graphics.SpriteBatch;
37 | import mdesl.graphics.text.BitmapFont;
38 |
39 | import org.lwjgl.LWJGLException;
40 | import org.lwjgl.Sys;
41 | import org.lwjgl.opengl.Display;
42 |
43 | public class FontTest extends SimpleGame {
44 |
45 | public static void main(String[] args) throws LWJGLException {
46 | Game game = new FontTest();
47 | game.setDisplayMode(640, 480, false);
48 | game.start();
49 | }
50 |
51 | BitmapFont font;
52 | SpriteBatch batch;
53 |
54 | protected void create() throws LWJGLException {
55 | super.create();
56 |
57 | //Load some textures
58 | try {
59 | font = new BitmapFont(Util.getResource("res/ptsans.fnt"), Util.getResource("res/ptsans_00.png"));
60 | } catch (IOException e) {
61 | // ... do something here ...
62 | Sys.alert("Error", "Could not decode font!");
63 | e.printStackTrace();
64 | System.exit(0);
65 | }
66 | //create our sprite batch
67 | batch = new SpriteBatch();
68 | }
69 |
70 | protected void render() throws LWJGLException {
71 | super.render();
72 |
73 | //start the sprite batch
74 | batch.begin();
75 |
76 | batch.setColor(Color.WHITE);
77 | font.drawText(batch, "The quick brown fox jumps over the lazy dog!", 10, 10);
78 |
79 | //testing some unicode values
80 | batch.setColor(Color.GRAY);
81 | font.drawText(batch, "\u2122\u00e2\u00C9\u0110\u2082\u2264", 10, font.getLineHeight() + 10);
82 |
83 | batch.end();
84 | }
85 |
86 |
87 | protected void resize() throws LWJGLException {
88 | super.resize();
89 | batch.resize(Display.getWidth(), Display.getHeight());
90 | }
91 | }
--------------------------------------------------------------------------------
/test/mdesl/test/Game.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.test;
32 |
33 | import org.lwjgl.LWJGLException;
34 | import org.lwjgl.Sys;
35 | import org.lwjgl.input.Keyboard;
36 | import org.lwjgl.input.Mouse;
37 | import org.lwjgl.opengl.Display;
38 | import org.lwjgl.opengl.DisplayMode;
39 |
40 | /**
41 | * A bare-bones implementation of a LWJGL application.
42 | * @author davedes
43 | */
44 | public abstract class Game {
45 |
46 | // Whether our game loop is running
47 | protected boolean running = false;
48 |
49 |
50 | /** time at last frame */
51 | private long lastFrame;
52 | private int fpsTick;
53 | /** frames per second */
54 | private int fps;
55 | /** last fps time */
56 | private long lastFPS;
57 | /** the delta time in milliseconds */
58 | private int delta;
59 |
60 |
61 | private boolean mouseWasDown = false;
62 | private int lastMouseX, lastMouseY;
63 |
64 | public void setDisplayMode(int width, int height) throws LWJGLException {
65 | Display.setDisplayMode(new DisplayMode(width, height));
66 | }
67 |
68 | public void setDisplayMode(int width, int height, boolean fullscreen) throws LWJGLException {
69 | setDisplayMode(width, height);
70 | Display.setFullscreen(fullscreen);
71 | }
72 |
73 | // Start our game
74 | public void start() throws LWJGLException {
75 | // Set up our display
76 | Display.setTitle("Game");
77 | Display.setResizable(true);
78 | Display.setVSyncEnabled(true);
79 |
80 | Display.create();
81 |
82 | // Create our OpenGL context and initialize any resources
83 | create();
84 |
85 | // Starting size...
86 | resize();
87 |
88 | running = true;
89 |
90 | delta = tick();
91 | lastFPS = getTime();
92 |
93 | // While we're still running and the user hasn't closed the window...
94 | while (running && !Display.isCloseRequested()) {
95 | delta = tick();
96 |
97 | // If the game was resized, we need to update our projection
98 | if (Display.wasResized())
99 | resize();
100 |
101 | Keyboard.poll();
102 | while (Keyboard.next()) {
103 | char c = Keyboard.getEventCharacter();
104 | int k = Keyboard.getEventKey();
105 | boolean down = Keyboard.getEventKeyState();
106 | if (down)
107 | keyPressed(k, c);
108 | else
109 | keyReleased(k, c);
110 | }
111 | Mouse.poll();
112 | while (Mouse.next()) {
113 | int btn = Mouse.getEventButton();
114 | boolean btnDown = Mouse.getEventButtonState();
115 | int wheel = Mouse.getEventDWheel();
116 | int x = Mouse.getEventX();
117 | int y = Mouse.getEventY();
118 | // System.out.println(x+" "+y+" "+dx+" "+dy+" "+wheel+" "+btnDown);
119 |
120 | if (btnDown) {
121 | mouseWasDown = true;
122 | mousePressed(x, y, btn);
123 | } else if (mouseWasDown) {
124 | mouseWasDown = false;
125 | // mouseReleased(x, y, btn);
126 | }
127 | if (lastMouseX!=x || lastMouseY!=y) {
128 | // mouseMoved(x, y, lastMouseX, lastMouseY);
129 | lastMouseX = x;
130 | lastMouseY = y;
131 | }
132 |
133 | if (wheel!=0) {
134 | mouseWheelChanged(wheel/120);
135 | }
136 | }
137 |
138 | // Render the game
139 | render();
140 |
141 | //update FPS ticker
142 | updateFPS();
143 |
144 | // Flip the buffers and sync to 60 FPS
145 | Display.update();
146 | Display.sync(60);
147 | }
148 |
149 | // Dispose any resources and destroy our window
150 | dispose();
151 | Display.destroy();
152 | }
153 |
154 | // Exit our game loop and close the window
155 | public void exit() {
156 | running = false;
157 | }
158 |
159 | protected void keyPressed(int key, char c) {
160 |
161 | }
162 |
163 | protected void keyReleased(int key, char c) {
164 |
165 | }
166 |
167 | // protected void mouseMoved(int x, int y, int ox, int oy) {
168 | // System.out.println("moved");
169 | // }
170 |
171 | protected void mousePressed(int x, int y, int button) {
172 |
173 | }
174 | //
175 | // protected void mouseReleased(int x, int y, int button) {
176 | // System.out.println("rel");
177 | // }
178 |
179 | protected void mouseWheelChanged(int delta) {
180 | }
181 |
182 | // Called to setup our game and context
183 | protected abstract void create() throws LWJGLException;
184 |
185 | // Called to render our game
186 | protected abstract void render() throws LWJGLException;
187 |
188 | // Called to resize our game
189 | protected abstract void resize() throws LWJGLException;
190 |
191 | // Called to destroy our game upon exiting
192 | protected abstract void dispose() throws LWJGLException;
193 |
194 | public int getDeltaTime() {
195 | return delta;
196 | }
197 |
198 | public int getFPS() {
199 | return fps;
200 | }
201 |
202 | private int tick() {
203 | long time = getTime();
204 | int delta = (int)(time - lastFrame);
205 | lastFrame = time;
206 | return delta;
207 | }
208 |
209 | public void updateFPS() {
210 | if (getTime() - lastFPS > 1000) {
211 | fps = fpsTick;
212 | fpsTick = 0;
213 | lastFPS += 1000;
214 | }
215 | fpsTick++;
216 | }
217 |
218 | /**
219 | * Get the time in milliseconds
220 | *
221 | * @return The system time in milliseconds
222 | */
223 | public long getTime() {
224 | return (Sys.getTime() * 1000) / Sys.getTimerResolution();
225 | }
226 | }
--------------------------------------------------------------------------------
/test/mdesl/test/RectTest.java:
--------------------------------------------------------------------------------
1 | package mdesl.test;
2 |
3 | import static org.lwjgl.opengl.GL11.GL_RGBA;
4 | import static org.lwjgl.opengl.GL11.glClearColor;
5 |
6 | import java.io.IOException;
7 | import java.nio.ByteBuffer;
8 |
9 | import mdesl.graphics.Color;
10 | import mdesl.graphics.SpriteBatch;
11 | import mdesl.graphics.Texture;
12 | import mdesl.graphics.TextureRegion;
13 | import mdesl.graphics.glutils.FrameBuffer;
14 | import mdesl.graphics.text.BitmapFont;
15 |
16 | import org.lwjgl.BufferUtils;
17 | import org.lwjgl.LWJGLException;
18 | import org.lwjgl.input.Mouse;
19 | import org.lwjgl.opengl.Display;
20 |
21 | public class RectTest extends SimpleGame {
22 |
23 | public static void main(String[] args) throws LWJGLException {
24 | Game game = new RectTest();
25 | game.setDisplayMode(640, 480, false);
26 | game.start();
27 | }
28 |
29 | final int FBO_SIZE = 512;
30 |
31 | //a simple font to play with
32 | BitmapFont font;
33 |
34 | //our sprite batch
35 | SpriteBatch batch;
36 |
37 | Texture fontTex;
38 | TextureRegion rect;
39 |
40 | Color dark = new Color(0x4e4e4e);
41 | Color blue = new Color(0x96a2a5);
42 | Color light = new Color(0xc9c9c9);
43 |
44 | protected void create() throws LWJGLException {
45 | super.create();
46 | //create our font
47 | try {
48 | fontTex = new Texture(Util.getResource("res/ptsans_00.png"), Texture.NEAREST);
49 |
50 | //in Photoshop, we included a small white box at the bottom right of our font sheet
51 | //we will use this to draw lines and rectangles within the same batch as our text
52 | rect = new TextureRegion(fontTex, fontTex.getWidth()-2, fontTex.getHeight()-2, 1, 1);
53 |
54 | font = new BitmapFont(Util.getResource("res/ptsans.fnt"), fontTex);
55 | } catch (IOException e) {
56 | throw new RuntimeException("couldn't decode texture");
57 | }
58 |
59 | glClearColor(0.5f, .5f, .5f, 1f);
60 | batch = new SpriteBatch();
61 | }
62 |
63 | void drawRect(int x, int y, int width, int height, int thickness) {
64 | batch.draw(rect, x, y, width, thickness);
65 | batch.draw(rect, x, y, thickness, height);
66 | batch.draw(rect, x, y+height-thickness, width, thickness);
67 | batch.draw(rect, x+width-thickness, y, thickness, height);
68 | }
69 |
70 | void drawLine(int x1, int y1, int x2, int y2, int thickness) {
71 | int dx = x2-x1;
72 | int dy = y2-y1;
73 | float dist = (float)Math.sqrt(dx*dx + dy*dy);
74 | float rad = (float)Math.atan2(dy, dx);
75 | batch.draw(rect, x1, y1, dist, thickness, 0, 0, rad);
76 | }
77 |
78 |
79 | protected void render() throws LWJGLException {
80 | super.render();
81 |
82 | batch.begin();
83 |
84 | int x = 25;
85 | int y = 50;
86 | int width = 250;
87 | int height = font.getLineHeight() * 2;
88 | batch.setColor(dark);
89 | batch.draw(rect, x, y, width, height);
90 | batch.setColor(blue);
91 | batch.draw(rect, x+=2, y+=2, width-=4, height-=4);
92 | batch.setColor(light);
93 | batch.draw(rect, x+=5, y+=5, width-=10, height-=10);
94 | batch.setColor(dark);
95 |
96 | String str = "Hello world, muchos jalepe\u00f1o";
97 |
98 | int fw = font.getWidth(str);
99 | int fx = x + width/2 - fw/2;
100 | int fy = y + height/2 - font.getLineHeight()/2;
101 | int base = fy+font.getBaseline() + 1;
102 | font.drawText(batch, str, fx, fy);
103 |
104 | //underline only a portion of the string
105 | fx += font.getWidth(str, 0, 6);
106 | fw = font.getWidth(str, 6, 11);
107 |
108 | //draw underline
109 | drawLine(fx, base, fx + fw, base, 1);
110 |
111 | //draw some other stuff
112 | batch.setColor(Color.WHITE);
113 |
114 | //test drawing a rectangle
115 | drawRect(180, y + 50, 50, 25, 3);
116 |
117 | //test drawing a rotated line
118 | batch.draw(rect, x + width + 30, 25, 100, 1, 0, 0, (float)Math.toRadians(45));
119 |
120 | //test drawing line from point A to point B
121 | batch.setColor(Color.PINK);
122 | drawLine(400, 300, Mouse.getX(), Display.getHeight()-Mouse.getY()-1, 3);
123 |
124 | batch.end();
125 | }
126 |
127 | // called to resize the display
128 | protected void resize() throws LWJGLException {
129 | super.resize();
130 | // resize our batch with the new screen size
131 | batch.resize(Display.getWidth(), Display.getHeight());
132 | }
133 | }
--------------------------------------------------------------------------------
/test/mdesl/test/SimpleGame.java:
--------------------------------------------------------------------------------
1 | package mdesl.test;
2 |
3 | import static org.lwjgl.opengl.GL11.GL_BLEND;
4 | import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
5 | import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
6 | import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
7 | import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
8 | import static org.lwjgl.opengl.GL11.glBlendFunc;
9 | import static org.lwjgl.opengl.GL11.glClear;
10 | import static org.lwjgl.opengl.GL11.glClearColor;
11 | import static org.lwjgl.opengl.GL11.glDisable;
12 | import static org.lwjgl.opengl.GL11.glEnable;
13 | import static org.lwjgl.opengl.GL11.glViewport;
14 |
15 | import org.lwjgl.LWJGLException;
16 | import org.lwjgl.opengl.Display;
17 |
18 | public class SimpleGame extends Game {
19 |
20 |
21 | @Override
22 | protected void resize() throws LWJGLException {
23 | glViewport(0, 0, Display.getWidth(), Display.getHeight());
24 | }
25 |
26 | @Override
27 | protected void render() throws LWJGLException {
28 | glClear(GL_COLOR_BUFFER_BIT);
29 | }
30 |
31 | @Override
32 | protected void create() throws LWJGLException {
33 | // 2D games generally won't require depth testing
34 | glDisable(GL_DEPTH_TEST);
35 |
36 | // Enable blending
37 | glEnable(GL_BLEND);
38 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
39 |
40 | // Set clear to transparent black
41 | glClearColor(0f, 0f, 0f, 0f);
42 | }
43 |
44 | @Override
45 | protected void dispose() throws LWJGLException {
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test/mdesl/test/SpriteBatchTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012, Matt DesLauriers All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * * Redistributions of source code must retain the above copyright notice, this
8 | * list of conditions and the following disclaimer.
9 | *
10 | * * Redistributions in binary
11 | * form must reproduce the above copyright notice, this list of conditions and
12 | * the following disclaimer in the documentation and/or other materials provided
13 | * with the distribution.
14 | *
15 | * * Neither the name of the Matt DesLauriers nor the names
16 | * of his contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | package mdesl.test;
32 |
33 | import static org.lwjgl.opengl.GL11.glClearColor;
34 |
35 | import java.io.IOException;
36 |
37 | import mdesl.graphics.Color;
38 | import mdesl.graphics.SpriteBatch;
39 | import mdesl.graphics.Texture;
40 | import mdesl.graphics.TextureRegion;
41 | import mdesl.graphics.text.BitmapFont;
42 |
43 | import org.lwjgl.LWJGLException;
44 | import org.lwjgl.Sys;
45 | import org.lwjgl.input.Keyboard;
46 | import org.lwjgl.opengl.Display;
47 | import org.lwjgl.util.vector.Matrix4f;
48 | import org.lwjgl.util.vector.Vector2f;
49 | import org.lwjgl.util.vector.Vector3f;
50 |
51 | public class SpriteBatchTest extends SimpleGame {
52 |
53 | public static void main(String[] args) throws LWJGLException {
54 | Game game = new SpriteBatchTest();
55 | game.setDisplayMode(640, 480, false);
56 | game.start();
57 | }
58 |
59 | Texture tex, tex2;
60 | TextureRegion tile;
61 | SpriteBatch batch;
62 |
63 | float panX, panY, rot, zoom=1f;
64 | BitmapFont font;
65 | final float MOVE_SPEED = 10f;
66 | final float ZOOM_SPEED = 0.025f;
67 | final float ROT_SPEED = 0.05f;
68 |
69 | protected void create() throws LWJGLException {
70 | super.create();
71 |
72 | //Load some textures
73 | try {
74 | tex = new Texture(Util.getResource("res/tiles.png"), Texture.NEAREST);
75 | tex2 = new Texture(Util.getResource("res/ptsans_00.png"));
76 | tile = new TextureRegion(tex, 128, 64, 64, 64);
77 |
78 | font = new BitmapFont(Util.getResource("res/ptsans.fnt"), Util.getResource("res/ptsans_00.png"));
79 |
80 | } catch (IOException e) {
81 | // ... do something here ...
82 | Sys.alert("Error", "Could not decode images!");
83 | e.printStackTrace();
84 | System.exit(0);
85 | }
86 | glClearColor(0.5f, .5f, .5f, 1f);
87 | //create our sprite batch
88 | batch = new SpriteBatch();
89 | }
90 |
91 | void drawGame() {
92 | //get the instance of the view matrix for our batch
93 | Matrix4f view = batch.getViewMatrix();
94 |
95 | //reset the matrix to identity, i.e. "no camera transform"
96 | view.setIdentity();
97 |
98 | //scale the view
99 | if (zoom != 1f) {
100 | view.scale(new Vector3f(zoom, zoom, 1f));
101 | }
102 |
103 | //pan the camera by translating the view matrix
104 | view.translate(new Vector2f(panX, panY));
105 |
106 | //after translation, we can rotate...
107 | if (rot!=0f) {
108 | //we want to rotate by a center origin point, so first we translate
109 | view.translate(new Vector2f(Display.getWidth()/2, Display.getHeight()/2));
110 |
111 | //then we rotate
112 | view.rotate(rot, new Vector3f(0, 0, 1));
113 |
114 | //then we translate back
115 | view.translate(new Vector2f(-Display.getWidth()/2, -Display.getHeight()/2));
116 | }
117 |
118 | //apply other transformations here...
119 |
120 |
121 | //update the new view matrix
122 | batch.updateUniforms();
123 |
124 | //start the sprite batch
125 | batch.begin();
126 |
127 | //draw a tile from our sprite sheet
128 | batch.draw(tile, 10, 10);
129 |
130 | batch.draw(tile, 10, 100, 128, 128); //we can stretch it with a new width/height
131 |
132 | //we can also draw a region of a Texture on the fly like so:
133 | batch.drawRegion(tex, 0, 0, 32, 32, //srcX, srcY, srcWidth, srcHeight
134 | 10, 250, 32, 32); //dstX, dstY, dstWidth, dstHeight
135 |
136 | //tint batch red
137 | batch.setColor(Color.RED);
138 | batch.draw(tex2, 0, 0, Display.getWidth(), Display.getHeight());
139 |
140 | //reset color
141 | batch.setColor(Color.WHITE);
142 |
143 |
144 | //finish the sprite batch and push the tiles to the GPU
145 | batch.end();
146 | }
147 |
148 | void drawHUD() {
149 | //draw the text with identity matrix, i.e. no camera transformation
150 | batch.getViewMatrix().setIdentity();
151 | batch.updateUniforms();
152 |
153 |
154 | batch.begin();
155 | // ... render any hud elements
156 | font.drawText(batch, "Control camera with WASD, UP/DOWN and LEFT/RIGHT", 10, 10);
157 | batch.end();
158 | }
159 |
160 | protected void render() throws LWJGLException {
161 | super.render();
162 |
163 |
164 | if (Keyboard.isKeyDown(Keyboard.KEY_A))
165 | panX -= MOVE_SPEED;
166 | if (Keyboard.isKeyDown(Keyboard.KEY_D))
167 | panX += MOVE_SPEED;
168 | if (Keyboard.isKeyDown(Keyboard.KEY_W))
169 | panY -= MOVE_SPEED;
170 | if (Keyboard.isKeyDown(Keyboard.KEY_S))
171 | panY += MOVE_SPEED;
172 |
173 | if (Keyboard.isKeyDown(Keyboard.KEY_UP))
174 | zoom += ZOOM_SPEED;
175 | if (Keyboard.isKeyDown(Keyboard.KEY_DOWN))
176 | zoom -= ZOOM_SPEED;
177 |
178 | zoom = Math.max(0.15f, zoom);
179 |
180 | if (Keyboard.isKeyDown(Keyboard.KEY_LEFT))
181 | rot -= ROT_SPEED;
182 | if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT))
183 | rot += ROT_SPEED;
184 |
185 | drawGame();
186 |
187 | drawHUD();
188 | }
189 |
190 |
191 | protected void resize() throws LWJGLException {
192 | super.resize();
193 | batch.resize(Display.getWidth(), Display.getHeight());
194 | }
195 |
196 | }
--------------------------------------------------------------------------------
/test/mdesl/test/TextureBlendTest.java:
--------------------------------------------------------------------------------
1 | package mdesl.test;
2 |
3 | import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
4 | import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
5 | import static org.lwjgl.opengl.GL13.GL_TEXTURE2;
6 | import static org.lwjgl.opengl.GL13.glActiveTexture;
7 | import static org.lwjgl.opengl.GL20.glUniform1i;
8 | import static org.lwjgl.opengl.GL11.*;
9 |
10 | import java.io.IOException;
11 |
12 | import mdesl.graphics.SpriteBatch;
13 | import mdesl.graphics.Texture;
14 | import mdesl.graphics.glutils.ShaderProgram;
15 |
16 | import org.lwjgl.LWJGLException;
17 | import org.lwjgl.Sys;
18 |
19 | public class TextureBlendTest extends SimpleGame {
20 |
21 | public static final String TEX_ALT = "u_texture1";
22 | public static final String TEX_MASK = "u_mask";
23 |
24 | public static final String VERT_SHADER =
25 | "uniform mat4 "+SpriteBatch.U_PROJ_VIEW+";\n" +
26 | "attribute vec4 "+SpriteBatch.ATTR_COLOR+";\n" +
27 | "attribute vec2 "+SpriteBatch.ATTR_TEXCOORD+";\n" +
28 | "attribute vec2 "+SpriteBatch.ATTR_POSITION+";\n" +
29 | "varying vec4 vColor;\n" +
30 | "varying vec2 vTexCoord; \n" +
31 | "void main() {\n" +
32 | " vColor = "+SpriteBatch.ATTR_COLOR+";\n" +
33 | " vTexCoord = "+SpriteBatch.ATTR_TEXCOORD+";\n" +
34 | " gl_Position = "+SpriteBatch.U_PROJ_VIEW+" * vec4("+SpriteBatch.ATTR_POSITION+".xy, 0, 1);\n" +
35 | "}";
36 |
37 | public static final String FRAG_SHADER =
38 | "uniform sampler2D "+SpriteBatch.U_TEXTURE+";\n" +
39 | "uniform sampler2D "+TEX_ALT+";\n" +
40 | "uniform sampler2D "+TEX_MASK+";\n" +
41 | "varying vec4 vColor;\n" +
42 | "varying vec2 vTexCoord;\n" +
43 | "void main(void) {\n" +
44 | " vec4 texColor0 = texture2D("+SpriteBatch.U_TEXTURE+", vTexCoord);\n" +
45 | " vec4 texColor1 = texture2D("+TEX_ALT+", vTexCoord);\n" +
46 | " float mask = texture2D("+TEX_MASK+", vTexCoord).a;\n" +
47 | " gl_FragColor = vColor * mix(texColor0, texColor1, mask);\n" +
48 | "}";
49 |
50 |
51 | SpriteBatch batch;
52 | Texture tex0, tex1, mask;
53 |
54 | public void create() throws LWJGLException {
55 | super.create();
56 |
57 | ShaderProgram shader = new ShaderProgram(VERT_SHADER, FRAG_SHADER, SpriteBatch.ATTRIBUTES);
58 | //setup our custom uniforms
59 | shader.use();
60 |
61 | shader.setUniformi(TEX_ALT, 1);
62 | shader.setUniformi(TEX_MASK, 2);
63 |
64 | System.out.println(VERT_SHADER);
65 | System.out.println();
66 | System.out.println(FRAG_SHADER);
67 |
68 | batch = new SpriteBatch(shader, 1000);
69 |
70 |
71 | try {
72 | tex0 = new Texture(Util.getResource("res/dirt.png"));
73 | tex1 = new Texture(Util.getResource("res/grass.png"));
74 | mask = new Texture(Util.getResource("res/mask.png"));
75 | } catch (IOException e) {
76 | // TODO Auto-generated catch block
77 | e.printStackTrace();
78 | Sys.alert("Error", "Could not load images");
79 | System.exit(0);
80 | }
81 |
82 | System.out.println(VERT_SHADER);
83 | System.out.println(FRAG_SHADER);
84 |
85 | //in this example our texture1 won't change, so we can bind it once and forget about it
86 | glActiveTexture(GL_TEXTURE2);
87 | mask.bind();
88 |
89 | glActiveTexture(GL_TEXTURE1);
90 | tex1.bind();
91 |
92 | glActiveTexture(GL_TEXTURE0);
93 | tex0.bind();
94 |
95 | glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
96 | }
97 |
98 | public void render() throws LWJGLException {
99 | super.render();
100 |
101 | batch.begin();
102 |
103 | batch.draw(tex0, 50, 50);
104 |
105 | batch.end();
106 | }
107 |
108 | public static void main(String[] args) throws LWJGLException {
109 | Game game = new TextureBlendTest();
110 | game.setDisplayMode(800, 600, false);
111 | game.start();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/test/mdesl/test/TextureRepeat.java:
--------------------------------------------------------------------------------
1 | package mdesl.test;
2 |
3 | import static org.lwjgl.opengl.GL11.GL_BACK;
4 | import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
5 | import static org.lwjgl.opengl.GL11.GL_COLOR_LOGIC_OP;
6 | import static org.lwjgl.opengl.GL11.GL_CULL_FACE;
7 | import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
8 | import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
9 | import static org.lwjgl.opengl.GL11.GL_FRONT;
10 | import static org.lwjgl.opengl.GL11.GL_FRONT_FACE;
11 | import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
12 | import static org.lwjgl.opengl.GL11.GL_TRIANGLE_STRIP;
13 | import static org.lwjgl.opengl.GL11.GL_XOR;
14 | import static org.lwjgl.opengl.GL11.glClear;
15 | import static org.lwjgl.opengl.GL11.glClearColor;
16 | import static org.lwjgl.opengl.GL11.glCullFace;
17 | import static org.lwjgl.opengl.GL11.glDisable;
18 | import static org.lwjgl.opengl.GL11.glEnable;
19 | import static org.lwjgl.opengl.GL11.glLogicOp;
20 |
21 | import java.awt.Canvas;
22 | import java.awt.event.WindowAdapter;
23 | import java.awt.event.WindowEvent;
24 | import java.awt.image.BufferedImage;
25 | import java.awt.image.DataBufferByte;
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.net.MalformedURLException;
29 | import java.net.URL;
30 | import java.net.URLDecoder;
31 | import java.util.Arrays;
32 | import java.util.List;
33 | import java.util.prefs.BackingStoreException;
34 | import java.util.prefs.Preferences;
35 |
36 | import javax.imageio.ImageIO;
37 | import javax.swing.JFrame;
38 |
39 | import mdesl.graphics.Color;
40 | import mdesl.graphics.SpriteBatch;
41 | import mdesl.graphics.Texture;
42 | import mdesl.graphics.TextureRegion;
43 | import mdesl.graphics.glutils.ShaderProgram;
44 | import mdesl.graphics.glutils.VertexArray;
45 | import mdesl.graphics.glutils.VertexAttrib;
46 | import mdesl.graphics.glutils.VertexData;
47 | import mdesl.graphics.text.BitmapFont;
48 | import mdesl.util.MathUtil;
49 |
50 | import org.lwjgl.LWJGLException;
51 | import org.lwjgl.input.Keyboard;
52 | import org.lwjgl.opengl.Display;
53 | import org.lwjgl.util.vector.Matrix4f;
54 | import org.lwjgl.util.vector.Vector3f;
55 |
56 | public class TextureRepeat extends SimpleGame implements FileDrop.Listener {
57 |
58 | static Preferences prefs = Preferences.userNodeForPackage(TextureRepeat.class);
59 |
60 | public static void main(String[] args) throws LWJGLException {
61 | final TextureRepeat game = new TextureRepeat();
62 |
63 | final JFrame f = new JFrame();
64 | f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
65 | f.addWindowListener(new WindowAdapter() {
66 |
67 | @Override
68 | public void windowClosing(WindowEvent arg0) {
69 |
70 | }
71 |
72 | @Override
73 | public void windowClosed(WindowEvent arg0) {
74 | game.exit();
75 | }
76 | });
77 | f.setTitle("Test");
78 |
79 | final Canvas c = new Canvas();
80 |
81 | f.add(c);
82 | f.setSize(prefs.getInt("window.width", 800),
83 | prefs.getInt("window.height", 600));
84 | f.setBackground(java.awt.Color.gray);
85 | Display.setParent(c);
86 |
87 | f.setLocationRelativeTo(null);
88 | f.setVisible(true);
89 |
90 |
91 | new FileDrop(f, game);
92 |
93 | game.setDisplayMode(f.getWidth(), f.getHeight(), false);
94 |
95 | game.start();
96 | }
97 |
98 | final int FBO_SIZE = 512;
99 |
100 | //a simple font to play with
101 | BitmapFont font;
102 |
103 | //our sprite batch
104 | SpriteBatch batch;
105 |
106 | URL url;
107 | File file;
108 | Texture tex;
109 |
110 | final int DEFAULT_SCALE_INDEX = 5;
111 | int scale = DEFAULT_SCALE_INDEX;
112 | float[] scales = { 0.05f, 0.15f, 0.25f, 0.5f, 0.75f, 1f, 2f, 3f, 4f, 5f, 10f, 12.5f, 15f, 20f };
113 | boolean grid = false;
114 |
115 | Color gridColor = new Color(1f,1f,1f, 1f);
116 | Color checkColor = new Color(0.85f, 0.85f, 0.85f, 1f);
117 | Color uiColor = new Color(0f, 0f, 0f, 0.5f);
118 | TextureRegion rect;
119 |
120 | int time = 0;
121 | int pollDelay = 500;
122 | int curFilter = Texture.LINEAR;
123 |
124 | String errStr = "";
125 |
126 | boolean reload = false;
127 | int fpsWidth;
128 | private boolean help;
129 | private long lastModified;
130 | private boolean polling = true;
131 | boolean inFocus;
132 | private boolean checkBG = true;
133 |
134 | private TerrainMesh terrain;
135 |
136 | private boolean showTerrain = false;
137 |
138 | public void dispose() throws LWJGLException {
139 | if (tex!=null)
140 | tex.dispose();
141 | font.dispose();
142 | batch.getShader().dispose();
143 | prefs.putBoolean("linear", curFilter==Texture.LINEAR);
144 | prefs.putBoolean("grid", grid);
145 | prefs.putBoolean("polling", polling);
146 | prefs.putBoolean("checkBG", checkBG);
147 | prefs.put("url", url!=null ? url.getPath() : "");
148 | prefs.putInt("window.width", Display.getWidth());
149 | prefs.putInt("window.height", Display.getHeight());
150 | try {
151 | prefs.flush();
152 | } catch (BackingStoreException e) {
153 | // TODO Auto-generated catch block
154 | e.printStackTrace();
155 | }
156 | }
157 |
158 | public void create() throws LWJGLException {
159 | super.create();
160 |
161 | curFilter = prefs.getBoolean("linear", true) ? Texture.LINEAR : Texture.NEAREST;
162 | grid = prefs.getBoolean("grid", true);
163 | checkBG = prefs.getBoolean("checkBG", true);
164 | polling = prefs.getBoolean("polling", true);
165 | try {
166 | Texture fontTex = new Texture(Util.getResource("res/ptsans_00.png"));
167 | font = new BitmapFont(Util.getResource("res/ptsans.fnt"), fontTex);
168 |
169 | String path = prefs.get("url", null);
170 | if (path!=null&&path.length()!=0) {
171 | try {
172 | File file = new File(URLDecoder.decode(path, "UTF-8"));
173 | if (file.exists()) {
174 | url = file.toURI().toURL();
175 | this.file = file;
176 | lastModified = file.lastModified();
177 | }
178 | } catch (IOException e) {
179 | e.printStackTrace();
180 | }
181 | }
182 | if (url!=null)
183 | reload();
184 |
185 | terrain = new TerrainMesh(Util.getResource("res/height.png"));
186 | terrain.create(1, 55f, 25f);
187 |
188 | batch = new SpriteBatch();
189 |
190 | //in Photoshop, we included a small white box at the bottom right of our font sheet
191 | //we will use this to draw lines and rectangles within the same batch as our text
192 | rect = new TextureRegion(fontTex, fontTex.getWidth()-2, fontTex.getHeight()-2, 1, 1);
193 |
194 | fpsWidth = font.getWidth("FPS: 0000");
195 | } catch (IOException e) {
196 | // TODO Auto-generated catch block
197 | e.printStackTrace();
198 | }
199 |
200 | glDisable(GL_CULL_FACE);
201 | // glCullFace(GL_BACK);
202 | glClearColor(0f, 1f, 1f, 1f);
203 | }
204 |
205 | public void reload() {
206 | if (url==null)
207 | return;
208 | if (!file.canRead()) {
209 | errStr = "Could not read file";
210 | return;
211 | }
212 | if (!file.exists()) {
213 | errStr = "File no longer exists...";
214 | url = null;
215 | file = null;
216 | return;
217 | }
218 | try {
219 | if (tex!=null)
220 | tex.dispose();
221 | tex = new Texture(url, curFilter, Texture.REPEAT);
222 | errStr = "";
223 | } catch (IOException e) {
224 | e.printStackTrace();
225 | errStr = "Error decoding texture: "+e.getMessage();
226 | }
227 | }
228 |
229 | public void resize() throws LWJGLException {
230 | batch.resize(Display.getWidth(), Display.getHeight());
231 | setDisplayMode(Display.getWidth(), Display.getHeight());
232 | }
233 |
234 | public void render() throws LWJGLException {
235 | //super.render();
236 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
237 |
238 | inFocus = Display.isActive();
239 |
240 | time += getDeltaTime();
241 | if (time > pollDelay) {
242 | if (polling && url!=null) {
243 | if (file.lastModified()!=lastModified) {
244 | reload();
245 | }
246 | }
247 | time -= pollDelay;
248 | }
249 |
250 | if (reload) {
251 | reload();
252 | reload = false;
253 | }
254 |
255 | batch.begin();
256 |
257 | if (checkBG) {
258 | int size = Math.max((int)(16 * scales[scale]), 4);
259 | int count = Math.max(Display.getWidth(), Display.getHeight())/size + 1;
260 | count = count%2==0 ? count+1 : count;
261 | batch.setColor(checkColor);
262 | for (int x=0, pos=0; x0)
370 | scale--;
371 | } else if (k==Keyboard.KEY_G) {
372 | grid = !grid;
373 | } else if (k==Keyboard.KEY_F) {
374 | curFilter = curFilter==Texture.LINEAR ? Texture.NEAREST : Texture.LINEAR;
375 | if (tex!=null)
376 | tex.setFilter(curFilter);
377 | } else if (k==Keyboard.KEY_R) {
378 | reload();
379 | } else if (k==Keyboard.KEY_C) {
380 | checkBG = !checkBG;
381 | } else if (k==Keyboard.KEY_ESCAPE) {
382 | url = null;
383 | file = null;
384 | tex.dispose();
385 | tex = null;
386 | } else if (k==Keyboard.KEY_P){
387 | polling = !polling;
388 | } else if (k==Keyboard.KEY_T) {
389 | showTerrain = !showTerrain;
390 | }
391 | }
392 |
393 | public void mouseWheelChanged(int delta) {
394 | if (delta > 0 && scale0)
397 | scale--;
398 | }
399 |
400 | public void mousePressed(int x, int y, int button) {
401 | if (errStr.length()!=0) {
402 | errStr = "";
403 | help = false;
404 | } else if (inFocus)
405 | help = !help;
406 | }
407 |
408 | @Override
409 | public void filesDropped(File[] files) {
410 | if (files!=null && files.length>0) {
411 | String uri = files[0].getPath();
412 | if (uri.toLowerCase().endsWith(".png")) {
413 | try {
414 | this.url = files[0].toURI().toURL();
415 | file = files[0];
416 | lastModified = file.lastModified();
417 | reload = true;
418 | scale = DEFAULT_SCALE_INDEX;
419 | } catch (MalformedURLException e) {
420 | e.printStackTrace();
421 | errStr = "Could not convert path to URL";
422 | }
423 | } else {
424 | errStr = "Filetype must be PNG";
425 | }
426 | }
427 | }
428 |
429 |
430 | class TerrainMesh {
431 |
432 | VertexData data;
433 | byte[] px;
434 | int w, h;
435 |
436 | Matrix4f proj = new Matrix4f();
437 | Matrix4f view = new Matrix4f();
438 | Matrix4f projView = new Matrix4f();
439 | Matrix4f transpositionPool = new Matrix4f();
440 | ShaderProgram program;
441 |
442 | public TerrainMesh(URL heightMap) throws IOException, LWJGLException {
443 | BufferedImage map = ImageIO.read(heightMap);
444 |
445 | BufferedImage buf = new BufferedImage(map.getWidth(), map.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
446 | buf.getGraphics().drawImage(map, 0, 0, null);
447 | w = buf.getWidth();
448 | h = buf.getHeight();
449 | px = ((DataBufferByte)buf.getRaster().getDataBuffer()).getData();
450 | List attr = Arrays.asList(
451 | new VertexAttrib(0, "Position", 3),
452 | new VertexAttrib(1, "TexCoord", 2));
453 | data = new VertexArray(w*h*2, attr);
454 |
455 | final String VERT = "uniform mat4 u_projView;\n"
456 | + "attribute vec2 TexCoord;\n"
457 | + "attribute vec3 Position;\n"
458 | + "varying vec2 vTexCoord; \n"
459 | + "void main() {\n"
460 | + " vTexCoord = TexCoord;\n"
461 | + " gl_Position = u_projView * vec4(Position, 1.0);\n" + "}";
462 |
463 | final String FRAG = "uniform sampler2D u_texture;\n"
464 | + "varying vec2 vTexCoord;\n" + "void main() {\n"
465 | + " vec4 texColor = texture2D(u_texture, vTexCoord);\n"
466 | + " gl_FragColor = texColor;\n" + "}";
467 |
468 | ShaderProgram.setStrictMode(false);
469 | program = new ShaderProgram(VERT, FRAG, attr);
470 | if (program.getLog().length()!=0)
471 | System.out.println("Shader Log: "+program.getLog());
472 |
473 | MathUtil.setToProjection(proj, 0.01f, 1000f, 45f, Display.getWidth()/(float)Display.getHeight());
474 |
475 | program.use();
476 | program.setUniformi("u_texture", 0);
477 | }
478 |
479 | void create(int unit, float texSize, float heightScale) {
480 | data.clear();
481 |
482 | // for (int i=0; i -1) {
82 | sBuffer.append(buffer, 0, cnt);
83 | }
84 | br.close();
85 | in.close();
86 | return sBuffer.toString();
87 | }
88 |
89 | public static URL getResource(String str) {
90 | URL u = getResourceLocator().getResource(str);
91 | return u;
92 | }
93 |
94 | public static InputStream getResourceAsStream(String str) {
95 | InputStream in = getResourceLocator().getResourceAsStream(str);
96 | return in;
97 | }
98 |
99 | public static void setResourceLocator(ResourceLocator r) {
100 | resourceLocator = r;
101 | }
102 |
103 | public static ResourceLocator getResourceLocator() {
104 | return resourceLocator;
105 | }
106 |
107 | public static final class DefaultResourceLocator implements ResourceLocator {
108 |
109 | public static final File ROOT = new File(".");
110 |
111 | private static File createFile(String ref) {
112 | File file = new File(ROOT, ref);
113 | if (!file.exists()) {
114 | file = new File(ref);
115 | }
116 |
117 | return file;
118 | }
119 |
120 | public InputStream getResourceAsStream(String ref) {
121 | InputStream in = Util.class.getClassLoader().getResourceAsStream(ref);
122 | if (in==null) { // try file system
123 | try { return new FileInputStream(createFile(ref)); }
124 | catch (IOException e) {}
125 | }
126 | return in;
127 | }
128 |
129 | public URL getResource(String ref) {
130 | URL url = Util.class.getClassLoader().getResource(ref);
131 | if (url==null) {
132 | try {
133 | File f = createFile(ref);
134 | if (f.exists())
135 | return f.toURI().toURL();
136 | } catch (IOException e) {}
137 | }
138 | return url;
139 | }
140 | }
141 |
142 | public static interface ResourceLocator {
143 | public URL getResource(String str);
144 | public InputStream getResourceAsStream(String str);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson1.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import java.io.IOException;
4 |
5 | import mdesl.graphics.SpriteBatch;
6 | import mdesl.graphics.Texture;
7 | import mdesl.graphics.glutils.ShaderProgram;
8 | import mdesl.test.Game;
9 | import mdesl.test.SimpleGame;
10 | import mdesl.test.Util;
11 |
12 | import org.lwjgl.LWJGLException;
13 | import org.lwjgl.opengl.Display;
14 |
15 | public class ShaderLesson1 extends SimpleGame {
16 |
17 | public static void main(String[] args) throws LWJGLException {
18 | Game game = new ShaderLesson1();
19 | game.setDisplayMode(640, 480, false);
20 | game.start();
21 | }
22 |
23 | //our texture
24 | Texture tex;
25 |
26 | //our sprite batch
27 | SpriteBatch batch;
28 |
29 | protected void create() throws LWJGLException {
30 | super.create();
31 |
32 | //this will be ignored in this lesson...
33 | try {
34 | tex = new Texture(Util.getResource("res/grass.png"), Texture.NEAREST);
35 | } catch (IOException e) {
36 | throw new RuntimeException("couldn't decode texture");
37 | }
38 |
39 | //load our shader program and sprite batch
40 | try {
41 | final String VERTEX = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson1.vert"));
42 | final String FRAGMENT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson1.frag"));
43 |
44 | //create our shader program -- be sure to pass SpriteBatch's default attributes!
45 | ShaderProgram program = new ShaderProgram(VERTEX, FRAGMENT, SpriteBatch.ATTRIBUTES);
46 |
47 | //Good idea to log any warnings if they exist
48 | if (program.getLog().length()!=0)
49 | System.out.println(program.getLog());
50 |
51 | //create our sprite batch
52 | batch = new SpriteBatch(program);
53 | } catch (Exception e) {
54 | //simple exception handling...
55 | e.printStackTrace();
56 | System.exit(0);
57 | }
58 | }
59 |
60 | protected void render() throws LWJGLException {
61 | super.render();
62 |
63 | // start our batch
64 | batch.begin();
65 |
66 | // draw some sprites... they will all be affected by our shaders
67 | batch.draw(tex, 10, 10);
68 | batch.draw(tex, 10, 320, 32, 32);
69 |
70 | // end our batch
71 | batch.end();
72 | }
73 |
74 | // called to resize the display
75 | protected void resize() throws LWJGLException {
76 | super.resize();
77 |
78 | // resize our batch with the new screen size
79 | batch.resize(Display.getWidth(), Display.getHeight());
80 | }
81 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson2.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import java.io.IOException;
4 |
5 | import mdesl.graphics.SpriteBatch;
6 | import mdesl.graphics.Texture;
7 | import mdesl.graphics.glutils.ShaderProgram;
8 | import mdesl.test.Game;
9 | import mdesl.test.SimpleGame;
10 | import mdesl.test.Util;
11 |
12 | import org.lwjgl.LWJGLException;
13 | import org.lwjgl.opengl.Display;
14 |
15 | public class ShaderLesson2 extends SimpleGame {
16 |
17 | public static void main(String[] args) throws LWJGLException {
18 | Game game = new ShaderLesson2();
19 | game.setDisplayMode(640, 480, false);
20 | game.start();
21 | }
22 |
23 | //our texture
24 | Texture tex;
25 |
26 | //our sprite batch
27 | SpriteBatch batch;
28 |
29 | protected void create() throws LWJGLException {
30 | super.create();
31 |
32 | //this will be ignored in this lesson...
33 | try {
34 | tex = new Texture(Util.getResource("res/grass.png"), Texture.NEAREST);
35 | } catch (IOException e) {
36 | throw new RuntimeException("couldn't decode texture");
37 | }
38 |
39 | //load our shader program and sprite batch
40 | try {
41 | final String VERTEX = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson2.vert"));
42 | final String FRAGMENT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson2.frag"));
43 |
44 | //create our shader program -- be sure to pass SpriteBatch's default attributes!
45 | ShaderProgram program = new ShaderProgram(VERTEX, FRAGMENT, SpriteBatch.ATTRIBUTES);
46 |
47 | //Good idea to log any warnings if they exist
48 | if (program.getLog().length()!=0)
49 | System.out.println(program.getLog());
50 |
51 | //create our sprite batch
52 | batch = new SpriteBatch(program);
53 | } catch (Exception e) {
54 | //simple exception handling...
55 | e.printStackTrace();
56 | System.exit(0);
57 | }
58 | }
59 |
60 | protected void render() throws LWJGLException {
61 | super.render();
62 |
63 | // start our batch
64 | batch.begin();
65 |
66 | // draw some sprites... they will all be affected by our shaders
67 | batch.draw(tex, 10, 10);
68 | batch.draw(tex, 10, 320, 32, 32);
69 |
70 | // end our batch
71 | batch.end();
72 | }
73 |
74 | // called to resize the display
75 | protected void resize() throws LWJGLException {
76 | super.resize();
77 |
78 | // resize our batch with the new screen size
79 | batch.resize(Display.getWidth(), Display.getHeight());
80 | }
81 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson3.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import java.io.IOException;
4 |
5 | import mdesl.graphics.SpriteBatch;
6 | import mdesl.graphics.Texture;
7 | import mdesl.graphics.glutils.ShaderProgram;
8 | import mdesl.test.Game;
9 | import mdesl.test.SimpleGame;
10 | import mdesl.test.Util;
11 |
12 | import org.lwjgl.LWJGLException;
13 | import org.lwjgl.opengl.Display;
14 |
15 | public class ShaderLesson3 extends SimpleGame {
16 |
17 | public static void main(String[] args) throws LWJGLException {
18 | Game game = new ShaderLesson3();
19 | game.setDisplayMode(320, 240, false);
20 | game.start();
21 | }
22 |
23 | //our texture
24 | Texture tex;
25 |
26 | //our sprite batch
27 | SpriteBatch batch;
28 |
29 | //our program
30 | ShaderProgram program;
31 |
32 | protected void create() throws LWJGLException {
33 | super.create();
34 |
35 | //our small demo will use a fixed-size display
36 | Display.setResizable(false);
37 |
38 | //In later lessons, we'll learn about "post-processing" an entire scene using an FBO.
39 | //For now we will apply the concepts to individual textures.
40 | try {
41 | tex = new Texture(Util.getResource("res/scene.png"), Texture.NEAREST);
42 | } catch (IOException e) {
43 | throw new RuntimeException("couldn't decode texture");
44 | }
45 |
46 | //load our shader program and sprite batch
47 | try {
48 | final String VERTEX = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson3.vert"));
49 | final String FRAGMENT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson3.frag"));
50 |
51 | //create our shader program -- be sure to pass SpriteBatch's default attributes!
52 | program = new ShaderProgram(VERTEX, FRAGMENT, SpriteBatch.ATTRIBUTES);
53 |
54 | //Good idea to log any warnings if they exist
55 | if (program.getLog().length()!=0)
56 | System.out.println(program.getLog());
57 |
58 | //create our sprite batch
59 | batch = new SpriteBatch(program);
60 | } catch (Exception e) {
61 | //simple exception handling...
62 | e.printStackTrace();
63 | System.exit(0);
64 | }
65 | }
66 |
67 | protected void render() throws LWJGLException {
68 | super.render();
69 |
70 | batch.begin();
71 |
72 | //draw the texture at top left
73 | batch.draw(tex, 0, 0);
74 |
75 | batch.end();
76 | }
77 |
78 | // called to resize the display
79 | protected void resize() throws LWJGLException {
80 | super.resize();
81 |
82 | // resize our batch with the new screen size
83 | batch.resize(Display.getWidth(), Display.getHeight());
84 |
85 | // whenever our screen resizes, we need to update our uniform
86 | program.use();
87 | program.setUniformf("resolution", Display.getWidth(), Display.getHeight());
88 | }
89 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson4.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import static org.lwjgl.opengl.GL11.glClearColor;
4 | import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
5 | import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
6 | import static org.lwjgl.opengl.GL13.GL_TEXTURE2;
7 | import static org.lwjgl.opengl.GL13.glActiveTexture;
8 |
9 | import java.io.IOException;
10 |
11 | import mdesl.graphics.SpriteBatch;
12 | import mdesl.graphics.Texture;
13 | import mdesl.graphics.glutils.ShaderProgram;
14 | import mdesl.test.Game;
15 | import mdesl.test.SimpleGame;
16 | import mdesl.test.Util;
17 |
18 | import org.lwjgl.LWJGLException;
19 | import org.lwjgl.opengl.Display;
20 |
21 | public class ShaderLesson4 extends SimpleGame {
22 |
23 | public static void main(String[] args) throws LWJGLException {
24 | Game game = new ShaderLesson4();
25 | game.setDisplayMode(640, 480, false);
26 | game.start();
27 | }
28 |
29 | //our grass texture
30 | Texture tex0;
31 |
32 | //our dirt texture
33 | Texture tex1;
34 |
35 | //our mask texture
36 | Texture mask;
37 |
38 | //our sprite batch
39 | SpriteBatch batch;
40 |
41 | //our program
42 | ShaderProgram program;
43 |
44 | protected void create() throws LWJGLException {
45 | super.create();
46 |
47 | try {
48 | tex0 = new Texture(Util.getResource("res/grass.png"), Texture.LINEAR, Texture.REPEAT);
49 | tex1 = new Texture(Util.getResource("res/dirt.png"), Texture.LINEAR, Texture.REPEAT);
50 | mask = new Texture(Util.getResource("res/mask.png"), Texture.LINEAR, Texture.REPEAT);
51 | } catch (IOException e) {
52 | throw new RuntimeException("couldn't decode textures");
53 | }
54 |
55 | //load our shader program and sprite batch
56 | try {
57 | final String VERTEX = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson4.vert"));
58 | final String FRAGMENT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson4.frag"));
59 |
60 | //create our shader program -- be sure to pass SpriteBatch's default attributes!
61 | program = new ShaderProgram(VERTEX, FRAGMENT, SpriteBatch.ATTRIBUTES);
62 |
63 | //Good idea to log any warnings if they exist
64 | if (program.getLog().length()!=0)
65 | System.out.println(program.getLog());
66 |
67 | //bind our program
68 | program.use();
69 |
70 | //set our sampler2D uniforms
71 | program.setUniformi("u_texture1", 1);
72 | program.setUniformi("u_mask", 2);
73 |
74 | //create our sprite batch
75 | batch = new SpriteBatch(program);
76 | } catch (Exception e) {
77 | //simple exception handling...
78 | e.printStackTrace();
79 | System.exit(0);
80 | }
81 |
82 |
83 | //make GL_TEXTURE2 the active texture unit, then bind our mask texture
84 | glActiveTexture(GL_TEXTURE2);
85 | mask.bind();
86 |
87 | //do the same for our other two texture units
88 | glActiveTexture(GL_TEXTURE1);
89 | tex1.bind();
90 |
91 | glActiveTexture(GL_TEXTURE0);
92 | tex0.bind();
93 |
94 | //gray clear colour
95 | glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
96 | }
97 |
98 | protected void render() throws LWJGLException {
99 | super.render();
100 |
101 | batch.begin();
102 |
103 | batch.draw(tex0, 10, 10);
104 |
105 | batch.end();
106 | }
107 |
108 | // called to resize the display
109 | protected void resize() throws LWJGLException {
110 | super.resize();
111 |
112 | // resize our batch with the new screen size
113 | batch.resize(Display.getWidth(), Display.getHeight());
114 | }
115 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson4B.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import static org.lwjgl.opengl.GL11.glClearColor;
4 | import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
5 | import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
6 | import static org.lwjgl.opengl.GL13.GL_TEXTURE2;
7 | import static org.lwjgl.opengl.GL13.glActiveTexture;
8 |
9 | import java.io.IOException;
10 |
11 | import mdesl.graphics.SpriteBatch;
12 | import mdesl.graphics.Texture;
13 | import mdesl.graphics.glutils.ShaderProgram;
14 | import mdesl.test.Game;
15 | import mdesl.test.SimpleGame;
16 | import mdesl.test.Util;
17 |
18 | import org.lwjgl.LWJGLException;
19 | import org.lwjgl.opengl.Display;
20 |
21 | public class ShaderLesson4B extends SimpleGame {
22 |
23 | public static void main(String[] args) throws LWJGLException {
24 | Game game = new ShaderLesson4B();
25 | game.setDisplayMode(640, 480, false);
26 | game.start();
27 | }
28 |
29 | //our grass texture
30 | Texture tex0;
31 |
32 | //our dirt texture
33 | Texture tex1;
34 |
35 | //our mask texture
36 | Texture mask;
37 |
38 | //our sprite batch
39 | SpriteBatch batch;
40 |
41 | //our program
42 | ShaderProgram program;
43 |
44 | //our very simple timing mechanism which we'll send to the shader
45 | float tick = 0;
46 |
47 | protected void create() throws LWJGLException {
48 | super.create();
49 |
50 | try {
51 | tex0 = new Texture(Util.getResource("res/grass.png"), Texture.NEAREST, Texture.REPEAT);
52 | tex1 = new Texture(Util.getResource("res/dirt.png"), Texture.NEAREST, Texture.REPEAT);
53 | mask = new Texture(Util.getResource("res/mask.png"), Texture.NEAREST, Texture.REPEAT);
54 | } catch (IOException e) {
55 | throw new RuntimeException("couldn't decode textures");
56 | }
57 |
58 | //load our shader program and sprite batch
59 | try {
60 | final String VERTEX = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson4.vert"));
61 | final String FRAGMENT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson4b.frag"));
62 |
63 | //create our shader program -- be sure to pass SpriteBatch's default attributes!
64 | program = new ShaderProgram(VERTEX, FRAGMENT, SpriteBatch.ATTRIBUTES);
65 |
66 | //Good idea to log any warnings if they exist
67 | if (program.getLog().length()!=0)
68 | System.out.println(program.getLog());
69 |
70 | //bind our program
71 | program.use();
72 |
73 | //set our sampler2D uniforms
74 | program.setUniformi("u_texture1", 1);
75 | program.setUniformi("u_mask", 2);
76 | program.setUniformf("time", tick);
77 |
78 | //create our sprite batch
79 | batch = new SpriteBatch(program);
80 | } catch (Exception e) {
81 | //simple exception handling...
82 | e.printStackTrace();
83 | System.exit(0);
84 | }
85 |
86 |
87 | //make GL_TEXTURE2 the active texture unit, then bind our mask texture
88 | glActiveTexture(GL_TEXTURE2);
89 | mask.bind();
90 |
91 | //do the same for our other two texture units
92 | glActiveTexture(GL_TEXTURE1);
93 | tex1.bind();
94 |
95 | glActiveTexture(GL_TEXTURE0);
96 | tex0.bind();
97 |
98 | //gray clear colour
99 | glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
100 | }
101 |
102 | protected void render() throws LWJGLException {
103 | super.render();
104 |
105 | batch.begin();
106 |
107 | //shader will be bound already
108 | program.setUniformf("time", tick+=0.01f);
109 |
110 | batch.draw(tex0, 10, 10);
111 |
112 | batch.end();
113 | }
114 |
115 | // called to resize the display
116 | protected void resize() throws LWJGLException {
117 | super.resize();
118 |
119 | // resize our batch with the new screen size
120 | batch.resize(Display.getWidth(), Display.getHeight());
121 | }
122 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson5.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
4 | import static org.lwjgl.opengl.GL11.glClear;
5 | import static org.lwjgl.opengl.GL11.glClearColor;
6 |
7 | import java.io.IOException;
8 |
9 | import mdesl.graphics.SpriteBatch;
10 | import mdesl.graphics.Texture;
11 | import mdesl.graphics.glutils.FrameBuffer;
12 | import mdesl.graphics.glutils.ShaderProgram;
13 | import mdesl.test.Game;
14 | import mdesl.test.SimpleGame;
15 | import mdesl.test.Util;
16 | import mdesl.util.MathUtil;
17 |
18 | import org.lwjgl.LWJGLException;
19 | import org.lwjgl.input.Mouse;
20 | import org.lwjgl.opengl.Display;
21 | import org.lwjgl.util.vector.Matrix4f;
22 |
23 | public class ShaderLesson5 extends SimpleGame {
24 |
25 | //should be at least as large as our display
26 | public static final int FBO_SIZE = 1024;
27 |
28 | public static void main(String[] args) throws LWJGLException {
29 | Game game = new ShaderLesson5();
30 | game.setDisplayMode(800, 600, false);
31 | game.start();
32 | }
33 |
34 | //our texture to blur
35 | Texture tex, tex2;
36 |
37 | //we'll use a single batch for everything
38 | SpriteBatch batch;
39 |
40 | //our blur shader
41 | ShaderProgram blurShader;
42 |
43 | //our offscreen buffers
44 | FrameBuffer blurTargetA, blurTargetB;
45 |
46 | float radius = 3f;
47 | final static float MAX_BLUR = 3f;
48 |
49 | protected void create() throws LWJGLException {
50 | super.create();
51 |
52 | try {
53 | //load our texture with linear filter
54 | tex = new Texture(Util.getResource("res/slider.png"), Texture.LINEAR);
55 | tex2 = new Texture(Util.getResource("res/tiles.png"), Texture.LINEAR);
56 | } catch (IOException e) {
57 | throw new RuntimeException("couldn't decode texture");
58 | }
59 |
60 | //our simple demo won't support display resizing
61 | Display.setResizable(false);
62 |
63 | //load our shader program and sprite batch
64 | try {
65 | //create our FBOs
66 | blurTargetA = new FrameBuffer(FBO_SIZE, FBO_SIZE, Texture.LINEAR);
67 | blurTargetB = new FrameBuffer(FBO_SIZE, FBO_SIZE, Texture.LINEAR);
68 |
69 | //our basic pass-through vertex shader
70 | final String VERT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson5.vert"));
71 |
72 | //our fragment shader, which does the blur in one direction at a time
73 | final String FRAG = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson5.frag"));
74 |
75 | //create our shader program
76 | blurShader = new ShaderProgram(VERT, FRAG, SpriteBatch.ATTRIBUTES);
77 |
78 | //Good idea to log any warnings if they exist
79 | if (blurShader.getLog().length()!=0)
80 | System.out.println(blurShader.getLog());
81 |
82 | //always a good idea to set up default uniforms...
83 | blurShader.use();
84 | blurShader.setUniformf("dir", 0f, 0f); //direction of blur; nil for now
85 | blurShader.setUniformf("resolution", FBO_SIZE); //size of FBO texture
86 | blurShader.setUniformf("radius", radius); //radius of blur
87 |
88 | batch = new SpriteBatch();
89 | } catch (Exception e) {
90 | //simple exception handling...
91 | e.printStackTrace();
92 | System.exit(0);
93 | }
94 | }
95 |
96 |
97 | protected void drawEntities(SpriteBatch batch) {
98 | batch.draw(tex, 50, 50);
99 | batch.draw(tex2, tex.getWidth()+20, 100);
100 | }
101 |
102 | void renderScene() throws LWJGLException {
103 | //Bind FBO target A
104 | blurTargetA.begin();
105 |
106 | //Clear FBO A with an opaque colour to minimize blending issues
107 | glClearColor(0.5f, 0.5f, 0.5f, 1f);
108 | glClear(GL_COLOR_BUFFER_BIT);
109 |
110 | //Reset batch to default shader (without blur)
111 | batch.setShader(SpriteBatch.getDefaultShader());
112 |
113 | //send the new projection matrix (FBO size) to the default shader
114 | batch.resize(blurTargetA.getWidth(), blurTargetA.getHeight());
115 |
116 | //now we can start our batch
117 | batch.begin();
118 |
119 | //render our scene fully to FBO A
120 | drawEntities(batch);
121 |
122 | //flush the batch, i.e. render entities to GPU
123 | batch.flush();
124 |
125 | //After flushing, we can finish rendering to FBO target A
126 | blurTargetA.end();
127 | }
128 |
129 | void horizontalBlur() throws LWJGLException {
130 | //swap the shaders
131 | //this will send the batch's (FBO-sized) projection matrix to our blur shader
132 | batch.setShader(blurShader);
133 |
134 | //ensure the direction is along the X-axis only
135 | blurShader.setUniformf("dir", 1f, 0f);
136 |
137 | //determine radius of blur based on mouse position
138 | float mouseXAmt = Mouse.getX() / (float)Display.getWidth();
139 | blurShader.setUniformf("radius", mouseXAmt * MAX_BLUR);
140 |
141 | //start rendering to target B
142 | blurTargetB.begin();
143 |
144 | //no need to clear since targetA has an opaque background
145 | //render target A (the scene) using our horizontal blur shader
146 | //it will be placed into target B
147 | batch.draw(blurTargetA, 0, 0);
148 |
149 | //flush the batch before ending target B
150 | batch.flush();
151 |
152 | //finish rendering target B
153 | blurTargetB.end();
154 | }
155 |
156 | void verticalBlur() throws LWJGLException {
157 | //now we can render to the screen using the vertical blur shader
158 |
159 | //send the screen-size projection matrix to the blurShader
160 | batch.resize(Display.getWidth(), Display.getHeight());
161 |
162 | //apply the blur only along Y-axis
163 | blurShader.setUniformf("dir", 0f, 1f);
164 |
165 | //update Y-axis blur radius based on mouse
166 | float mouseYAmt = (Display.getHeight()-Mouse.getY()-1) / (float)Display.getHeight();
167 | blurShader.setUniformf("radius", mouseYAmt * MAX_BLUR);
168 |
169 | //draw the horizontally-blurred FBO B to the screen, applying the vertical blur as we go
170 | batch.draw(blurTargetB, 0, 0);
171 |
172 | batch.end();
173 | }
174 |
175 | protected void render() throws LWJGLException {
176 | //render scene to FBO A
177 | renderScene();
178 |
179 | //render FBO A to FBO B, using horizontal blur
180 | horizontalBlur();
181 |
182 | //render FBO B to scene, using vertical blur
183 | verticalBlur();
184 | }
185 |
186 | // called to resize the display
187 | protected void resize() throws LWJGLException {
188 | super.resize();
189 | //we will call batch.resize() in render
190 | }
191 | }
--------------------------------------------------------------------------------
/test/mdesl/test/shadertut/ShaderLesson6.java:
--------------------------------------------------------------------------------
1 | package mdesl.test.shadertut;
2 |
3 | import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
4 | import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
5 | import static org.lwjgl.opengl.GL13.glActiveTexture;
6 |
7 | import java.io.IOException;
8 |
9 | import mdesl.graphics.SpriteBatch;
10 | import mdesl.graphics.Texture;
11 | import mdesl.graphics.glutils.ShaderProgram;
12 | import mdesl.test.Game;
13 | import mdesl.test.SimpleGame;
14 | import mdesl.test.Util;
15 |
16 | import org.lwjgl.LWJGLException;
17 | import org.lwjgl.input.Mouse;
18 | import org.lwjgl.opengl.Display;
19 | import org.lwjgl.util.vector.Vector3f;
20 | import org.lwjgl.util.vector.Vector4f;
21 |
22 | public class ShaderLesson6 extends SimpleGame {
23 |
24 | public static void main(String[] args) throws LWJGLException {
25 | Game game = new ShaderLesson6();
26 | game.setDisplayMode(800, 600, false);
27 | game.start();
28 | }
29 |
30 | //our texture to blur
31 | Texture rock, rockNormals;
32 |
33 | //we'll use a single batch for everything
34 | SpriteBatch batch;
35 |
36 | //our lighting shader
37 | ShaderProgram shader;
38 |
39 | public static final float DEFAULT_LIGHT_Z = 0.075f;
40 |
41 | public static final Vector3f LIGHT_POS = new Vector3f(0f,0f,DEFAULT_LIGHT_Z);
42 |
43 | //Light RGB and intensity (alpha)
44 | public static final Vector4f LIGHT_COLOR = new Vector4f(1f, 0.8f, 0.6f, 1f);
45 |
46 | //Ambient RGB and intensity (alpha)
47 | public static final Vector4f AMBIENT_COLOR = new Vector4f(0.6f, 0.6f, 1f, 0.2f);
48 |
49 | //Attenuation coefficients for light falloff
50 | public static final Vector3f FALLOFF = new Vector3f(.4f, 3f, 20f);
51 |
52 | protected void create() throws LWJGLException {
53 | super.create();
54 |
55 | try {
56 | //load our texture with linear filter
57 | rock = new Texture(Util.getResource("res/rock.png"), Texture.LINEAR);
58 | rockNormals = new Texture(Util.getResource("res/rock_n.png"), Texture.LINEAR);
59 | } catch (IOException e) {
60 | throw new RuntimeException("couldn't decode texture");
61 | }
62 |
63 | //load our shader program and sprite batch
64 | try {
65 | //our basic pass-through vertex shader
66 | final String VERT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson6.vert"));
67 |
68 | //our fragment shader, which does the blur in one direction at a time
69 | final String FRAG = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson6.frag"));
70 |
71 | //create our shader program
72 | ShaderProgram.setStrictMode(false);
73 | shader = new ShaderProgram(VERT, FRAG, SpriteBatch.ATTRIBUTES);
74 |
75 | //Good idea to log any warnings if they exist
76 | if (shader.getLog().length()!=0)
77 | System.out.println(shader.getLog());
78 |
79 | //always a good idea to set up default uniforms...
80 | shader.use();
81 |
82 | //our normal map
83 | shader.setUniformi("u_normals", 1); //GL_TEXTURE1
84 |
85 | //light/ambient colors
86 | shader.setUniformf("LightColor", LIGHT_COLOR);
87 | shader.setUniformf("AmbientColor", AMBIENT_COLOR);
88 | shader.setUniformf("Falloff", FALLOFF);
89 |
90 | batch = new SpriteBatch(shader);
91 | } catch (Exception e) {
92 | //simple exception handling...
93 | e.printStackTrace();
94 | System.exit(0);
95 | }
96 | }
97 |
98 | protected void render() throws LWJGLException {
99 | super.render();
100 |
101 | batch.begin();
102 |
103 | //shader will now be in use...
104 |
105 | //update light position, normalized to screen resolution
106 | float x = Mouse.getX() / (float)Display.getWidth();
107 | float y = Mouse.getY() / (float)Display.getHeight();
108 | LIGHT_POS.x = x;
109 | LIGHT_POS.y = y;
110 |
111 | //send a Vector4f to GLSL
112 | shader.setUniformf("LightPos", LIGHT_POS);
113 |
114 | //bind normal map to texture unit 1
115 | glActiveTexture(GL_TEXTURE1);
116 | rockNormals.bind();
117 |
118 | //bind diffuse color to texture unit 0
119 | glActiveTexture(GL_TEXTURE0);
120 | rock.bind();
121 |
122 | //draw the texture unit 0 with our shader effect applied
123 | batch.draw(rock, 50, 50);
124 |
125 | batch.end();
126 | }
127 |
128 | public void mousePressed(int x, int y, int button) {
129 | LIGHT_POS.z = DEFAULT_LIGHT_Z;
130 | System.out.println("New light Z: "+LIGHT_POS.z);
131 | }
132 |
133 | public void mouseWheelChanged(int delta) {
134 | LIGHT_POS.z = Math.max(0f, LIGHT_POS.z + (delta * 0.005f));
135 | System.out.println("New light Z: "+LIGHT_POS.z);
136 | }
137 |
138 |
139 | // called to resize the display
140 | protected void resize() throws LWJGLException {
141 | super.resize();
142 | shader.use();
143 | shader.setUniformf("Resolution", Display.getWidth(), Display.getHeight());
144 | batch.resize(Display.getWidth(), Display.getHeight());
145 | }
146 | }
--------------------------------------------------------------------------------
/test/res/dirt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/dirt.png
--------------------------------------------------------------------------------
/test/res/grass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/grass.png
--------------------------------------------------------------------------------
/test/res/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/heart.png
--------------------------------------------------------------------------------
/test/res/height.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/height.png
--------------------------------------------------------------------------------
/test/res/mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/mask.png
--------------------------------------------------------------------------------
/test/res/ptsans_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/ptsans_00.png
--------------------------------------------------------------------------------
/test/res/ptsans_00_atlas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/ptsans_00_atlas.png
--------------------------------------------------------------------------------
/test/res/rock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/rock.png
--------------------------------------------------------------------------------
/test/res/rock_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/rock_n.png
--------------------------------------------------------------------------------
/test/res/scene.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/scene.png
--------------------------------------------------------------------------------
/test/res/shadertut/lesson1.frag:
--------------------------------------------------------------------------------
1 | void main() {
2 | //final color
3 | gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/res/shadertut/lesson1.vert:
--------------------------------------------------------------------------------
1 | //incoming Position attribute from our SpriteBatch
2 | attribute vec2 Position;
3 |
4 | //the transformation matrix of our SpriteBatch
5 | uniform mat4 u_projView;
6 |
7 | void main() {
8 | //transform our 2D screen space position into 3D world space
9 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
10 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson2.frag:
--------------------------------------------------------------------------------
1 | //SpriteBatch will use texture unit 0
2 | uniform sampler2D u_texture;
3 |
4 | //"in" varyings from our vertex shader
5 | varying vec4 vColor;
6 | varying vec2 vTexCoord;
7 |
8 | void main() {
9 | //sample the texture
10 | vec4 texColor = texture2D(u_texture, vTexCoord);
11 |
12 | //invert the red, green and blue channels
13 | texColor.rgb = 1.0 - texColor.rgb;
14 |
15 | //final color
16 | gl_FragColor = texColor * vColor;
17 | }
18 |
--------------------------------------------------------------------------------
/test/res/shadertut/lesson2.vert:
--------------------------------------------------------------------------------
1 | //combined projection and view matrix
2 | uniform mat4 u_projView;
3 |
4 | //"in" attributes from our SpriteBatch
5 | attribute vec2 Position;
6 | attribute vec2 TexCoord;
7 | attribute vec4 Color;
8 |
9 | //"out" varyings to our fragment shader
10 | varying vec4 vColor;
11 | varying vec2 vTexCoord;
12 |
13 | void main() {
14 | vColor = Color;
15 | vTexCoord = TexCoord;
16 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
17 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson3.frag:
--------------------------------------------------------------------------------
1 | //texture 0
2 | uniform sampler2D u_texture;
3 |
4 | //our screen resolution, set from Java whenever the display is resized
5 | uniform vec2 resolution;
6 |
7 | //"in" attributes from our vertex shader
8 | varying vec4 vColor;
9 | varying vec2 vTexCoord;
10 |
11 | //RADIUS of our vignette, where 0.5 results in a circle fitting the screen
12 | const float RADIUS = 0.75;
13 |
14 | //softness of our vignette, between 0.0 and 1.0
15 | const float SOFTNESS = 0.45;
16 |
17 | //sepia colour, adjust to taste
18 | const vec3 SEPIA = vec3(1.2, 1.0, 0.8);
19 |
20 | void main() {
21 | //sample our texture
22 | vec4 texColor = texture2D(u_texture, vTexCoord);
23 |
24 | //1. VIGNETTE
25 |
26 | //determine center position
27 | vec2 position = (gl_FragCoord.xy / resolution.xy) - vec2(0.5);
28 |
29 | //determine the vector length of the center position
30 | float len = length(position);
31 |
32 | //use smoothstep to create a smooth vignette
33 | float vignette = smoothstep(RADIUS, RADIUS-SOFTNESS, len);
34 |
35 | //apply the vignette with 50% opacity
36 | texColor.rgb = mix(texColor.rgb, texColor.rgb * vignette, 0.5);
37 |
38 | //2. GRAYSCALE
39 |
40 | //convert to grayscale using NTSC conversion weights
41 | float gray = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
42 |
43 | //3. SEPIA
44 |
45 | //create our sepia tone from some constant value
46 | vec3 sepiaColor = vec3(gray) * SEPIA;
47 |
48 | //again we'll use mix so that the sepia effect is at 75%
49 | texColor.rgb = mix(texColor.rgb, sepiaColor, 0.75);
50 |
51 | //final colour, multiplied by vertex colour
52 | gl_FragColor = texColor * vColor;
53 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson3.vert:
--------------------------------------------------------------------------------
1 | //combined projection and view matrix
2 | uniform mat4 u_projView;
3 |
4 | //"in" attributes from our SpriteBatch
5 | attribute vec2 Position;
6 | attribute vec2 TexCoord;
7 | attribute vec4 Color;
8 |
9 | //"out" varyings to our fragment shader
10 | varying vec4 vColor;
11 | varying vec2 vTexCoord;
12 |
13 | void main() {
14 | vColor = Color;
15 | vTexCoord = TexCoord;
16 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
17 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson4.frag:
--------------------------------------------------------------------------------
1 | //"in" attributes from our vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 |
6 | //our different texture units
7 | uniform sampler2D u_texture; //default GL_TEXTURE0, expected by SpriteBatch
8 | uniform sampler2D u_texture1;
9 | uniform sampler2D u_mask;
10 |
11 | void main(void) {
12 | //sample the colour from the first texture
13 | vec4 texColor0 = texture2D(u_texture, vTexCoord);
14 | //sample the colour from the second texture
15 | vec4 texColor1 = texture2D(u_texture1, vTexCoord);
16 |
17 | //get the mask; we will only use the alpha channel
18 | float mask = texture2D(u_mask, vTexCoord).a;
19 |
20 | //interpolate the colours based on the mask
21 | gl_FragColor = vColor * mix(texColor0, texColor1, mask);
22 | }
23 |
--------------------------------------------------------------------------------
/test/res/shadertut/lesson4.vert:
--------------------------------------------------------------------------------
1 | //combined projection and view matrix
2 | uniform mat4 u_projView;
3 |
4 | //"in" attributes from our SpriteBatch
5 | attribute vec2 Position;
6 | attribute vec2 TexCoord;
7 | attribute vec4 Color;
8 |
9 | //"out" varyings to our fragment shader
10 | varying vec4 vColor;
11 | varying vec2 vTexCoord;
12 |
13 | void main() {
14 | vColor = Color;
15 | vTexCoord = TexCoord;
16 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
17 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson4b.frag:
--------------------------------------------------------------------------------
1 | //"in" attributes from our vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | //our different texture units
6 | uniform sampler2D u_texture; //default GL_TEXTURE0, expected by SpriteBatch
7 | uniform sampler2D u_texture1;
8 | uniform sampler2D u_mask;
9 |
10 | uniform float time;
11 |
12 | /////////////////////////////////////////////////////////////////////////
13 | /////////////////// SIMPLEX NOISE FROM WEBGL-NOISE //////////////////////
14 | /////////////////////////////////////////////////////////////////////////
15 | // https://github.com/ashima/webgl-noise/wiki //
16 | /////////////////////////////////////////////////////////////////////////
17 |
18 | vec3 mod289(vec3 x) {
19 | return x - floor(x * (1.0 / 289.0)) * 289.0;
20 | }
21 |
22 | vec2 mod289(vec2 x) {
23 | return x - floor(x * (1.0 / 289.0)) * 289.0;
24 | }
25 |
26 | vec3 permute(vec3 x) {
27 | return mod289(((x*34.0)+1.0)*x);
28 | }
29 |
30 | float snoise(vec2 v) {
31 | const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
32 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
33 | -0.577350269189626, // -1.0 + 2.0 * C.x
34 | 0.024390243902439); // 1.0 / 41.0
35 | // First corner
36 | vec2 i = floor(v + dot(v, C.yy) );
37 | vec2 x0 = v - i + dot(i, C.xx);
38 |
39 | // Other corners
40 | vec2 i1;
41 | //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
42 | //i1.y = 1.0 - i1.x;
43 | i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
44 | // x0 = x0 - 0.0 + 0.0 * C.xx ;
45 | // x1 = x0 - i1 + 1.0 * C.xx ;
46 | // x2 = x0 - 1.0 + 2.0 * C.xx ;
47 | vec4 x12 = x0.xyxy + C.xxzz;
48 | x12.xy -= i1;
49 |
50 | // Permutations
51 | i = mod289(i); // Avoid truncation effects in permutation
52 | vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
53 | + i.x + vec3(0.0, i1.x, 1.0 ));
54 |
55 | vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
56 | m = m*m ;
57 | m = m*m ;
58 |
59 | // Gradients: 41 points uniformly over a line, mapped onto a diamond.
60 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
61 |
62 | vec3 x = 2.0 * fract(p * C.www) - 1.0;
63 | vec3 h = abs(x) - 0.5;
64 | vec3 ox = floor(x + 0.5);
65 | vec3 a0 = x - ox;
66 |
67 | // Normalise gradients implicitly by scaling m
68 | // Approximation of: m *= inversesqrt( a0*a0 + h*h );
69 | m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
70 |
71 | // Compute final noise value at P
72 | vec3 g;
73 | g.x = a0.x * x0.x + h.x * x0.y;
74 | g.yz = a0.yz * x12.xz + h.yz * x12.yw;
75 | return 130.0 * dot(m, g);
76 | }
77 |
78 |
79 | /////////////////////////////////////////////////////////////////////////
80 | //////////////////// END SIMPLEX NOISE ////////////////////////
81 | /////////////////////////////////////////////////////////////////////////
82 |
83 |
84 | void main(void) {
85 | //sample the colour from the first texture
86 | vec4 texColor0 = texture2D(u_texture, vTexCoord);
87 | //sample the colour from the second texture
88 | vec4 texColor1 = texture2D(u_texture1, vTexCoord);
89 |
90 | //pertube texcoord by x and y
91 | vec2 distort = 0.2 * vec2(snoise(vTexCoord + vec2(0.0, time/3.0)),
92 | snoise(vTexCoord + vec2(time/3.0, 0.0)) );
93 |
94 | //get the mask; we will only use the alpha channel
95 | float mask = texture2D(u_mask, vTexCoord + distort).a;
96 |
97 | //interpolate the colours based on the mask
98 | gl_FragColor = vColor * mix(texColor0, texColor1, mask);
99 | }
100 |
--------------------------------------------------------------------------------
/test/res/shadertut/lesson5.frag:
--------------------------------------------------------------------------------
1 | //"in" attributes from our vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | //declare uniforms
6 | uniform sampler2D u_texture;
7 | uniform float resolution;
8 | uniform float radius;
9 | uniform vec2 dir;
10 |
11 | void main() {
12 | //this will be our RGBA sum
13 | vec4 sum = vec4(0.0);
14 |
15 | //our original texcoord for this fragment
16 | vec2 tc = vTexCoord;
17 |
18 | //the amount to blur, i.e. how far off center to sample from
19 | //1.0 -> blur by one pixel
20 | //2.0 -> blur by two pixels, etc.
21 | float blur = radius/resolution;
22 |
23 | //the direction of our blur
24 | //(1.0, 0.0) -> x-axis blur
25 | //(0.0, 1.0) -> y-axis blur
26 | float hstep = dir.x;
27 | float vstep = dir.y;
28 |
29 |
30 | //apply blurring, using a 9-tap filter with predefined gaussian weights
31 |
32 | sum += texture2D(u_texture, vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)) * 0.0162162162;
33 | sum += texture2D(u_texture, vec2(tc.x - 3.0*blur*hstep, tc.y - 3.0*blur*vstep)) * 0.0540540541;
34 | sum += texture2D(u_texture, vec2(tc.x - 2.0*blur*hstep, tc.y - 2.0*blur*vstep)) * 0.1216216216;
35 | sum += texture2D(u_texture, vec2(tc.x - 1.0*blur*hstep, tc.y - 1.0*blur*vstep)) * 0.1945945946;
36 |
37 | sum += texture2D(u_texture, vec2(tc.x, tc.y)) * 0.2270270270;
38 |
39 | sum += texture2D(u_texture, vec2(tc.x + 1.0*blur*hstep, tc.y + 1.0*blur*vstep)) * 0.1945945946;
40 | sum += texture2D(u_texture, vec2(tc.x + 2.0*blur*hstep, tc.y + 2.0*blur*vstep)) * 0.1216216216;
41 | sum += texture2D(u_texture, vec2(tc.x + 3.0*blur*hstep, tc.y + 3.0*blur*vstep)) * 0.0540540541;
42 | sum += texture2D(u_texture, vec2(tc.x + 4.0*blur*hstep, tc.y + 4.0*blur*vstep)) * 0.0162162162;
43 |
44 | //discard alpha for our simple demo, multiply by vertex color and return
45 | gl_FragColor = vColor * vec4(sum.rgb, 1.0);
46 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson5.vert:
--------------------------------------------------------------------------------
1 | //combined projection and view matrix
2 | uniform mat4 u_projView;
3 |
4 | //"in" attributes from our SpriteBatch
5 | attribute vec2 Position;
6 | attribute vec2 TexCoord;
7 | attribute vec4 Color;
8 |
9 | //"out" varyings to our fragment shader
10 | varying vec4 vColor;
11 | varying vec2 vTexCoord;
12 |
13 | void main() {
14 | vColor = Color;
15 | vTexCoord = TexCoord;
16 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
17 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson5_horiz.frag:
--------------------------------------------------------------------------------
1 | //"in" attributes from our vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | uniform sampler2D tex0;
6 | uniform float resolution;
7 | uniform float radius;
8 |
9 | void main() {
10 | vec4 sum = vec4(0.0);
11 | vec2 tc = vTexCoord;
12 | float blur = radius/resolution;
13 |
14 | sum += texture2D(tex0, vec2(tc.x - 4.0*blur, tc.y)) * 0.05;
15 | sum += texture2D(tex0, vec2(tc.x - 3.0*blur, tc.y)) * 0.09;
16 | sum += texture2D(tex0, vec2(tc.x - 2.0*blur, tc.y)) * 0.12;
17 | sum += texture2D(tex0, vec2(tc.x - 1.0*blur, tc.y)) * 0.15;
18 |
19 | sum += texture2D(tex0, vec2(tc.x, tc.y)) * 0.16;
20 |
21 | sum += texture2D(tex0, vec2(tc.x + 1.0*blur, tc.y)) * 0.15;
22 | sum += texture2D(tex0, vec2(tc.x + 2.0*blur, tc.y)) * 0.12;
23 | sum += texture2D(tex0, vec2(tc.x + 3.0*blur, tc.y)) * 0.09;
24 | sum += texture2D(tex0, vec2(tc.x + 4.0*blur, tc.y)) * 0.05;
25 |
26 | gl_FragColor = vColor * sum;
27 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson5_vert.frag:
--------------------------------------------------------------------------------
1 | //"in" attributes from our vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | uniform sampler2D tex0;
6 | uniform float resolution;
7 | uniform float radius;
8 |
9 | void main() {
10 | vec4 sum = vec4(0.0);
11 | vec2 tc = vTexCoord;
12 | float blur = radius/resolution;
13 |
14 | sum += texture2D(tex0, vec2(tc.x, tc.y - 4.0*blur)) * 0.05;
15 | sum += texture2D(tex0, vec2(tc.x, tc.y - 3.0*blur)) * 0.09;
16 | sum += texture2D(tex0, vec2(tc.x, tc.y - 2.0*blur)) * 0.12;
17 | sum += texture2D(tex0, vec2(tc.x, tc.y - 1.0*blur)) * 0.15;
18 |
19 | sum += texture2D(tex0, vec2(tc.x, tc.y)) * 0.16;
20 |
21 | sum += texture2D(tex0, vec2(tc.x, tc.y + 1.0*blur)) * 0.15;
22 | sum += texture2D(tex0, vec2(tc.x, tc.y + 2.0*blur)) * 0.12;
23 | sum += texture2D(tex0, vec2(tc.x, tc.y + 3.0*blur)) * 0.09;
24 | sum += texture2D(tex0, vec2(tc.x, tc.y + 4.0*blur)) * 0.05;
25 |
26 | gl_FragColor = vColor * sum;
27 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson6.frag:
--------------------------------------------------------------------------------
1 | //attributes from vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | //our texture samplers
6 | uniform sampler2D u_texture; //diffuse map
7 | uniform sampler2D u_normals; //normal map
8 |
9 | //values used for shading algorithm...
10 | uniform vec2 Resolution; //resolution of screen
11 | uniform vec3 LightPos; //light position, normalized
12 | uniform vec4 LightColor; //light RGBA -- alpha is intensity
13 | uniform vec4 AmbientColor; //ambient RGBA -- alpha is intensity
14 | uniform vec3 Falloff; //attenuation coefficients
15 |
16 | void main() {
17 | //RGBA of our diffuse color
18 | vec4 DiffuseColor = texture2D(u_texture, vTexCoord);
19 |
20 | //RGB of our normal map
21 | vec3 NormalMap = texture2D(u_normals, vTexCoord).rgb;
22 |
23 | //The delta position of light
24 | vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);
25 |
26 | //Correct for aspect ratio
27 | LightDir.x *= Resolution.x / Resolution.y;
28 |
29 | //Determine distance (used for attenuation) BEFORE we normalize our LightDir
30 | float D = length(LightDir);
31 |
32 | //normalize our vectors
33 | vec3 N = normalize(NormalMap * 2.0 - 1.0);
34 | vec3 L = normalize(LightDir);
35 |
36 | //Pre-multiply light color with intensity
37 | //Then perform "N dot L" to determine our diffuse term
38 | vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);
39 |
40 | //pre-multiply ambient color with intensity
41 | vec3 Ambient = AmbientColor.rgb * AmbientColor.a;
42 |
43 | //calculate attenuation
44 | float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );
45 |
46 | //the calculation which brings it all together
47 | vec3 Intensity = Ambient + Diffuse * Attenuation;
48 | vec3 FinalColor = DiffuseColor.rgb * Intensity;
49 | gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);
50 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson6.vert:
--------------------------------------------------------------------------------
1 | //combined projection and view matrix
2 | uniform mat4 u_projView;
3 |
4 | //"in" attributes from our SpriteBatch
5 | attribute vec2 Position;
6 | attribute vec2 TexCoord;
7 | attribute vec4 Color;
8 |
9 | //"out" varyings to our fragment shader
10 | varying vec4 vColor;
11 | varying vec2 vTexCoord;
12 |
13 | void main() {
14 | vColor = Color;
15 | vTexCoord = TexCoord;
16 | gl_Position = u_projView * vec4(Position, 0.0, 1.0);
17 | }
--------------------------------------------------------------------------------
/test/res/shadertut/lesson6a.frag:
--------------------------------------------------------------------------------
1 | //attributes from vertex shader
2 | varying vec4 vColor;
3 | varying vec2 vTexCoord;
4 |
5 | //our texture samplers
6 | uniform sampler2D u_texture; //diffuse map
7 | uniform sampler2D u_normals; //normal map
8 |
9 | //values used for shading algorithm...
10 | uniform vec2 Resolution; //resolution of screen
11 | uniform vec3 LightPos; //light position, normalized
12 | uniform vec4 LightColor; //light RGBA -- alpha is intensity
13 | uniform vec4 AmbientColor; //ambient RGBA -- alpha is intensity
14 | uniform vec3 Attenuation; //attenuation coefficients
15 |
16 | void main() {
17 | //RGBA of our diffuse color
18 | vec4 DiffuseColor = texture2D(u_texture, vTexCoord);
19 |
20 | //RGB of our normal map
21 | vec3 NormalMap = texture2D(u_normals, vTexCoord).rgb;
22 |
23 | //The delta position of light
24 | vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);
25 |
26 | //normalize our vectors
27 | vec3 N = normalize(NormalMap * 2.0 - 1.0);
28 | vec3 L = normalize(LightDir);
29 |
30 | //Then perform "N dot L" to determine our diffuse term
31 | vec3 Diffuse = vec3(1.0) * max(dot(N, L), 0.0);
32 |
33 | //the calculation which brings it all together
34 | vec3 Intensity = Diffuse;
35 |
36 | vec3 FinalColor = DiffuseColor.rgb * Intensity;
37 |
38 | gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);
39 | }
--------------------------------------------------------------------------------
/test/res/slider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/slider.png
--------------------------------------------------------------------------------
/test/res/slider_opaque.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/slider_opaque.png
--------------------------------------------------------------------------------
/test/res/suzanne.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/suzanne.png
--------------------------------------------------------------------------------
/test/res/suzanne_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/suzanne_n.png
--------------------------------------------------------------------------------
/test/res/tiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/test/res/tiles.png
--------------------------------------------------------------------------------
/tools/blender-normals/normals_template.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/tools/blender-normals/normals_template.blend
--------------------------------------------------------------------------------
/tools/blender-normals/readme.md:
--------------------------------------------------------------------------------
1 | ## Blender Template: Normal Map Pass
2 |
3 | Renders the scene as a tangent-space normal map pass.
4 |
5 | 
6 |
7 | #Set Up
8 |
9 | - If you're using a different coordinate system, adjust the colors and positions of your hemi lights as necessary.
10 | - Use the "WhiteNormalMaterial" on your objects to ensure proper illumination.
11 | - Ensure your objects are centered correctly, for e.g. xyz=(0, 0, 0).
12 | - Use ortho projection (`Numpad 5`) and front (`Numpad 1`), then `Ctrl + Alt + Numpad 0` to set the camera to that view.
13 | - In order to render correctly, the template uses `None` as the Display Device and `Raw` for Color Space (in `Scene > Color Management`).
14 |
15 | ## Credits
16 |
17 | Idea from Roy Schulz:
18 | http://download.blender.org/documentation/bc2004/Roy_Schulz/normal.html
19 |
20 | Project by Matt DesLauriers (davedes). More details to come in a later article:
21 | https://github.com/mattdesl/lwjgl-basics/wiki
--------------------------------------------------------------------------------
/tools/blender-normals/suzanne.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/tools/blender-normals/suzanne.png
--------------------------------------------------------------------------------
/tools/blender-normals/suzanne_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/lwjgl-basics/552b1f9cbb00000fb4132d6a792af6e0c7476eab/tools/blender-normals/suzanne_n.png
--------------------------------------------------------------------------------