├── .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 | ![ZIP](http://i.imgur.com/Dkvp0.png) 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 | ![Image](http://i.imgur.com/dFRsM.png) 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 --------------------------------------------------------------------------------