Main repository of MikuMikuStudio
Revisión | 20e66b4d9846e2cbb2bca11dd18bcf082de8fbcd (tree) |
---|---|
Tiempo | 2014-02-17 04:11:46 |
Autor | kobayasi <kobayasi@pscn...> |
Commiter | kobayasi |
Add libgdx support.
@@ -10,7 +10,7 @@ lazy val desktop = project.dependsOn(engine) | ||
10 | 10 | |
11 | 11 | lazy val android = project |
12 | 12 | |
13 | -lazy val gdx = project | |
13 | +lazy val gdx = project.dependsOn(engine) | |
14 | 14 | |
15 | 15 | lazy val niftygui = project.dependsOn(engine) |
16 | 16 |
@@ -10,10 +10,6 @@ unmanagedSourceDirectories in Compile ++= Seq( | ||
10 | 10 | |
11 | 11 | libraryDependencies += "org.lwjgl.lwjgl" % "lwjgl" % "2.9.0" |
12 | 12 | |
13 | -libraryDependencies += "net.sf.sociaal" % "j-ogg-oggd" % "3.0.0.20130526" | |
14 | - | |
15 | -libraryDependencies += "net.sf.sociaal" % "j-ogg-vorbisd" % "3.0.0.20130526" | |
16 | - | |
17 | 13 | libraryDependencies += "net.java.jinput" % "jinput" % "2.0.5" |
18 | 14 | |
19 | 15 | libraryDependencies += "org.bushe" % "eventbus" % "1.4" |
@@ -1,24 +1,24 @@ | ||
1 | -LOCATOR / com.jme3.asset.plugins.ClasspathLocator | |
2 | - | |
3 | -LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg, sph, spa | |
4 | -LOADER com.jme3.audio.plugins.WAVLoader : wav | |
5 | -LOADER com.jme3.audio.plugins.OGGLoader : ogg | |
6 | -LOADER com.jme3.material.plugins.J3MLoader : j3m | |
7 | -LOADER com.jme3.material.plugins.J3MLoader : j3md | |
8 | -LOADER com.jme3.font.plugins.BitmapFontLoader : fnt | |
9 | -LOADER com.jme3.texture.plugins.DDSLoader : dds | |
10 | -LOADER com.jme3.texture.plugins.PFMLoader : pfm | |
11 | -LOADER com.jme3.texture.plugins.HDRLoader : hdr | |
12 | -LOADER com.jme3.texture.plugins.TGALoader : tga | |
13 | -LOADER com.jme3.export.binary.BinaryImporter : j3o | |
14 | -LOADER com.jme3.export.binary.BinaryImporter : j3f | |
15 | -LOADER com.jme3.scene.plugins.OBJLoader : obj | |
16 | -LOADER com.jme3.scene.plugins.MTLLoader : mtl | |
17 | -LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml | |
18 | -LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml | |
19 | -LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material | |
20 | -LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene | |
21 | -LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend | |
22 | -LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib | |
23 | -LOADER projectkyoto.jme3.mmd.PMDLoaderGLSLSkinning2 : pmd | |
24 | -LOADER projectkyoto.jme3.mmd.VMDLoader : vmd | |
1 | +LOCATOR / com.jme3.asset.plugins.ClasspathLocator | |
2 | + | |
3 | +LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg, sph, spa | |
4 | +LOADER com.jme3.audio.plugins.WAVLoader : wav | |
5 | +LOADER com.jme3.audio.plugins.OGGLoader : ogg | |
6 | +LOADER com.jme3.material.plugins.J3MLoader : j3m | |
7 | +LOADER com.jme3.material.plugins.J3MLoader : j3md | |
8 | +LOADER com.jme3.font.plugins.BitmapFontLoader : fnt | |
9 | +LOADER com.jme3.texture.plugins.DDSLoader : dds | |
10 | +LOADER com.jme3.texture.plugins.PFMLoader : pfm | |
11 | +LOADER com.jme3.texture.plugins.HDRLoader : hdr | |
12 | +LOADER com.jme3.texture.plugins.TGALoader : tga | |
13 | +LOADER com.jme3.export.binary.BinaryImporter : j3o | |
14 | +LOADER com.jme3.export.binary.BinaryImporter : j3f | |
15 | +LOADER com.jme3.scene.plugins.OBJLoader : obj | |
16 | +LOADER com.jme3.scene.plugins.MTLLoader : mtl | |
17 | +LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml | |
18 | +LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml | |
19 | +LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material | |
20 | +LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene | |
21 | +LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend | |
22 | +LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib | |
23 | +LOADER projectkyoto.jme3.mmd.PMDLoaderGLSLSkinning2 : pmd | |
24 | +LOADER projectkyoto.jme3.mmd.VMDLoader : vmd |
@@ -15,6 +15,7 @@ unmanagedSourceDirectories in Compile := Seq( | ||
15 | 15 | , baseDirectory.value / "src/desktop-fx" |
16 | 16 | , baseDirectory.value / "src/games" |
17 | 17 | // , baseDirectory.value / "src/jheora" |
18 | + , baseDirectory.value / "src/jogg" | |
18 | 19 | // , baseDirectory.value / "src/lwjgl-oal" |
19 | 20 | // , baseDirectory.value / "src/lwjgl-ogl" |
20 | 21 | , baseDirectory.value / "src/mmd" |
@@ -45,3 +46,6 @@ libraryDependencies += "xpp3" % "xpp3" % "1.1.4c" | ||
45 | 46 | |
46 | 47 | libraryDependencies += "com.jme3" % "noise" % "3.0.0-SNAPSHOT" |
47 | 48 | |
49 | +libraryDependencies += "net.sf.sociaal" % "j-ogg-oggd" % "3.0.0.20130526" | |
50 | + | |
51 | +libraryDependencies += "net.sf.sociaal" % "j-ogg-vorbisd" % "3.0.0.20130526" | |
\ No newline at end of file |
@@ -31,6 +31,7 @@ | ||
31 | 31 | */ |
32 | 32 | package com.jme3.system; |
33 | 33 | |
34 | +import com.jme3.app.Application; | |
34 | 35 | import com.jme3.asset.AssetManager; |
35 | 36 | import com.jme3.audio.AudioRenderer; |
36 | 37 |
@@ -44,6 +45,7 @@ public class JmeSystem { | ||
44 | 45 | private static boolean initialized = false; |
45 | 46 | |
46 | 47 | private static JmeSystemDelegate delegate; |
48 | + protected static ThreadLocal<Application> app = new ThreadLocal<Application>(); | |
47 | 49 | |
48 | 50 | static { |
49 | 51 | try { |
@@ -0,0 +1,7 @@ | ||
1 | +Common.settings | |
2 | + | |
3 | +name := "mms-gdx" | |
4 | + | |
5 | +libraryDependencies ++= Seq( | |
6 | + "com.badlogicgames.gdx" % "gdx" % "1.0-SNAPSHOT" | |
7 | +) | |
\ No newline at end of file |
@@ -0,0 +1,47 @@ | ||
1 | +package com.jme3.asset.gdx; | |
2 | + | |
3 | +import com.jme3.asset.*; | |
4 | +import com.jme3.material.Material; | |
5 | +import com.jme3.system.gdx.GdxAudioLoader; | |
6 | +import com.jme3.texture.Texture; | |
7 | +import com.jme3.texture.plugins.gdx.GdxTGALoader; | |
8 | +import com.jme3.texture.plugins.gdx.GdxImageLoader; | |
9 | + | |
10 | +/** | |
11 | + * Created with IntelliJ IDEA. | |
12 | + * User: kobayasi | |
13 | + * Date: 13/10/08 | |
14 | + * Time: 0:56 | |
15 | + * To change this template use File | Settings | File Templates. | |
16 | + */ | |
17 | +public class GdxAssetManager extends DesktopAssetManager { | |
18 | + public GdxAssetManager() { | |
19 | + super(true); | |
20 | + registerLoader(GdxTGALoader.class, "tga"); | |
21 | + this.registerLoader(GdxImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg","spa","sph"); | |
22 | + this.registerLoader(GdxAudioLoader.class, "wav", "mp3", "ogg"); | |
23 | + } | |
24 | + | |
25 | + @Override | |
26 | + public <T> T loadAsset(AssetKey<T> key) { | |
27 | + return super.loadAsset(key); //To change body of overridden methods use File | Settings | File Templates. | |
28 | + } | |
29 | + | |
30 | + @Override | |
31 | + public Object loadAsset(String name) { | |
32 | + return super.loadAsset(name); //To change body of overridden methods use File | Settings | File Templates. | |
33 | + } | |
34 | + | |
35 | + @Override | |
36 | + public Texture loadTexture(TextureKey key) { | |
37 | + return super.loadTexture(key); //To change body of overridden methods use File | Settings | File Templates. | |
38 | + } | |
39 | + | |
40 | + @Override | |
41 | + public Material loadMaterial(String name) { | |
42 | + return super.loadMaterial(name); //To change body of overridden methods use File | Settings | File Templates. | |
43 | + } | |
44 | + | |
45 | + | |
46 | + | |
47 | +} |
@@ -0,0 +1,109 @@ | ||
1 | +package com.jme3.asset.gdx; | |
2 | + | |
3 | +import java.io.FilterInputStream; | |
4 | +import java.io.IOException; | |
5 | +import java.io.InputStream; | |
6 | + | |
7 | +/** | |
8 | + * | |
9 | + * @author kobayasi | |
10 | + */ | |
11 | +public class MMSFilterInputStream extends FilterInputStream { | |
12 | + | |
13 | + int size; | |
14 | + | |
15 | + public MMSFilterInputStream(InputStream in, int size) { | |
16 | + super(in); | |
17 | + this.size = size; | |
18 | + } | |
19 | + | |
20 | + @Override | |
21 | + public int available() throws IOException { | |
22 | + return size; | |
23 | + } | |
24 | + | |
25 | + @Override | |
26 | + public void close() throws IOException { | |
27 | + super.close(); | |
28 | + } | |
29 | + | |
30 | + @Override | |
31 | + public synchronized void mark(int i) { | |
32 | + super.mark(i); | |
33 | + } | |
34 | + | |
35 | + @Override | |
36 | + public boolean markSupported() { | |
37 | + return true; | |
38 | + } | |
39 | + | |
40 | + @Override | |
41 | + public int read() throws IOException { | |
42 | + if (size == 0) { | |
43 | + return -1; | |
44 | + } | |
45 | + int i = super.read(); | |
46 | + if (i >= 0) { | |
47 | + size--; | |
48 | + } | |
49 | + return i; | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public int read(byte[] bytes) throws IOException { | |
54 | + int i = read(bytes, 0, bytes.length); | |
55 | + return i; | |
56 | + } | |
57 | + | |
58 | + @Override | |
59 | + public int read(byte[] bytes, int i, int i1) throws IOException { | |
60 | + if (size == 0) { | |
61 | + return -1; | |
62 | + } | |
63 | + int readSize = 0; | |
64 | + if (i1 > size) { | |
65 | + i1 = size; | |
66 | + } | |
67 | + while(size > 0 && readSize != i1) { | |
68 | + int i2 = super.read(bytes, i+readSize, i1 - readSize); | |
69 | + if (i2 >= 0) { | |
70 | + size = size - i2; | |
71 | + readSize += i2; | |
72 | + } else { | |
73 | + break; | |
74 | + } | |
75 | + } | |
76 | + return readSize; | |
77 | + } | |
78 | + | |
79 | + @Override | |
80 | + public synchronized void reset() throws IOException { | |
81 | + super.reset(); | |
82 | + } | |
83 | + | |
84 | + @Override | |
85 | + public long skip(long n) throws IOException { | |
86 | +// long totalBytesSkipped = 0L; | |
87 | +// while (totalBytesSkipped < n && size > 0) { | |
88 | +// long bytesSkipped = in.skip(n - totalBytesSkipped); | |
89 | +// size = size - (int) bytesSkipped; | |
90 | +// if (bytesSkipped == 0L) { | |
91 | +// int b = read(); | |
92 | +// if (b < 0) { | |
93 | +// break; // we reached EOF | |
94 | +// } else { | |
95 | +// bytesSkipped = 1; // we read one byte | |
96 | +//// size = size - 1; | |
97 | +// } | |
98 | +// } | |
99 | +// totalBytesSkipped += bytesSkipped; | |
100 | +// } | |
101 | + for(long i = 0;i<n;i++) { | |
102 | + if (read() < 0) { | |
103 | + return i-1; | |
104 | + } | |
105 | + } | |
106 | + return n; | |
107 | + } | |
108 | +} | |
109 | + |
@@ -0,0 +1,3187 @@ | ||
1 | +/* | |
2 | + * Copyright (c) 2009-2010 jMonkeyEngine | |
3 | + * All rights reserved. | |
4 | + * | |
5 | + * Redistribution and use in source and binary forms, with or without | |
6 | + * modification, are permitted provided that the following conditions are | |
7 | + * met: | |
8 | + * | |
9 | + * * Redistributions of source code must retain the above copyright | |
10 | + * notice, this list of conditions and the following disclaimer. | |
11 | + * | |
12 | + * * Redistributions in binary form must reproduce the above copyright | |
13 | + * notice, this list of conditions and the following disclaimer in the | |
14 | + * documentation and/or other materials provided with the distribution. | |
15 | + * | |
16 | + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | |
17 | + * may be used to endorse or promote products derived from this software | |
18 | + * without specific prior written permission. | |
19 | + * | |
20 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 | + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 | + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
24 | + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
25 | + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
26 | + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
27 | + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
28 | + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
29 | + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | + */ | |
32 | +package com.jme3.renderer.gdx; | |
33 | + | |
34 | +import com.badlogic.gdx.Gdx; | |
35 | +import com.badlogic.gdx.graphics.GL10; | |
36 | +import com.badlogic.gdx.graphics.GL20; | |
37 | +import com.jme3.light.LightList; | |
38 | +import com.jme3.material.RenderState; | |
39 | +import com.jme3.math.*; | |
40 | +import com.jme3.renderer.*; | |
41 | +import com.jme3.scene.Mesh; | |
42 | +import com.jme3.scene.Mesh.Mode; | |
43 | +import com.jme3.scene.VertexBuffer; | |
44 | +import com.jme3.scene.VertexBuffer.Format; | |
45 | +import com.jme3.scene.VertexBuffer.Type; | |
46 | +import com.jme3.scene.VertexBuffer.Usage; | |
47 | +import com.jme3.shader.Attribute; | |
48 | +import com.jme3.shader.Shader; | |
49 | +import com.jme3.shader.Shader.ShaderSource; | |
50 | +import com.jme3.shader.Shader.ShaderType; | |
51 | +import com.jme3.shader.Uniform; | |
52 | +import com.jme3.texture.FrameBuffer; | |
53 | +import com.jme3.texture.FrameBuffer.RenderBuffer; | |
54 | +import com.jme3.texture.Image; | |
55 | +import com.jme3.texture.Texture; | |
56 | +import com.jme3.texture.Texture.WrapAxis; | |
57 | +import com.jme3.util.BufferUtils; | |
58 | +import com.jme3.util.IntMap; | |
59 | +import com.jme3.util.ListMap; | |
60 | +import com.jme3.util.NativeObjectManager; | |
61 | +import com.jme3.util.SafeArrayList; | |
62 | +import java.nio.*; | |
63 | +import java.util.EnumSet; | |
64 | +import java.util.logging.Level; | |
65 | +import java.util.logging.Logger; | |
66 | + | |
67 | +public final class GdxRenderer implements Renderer { | |
68 | + | |
69 | + private static final Logger logger = Logger.getLogger(GdxRenderer.class.getName()); | |
70 | + private static final boolean VALIDATE_SHADER = false; | |
71 | + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); | |
72 | + private final StringBuilder stringBuf = new StringBuilder(250); | |
73 | + private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); | |
74 | + private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); | |
75 | + private final RenderContext context = new RenderContext(); | |
76 | + private final NativeObjectManager objManager = new NativeObjectManager(); | |
77 | + private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class); | |
78 | + // current state | |
79 | + private Shader boundShader; | |
80 | + private int initialDrawBuf, initialReadBuf; | |
81 | + private int glslVer; | |
82 | + private int vertexTextureUnits; | |
83 | + private int fragTextureUnits; | |
84 | + private int vertexUniforms; | |
85 | + private int fragUniforms; | |
86 | + private int vertexAttribs; | |
87 | + private int maxFBOSamples; | |
88 | + private int maxFBOAttachs = 1; | |
89 | + private int maxMRTFBOAttachs; | |
90 | + private int maxRBSize; | |
91 | + private int maxTexSize; | |
92 | + private int maxCubeTexSize; | |
93 | + private int maxVertCount; | |
94 | + private int maxTriCount; | |
95 | + private boolean tdc; | |
96 | + private FrameBuffer lastFb = null; | |
97 | + private FrameBuffer mainFbOverride = null; | |
98 | + private final Statistics statistics = new Statistics(); | |
99 | + private int vpX, vpY, vpW, vpH; | |
100 | + private int clipX, clipY, clipW, clipH; | |
101 | + //private final GL10 gl; | |
102 | + private boolean powerOf2 = false; | |
103 | + private boolean verboseLogging = false; | |
104 | + private boolean useVBO = true; | |
105 | + public boolean adreno_finish_bug = false; | |
106 | + | |
107 | + public GdxRenderer() { | |
108 | + } | |
109 | + | |
110 | + public void setUseVA(boolean value) { | |
111 | + logger.log(Level.INFO, "use_VBO [{0}] -> [{1}]", new Object[]{useVBO, !value}); | |
112 | + useVBO = !value; | |
113 | + } | |
114 | + | |
115 | + public void setVerboseLogging(boolean value) { | |
116 | + logger.log(Level.INFO, "verboseLogging [{0}] -> [{1}]", new Object[]{verboseLogging, value}); | |
117 | + verboseLogging = value; | |
118 | + } | |
119 | + | |
120 | + protected void updateNameBuffer() { | |
121 | + int len = stringBuf.length(); | |
122 | + | |
123 | + nameBuf.position(0); | |
124 | + nameBuf.limit(len); | |
125 | + for (int i = 0; i < len; i++) { | |
126 | + nameBuf.put((byte) stringBuf.charAt(i)); | |
127 | + } | |
128 | + | |
129 | + nameBuf.rewind(); | |
130 | + } | |
131 | + | |
132 | + public Statistics getStatistics() { | |
133 | + return statistics; | |
134 | + } | |
135 | + | |
136 | + public EnumSet<Caps> getCaps() { | |
137 | + return caps; | |
138 | + } | |
139 | + | |
140 | + public void initialize() { | |
141 | + | |
142 | + logger.info("Vendor: " + Gdx.gl20.glGetString(GL20.GL_VENDOR)); | |
143 | + logger.info("Renderer: " + Gdx.gl20.glGetString(GL20.GL_RENDERER)); | |
144 | + logger.info("Version: " + Gdx.gl20.glGetString(GL20.GL_VERSION)); | |
145 | + | |
146 | + String shadingLanguageVersion = Gdx.gl20.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION); | |
147 | + logger.log(Level.INFO, "GLES20.Shading Language Version: {0}", shadingLanguageVersion); | |
148 | + | |
149 | + /* | |
150 | + ContextCapabilities ctxCaps = GLContext.getCapabilities(); | |
151 | + if (ctxCaps.OpenGL20){ | |
152 | + caps.add(Caps.OpenGL20); | |
153 | + } | |
154 | + if (ctxCaps.OpenGL21){ | |
155 | + caps.add(Caps.OpenGL21); | |
156 | + } | |
157 | + if (ctxCaps.OpenGL30){ | |
158 | + caps.add(Caps.OpenGL30); | |
159 | + } | |
160 | + */ | |
161 | + String versionStr = Gdx.gl20.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION); | |
162 | + if (versionStr == null || versionStr.equals("")) { | |
163 | +// glslVer = -1; | |
164 | +// throw new UnsupportedOperationException("GLSL and OpenGL2 is " | |
165 | +// + "required for the OpenGL ES " | |
166 | +// + "renderer!"); | |
167 | + versionStr = ""; | |
168 | + } | |
169 | + logger.info("GLES20.GL_SHADING_LANGUAGE_VERSION = " + versionStr); | |
170 | + | |
171 | + // Fix issue in TestRenderToMemory when GL_FRONT is the main | |
172 | + // buffer being used. | |
173 | + | |
174 | +// initialDrawBuf = GLES20.glGetIntegeri(GLES20.GL_DRAW_BUFFER); | |
175 | +// initialReadBuf = GLES20.glGetIntegeri(GLES20.GL_READ_BUFFER); | |
176 | + | |
177 | + int spaceIdx = versionStr.lastIndexOf(" "); | |
178 | + if (spaceIdx >= 1) { | |
179 | + versionStr = versionStr.substring(spaceIdx, versionStr.length()); | |
180 | + } | |
181 | + | |
182 | + float version = 1; | |
183 | + try { | |
184 | + version = Float.parseFloat(versionStr); | |
185 | + } catch (Exception ex) { | |
186 | + } | |
187 | + glslVer = (int) (version * 100); | |
188 | + | |
189 | + switch (glslVer) { | |
190 | + default: | |
191 | + if (glslVer < 400) { | |
192 | + break; | |
193 | + } | |
194 | + | |
195 | + // so that future OpenGL revisions wont break jme3 | |
196 | + | |
197 | + // fall through intentional | |
198 | + case 400: | |
199 | + case 330: | |
200 | + case 150: | |
201 | + caps.add(Caps.GLSL150); | |
202 | + case 140: | |
203 | + caps.add(Caps.GLSL140); | |
204 | + case 130: | |
205 | + caps.add(Caps.GLSL130); | |
206 | + case 120: | |
207 | + caps.add(Caps.GLSL120); | |
208 | + case 110: | |
209 | + caps.add(Caps.GLSL110); | |
210 | + case 100: | |
211 | + caps.add(Caps.GLSL100); | |
212 | + break; | |
213 | + } | |
214 | + | |
215 | + if (!caps.contains(Caps.GLSL100)) { | |
216 | + logger.info("Force-adding GLSL100 support, since OpenGL is supported."); | |
217 | + caps.add(Caps.GLSL100); | |
218 | + } | |
219 | + | |
220 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16); | |
221 | + vertexTextureUnits = intBuf16.get(0); | |
222 | + logger.log(Level.INFO, "VTF Units: {0}", vertexTextureUnits); | |
223 | + if (vertexTextureUnits > 0) { | |
224 | + caps.add(Caps.VertexTextureFetch); | |
225 | + } | |
226 | + | |
227 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16); | |
228 | + fragTextureUnits = intBuf16.get(0); | |
229 | + logger.log(Level.INFO, "Texture Units: {0}", fragTextureUnits); | |
230 | + /* | |
231 | + GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); | |
232 | + vertexUniforms = intBuf16.get(0); | |
233 | + logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); | |
234 | + | |
235 | + GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); | |
236 | + fragUniforms = intBuf16.get(0); | |
237 | + logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); | |
238 | + */ | |
239 | + | |
240 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_VERTEX_ATTRIBS, intBuf16); | |
241 | + vertexAttribs = intBuf16.get(0); | |
242 | + logger.log(Level.INFO, "Vertex Attributes: {0}", vertexAttribs); | |
243 | + | |
244 | + /* | |
245 | + GLES20.glGetIntegerv(GLES20.GL_MAX_VARYING_FLOATS, intBuf16); | |
246 | + int varyingFloats = intBuf16.get(0); | |
247 | + logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); | |
248 | + */ | |
249 | + | |
250 | + Gdx.gl20.glGetIntegerv(GL20.GL_SUBPIXEL_BITS, intBuf16); | |
251 | + int subpixelBits = intBuf16.get(0); | |
252 | + logger.log(Level.INFO, "Subpixel Bits: {0}", subpixelBits); | |
253 | + /* | |
254 | + GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_VERTICES, intBuf16); | |
255 | + maxVertCount = intBuf16.get(0); | |
256 | + logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); | |
257 | + | |
258 | + GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_INDICES, intBuf16); | |
259 | + maxTriCount = intBuf16.get(0); | |
260 | + logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); | |
261 | + */ | |
262 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_TEXTURE_SIZE, intBuf16); | |
263 | + maxTexSize = intBuf16.get(0); | |
264 | + logger.log(Level.INFO, "Maximum Texture Resolution: {0}" + maxTexSize); | |
265 | + | |
266 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_CUBE_MAP_TEXTURE_SIZE, intBuf16); | |
267 | + maxCubeTexSize = intBuf16.get(0); | |
268 | + logger.log(Level.INFO, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); | |
269 | + | |
270 | + | |
271 | + /* | |
272 | + if (ctxCaps.GL_ARB_color_buffer_float){ | |
273 | + // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. | |
274 | + if (ctxCaps.GL_ARB_half_float_pixel){ | |
275 | + caps.add(Caps.FloatColorBuffer); | |
276 | + } | |
277 | + } | |
278 | + | |
279 | + if (ctxCaps.GL_ARB_depth_buffer_float){ | |
280 | + caps.add(Caps.FloatDepthBuffer); | |
281 | + } | |
282 | + | |
283 | + if (ctxCaps.GL_ARB_draw_instanced) | |
284 | + caps.add(Caps.MeshInstancing); | |
285 | + | |
286 | + if (ctxCaps.GL_ARB_fragment_program) | |
287 | + caps.add(Caps.ARBprogram); | |
288 | + | |
289 | + if (ctxCaps.GL_ARB_texture_buffer_object) | |
290 | + caps.add(Caps.TextureBuffer); | |
291 | + | |
292 | + if (ctxCaps.GL_ARB_texture_float){ | |
293 | + if (ctxCaps.GL_ARB_half_float_pixel){ | |
294 | + caps.add(Caps.FloatTexture); | |
295 | + } | |
296 | + } | |
297 | + | |
298 | + if (ctxCaps.GL_ARB_vertex_array_object) | |
299 | + caps.add(Caps.VertexBufferArray); | |
300 | + | |
301 | + boolean latc = ctxCaps.GL_EXT_texture_compression_latc; | |
302 | + boolean atdc = ctxCaps.GL_ATI_texture_compression_3dc; | |
303 | + if (latc || atdc){ | |
304 | + caps.add(Caps.TextureCompressionLATC); | |
305 | + if (atdc && !latc){ | |
306 | + tdc = true; | |
307 | + } | |
308 | + } | |
309 | + | |
310 | + if (ctxCaps.GL_EXT_packed_float){ | |
311 | + caps.add(Caps.PackedFloatColorBuffer); | |
312 | + if (ctxCaps.GL_ARB_half_float_pixel){ | |
313 | + // because textures are usually uploaded as RGB16F | |
314 | + // need half-float pixel | |
315 | + caps.add(Caps.PackedFloatTexture); | |
316 | + } | |
317 | + } | |
318 | + | |
319 | + if (ctxCaps.GL_EXT_texture_array) | |
320 | + caps.add(Caps.TextureArray); | |
321 | + | |
322 | + if (ctxCaps.GL_EXT_texture_shared_exponent) | |
323 | + caps.add(Caps.SharedExponentTexture); | |
324 | + | |
325 | + if (ctxCaps.GL_EXT_framebuffer_object){ | |
326 | + caps.add(Caps.FrameBuffer); | |
327 | + | |
328 | + glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); | |
329 | + maxRBSize = intBuf16.get(0); | |
330 | + logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); | |
331 | + | |
332 | + glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT, intBuf16); | |
333 | + maxFBOAttachs = intBuf16.get(0); | |
334 | + logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); | |
335 | + | |
336 | + if (ctxCaps.GL_EXT_framebuffer_multisample){ | |
337 | + caps.add(Caps.FrameBufferMultisample); | |
338 | + | |
339 | + glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); | |
340 | + maxFBOSamples = intBuf16.get(0); | |
341 | + logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); | |
342 | + } | |
343 | + | |
344 | + if (ctxCaps.GL_ARB_draw_buffers){ | |
345 | + caps.add(Caps.FrameBufferMRT); | |
346 | + glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); | |
347 | + maxMRTFBOAttachs = intBuf16.get(0); | |
348 | + logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); | |
349 | + } | |
350 | + } | |
351 | + | |
352 | + if (ctxCaps.GL_ARB_multisample){ | |
353 | + glGetInteger(ARBMultisample.GL_SAMPLE_BUFFERS_ARB, intBuf16); | |
354 | + boolean available = intBuf16.get(0) != 0; | |
355 | + glGetInteger(ARBMultisample.GL_SAMPLES_ARB, intBuf16); | |
356 | + int samples = intBuf16.get(0); | |
357 | + logger.log(Level.FINER, "Samples: {0}", samples); | |
358 | + boolean enabled = glIsEnabled(ARBMultisample.GL_MULTISAMPLE_ARB); | |
359 | + if (samples > 0 && available && !enabled){ | |
360 | + glEnable(ARBMultisample.GL_MULTISAMPLE_ARB); | |
361 | + } | |
362 | + } | |
363 | + */ | |
364 | + Gdx.gl20.glGetIntegerv(GL20.GL_MAX_RENDERBUFFER_SIZE, intBuf16); | |
365 | + maxRBSize = intBuf16.get(0); | |
366 | + logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); | |
367 | + | |
368 | + String extensions = Gdx.gl20.glGetString(GL20.GL_EXTENSIONS); | |
369 | + logger.log(Level.INFO, "GL_EXTENSIONS: {0}", extensions); | |
370 | + | |
371 | +// GLES20.glGetIntegerv(GLES20.GL_COMPRESSED_TEXTURE_FORMATS, intBuf16); | |
372 | +// for (int i = 0; i < intBuf16.limit(); i++) { | |
373 | +// logger.log(Level.INFO, "Compressed Texture Formats: {0}", intBuf16.get(i)); | |
374 | +// } | |
375 | + | |
376 | + if (extensions.contains("GL_OES_texture_npot")) { | |
377 | + powerOf2 = true; | |
378 | + } | |
379 | + | |
380 | + | |
381 | + | |
382 | + applyRenderState(RenderState.DEFAULT); | |
383 | +// GLES20.glClearDepthf(1.0f); | |
384 | + | |
385 | + if (verboseLogging) { | |
386 | + logger.info("GLES20.glDisable(GL10.GL_DITHER)"); | |
387 | + } | |
388 | + | |
389 | + Gdx.gl20.glDisable(GL20.GL_DITHER); | |
390 | + | |
391 | + checkGLError(); | |
392 | + | |
393 | + if (verboseLogging) { | |
394 | + logger.info("GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST)"); | |
395 | + } | |
396 | + | |
397 | + Gdx.gl20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); | |
398 | + | |
399 | +// checkGLError(); | |
400 | + | |
401 | + useVBO = true; | |
402 | + | |
403 | + // NOTE: SDK_INT is only available since 1.6, | |
404 | + // but for jME3 it doesn't matter since android versions 1.5 and below | |
405 | + // are not supported. | |
406 | + //if (Build.VERSION.SDK_INT >= 9) { | |
407 | + // useVBO = true; | |
408 | + //} | |
409 | + // chekc Adreno200,205,220 bug | |
410 | + if (Gdx.gl20.glGetString(GL20.GL_RENDERER).indexOf("Adreno") >= 0) { | |
411 | + adreno_finish_bug = true; | |
412 | + } | |
413 | + logger.log(Level.INFO, "Caps: {0}", caps); | |
414 | + } | |
415 | + | |
416 | + /** | |
417 | + * <code>resetGLObjects</code> should be called when die GLView gets recreated to reset all GPU objects | |
418 | + */ | |
419 | + public void resetGLObjects() { | |
420 | + objManager.resetObjects(); | |
421 | + statistics.clearMemory(); | |
422 | + boundShader = null; | |
423 | + lastFb = null; | |
424 | + context.reset(); | |
425 | + } | |
426 | + | |
427 | + public void cleanup() { | |
428 | + objManager.deleteAllObjects(this); | |
429 | + statistics.clearMemory(); | |
430 | + } | |
431 | + | |
432 | + private void checkCap(Caps cap) { | |
433 | + if (!caps.contains(cap)) { | |
434 | + throw new UnsupportedOperationException("Required capability missing: " + cap.name()); | |
435 | + } | |
436 | + } | |
437 | + | |
438 | + /*********************************************************************\ | |
439 | + |* Render State *| | |
440 | + \*********************************************************************/ | |
441 | + public void setDepthRange(float start, float end) { | |
442 | + | |
443 | + if (verboseLogging) { | |
444 | + logger.log(Level.INFO, "GLES20.glDepthRangef({0}, {1})", new Object[]{start, end}); | |
445 | + } | |
446 | + Gdx.gl20.glDepthRangef(start, end); | |
447 | + checkGLError(); | |
448 | + } | |
449 | + | |
450 | + public void clearBuffers(boolean color, boolean depth, boolean stencil) { | |
451 | + int bits = 0; | |
452 | + if (color) { | |
453 | + bits = GL20.GL_COLOR_BUFFER_BIT; | |
454 | + } | |
455 | + if (depth) { | |
456 | + bits |= GL20.GL_DEPTH_BUFFER_BIT; | |
457 | + if (context.depthWriteEnabled == false) { | |
458 | + Gdx.gl20.glDepthMask(true); | |
459 | + context.depthWriteEnabled = true; | |
460 | + } | |
461 | + } | |
462 | + if (stencil) { | |
463 | + bits |= GL20.GL_STENCIL_BUFFER_BIT; | |
464 | + } | |
465 | + if (bits != 0) { | |
466 | + if (verboseLogging) { | |
467 | + logger.log(Level.INFO, "GLES20.glClear(color={0}, depth={1}, stencil={2})", new Object[]{color, depth, stencil}); | |
468 | + } | |
469 | + Gdx.gl20.glClear(bits); | |
470 | + checkGLError(); | |
471 | + } | |
472 | + } | |
473 | + | |
474 | + public void setBackgroundColor(ColorRGBA color) { | |
475 | + if (verboseLogging) { | |
476 | + logger.log(Level.INFO, "GLES20.glClearColor({0}, {1}, {2}, {3})", new Object[]{color.r, color.g, color.b, color.a}); | |
477 | + } | |
478 | + Gdx.gl20.glClearColor(color.r, color.g, color.b, color.a); | |
479 | + checkGLError(); | |
480 | + } | |
481 | + | |
482 | + public void applyRenderState(RenderState state) { | |
483 | + /* | |
484 | + if (state.isWireframe() && !context.wireframe){ | |
485 | + GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_LINE); | |
486 | + context.wireframe = true; | |
487 | + }else if (!state.isWireframe() && context.wireframe){ | |
488 | + GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_FILL); | |
489 | + context.wireframe = false; | |
490 | + } | |
491 | + */ | |
492 | + if (state.isDepthTest() && !context.depthTestEnabled) { | |
493 | + if (verboseLogging) { | |
494 | + logger.info("GLES20.glEnable(GLES20.GL_DEPTH_TEST)"); | |
495 | + } | |
496 | + Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST); | |
497 | + checkGLError(); | |
498 | + if (verboseLogging) { | |
499 | + logger.info("GLES20.glDepthFunc(GL20.LEQUAL)"); | |
500 | + } | |
501 | + Gdx.gl20.glDepthFunc(GL20.GL_LEQUAL); | |
502 | + checkGLError(); | |
503 | + context.depthTestEnabled = true; | |
504 | + } else if (!state.isDepthTest() && context.depthTestEnabled) { | |
505 | + if (verboseLogging) { | |
506 | + logger.info("GLES20.glDisable(GLES20.GL_DEPTH_TEST)"); | |
507 | + } | |
508 | + Gdx.gl20.glDisable(GL20.GL_DEPTH_TEST); | |
509 | + checkGLError(); | |
510 | + context.depthTestEnabled = false; | |
511 | + } | |
512 | + if (state.isAlphaTest() && !context.alphaTestEnabled) { | |
513 | +// GLES20.glEnable(GLES20.GL_ALPHA_TEST); | |
514 | +// GLES20.glAlphaFunc(GLES20.GL_GREATER, state.getAlphaFallOff()); | |
515 | + context.alphaTestEnabled = true; | |
516 | + } else if (!state.isAlphaTest() && context.alphaTestEnabled) { | |
517 | +// GLES20.glDisable(GLES20.GL_ALPHA_TEST); | |
518 | + context.alphaTestEnabled = false; | |
519 | + } | |
520 | + if (state.isDepthWrite() && !context.depthWriteEnabled) { | |
521 | + if (verboseLogging) { | |
522 | + logger.info("GLES20.glDepthMask(true)"); | |
523 | + } | |
524 | + Gdx.gl20.glDepthMask(true); | |
525 | + checkGLError(); | |
526 | + context.depthWriteEnabled = true; | |
527 | + } else if (!state.isDepthWrite() && context.depthWriteEnabled) { | |
528 | + if (verboseLogging) { | |
529 | + logger.info("GLES20.glDepthMask(false)"); | |
530 | + } | |
531 | + Gdx.gl20.glDepthMask(false); | |
532 | + checkGLError(); | |
533 | + context.depthWriteEnabled = false; | |
534 | + } | |
535 | + if (state.isColorWrite() && !context.colorWriteEnabled) { | |
536 | + if (verboseLogging) { | |
537 | + logger.info("GLES20.glColorMask(true, true, true, true)"); | |
538 | + } | |
539 | + Gdx.gl20.glColorMask(true, true, true, true); | |
540 | + checkGLError(); | |
541 | + context.colorWriteEnabled = true; | |
542 | + } else if (!state.isColorWrite() && context.colorWriteEnabled) { | |
543 | + if (verboseLogging) { | |
544 | + logger.info("GLES20.glColorMask(false, false, false, false)"); | |
545 | + } | |
546 | + Gdx.gl20.glColorMask(false, false, false, false); | |
547 | + checkGLError(); | |
548 | + context.colorWriteEnabled = false; | |
549 | + } | |
550 | + if (state.isPointSprite() && !context.pointSprite) { | |
551 | +// GLES20.glEnable(GLES20.GL_POINT_SPRITE); | |
552 | +// GLES20.glTexEnvi(GLES20.GL_POINT_SPRITE, GLES20.GL_COORD_REPLACE, GLES20.GL_TRUE); | |
553 | +// GLES20.glEnable(GLES20.GL_VERTEX_PROGRAM_POINT_SIZE); | |
554 | +// GLES20.glPointParameterf(GLES20.GL_POINT_SIZE_MIN, 1.0f); | |
555 | + } else if (!state.isPointSprite() && context.pointSprite) { | |
556 | +// GLES20.glDisable(GLES20.GL_POINT_SPRITE); | |
557 | + } | |
558 | + | |
559 | + if (state.isPolyOffset()) { | |
560 | + if (!context.polyOffsetEnabled) { | |
561 | + if (verboseLogging) { | |
562 | + logger.info("GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL)"); | |
563 | + } | |
564 | + Gdx.gl20.glEnable(GL20.GL_POLYGON_OFFSET_FILL); | |
565 | + checkGLError(); | |
566 | + if (verboseLogging) { | |
567 | + logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); | |
568 | + } | |
569 | + Gdx.gl20.glPolygonOffset(state.getPolyOffsetFactor(), | |
570 | + state.getPolyOffsetUnits()); | |
571 | + checkGLError(); | |
572 | + context.polyOffsetEnabled = true; | |
573 | + context.polyOffsetFactor = state.getPolyOffsetFactor(); | |
574 | + context.polyOffsetUnits = state.getPolyOffsetUnits(); | |
575 | + } else { | |
576 | + if (state.getPolyOffsetFactor() != context.polyOffsetFactor | |
577 | + || state.getPolyOffsetUnits() != context.polyOffsetUnits) { | |
578 | + if (verboseLogging) { | |
579 | + logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); | |
580 | + } | |
581 | + Gdx.gl20.glPolygonOffset(state.getPolyOffsetFactor(), | |
582 | + state.getPolyOffsetUnits()); | |
583 | + checkGLError(); | |
584 | + context.polyOffsetFactor = state.getPolyOffsetFactor(); | |
585 | + context.polyOffsetUnits = state.getPolyOffsetUnits(); | |
586 | + } | |
587 | + } | |
588 | + } else { | |
589 | + if (context.polyOffsetEnabled) { | |
590 | + if (verboseLogging) { | |
591 | + logger.info("GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL)"); | |
592 | + } | |
593 | + Gdx.gl20.glDisable(GL20.GL_POLYGON_OFFSET_FILL); | |
594 | + checkGLError(); | |
595 | + context.polyOffsetEnabled = false; | |
596 | + context.polyOffsetFactor = 0; | |
597 | + context.polyOffsetUnits = 0; | |
598 | + } | |
599 | + } | |
600 | + if (state.getFaceCullMode() != context.cullMode) { | |
601 | + if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { | |
602 | + if (verboseLogging) { | |
603 | + logger.info("GLES20.glDisable(GLES20.GL_CULL_FACE)"); | |
604 | + } | |
605 | + Gdx.gl20.glDisable(GL20.GL_CULL_FACE); | |
606 | + } else { | |
607 | + if (verboseLogging) { | |
608 | + logger.info("GLES20.glEnable(GLES20.GL_CULL_FACE)"); | |
609 | + } | |
610 | + Gdx.gl20.glEnable(GL20.GL_CULL_FACE); | |
611 | + } | |
612 | + | |
613 | + checkGLError(); | |
614 | + | |
615 | + switch (state.getFaceCullMode()) { | |
616 | + case Off: | |
617 | + break; | |
618 | + case Back: | |
619 | + if (verboseLogging) { | |
620 | + logger.info("GLES20.glCullFace(GLES20.GL_BACK)"); | |
621 | + } | |
622 | + Gdx.gl20.glCullFace(GL20.GL_BACK); | |
623 | + break; | |
624 | + case Front: | |
625 | + if (verboseLogging) { | |
626 | + logger.info("GLES20.glCullFace(GLES20.GL_FRONT)"); | |
627 | + } | |
628 | + Gdx.gl20.glCullFace(GL20.GL_FRONT); | |
629 | + break; | |
630 | + case FrontAndBack: | |
631 | + if (verboseLogging) { | |
632 | + logger.info("GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK)"); | |
633 | + } | |
634 | + Gdx.gl20.glCullFace(GL20.GL_FRONT_AND_BACK); | |
635 | + break; | |
636 | + default: | |
637 | + throw new UnsupportedOperationException("Unrecognized face cull mode: " | |
638 | + + state.getFaceCullMode()); | |
639 | + } | |
640 | + | |
641 | + checkGLError(); | |
642 | + | |
643 | + context.cullMode = state.getFaceCullMode(); | |
644 | + } | |
645 | + | |
646 | + if (state.getBlendMode() != context.blendMode) { | |
647 | + if (state.getBlendMode() == RenderState.BlendMode.Off) { | |
648 | + if (verboseLogging) { | |
649 | + logger.info("GLES20.glDisable(GLES20.GL_BLEND)"); | |
650 | + } | |
651 | + Gdx.gl20.glDisable(GL20.GL_BLEND); | |
652 | + } else { | |
653 | + if (verboseLogging) { | |
654 | + logger.info("GLES20.glEnable(GLES20.GL_BLEND)"); | |
655 | + } | |
656 | + Gdx.gl20.glEnable(GL20.GL_BLEND); | |
657 | + switch (state.getBlendMode()) { | |
658 | + case Off: | |
659 | + break; | |
660 | + case Additive: | |
661 | + if (verboseLogging) { | |
662 | + logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE)"); | |
663 | + } | |
664 | + Gdx.gl20.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE); | |
665 | + break; | |
666 | + case AlphaAdditive: | |
667 | + if (verboseLogging) { | |
668 | + logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE)"); | |
669 | + } | |
670 | + Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE); | |
671 | + break; | |
672 | + case Color: | |
673 | + if (verboseLogging) { | |
674 | + logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR)"); | |
675 | + } | |
676 | + Gdx.gl20.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR); | |
677 | + break; | |
678 | + case Alpha: | |
679 | + if (verboseLogging) { | |
680 | + logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); | |
681 | + } | |
682 | + Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); | |
683 | + break; | |
684 | + case PremultAlpha: | |
685 | + if (verboseLogging) { | |
686 | + logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); | |
687 | + } | |
688 | + Gdx.gl20.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA); | |
689 | + break; | |
690 | + case Modulate: | |
691 | + if (verboseLogging) { | |
692 | + logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO)"); | |
693 | + } | |
694 | + Gdx.gl20.glBlendFunc(GL20.GL_DST_COLOR, GL20.GL_ZERO); | |
695 | + break; | |
696 | + case ModulateX2: | |
697 | + if (verboseLogging) { | |
698 | + logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR)"); | |
699 | + } | |
700 | + Gdx.gl20.glBlendFunc(GL20.GL_DST_COLOR, GL20.GL_SRC_COLOR); | |
701 | + break; | |
702 | + default: | |
703 | + throw new UnsupportedOperationException("Unrecognized blend mode: " | |
704 | + + state.getBlendMode()); | |
705 | + } | |
706 | + } | |
707 | + | |
708 | + checkGLError(); | |
709 | + | |
710 | + context.blendMode = state.getBlendMode(); | |
711 | + } | |
712 | + } | |
713 | + | |
714 | + /*********************************************************************\ | |
715 | + |* Camera and World transforms *| | |
716 | + \*********************************************************************/ | |
717 | + public void setViewPort(int x, int y, int w, int h) { | |
718 | + if (x != vpX || vpY != y || vpW != w || vpH != h) { | |
719 | + if (verboseLogging) { | |
720 | + logger.log(Level.INFO, "GLES20.glViewport({0}, {1}, {2}, {3})", new Object[]{x, y, w, h}); | |
721 | + } | |
722 | + Gdx.gl20.glViewport(x, y, w, h); | |
723 | + checkGLError(); | |
724 | + vpX = x; | |
725 | + vpY = y; | |
726 | + vpW = w; | |
727 | + vpH = h; | |
728 | + } | |
729 | + } | |
730 | + | |
731 | + public void setClipRect(int x, int y, int width, int height) { | |
732 | + if (!context.clipRectEnabled) { | |
733 | + if (verboseLogging) { | |
734 | + logger.info("GLES20.glEnable(GLES20.GL_SCISSOR_TEST)"); | |
735 | + } | |
736 | + Gdx.gl20.glEnable(GL20.GL_SCISSOR_TEST); | |
737 | + checkGLError(); | |
738 | + context.clipRectEnabled = true; | |
739 | + } | |
740 | + if (clipX != x || clipY != y || clipW != width || clipH != height) { | |
741 | + if (verboseLogging) { | |
742 | + logger.log(Level.INFO, "GLES20.glScissor({0}, {1}, {2}, {3})", new Object[]{x, y, width, height}); | |
743 | + } | |
744 | + Gdx.gl20.glScissor(x, y, width, height); | |
745 | + clipX = x; | |
746 | + clipY = y; | |
747 | + clipW = width; | |
748 | + clipH = height; | |
749 | + checkGLError(); | |
750 | + } | |
751 | + } | |
752 | + | |
753 | + public void clearClipRect() { | |
754 | + if (context.clipRectEnabled) { | |
755 | + if (verboseLogging) { | |
756 | + logger.info("GLES20.glDisable(GLES20.GL_SCISSOR_TEST)"); | |
757 | + } | |
758 | + Gdx.gl20.glDisable(GL20.GL_SCISSOR_TEST); | |
759 | + checkGLError(); | |
760 | + context.clipRectEnabled = false; | |
761 | + | |
762 | + clipX = 0; | |
763 | + clipY = 0; | |
764 | + clipW = 0; | |
765 | + clipH = 0; | |
766 | + } | |
767 | + } | |
768 | + | |
769 | + public void onFrame() { | |
770 | + objManager.deleteUnused(this); | |
771 | +// statistics.clearFrame(); | |
772 | + } | |
773 | + | |
774 | + public void setWorldMatrix(Matrix4f worldMatrix) { | |
775 | + } | |
776 | + | |
777 | + public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { | |
778 | + } | |
779 | + | |
780 | + /*********************************************************************\ | |
781 | + |* Shaders *| | |
782 | + \*********************************************************************/ | |
783 | + protected void updateUniformLocation(Shader shader, Uniform uniform) { | |
784 | + stringBuf.setLength(0); | |
785 | + stringBuf.append(uniform.getName()).append('\0'); | |
786 | + updateNameBuffer(); | |
787 | + if (verboseLogging) { | |
788 | + logger.log(Level.INFO, "GLES20.glGetUniformLocation({0}, {1})", new Object[]{shader.getId(), uniform.getName()}); | |
789 | + } | |
790 | + int loc = Gdx.gl20.glGetUniformLocation(shader.getId(), uniform.getName()); | |
791 | + checkGLError(); | |
792 | + if (loc < 0) { | |
793 | + uniform.setLocation(-1); | |
794 | + // uniform is not declared in shader | |
795 | + if (verboseLogging) { | |
796 | + logger.log(Level.WARNING, "Uniform [{0}] is not declared in shader.", uniform.getName()); | |
797 | + } | |
798 | + } else { | |
799 | + uniform.setLocation(loc); | |
800 | + } | |
801 | + } | |
802 | + | |
803 | + protected void updateUniform(Shader shader, Uniform uniform) { | |
804 | + int shaderId = shader.getId(); | |
805 | + | |
806 | + assert uniform.getName() != null; | |
807 | + assert shader.getId() > 0; | |
808 | + | |
809 | + if (context.boundShaderProgram != shaderId) { | |
810 | + if (verboseLogging) { | |
811 | + logger.log(Level.INFO, "GLES20.glUseProgram({0})", shaderId); | |
812 | + } | |
813 | + Gdx.gl20.glUseProgram(shaderId); | |
814 | + checkGLError(); | |
815 | + statistics.onShaderUse(shader, true); | |
816 | + boundShader = shader; | |
817 | + context.boundShaderProgram = shaderId; | |
818 | + } else { | |
819 | + statistics.onShaderUse(shader, false); | |
820 | + } | |
821 | + | |
822 | + int loc = uniform.getLocation(); | |
823 | + if (loc == -1) { | |
824 | + if (verboseLogging) { | |
825 | + logger.log(Level.WARNING, "no location for uniform [{0}]", uniform.getName()); | |
826 | + } | |
827 | + return; | |
828 | + } | |
829 | + | |
830 | + if (loc == -2) { | |
831 | + // get uniform location | |
832 | + updateUniformLocation(shader, uniform); | |
833 | + if (uniform.getLocation() == -1) { | |
834 | + // not declared, ignore | |
835 | + | |
836 | + if (verboseLogging) { | |
837 | + logger.log(Level.WARNING, "not declared uniform: [{0}]", uniform.getName()); | |
838 | + } | |
839 | + | |
840 | + uniform.clearUpdateNeeded(); | |
841 | + return; | |
842 | + } | |
843 | + loc = uniform.getLocation(); | |
844 | + } | |
845 | + | |
846 | + if (uniform.getVarType() == null) { | |
847 | + logger.warning("value is not set yet."); | |
848 | + return; // value not set yet.. | |
849 | + } | |
850 | + | |
851 | + statistics.onUniformSet(); | |
852 | + | |
853 | + uniform.clearUpdateNeeded(); | |
854 | + FloatBuffer fb; | |
855 | + switch (uniform.getVarType()) { | |
856 | + case Float: | |
857 | + if (verboseLogging) { | |
858 | + logger.info("GLES20.glUniform1f set Float. " + uniform.getName()); | |
859 | + } | |
860 | + Float f = (Float) uniform.getValue(); | |
861 | + Gdx.gl20.glUniform1f(loc, f.floatValue()); | |
862 | + break; | |
863 | + case Vector2: | |
864 | + if (verboseLogging) { | |
865 | + logger.info("GLES20.glUniform2f set Vector2. " + uniform.getName()); | |
866 | + } | |
867 | + Vector2f v2 = (Vector2f) uniform.getValue(); | |
868 | + Gdx.gl20.glUniform2f(loc, v2.getX(), v2.getY()); | |
869 | + break; | |
870 | + case Vector3: | |
871 | + if (verboseLogging) { | |
872 | + logger.info("GLES20.glUniform3f set Vector3. " + uniform.getName()); | |
873 | + } | |
874 | + Vector3f v3 = (Vector3f) uniform.getValue(); | |
875 | + Gdx.gl20.glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); | |
876 | + break; | |
877 | + case Vector4: | |
878 | + if (verboseLogging) { | |
879 | + logger.info("GLES20.glUniform4f set Vector4." + uniform.getName()); | |
880 | + } | |
881 | + Object val = uniform.getValue(); | |
882 | + if (val instanceof ColorRGBA) { | |
883 | + ColorRGBA c = (ColorRGBA) val; | |
884 | + Gdx.gl20.glUniform4f(loc, c.r, c.g, c.b, c.a); | |
885 | + } else if (val instanceof Vector4f) { | |
886 | + Vector4f c = (Vector4f) val; | |
887 | + Gdx.gl20.glUniform4f(loc, c.x, c.y, c.z, c.w); | |
888 | + } else { | |
889 | + Quaternion c = (Quaternion) uniform.getValue(); | |
890 | + Gdx.gl20.glUniform4f(loc, c.getX(), c.getY(), c.getZ(), c.getW()); | |
891 | + } | |
892 | + break; | |
893 | + case Boolean: | |
894 | + if (verboseLogging) { | |
895 | + logger.info("GLES20.glUniform1i set Boolean." + uniform.getName()); | |
896 | + } | |
897 | + Boolean b = (Boolean) uniform.getValue(); | |
898 | + Gdx.gl20.glUniform1i(loc, b.booleanValue() ? GL20.GL_TRUE : GL20.GL_FALSE); | |
899 | + break; | |
900 | + case Matrix3: | |
901 | + if (verboseLogging) { | |
902 | + logger.info("GLES20.glUniformMatrix3fv set Matrix3." + uniform.getName()); | |
903 | + } | |
904 | + fb = (FloatBuffer) uniform.getValue(); | |
905 | + assert fb.remaining() == 9; | |
906 | + Gdx.gl20.glUniformMatrix3fv(loc, 1, false, fb); | |
907 | + break; | |
908 | + case Matrix4: | |
909 | + if (verboseLogging) { | |
910 | + logger.info("GLES20.glUniformMatrix4fv set Matrix4." + uniform.getName()); | |
911 | + } | |
912 | + fb = (FloatBuffer) uniform.getValue(); | |
913 | + assert fb.remaining() == 16; | |
914 | + Gdx.gl20.glUniformMatrix4fv(loc, 1, false, fb); | |
915 | + break; | |
916 | + case FloatArray: | |
917 | + if (verboseLogging) { | |
918 | + logger.info("GLES20.glUniform1fv set FloatArray." + uniform.getName()); | |
919 | + } | |
920 | + fb = (FloatBuffer) uniform.getValue(); | |
921 | + Gdx.gl20.glUniform1fv(loc, fb.capacity(), fb); | |
922 | + break; | |
923 | + case Vector2Array: | |
924 | + if (verboseLogging) { | |
925 | + logger.info("GLES20.glUniform2fv set Vector2Array." + uniform.getName()); | |
926 | + } | |
927 | + fb = (FloatBuffer) uniform.getValue(); | |
928 | + Gdx.gl20.glUniform2fv(loc, fb.capacity() / 2, fb); | |
929 | + break; | |
930 | + case Vector3Array: | |
931 | + if (verboseLogging) { | |
932 | + logger.info("GLES20.glUniform3fv set Vector3Array." + uniform.getName()); | |
933 | + } | |
934 | + fb = (FloatBuffer) uniform.getValue(); | |
935 | + Gdx.gl20.glUniform3fv(loc, fb.capacity() / 3, fb); | |
936 | + break; | |
937 | + case Vector4Array: | |
938 | + if (verboseLogging) { | |
939 | + logger.info("GLES20.glUniform4fv set Vector4Array." + uniform.getName()); | |
940 | + } | |
941 | + fb = (FloatBuffer) uniform.getValue(); | |
942 | + Gdx.gl20.glUniform4fv(loc, fb.capacity() / 4, fb); | |
943 | + break; | |
944 | + case Matrix4Array: | |
945 | + if (verboseLogging) { | |
946 | + logger.info("GLES20.glUniform4fv set Matrix4Array." + uniform.getName()); | |
947 | + } | |
948 | + fb = (FloatBuffer) uniform.getValue(); | |
949 | + Gdx.gl20.glUniformMatrix4fv(loc, fb.capacity() / 16, false, fb); | |
950 | + break; | |
951 | + case Int: | |
952 | + if (verboseLogging) { | |
953 | + logger.info("GLES20.glUniform1i set Int." + uniform.getName()); | |
954 | + } | |
955 | + Integer i = (Integer) uniform.getValue(); | |
956 | + Gdx.gl20.glUniform1i(loc, i.intValue()); | |
957 | + break; | |
958 | + default: | |
959 | + throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); | |
960 | + } | |
961 | + checkGLError(); | |
962 | + } | |
963 | + | |
964 | + protected void updateShaderUniforms(Shader shader) { | |
965 | + ListMap<String, Uniform> uniforms = shader.getUniformMap(); | |
966 | +// for (Uniform uniform : shader.getUniforms()){ | |
967 | + for (int i = 0; i < uniforms.size(); i++) { | |
968 | + Uniform uniform = uniforms.getValue(i); | |
969 | + if (uniform.isUpdateNeeded()) { | |
970 | + updateUniform(shader, uniform); | |
971 | + } | |
972 | + } | |
973 | + } | |
974 | + | |
975 | + protected void resetUniformLocations(Shader shader) { | |
976 | + ListMap<String, Uniform> uniforms = shader.getUniformMap(); | |
977 | +// for (Uniform uniform : shader.getUniforms()){ | |
978 | + for (int i = 0; i < uniforms.size(); i++) { | |
979 | + Uniform uniform = uniforms.getValue(i); | |
980 | + uniform.reset(); // e.g check location again | |
981 | + } | |
982 | + } | |
983 | + | |
984 | + /* | |
985 | + * (Non-javadoc) | |
986 | + * Only used for fixed-function. Ignored. | |
987 | + */ | |
988 | + public void setLighting(LightList list) { | |
989 | + } | |
990 | + | |
991 | + public int convertShaderType(ShaderType type) { | |
992 | + switch (type) { | |
993 | + case Fragment: | |
994 | + return GL20.GL_FRAGMENT_SHADER; | |
995 | + case Vertex: | |
996 | + return GL20.GL_VERTEX_SHADER; | |
997 | +// case Geometry: | |
998 | +// return ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB; | |
999 | + default: | |
1000 | + throw new RuntimeException("Unrecognized shader type."); | |
1001 | + } | |
1002 | + } | |
1003 | + | |
1004 | + public void updateShaderSourceData(ShaderSource source, String language) { | |
1005 | + int id = source.getId(); | |
1006 | + if (id == -1) { | |
1007 | + // create id | |
1008 | + if (verboseLogging) { | |
1009 | + logger.info("GLES20.glCreateShader(" + source.getType() + ")"); | |
1010 | + } | |
1011 | + id = Gdx.gl20.glCreateShader(convertShaderType(source.getType())); | |
1012 | + checkGLError(); | |
1013 | + if (id <= 0) { | |
1014 | + throw new RendererException("Invalid ID received when trying to create shader."); | |
1015 | + } | |
1016 | + | |
1017 | + source.setId(id); | |
1018 | + } | |
1019 | + | |
1020 | + // upload shader source | |
1021 | + // merge the defines and source code | |
1022 | + byte[] versionData = new byte[]{};//"#version 140\n".getBytes(); | |
1023 | +// versionData = "#define INSTANCING 1\n".getBytes(); | |
1024 | + byte[] definesCodeData = source.getDefines().getBytes(); | |
1025 | + byte[] sourceCodeData = source.getSource().getBytes(); | |
1026 | + ByteBuffer codeBuf = BufferUtils.createByteBuffer(versionData.length | |
1027 | + + definesCodeData.length | |
1028 | + + sourceCodeData.length); | |
1029 | + codeBuf.put(versionData); | |
1030 | + codeBuf.put(definesCodeData); | |
1031 | + codeBuf.put(sourceCodeData); | |
1032 | + codeBuf.flip(); | |
1033 | + | |
1034 | + if (verboseLogging) { | |
1035 | + logger.info("GLES20.glShaderSource(" + id + ")"); | |
1036 | + } | |
1037 | + if (source.getType().equals(ShaderType.Vertex) | |
1038 | + && Gdx.gl20.glGetString(GL20.GL_RENDERER).indexOf("PowerVR") >= 0) { | |
1039 | + Gdx.gl20.glShaderSource( | |
1040 | + id, | |
1041 | + source.getDefines() | |
1042 | + + source.getSource()); | |
1043 | + } else { | |
1044 | + if (!Gdx.app.getType().equals(com.badlogic.gdx.Application.ApplicationType.Desktop)) { | |
1045 | + Gdx.gl20.glShaderSource( | |
1046 | + id, | |
1047 | + "precision mediump float;\n" | |
1048 | + + source.getDefines() | |
1049 | + + source.getSource()); | |
1050 | + } else { | |
1051 | + Gdx.gl20.glShaderSource( | |
1052 | + id, | |
1053 | + source.getDefines() | |
1054 | + + source.getSource()); | |
1055 | + } | |
1056 | + } | |
1057 | + checkGLError(); | |
1058 | + | |
1059 | + if (verboseLogging) { | |
1060 | + logger.info("GLES20.glCompileShader(" + id + ")"); | |
1061 | + } | |
1062 | + | |
1063 | + Gdx.gl20.glCompileShader(id); | |
1064 | + | |
1065 | + checkGLError(); | |
1066 | + | |
1067 | + if (verboseLogging) { | |
1068 | + logger.info("GLES20.glGetShaderiv(" + id + ", GLES20.GL_COMPILE_STATUS)"); | |
1069 | + } | |
1070 | + | |
1071 | + Gdx.gl20.glGetShaderiv(id, GL20.GL_COMPILE_STATUS, intBuf1); | |
1072 | + | |
1073 | + checkGLError(); | |
1074 | + | |
1075 | + boolean compiledOK = intBuf1.get(0) == GL20.GL_TRUE; | |
1076 | + String infoLog = null; | |
1077 | + | |
1078 | + if (VALIDATE_SHADER || !compiledOK) { | |
1079 | + // even if compile succeeded, check | |
1080 | + // log for warnings | |
1081 | + if (verboseLogging) { | |
1082 | + logger.info("GLES20.glGetShaderiv()"); | |
1083 | + } | |
1084 | + Gdx.gl20.glGetShaderiv(id, GL20.GL_INFO_LOG_LENGTH, intBuf1); | |
1085 | + checkGLError(); | |
1086 | + if (verboseLogging) { | |
1087 | + logger.info("GLES20.glGetShaderInfoLog(" + id + ")"); | |
1088 | + } | |
1089 | + infoLog = Gdx.gl20.glGetShaderInfoLog(id); | |
1090 | + logger.severe("Errooooooooooot(" + id + ")"); | |
1091 | + } | |
1092 | + | |
1093 | + if (compiledOK) { | |
1094 | + if (infoLog != null) { | |
1095 | + logger.log(Level.INFO, "compile success: " + source.getName() + ", " + infoLog); | |
1096 | + } else { | |
1097 | + logger.log(Level.FINE, "compile success: " + source.getName()); | |
1098 | + } | |
1099 | + } else { | |
1100 | + logger.log(Level.WARNING, "Bad compile of:\n{0}{1}", | |
1101 | + new Object[]{source.getDefines(), source.getSource()}); | |
1102 | + if (infoLog != null) { | |
1103 | + throw new RendererException("compile error in:" + source + " error:" + infoLog); | |
1104 | + } else { | |
1105 | + throw new RendererException("compile error in:" + source + " error: <not provided>"); | |
1106 | + } | |
1107 | + } | |
1108 | + | |
1109 | + source.clearUpdateNeeded(); | |
1110 | + // only usable if compiled | |
1111 | + source.setUsable(compiledOK); | |
1112 | + if (!compiledOK) { | |
1113 | + // make sure to dispose id cause all program's | |
1114 | + // shaders will be cleared later. | |
1115 | + if (verboseLogging) { | |
1116 | + logger.info("GLES20.glDeleteShader(" + id + ")"); | |
1117 | + } | |
1118 | + Gdx.gl20.glDeleteShader(id); | |
1119 | + checkGLError(); | |
1120 | + } else { | |
1121 | + // register for cleanup since the ID is usable | |
1122 | + objManager.registerForCleanup(source); | |
1123 | + } | |
1124 | + } | |
1125 | + | |
1126 | + public void updateShaderData(Shader shader) { | |
1127 | + int id = shader.getId(); | |
1128 | + boolean needRegister = false; | |
1129 | + if (id == -1) { | |
1130 | + // create program | |
1131 | + | |
1132 | + if (verboseLogging) { | |
1133 | + logger.info("GLES20.glCreateProgram()"); | |
1134 | + } | |
1135 | + | |
1136 | + id = Gdx.gl20.glCreateProgram(); | |
1137 | + | |
1138 | + if (id <= 0) { | |
1139 | + throw new RendererException("Invalid ID received when trying to create shader program."); | |
1140 | + } | |
1141 | + | |
1142 | + shader.setId(id); | |
1143 | + needRegister = true; | |
1144 | + } | |
1145 | + | |
1146 | + for (ShaderSource source : shader.getSources()) { | |
1147 | + if (source.isUpdateNeeded()) { | |
1148 | + updateShaderSourceData(source, shader.getLanguage()); | |
1149 | + // shader has been compiled here | |
1150 | + } | |
1151 | + | |
1152 | + if (!source.isUsable()) { | |
1153 | + // it's useless.. just forget about everything.. | |
1154 | + shader.setUsable(false); | |
1155 | + shader.clearUpdateNeeded(); | |
1156 | + return; | |
1157 | + } | |
1158 | + if (verboseLogging) { | |
1159 | + logger.info("GLES20.glAttachShader(" + id + ", " + source.getId() + ")"); | |
1160 | + } | |
1161 | + | |
1162 | + Gdx.gl20.glAttachShader(id, source.getId()); | |
1163 | + } | |
1164 | + | |
1165 | + // link shaders to program | |
1166 | + if (verboseLogging) { | |
1167 | + logger.info("GLES20.glLinkProgram(" + id + ")"); | |
1168 | + } | |
1169 | + | |
1170 | + Gdx.gl20.glLinkProgram(id); | |
1171 | + | |
1172 | + | |
1173 | + if (verboseLogging) { | |
1174 | + logger.info("GLES20.glGetProgramiv(" + id + ")"); | |
1175 | + } | |
1176 | + | |
1177 | + Gdx.gl20.glGetProgramiv(id, GL20.GL_LINK_STATUS, intBuf1); | |
1178 | + | |
1179 | + boolean linkOK = intBuf1.get(0) == GL20.GL_TRUE; | |
1180 | + String infoLog = null; | |
1181 | + | |
1182 | + if (VALIDATE_SHADER || !linkOK) { | |
1183 | + if (verboseLogging) { | |
1184 | + logger.info("GLES20.glGetProgramiv(" + id + ", GLES20.GL_INFO_LOG_LENGTH, buffer)"); | |
1185 | + } | |
1186 | + | |
1187 | + Gdx.gl20.glGetProgramiv(id, GL20.GL_INFO_LOG_LENGTH, intBuf1); | |
1188 | + | |
1189 | + int length = intBuf1.get(0); | |
1190 | + if (length > 3) { | |
1191 | + // get infos | |
1192 | + | |
1193 | + if (verboseLogging) { | |
1194 | + logger.info("GLES20.glGetProgramInfoLog(" + id + ")"); | |
1195 | + } | |
1196 | + | |
1197 | + infoLog = Gdx.gl20.glGetProgramInfoLog(id); | |
1198 | + } | |
1199 | + } | |
1200 | + | |
1201 | + if (linkOK) { | |
1202 | + if (infoLog != null) { | |
1203 | + logger.log(Level.INFO, "shader link success. \n{0}", infoLog); | |
1204 | + } else { | |
1205 | + logger.fine("shader link success"); | |
1206 | + } | |
1207 | + } else { | |
1208 | + if (infoLog != null) { | |
1209 | + throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog); | |
1210 | + } else { | |
1211 | + throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>"); | |
1212 | + } | |
1213 | + } | |
1214 | + | |
1215 | + shader.clearUpdateNeeded(); | |
1216 | + if (!linkOK) { | |
1217 | + // failure.. forget about everything | |
1218 | + shader.resetSources(); | |
1219 | + shader.setUsable(false); | |
1220 | + deleteShader(shader); | |
1221 | + } else { | |
1222 | + shader.setUsable(true); | |
1223 | + if (needRegister) { | |
1224 | + objManager.registerForCleanup(shader); | |
1225 | + statistics.onNewShader(); | |
1226 | + } else { | |
1227 | + // OpenGL spec: uniform locations may change after re-link | |
1228 | + resetUniformLocations(shader); | |
1229 | + } | |
1230 | + } | |
1231 | + } | |
1232 | + | |
1233 | + public void setShader(Shader shader) { | |
1234 | + if (verboseLogging) { | |
1235 | + logger.info("setShader(" + shader + ")"); | |
1236 | + } | |
1237 | + | |
1238 | + if (shader == null) { | |
1239 | + if (context.boundShaderProgram > 0) { | |
1240 | + | |
1241 | + if (verboseLogging) { | |
1242 | + logger.info("GLES20.glUseProgram(0)"); | |
1243 | + } | |
1244 | + | |
1245 | + Gdx.gl20.glUseProgram(0); | |
1246 | + | |
1247 | + statistics.onShaderUse(null, true); | |
1248 | + context.boundShaderProgram = 0; | |
1249 | + boundShader = null; | |
1250 | + } | |
1251 | + } else { | |
1252 | + if (shader.isUpdateNeeded()) { | |
1253 | + updateShaderData(shader); | |
1254 | + } | |
1255 | + | |
1256 | + // NOTE: might want to check if any of the | |
1257 | + // sources need an update? | |
1258 | + | |
1259 | + if (!shader.isUsable()) { | |
1260 | + logger.warning("shader is not usable."); | |
1261 | + return; | |
1262 | + } | |
1263 | + | |
1264 | + assert shader.getId() > 0; | |
1265 | + | |
1266 | + updateShaderUniforms(shader); | |
1267 | + if (context.boundShaderProgram != shader.getId()) { | |
1268 | + if (VALIDATE_SHADER) { | |
1269 | + // check if shader can be used | |
1270 | + // with current state | |
1271 | + if (verboseLogging) { | |
1272 | + logger.info("GLES20.glValidateProgram(" + shader.getId() + ")"); | |
1273 | + } | |
1274 | + | |
1275 | + Gdx.gl20.glValidateProgram(shader.getId()); | |
1276 | + | |
1277 | + if (verboseLogging) { | |
1278 | + logger.info("GLES20.glGetProgramiv(" + shader.getId() + ", GLES20.GL_VALIDATE_STATUS, buffer)"); | |
1279 | + } | |
1280 | + | |
1281 | + Gdx.gl20.glGetProgramiv(shader.getId(), GL20.GL_VALIDATE_STATUS, intBuf1); | |
1282 | + | |
1283 | + boolean validateOK = intBuf1.get(0) == GL20.GL_TRUE; | |
1284 | + | |
1285 | + if (validateOK) { | |
1286 | + logger.fine("shader validate success"); | |
1287 | + } else { | |
1288 | + logger.warning("shader validate failure"); | |
1289 | + } | |
1290 | + } | |
1291 | + | |
1292 | + if (verboseLogging) { | |
1293 | + logger.info("GLES20.glUseProgram(" + shader.getId() + ")"); | |
1294 | + } | |
1295 | + | |
1296 | + Gdx.gl20.glUseProgram(shader.getId()); | |
1297 | + | |
1298 | + statistics.onShaderUse(shader, true); | |
1299 | + context.boundShaderProgram = shader.getId(); | |
1300 | + boundShader = shader; | |
1301 | + } else { | |
1302 | + statistics.onShaderUse(shader, false); | |
1303 | + } | |
1304 | + } | |
1305 | + } | |
1306 | + | |
1307 | + public void setShaderWithoutUpdateUniforms(Shader shader) { | |
1308 | + if (verboseLogging) { | |
1309 | + logger.info("setShader(" + shader + ")"); | |
1310 | + } | |
1311 | + | |
1312 | + if (shader == null) { | |
1313 | + if (context.boundShaderProgram > 0) { | |
1314 | + | |
1315 | + if (verboseLogging) { | |
1316 | + logger.info("GLES20.glUseProgram(0)"); | |
1317 | + } | |
1318 | + | |
1319 | + Gdx.gl20.glUseProgram(0); | |
1320 | + | |
1321 | + statistics.onShaderUse(null, true); | |
1322 | + context.boundShaderProgram = 0; | |
1323 | + boundShader = null; | |
1324 | + } | |
1325 | + } else { | |
1326 | + if (shader.isUpdateNeeded()) { | |
1327 | + updateShaderData(shader); | |
1328 | + } | |
1329 | + | |
1330 | + // NOTE: might want to check if any of the | |
1331 | + // sources need an update? | |
1332 | + | |
1333 | + if (!shader.isUsable()) { | |
1334 | + logger.warning("shader is not usable."); | |
1335 | + return; | |
1336 | + } | |
1337 | + | |
1338 | + assert shader.getId() > 0; | |
1339 | + | |
1340 | + if (context.boundShaderProgram != shader.getId()) { | |
1341 | + if (VALIDATE_SHADER) { | |
1342 | + // check if shader can be used | |
1343 | + // with current state | |
1344 | + if (verboseLogging) { | |
1345 | + logger.info("GLES20.glValidateProgram(" + shader.getId() + ")"); | |
1346 | + } | |
1347 | + | |
1348 | + Gdx.gl20.glValidateProgram(shader.getId()); | |
1349 | + | |
1350 | + if (verboseLogging) { | |
1351 | + logger.info("GLES20.glGetProgramiv(" + shader.getId() + ", GLES20.GL_VALIDATE_STATUS, buffer)"); | |
1352 | + } | |
1353 | + | |
1354 | + Gdx.gl20.glGetProgramiv(shader.getId(), GL20.GL_VALIDATE_STATUS, intBuf1); | |
1355 | + | |
1356 | + boolean validateOK = intBuf1.get(0) == GL20.GL_TRUE; | |
1357 | + | |
1358 | + if (validateOK) { | |
1359 | + logger.fine("shader validate success"); | |
1360 | + } else { | |
1361 | + logger.warning("shader validate failure"); | |
1362 | + } | |
1363 | + } | |
1364 | + | |
1365 | + if (verboseLogging) { | |
1366 | + logger.info("GLES20.glUseProgram(" + shader.getId() + ")"); | |
1367 | + } | |
1368 | + | |
1369 | + Gdx.gl20.glUseProgram(shader.getId()); | |
1370 | + | |
1371 | + statistics.onShaderUse(shader, true); | |
1372 | + context.boundShaderProgram = shader.getId(); | |
1373 | + boundShader = shader; | |
1374 | + } else { | |
1375 | + statistics.onShaderUse(shader, false); | |
1376 | + } | |
1377 | + } | |
1378 | + } | |
1379 | + | |
1380 | + public void deleteShaderSource(ShaderSource source) { | |
1381 | + if (source.getId() < 0) { | |
1382 | + logger.warning("Shader source is not uploaded to GPU, cannot delete."); | |
1383 | + return; | |
1384 | + } | |
1385 | + source.setUsable(false); | |
1386 | + source.clearUpdateNeeded(); | |
1387 | + | |
1388 | + if (verboseLogging) { | |
1389 | + logger.info("GLES20.glDeleteShader(" + source.getId() + ")"); | |
1390 | + } | |
1391 | + | |
1392 | + Gdx.gl20.glDeleteShader(source.getId()); | |
1393 | + source.resetObject(); | |
1394 | + } | |
1395 | + | |
1396 | + public void deleteShader(Shader shader) { | |
1397 | + if (shader.getId() == -1) { | |
1398 | + logger.warning("Shader is not uploaded to GPU, cannot delete."); | |
1399 | + return; | |
1400 | + } | |
1401 | + for (ShaderSource source : shader.getSources()) { | |
1402 | + if (source.getId() != -1) { | |
1403 | + | |
1404 | + if (verboseLogging) { | |
1405 | + logger.info("GLES20.glDetachShader(" + shader.getId() + ", " + source.getId() + ")"); | |
1406 | + } | |
1407 | + | |
1408 | + Gdx.gl20.glDetachShader(shader.getId(), source.getId()); | |
1409 | + // the next part is done by the GLObjectManager automatically | |
1410 | +// glDeleteShader(source.getId()); | |
1411 | + } | |
1412 | + } | |
1413 | + // kill all references so sources can be collected | |
1414 | + // if needed. | |
1415 | + shader.resetSources(); | |
1416 | + | |
1417 | + if (verboseLogging) { | |
1418 | + logger.info("GLES20.glDeleteProgram(" + shader.getId() + ")"); | |
1419 | + } | |
1420 | + | |
1421 | + Gdx.gl20.glDeleteProgram(shader.getId()); | |
1422 | + | |
1423 | + statistics.onDeleteShader(); | |
1424 | + } | |
1425 | + | |
1426 | + /*********************************************************************\ | |
1427 | + |* Framebuffers *| | |
1428 | + \*********************************************************************/ | |
1429 | + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { | |
1430 | + copyFrameBuffer(src, dst, true); | |
1431 | + } | |
1432 | + | |
1433 | + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { | |
1434 | + logger.warning("copyFrameBuffer is not supported."); | |
1435 | + } | |
1436 | + private void checkFrameBufferStatus(FrameBuffer fb) { | |
1437 | + try { | |
1438 | + checkFrameBufferError(); | |
1439 | + } catch (IllegalStateException ex) { | |
1440 | + logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb); | |
1441 | + printRealFrameBufferInfo(fb); | |
1442 | + throw ex; | |
1443 | + } | |
1444 | + } | |
1445 | + | |
1446 | + private void checkFrameBufferError() { | |
1447 | + int status = Gdx.gl20.glCheckFramebufferStatus(GL20.GL_FRAMEBUFFER); | |
1448 | + switch (status) { | |
1449 | + case GL20.GL_FRAMEBUFFER_COMPLETE: | |
1450 | + break; | |
1451 | + case GL20.GL_FRAMEBUFFER_UNSUPPORTED: | |
1452 | + //Choose different formats | |
1453 | + throw new IllegalStateException("Framebuffer object format is " | |
1454 | + + "unsupported by the video hardware."); | |
1455 | + case GL20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: | |
1456 | + throw new IllegalStateException("Framebuffer has erronous attachment."); | |
1457 | + case GL20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: | |
1458 | + throw new IllegalStateException("Framebuffer doesn't have any renderbuffers attached."); | |
1459 | + case GL20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: | |
1460 | + throw new IllegalStateException("Framebuffer attachments must have same dimensions."); | |
1461 | +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: | |
1462 | +// throw new IllegalStateException("Framebuffer attachments must have same formats."); | |
1463 | +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: | |
1464 | +// throw new IllegalStateException("Incomplete draw buffer."); | |
1465 | +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: | |
1466 | +// throw new IllegalStateException("Incomplete read buffer."); | |
1467 | +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: | |
1468 | +// throw new IllegalStateException("Incomplete multisample buffer."); | |
1469 | + default: | |
1470 | + //Programming error; will fail on all hardware | |
1471 | + throw new IllegalStateException("Some video driver error " | |
1472 | + + "or programming error occured. " | |
1473 | + + "Framebuffer object status is invalid: " + status); | |
1474 | + } | |
1475 | + } | |
1476 | + private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name) { | |
1477 | + System.out.println("== Renderbuffer " + name + " =="); | |
1478 | + System.out.println("RB ID: " + rb.getId()); | |
1479 | + System.out.println("Is proper? " + Gdx.gl20.glIsRenderbuffer(rb.getId())); | |
1480 | + | |
1481 | + int attachment = convertAttachmentSlot(rb.getSlot()); | |
1482 | + | |
1483 | + intBuf16.clear(); | |
1484 | + Gdx.gl20.glGetFramebufferAttachmentParameteriv(GL20.GL_FRAMEBUFFER, | |
1485 | + attachment, GL20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, intBuf16); | |
1486 | + int type = intBuf16.get(0); | |
1487 | + | |
1488 | + intBuf16.clear(); | |
1489 | + Gdx.gl20.glGetFramebufferAttachmentParameteriv(GL20.GL_FRAMEBUFFER, | |
1490 | + attachment, GL20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, intBuf16); | |
1491 | + int rbName = intBuf16.get(0); | |
1492 | + | |
1493 | + switch (type) { | |
1494 | + case GL20.GL_NONE: | |
1495 | + System.out.println("Type: None"); | |
1496 | + break; | |
1497 | + case GL20.GL_TEXTURE: | |
1498 | + System.out.println("Type: Texture"); | |
1499 | + break; | |
1500 | + case GL20.GL_RENDERBUFFER: | |
1501 | + System.out.println("Type: Buffer"); | |
1502 | + System.out.println("RB ID: " + rbName); | |
1503 | + break; | |
1504 | + } | |
1505 | + | |
1506 | + | |
1507 | + | |
1508 | + } | |
1509 | + | |
1510 | + private void printRealFrameBufferInfo(FrameBuffer fb) { | |
1511 | +// boolean doubleBuffer = GLES20.glGetBooleanv(GLES20.GL_DOUBLEBUFFER); | |
1512 | + boolean doubleBuffer = false; // FIXME | |
1513 | +// String drawBuf = getTargetBufferName(glGetInteger(GL_DRAW_BUFFER)); | |
1514 | +// String readBuf = getTargetBufferName(glGetInteger(GL_READ_BUFFER)); | |
1515 | + | |
1516 | + int fbId = fb.getId(); | |
1517 | + intBuf16.clear(); | |
1518 | +// int curDrawBinding = GLES20.glGetIntegerv(GLES20.GL_DRAW_FRAMEBUFFER_BINDING); | |
1519 | +// int curReadBinding = glGetInteger(ARBFramebufferObject.GL_READ_FRAMEBUFFER_BINDING); | |
1520 | + | |
1521 | + System.out.println("=== OpenGL FBO State ==="); | |
1522 | + System.out.println("Context doublebuffered? " + doubleBuffer); | |
1523 | + System.out.println("FBO ID: " + fbId); | |
1524 | + System.out.println("Is proper? " + Gdx.gl20.glIsFramebuffer(fbId)); | |
1525 | +// System.out.println("Is bound to draw? " + (fbId == curDrawBinding)); | |
1526 | +// System.out.println("Is bound to read? " + (fbId == curReadBinding)); | |
1527 | +// System.out.println("Draw buffer: " + drawBuf); | |
1528 | +// System.out.println("Read buffer: " + readBuf); | |
1529 | + | |
1530 | + if (context.boundFBO != fbId) { | |
1531 | + Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbId); | |
1532 | + context.boundFBO = fbId; | |
1533 | + } | |
1534 | + | |
1535 | + if (fb.getDepthBuffer() != null) { | |
1536 | + printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth"); | |
1537 | + } | |
1538 | + for (int i = 0; i < fb.getNumColorBuffers(); i++) { | |
1539 | + printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i); | |
1540 | + } | |
1541 | + } | |
1542 | + | |
1543 | + private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { | |
1544 | + int id = rb.getId(); | |
1545 | + if (id == -1) { | |
1546 | + Gdx.gl20.glGenRenderbuffers(1, intBuf1); | |
1547 | +// RendererUtil.checkGLError(); | |
1548 | + | |
1549 | + id = intBuf1.get(0); | |
1550 | + rb.setId(id); | |
1551 | + } | |
1552 | + | |
1553 | + if (context.boundRB != id) { | |
1554 | + Gdx.gl20.glBindRenderbuffer(GL20.GL_RENDERBUFFER, id); | |
1555 | +// RendererUtil.checkGLError(); | |
1556 | + | |
1557 | + context.boundRB = id; | |
1558 | + } | |
1559 | + | |
1560 | + if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { | |
1561 | + throw new RendererException("Resolution " + fb.getWidth() | |
1562 | + + ":" + fb.getHeight() + " is not supported."); | |
1563 | + } | |
1564 | + | |
1565 | + TextureUtilGdx.AndroidGLImageFormat imageFormat = TextureUtilGdx.getImageFormat(rb.getFormat()); | |
1566 | + if (imageFormat.renderBufferStorageFormat == 0) { | |
1567 | + throw new RendererException("The format '" + rb.getFormat() + "' cannot be used for renderbuffers."); | |
1568 | + } | |
1569 | + | |
1570 | +// if (fb.getSamples() > 1 && GLContext.getCapabilities().GL_EXT_framebuffer_multisample) { | |
1571 | + if (fb.getSamples() > 1) { | |
1572 | +// // FIXME | |
1573 | + throw new RendererException("Multisample FrameBuffer is not supported yet."); | |
1574 | +// int samples = fb.getSamples(); | |
1575 | +// if (maxFBOSamples < samples) { | |
1576 | +// samples = maxFBOSamples; | |
1577 | +// } | |
1578 | +// glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, | |
1579 | +// samples, | |
1580 | +// glFmt.internalFormat, | |
1581 | +// fb.getWidth(), | |
1582 | +// fb.getHeight()); | |
1583 | + } else { | |
1584 | + Gdx.gl20.glRenderbufferStorage(GL20.GL_RENDERBUFFER, | |
1585 | + imageFormat.renderBufferStorageFormat, | |
1586 | + fb.getWidth(), | |
1587 | + fb.getHeight()); | |
1588 | + | |
1589 | +// RendererUtil.checkGLError(); | |
1590 | + } | |
1591 | + } | |
1592 | + private int convertAttachmentSlot(int attachmentSlot) { | |
1593 | + // can also add support for stencil here | |
1594 | + if (attachmentSlot == -100) { | |
1595 | + return GL20.GL_DEPTH_ATTACHMENT; | |
1596 | + } else if (attachmentSlot == 0) { | |
1597 | + return GL20.GL_COLOR_ATTACHMENT0; | |
1598 | + } else { | |
1599 | + throw new UnsupportedOperationException("Android does not support multiple color attachments to an FBO"); | |
1600 | + } | |
1601 | + } | |
1602 | + | |
1603 | + public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { | |
1604 | + Texture tex = rb.getTexture(); | |
1605 | + Image image = tex.getImage(); | |
1606 | + if (image.isUpdateNeeded()) { | |
1607 | + updateTexImageData(image, tex.getType(), false); | |
1608 | + | |
1609 | + // NOTE: For depth textures, sets nearest/no-mips mode | |
1610 | + // Required to fix "framebuffer unsupported" | |
1611 | + // for old NVIDIA drivers! | |
1612 | + setupTextureParams(tex); | |
1613 | + } | |
1614 | + | |
1615 | + Gdx.gl20.glFramebufferTexture2D(GL20.GL_FRAMEBUFFER, | |
1616 | + convertAttachmentSlot(rb.getSlot()), | |
1617 | + convertTextureType(tex.getType()), | |
1618 | + image.getId(), | |
1619 | + 0); | |
1620 | + | |
1621 | +// RendererUtil.checkGLError(); | |
1622 | + } | |
1623 | + | |
1624 | + public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { | |
1625 | + boolean needAttach; | |
1626 | + if (rb.getTexture() == null) { | |
1627 | + // if it hasn't been created yet, then attach is required. | |
1628 | + needAttach = rb.getId() == -1; | |
1629 | + updateRenderBuffer(fb, rb); | |
1630 | + } else { | |
1631 | + needAttach = false; | |
1632 | + updateRenderTexture(fb, rb); | |
1633 | + } | |
1634 | + if (needAttach) { | |
1635 | + Gdx.gl20.glFramebufferRenderbuffer(GL20.GL_FRAMEBUFFER, | |
1636 | + convertAttachmentSlot(rb.getSlot()), | |
1637 | + GL20.GL_RENDERBUFFER, | |
1638 | + rb.getId()); | |
1639 | + | |
1640 | +// RendererUtil.checkGLError(); | |
1641 | + } | |
1642 | + } | |
1643 | + | |
1644 | + public void updateFrameBuffer(FrameBuffer fb) { | |
1645 | + int id = fb.getId(); | |
1646 | + if (id == -1) { | |
1647 | + intBuf1.clear(); | |
1648 | + // create FBO | |
1649 | + Gdx.gl20.glGenFramebuffers(1, intBuf1); | |
1650 | +// RendererUtil.checkGLError(); | |
1651 | + | |
1652 | + id = intBuf1.get(0); | |
1653 | + fb.setId(id); | |
1654 | + objManager.registerForCleanup(fb); | |
1655 | + | |
1656 | + statistics.onNewFrameBuffer(); | |
1657 | + } | |
1658 | + | |
1659 | + if (context.boundFBO != id) { | |
1660 | + Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, id); | |
1661 | +// RendererUtil.checkGLError(); | |
1662 | + | |
1663 | + // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 | |
1664 | + context.boundDrawBuf = 0; | |
1665 | + context.boundFBO = id; | |
1666 | + } | |
1667 | + | |
1668 | + RenderBuffer depthBuf = fb.getDepthBuffer(); | |
1669 | + if (depthBuf != null) { | |
1670 | + updateFrameBufferAttachment(fb, depthBuf); | |
1671 | + } | |
1672 | + | |
1673 | + for (int i = 0; i < fb.getNumColorBuffers(); i++) { | |
1674 | + RenderBuffer colorBuf = fb.getColorBuffer(i); | |
1675 | + updateFrameBufferAttachment(fb, colorBuf); | |
1676 | + } | |
1677 | + | |
1678 | + fb.clearUpdateNeeded(); | |
1679 | + } | |
1680 | + | |
1681 | + public void setMainFrameBufferOverride(FrameBuffer fb){ | |
1682 | + mainFbOverride = fb; | |
1683 | + } | |
1684 | + | |
1685 | + public void setFrameBuffer(FrameBuffer fb) { | |
1686 | + if (fb == null && mainFbOverride != null) { | |
1687 | + fb = mainFbOverride; | |
1688 | + } | |
1689 | + | |
1690 | + if (lastFb == fb) { | |
1691 | + if (fb == null || !fb.isUpdateNeeded()) { | |
1692 | + return; | |
1693 | + } | |
1694 | + } | |
1695 | + | |
1696 | + // generate mipmaps for last FB if needed | |
1697 | + if (lastFb != null) { | |
1698 | + for (int i = 0; i < lastFb.getNumColorBuffers(); i++) { | |
1699 | + RenderBuffer rb = lastFb.getColorBuffer(i); | |
1700 | + Texture tex = rb.getTexture(); | |
1701 | + if (tex != null | |
1702 | + && tex.getMinFilter().usesMipMapLevels()) { | |
1703 | + setTexture(0, rb.getTexture()); | |
1704 | + | |
1705 | +// int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); | |
1706 | + int textureType = convertTextureType(tex.getType()); | |
1707 | + Gdx.gl20.glGenerateMipmap(textureType); | |
1708 | +// RendererUtil.checkGLError(); | |
1709 | + } | |
1710 | + } | |
1711 | + } | |
1712 | + | |
1713 | + if (fb == null) { | |
1714 | + // unbind any fbos | |
1715 | + if (context.boundFBO != 0) { | |
1716 | + Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0); | |
1717 | +// RendererUtil.checkGLError(); | |
1718 | + | |
1719 | + statistics.onFrameBufferUse(null, true); | |
1720 | + | |
1721 | + context.boundFBO = 0; | |
1722 | + } | |
1723 | + | |
1724 | + /* | |
1725 | + // select back buffer | |
1726 | + if (context.boundDrawBuf != -1) { | |
1727 | + glDrawBuffer(initialDrawBuf); | |
1728 | + context.boundDrawBuf = -1; | |
1729 | + } | |
1730 | + if (context.boundReadBuf != -1) { | |
1731 | + glReadBuffer(initialReadBuf); | |
1732 | + context.boundReadBuf = -1; | |
1733 | + } | |
1734 | + */ | |
1735 | + | |
1736 | + lastFb = null; | |
1737 | + } else { | |
1738 | + if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null) { | |
1739 | + throw new IllegalArgumentException("The framebuffer: " + fb | |
1740 | + + "\nDoesn't have any color/depth buffers"); | |
1741 | + } | |
1742 | + | |
1743 | + if (fb.isUpdateNeeded()) { | |
1744 | + updateFrameBuffer(fb); | |
1745 | + } | |
1746 | + | |
1747 | + if (context.boundFBO != fb.getId()) { | |
1748 | + Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fb.getId()); | |
1749 | +// RendererUtil.checkGLError(); | |
1750 | + | |
1751 | + statistics.onFrameBufferUse(fb, true); | |
1752 | + | |
1753 | + // update viewport to reflect framebuffer's resolution | |
1754 | + setViewPort(0, 0, fb.getWidth(), fb.getHeight()); | |
1755 | + | |
1756 | + context.boundFBO = fb.getId(); | |
1757 | + } else { | |
1758 | + statistics.onFrameBufferUse(fb, false); | |
1759 | + } | |
1760 | + if (fb.getNumColorBuffers() == 0) { | |
1761 | +// // make sure to select NONE as draw buf | |
1762 | +// // no color buffer attached. select NONE | |
1763 | + if (context.boundDrawBuf != -2) { | |
1764 | +// glDrawBuffer(GL_NONE); | |
1765 | + context.boundDrawBuf = -2; | |
1766 | + } | |
1767 | + if (context.boundReadBuf != -2) { | |
1768 | +// glReadBuffer(GL_NONE); | |
1769 | + context.boundReadBuf = -2; | |
1770 | + } | |
1771 | + } else { | |
1772 | + if (fb.getNumColorBuffers() > maxFBOAttachs) { | |
1773 | + throw new RendererException("Framebuffer has more color " | |
1774 | + + "attachments than are supported" | |
1775 | + + " by the video hardware!"); | |
1776 | + } | |
1777 | + if (fb.isMultiTarget()) { | |
1778 | + if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { | |
1779 | + throw new RendererException("Framebuffer has more" | |
1780 | + + " multi targets than are supported" | |
1781 | + + " by the video hardware!"); | |
1782 | + } | |
1783 | + | |
1784 | + if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()) { | |
1785 | + intBuf16.clear(); | |
1786 | + for (int i = 0; i < fb.getNumColorBuffers(); i++) { | |
1787 | + intBuf16.put(Gdx.gl20.GL_COLOR_ATTACHMENT0 + i); | |
1788 | + } | |
1789 | + | |
1790 | + intBuf16.flip(); | |
1791 | +// glDrawBuffers(intBuf16); | |
1792 | + context.boundDrawBuf = 100 + fb.getNumColorBuffers(); | |
1793 | + } | |
1794 | + } else { | |
1795 | + RenderBuffer rb = fb.getColorBuffer(fb.getTargetIndex()); | |
1796 | + // select this draw buffer | |
1797 | + if (context.boundDrawBuf != rb.getSlot()) { | |
1798 | + Gdx.gl20.glActiveTexture(convertAttachmentSlot(rb.getSlot())); | |
1799 | +// RendererUtil.checkGLError(); | |
1800 | + | |
1801 | + context.boundDrawBuf = rb.getSlot(); | |
1802 | + } | |
1803 | + } | |
1804 | + } | |
1805 | + | |
1806 | + assert fb.getId() >= 0; | |
1807 | + assert context.boundFBO == fb.getId(); | |
1808 | + | |
1809 | + lastFb = fb; | |
1810 | + | |
1811 | + checkFrameBufferStatus(fb); | |
1812 | + } | |
1813 | + } | |
1814 | + | |
1815 | + /** | |
1816 | + * Reads the Color Buffer from OpenGL and stores into the ByteBuffer. | |
1817 | + * Make sure to call setViewPort with the appropriate viewport size before | |
1818 | + * calling readFrameBuffer. | |
1819 | + * @param fb FrameBuffer | |
1820 | + * @param byteBuf ByteBuffer to store the Color Buffer from OpenGL | |
1821 | + */ | |
1822 | + public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { | |
1823 | + if (fb != null) { | |
1824 | + RenderBuffer rb = fb.getColorBuffer(); | |
1825 | + if (rb == null) { | |
1826 | + throw new IllegalArgumentException("Specified framebuffer" | |
1827 | + + " does not have a colorbuffer"); | |
1828 | + } | |
1829 | + | |
1830 | + setFrameBuffer(fb); | |
1831 | + } else { | |
1832 | + setFrameBuffer(null); | |
1833 | + } | |
1834 | + | |
1835 | + Gdx.gl20.glReadPixels(vpX, vpY, vpW, vpH, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, byteBuf); | |
1836 | +// RendererUtil.checkGLError(); | |
1837 | + } | |
1838 | + | |
1839 | + private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { | |
1840 | + intBuf1.put(0, rb.getId()); | |
1841 | + Gdx.gl20.glDeleteRenderbuffers(1, intBuf1); | |
1842 | +// RendererUtil.checkGLError(); | |
1843 | + } | |
1844 | + | |
1845 | + public void deleteFrameBuffer(FrameBuffer fb) { | |
1846 | + if (fb.getId() != -1) { | |
1847 | + if (context.boundFBO == fb.getId()) { | |
1848 | + Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, 0); | |
1849 | +// RendererUtil.checkGLError(); | |
1850 | + | |
1851 | + context.boundFBO = 0; | |
1852 | + } | |
1853 | + | |
1854 | + if (fb.getDepthBuffer() != null) { | |
1855 | + deleteRenderBuffer(fb, fb.getDepthBuffer()); | |
1856 | + } | |
1857 | + if (fb.getColorBuffer() != null) { | |
1858 | + deleteRenderBuffer(fb, fb.getColorBuffer()); | |
1859 | + } | |
1860 | + | |
1861 | + intBuf1.put(0, fb.getId()); | |
1862 | + Gdx.gl20.glDeleteFramebuffers(1, intBuf1); | |
1863 | +// RendererUtil.checkGLError(); | |
1864 | + | |
1865 | + fb.resetObject(); | |
1866 | + | |
1867 | + statistics.onDeleteFrameBuffer(); | |
1868 | + } | |
1869 | + } | |
1870 | + | |
1871 | + /*********************************************************************\ | |
1872 | + |* Textures *| | |
1873 | + \*********************************************************************/ | |
1874 | + private int convertTextureType(Texture.Type type) { | |
1875 | + switch (type) { | |
1876 | + case TwoDimensional: | |
1877 | + return GL20.GL_TEXTURE_2D; | |
1878 | + // case TwoDimensionalArray: | |
1879 | + // return EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT; | |
1880 | +// case ThreeDimensional: | |
1881 | + // return GLES20.GL_TEXTURE_3D; | |
1882 | + case CubeMap: | |
1883 | + return GL20.GL_TEXTURE_CUBE_MAP; | |
1884 | + default: | |
1885 | + throw new UnsupportedOperationException("Unknown texture type: " + type); | |
1886 | + } | |
1887 | + } | |
1888 | + | |
1889 | + private int convertMagFilter(Texture.MagFilter filter) { | |
1890 | + switch (filter) { | |
1891 | + case Bilinear: | |
1892 | + return GL20.GL_LINEAR; | |
1893 | + case Nearest: | |
1894 | + return GL20.GL_NEAREST; | |
1895 | + default: | |
1896 | + throw new UnsupportedOperationException("Unknown mag filter: " + filter); | |
1897 | + } | |
1898 | + } | |
1899 | + | |
1900 | + private int convertMinFilter(Texture.MinFilter filter) { | |
1901 | + switch (filter) { | |
1902 | + case Trilinear: | |
1903 | + return GL20.GL_LINEAR_MIPMAP_LINEAR; | |
1904 | + case BilinearNearestMipMap: | |
1905 | + return GL20.GL_LINEAR_MIPMAP_NEAREST; | |
1906 | + case NearestLinearMipMap: | |
1907 | + return GL20.GL_NEAREST_MIPMAP_LINEAR; | |
1908 | + case NearestNearestMipMap: | |
1909 | + return GL20.GL_NEAREST_MIPMAP_NEAREST; | |
1910 | + case BilinearNoMipMaps: | |
1911 | + return GL20.GL_LINEAR; | |
1912 | + case NearestNoMipMaps: | |
1913 | + return GL20.GL_NEAREST; | |
1914 | + default: | |
1915 | + throw new UnsupportedOperationException("Unknown min filter: " + filter); | |
1916 | + } | |
1917 | + } | |
1918 | + | |
1919 | + private int convertWrapMode(Texture.WrapMode mode) { | |
1920 | + switch (mode) { | |
1921 | +// case BorderClamp: | |
1922 | +// return GLES20.GL_CLAMP_TO_BORDER; | |
1923 | +// case Clamp: | |
1924 | +// return GLES20.GL_CLAMP; | |
1925 | + case EdgeClamp: | |
1926 | + return GL20.GL_CLAMP_TO_EDGE; | |
1927 | + case Repeat: | |
1928 | + return GL20.GL_REPEAT; | |
1929 | + case MirroredRepeat: | |
1930 | + return GL20.GL_MIRRORED_REPEAT; | |
1931 | + default: | |
1932 | + throw new UnsupportedOperationException("Unknown wrap mode: " + mode); | |
1933 | + } | |
1934 | + } | |
1935 | + | |
1936 | + /** | |
1937 | + * <code>setupTextureParams</code> sets the OpenGL context texture parameters | |
1938 | + * @param tex the Texture to set the texture parameters from | |
1939 | + */ | |
1940 | + private void setupTextureParams(Texture tex) { | |
1941 | + int target = convertTextureType(tex.getType()); | |
1942 | + | |
1943 | + // filter things | |
1944 | + int minFilter = convertMinFilter(tex.getMinFilter()); | |
1945 | + int magFilter = convertMagFilter(tex.getMagFilter()); | |
1946 | + | |
1947 | + if (verboseLogging) { | |
1948 | + logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")"); | |
1949 | + } | |
1950 | + | |
1951 | + Gdx.gl20.glTexParameteri(target, GL20.GL_TEXTURE_MIN_FILTER, minFilter); | |
1952 | + | |
1953 | + if (verboseLogging) { | |
1954 | + logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")"); | |
1955 | + } | |
1956 | + | |
1957 | + Gdx.gl20.glTexParameteri(target, GL20.GL_TEXTURE_MAG_FILTER, magFilter); | |
1958 | + | |
1959 | + /* | |
1960 | + if (tex.getAnisotropicFilter() > 1){ | |
1961 | + | |
1962 | + if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){ | |
1963 | + glTexParameterf(target, | |
1964 | + EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, | |
1965 | + tex.getAnisotropicFilter()); | |
1966 | + } | |
1967 | + | |
1968 | + } | |
1969 | + */ | |
1970 | + // repeat modes | |
1971 | + | |
1972 | + switch (tex.getType()) { | |
1973 | + case ThreeDimensional: | |
1974 | + case CubeMap: // cubemaps use 3D coords | |
1975 | + // GL_TEXTURE_WRAP_R is not available in api 8 | |
1976 | + //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); | |
1977 | + case TwoDimensional: | |
1978 | + case TwoDimensionalArray: | |
1979 | + | |
1980 | + if (verboseLogging) { | |
1981 | + logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T))); | |
1982 | + } | |
1983 | + | |
1984 | + Gdx.gl20.glTexParameteri(target, GL20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); | |
1985 | + | |
1986 | + // fall down here is intentional.. | |
1987 | +// case OneDimensional: | |
1988 | + | |
1989 | + if (verboseLogging) { | |
1990 | + logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S))); | |
1991 | + } | |
1992 | + | |
1993 | + Gdx.gl20.glTexParameteri(target, GL20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); | |
1994 | + break; | |
1995 | + default: | |
1996 | + throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); | |
1997 | + } | |
1998 | + | |
1999 | + // R to Texture compare mode | |
2000 | +/* | |
2001 | + if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off){ | |
2002 | + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_MODE, GLES20.GL_COMPARE_R_TO_TEXTURE); | |
2003 | + GLES20.glTexParameteri(target, GLES20.GL_DEPTH_TEXTURE_MODE, GLES20.GL_INTENSITY); | |
2004 | + if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual){ | |
2005 | + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_GEQUAL); | |
2006 | + }else{ | |
2007 | + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_LEQUAL); | |
2008 | + } | |
2009 | + } | |
2010 | + */ | |
2011 | + } | |
2012 | + | |
2013 | + /** | |
2014 | + * <code>updateTexImageData</code> activates and binds the texture | |
2015 | + * @param img | |
2016 | + * @param type | |
2017 | + * @param mips | |
2018 | + */ | |
2019 | + public void updateTexImageData(Image img, Texture.Type type, boolean mips) { | |
2020 | + int texId = img.getId(); | |
2021 | + if (texId == -1) { | |
2022 | + // create texture | |
2023 | + if (verboseLogging) { | |
2024 | + logger.info("GLES20.glGenTexture(1, buffer)"); | |
2025 | + } | |
2026 | + | |
2027 | + Gdx.gl20.glGenTextures(1, intBuf1); | |
2028 | + texId = intBuf1.get(0); | |
2029 | + img.setId(texId); | |
2030 | + objManager.registerForCleanup(img); | |
2031 | + | |
2032 | + statistics.onNewTexture(); | |
2033 | + } | |
2034 | + | |
2035 | + // bind texture | |
2036 | + int target = convertTextureType(type); | |
2037 | + if (context.boundTextureUnit != 0) { | |
2038 | + if (verboseLogging) { | |
2039 | + logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)"); | |
2040 | + } | |
2041 | + | |
2042 | + Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE0); | |
2043 | + context.boundTextureUnit = 0; | |
2044 | + } | |
2045 | + if (context.boundTextures[0] != img) { | |
2046 | + | |
2047 | + if (verboseLogging) { | |
2048 | + logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")"); | |
2049 | + } | |
2050 | + | |
2051 | + Gdx.gl20.glBindTexture(target, texId); | |
2052 | + context.boundTextures[0] = img; | |
2053 | + } | |
2054 | + | |
2055 | + | |
2056 | + if (target == GL20.GL_TEXTURE_CUBE_MAP) { | |
2057 | + // Upload a cube map / sky box | |
2058 | + // TODO | |
2059 | +// @SuppressWarnings("unchecked") | |
2060 | +// List<Bitmap> bmps = (List<Bitmap>) img.getEfficentData(); | |
2061 | +// if (bmps != null) { | |
2062 | +// // Native android bitmap | |
2063 | +// if (bmps.size() != 6) { | |
2064 | +// throw new UnsupportedOperationException("Invalid texture: " + img | |
2065 | +// + "Cubemap textures must contain 6 data units."); | |
2066 | +// } | |
2067 | +// for (int i = 0; i < 6; i++) { | |
2068 | +// TextureUtilGdx.uploadTextureBitmap(GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i), false, powerOf2); | |
2069 | +// } | |
2070 | +// } else { | |
2071 | +// // Standard jme3 image data | |
2072 | +// List<ByteBuffer> data = img.getData(); | |
2073 | +// if (data.size() != 6) { | |
2074 | +// logger.log(Level.WARNING, "Invalid texture: {0}\n" | |
2075 | +// + "Cubemap textures must contain 6 data units.", img); | |
2076 | +// return; | |
2077 | +// } | |
2078 | +// for (int i = 0; i < 6; i++) { | |
2079 | +// TextureUtilGdx.uploadTexture(img, GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, false, powerOf2); | |
2080 | +// } | |
2081 | +// } | |
2082 | + } else { | |
2083 | + // TODO | |
2084 | + TextureUtilGdx.uploadTexture(img, target, 0, 0, tdc, false, powerOf2); | |
2085 | + | |
2086 | + if (verboseLogging) { | |
2087 | + logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)"); | |
2088 | + } | |
2089 | + | |
2090 | + if (!img.hasMipmaps() && mips) { | |
2091 | + // No pregenerated mips available, | |
2092 | + // generate from base level if required | |
2093 | + if (verboseLogging) { | |
2094 | + logger.info("GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D)"); | |
2095 | + } | |
2096 | + Gdx.gl20.glGenerateMipmap(GL20.GL_TEXTURE_2D); | |
2097 | + } | |
2098 | + } | |
2099 | + | |
2100 | + img.clearUpdateNeeded(); | |
2101 | + } | |
2102 | + public void setTexture(int unit, Texture tex) { | |
2103 | + Image image = tex.getImage(); | |
2104 | + // TODO | |
2105 | + if (image.getData().size() == 0 || image.getFormat() == null) { | |
2106 | + return; | |
2107 | + } | |
2108 | + if (image.isUpdateNeeded()) { | |
2109 | +// logger.warning("setTexture: isUpdateNeeded"); | |
2110 | +// if (image.getEfficentData() instanceof Bitmap) { | |
2111 | +// Bitmap bmp = (Bitmap) image.getEfficentData(); | |
2112 | +// if (bmp != null) { | |
2113 | +// // Check if the bitmap got recycled, can happen after wakeup/restart | |
2114 | +// if (bmp.isRecycled()) { | |
2115 | +// // We need to reload the bitmap | |
2116 | +// DesktopAssetManager assetManager; | |
2117 | +// try { | |
2118 | +// assetManager = (DesktopAssetManager) ((AndroidHarness) JmeSystem.getActivity()).getJmeApplication().getAssetManager(); | |
2119 | +// } catch (ClassCastException ex) { | |
2120 | +// Application app = JmeSystem.getApplication(); | |
2121 | +// assetManager = (DesktopAssetManager) app.getAssetManager(); | |
2122 | +// } | |
2123 | +// assetManager.deleteFromCache((TextureKey) tex.getKey()); | |
2124 | +// Texture textureReloaded = assetManager.loadTexture((TextureKey) tex.getKey()); | |
2125 | +// image.setEfficentData(textureReloaded.getImage().getEfficentData()); | |
2126 | +// } | |
2127 | +// } | |
2128 | +// } | |
2129 | + updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels()); | |
2130 | + setupTextureParams(tex); | |
2131 | + } | |
2132 | + | |
2133 | + int texId = image.getId(); | |
2134 | + assert texId != -1; | |
2135 | + | |
2136 | + if (texId == -1) { | |
2137 | + logger.warning("error: texture image has -1 id"); | |
2138 | + } | |
2139 | + | |
2140 | + Image[] textures = context.boundTextures; | |
2141 | + | |
2142 | + int type = convertTextureType(tex.getType()); | |
2143 | +// if (!context.textureIndexList.moveToNew(unit)) { | |
2144 | +// if (context.boundTextureUnit != unit){ | |
2145 | +// glActiveTexture(GL_TEXTURE0 + unit); | |
2146 | +// context.boundTextureUnit = unit; | |
2147 | +// } | |
2148 | +// glEnable(type); | |
2149 | +// } | |
2150 | + | |
2151 | + if (context.boundTextureUnit != unit) { | |
2152 | + if (verboseLogging) { | |
2153 | + logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + " + unit + ")"); | |
2154 | + } | |
2155 | + } | |
2156 | + if (textures[unit] != image) { | |
2157 | + | |
2158 | + if (verboseLogging) { | |
2159 | + logger.info("GLES20.glBindTexture(" + type + ", " + texId + ")"); | |
2160 | + } | |
2161 | + | |
2162 | + Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE0 + unit); | |
2163 | + context.boundTextureUnit = unit; | |
2164 | + Gdx.gl20.glBindTexture(type, texId); | |
2165 | + textures[unit] = image; | |
2166 | + | |
2167 | + statistics.onTextureUse(tex.getImage(), true); | |
2168 | + } else { | |
2169 | + statistics.onTextureUse(tex.getImage(), false); | |
2170 | + } | |
2171 | + | |
2172 | +// setupTextureParams(tex); | |
2173 | + } | |
2174 | + | |
2175 | + public void clearTextureUnits() { | |
2176 | +// IDList textureList = context.textureIndexList; | |
2177 | +// Image[] textures = context.boundTextures; | |
2178 | +// for (int i = 0; i < textureList.oldLen; i++) { | |
2179 | +// int idx = textureList.oldList[i]; | |
2180 | +// if (context.boundTextureUnit != idx){ | |
2181 | +// GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + idx); | |
2182 | +// context.boundTextureUnit = idx; | |
2183 | +// } | |
2184 | +// GLES20.glDisable(GLES20.GL_TEXTURE_2D/*convertTextureType(textures[idx].getType())*/); | |
2185 | +// textures[idx] = null; | |
2186 | +// } | |
2187 | +// context.textureIndexList.copyNewToOld(); | |
2188 | + } | |
2189 | + | |
2190 | + public void deleteImage(Image image) { | |
2191 | + int texId = image.getId(); | |
2192 | + if (texId != -1) { | |
2193 | + intBuf1.put(0, texId); | |
2194 | + intBuf1.position(0).limit(1); | |
2195 | + | |
2196 | + if (verboseLogging) { | |
2197 | + logger.info("GLES20.glDeleteTexture(1, buffer)"); | |
2198 | + } | |
2199 | + | |
2200 | + Gdx.gl20.glDeleteTextures(1, intBuf1); | |
2201 | + image.resetObject(); | |
2202 | + | |
2203 | + statistics.onDeleteTexture(); | |
2204 | + } | |
2205 | + } | |
2206 | + | |
2207 | + /*********************************************************************\ | |
2208 | + |* Vertex Buffers and Attributes *| | |
2209 | + \*********************************************************************/ | |
2210 | + private int convertUsage(Usage usage) { | |
2211 | + switch (usage) { | |
2212 | + case Static: | |
2213 | + return GL20.GL_STATIC_DRAW; | |
2214 | + case Dynamic: | |
2215 | + return GL20.GL_DYNAMIC_DRAW; | |
2216 | + case Stream: | |
2217 | + return GL20.GL_STREAM_DRAW; | |
2218 | + default: | |
2219 | + throw new RuntimeException("Unknown usage type."); | |
2220 | + } | |
2221 | + } | |
2222 | + | |
2223 | + private int convertFormat(Format format) { | |
2224 | + switch (format) { | |
2225 | + case Byte: | |
2226 | + return GL20.GL_BYTE; | |
2227 | + case UnsignedByte: | |
2228 | + return GL20.GL_UNSIGNED_BYTE; | |
2229 | + case Short: | |
2230 | + return GL20.GL_SHORT; | |
2231 | + case UnsignedShort: | |
2232 | + return GL20.GL_UNSIGNED_SHORT; | |
2233 | + case Int: | |
2234 | + return GL20.GL_INT; | |
2235 | + case UnsignedInt: | |
2236 | + return GL20.GL_UNSIGNED_INT; | |
2237 | + /* | |
2238 | + case Half: | |
2239 | + return NVHalfFloat.GL_HALF_FLOAT_NV; | |
2240 | + // return ARBHalfFloatVertex.GL_HALF_FLOAT; | |
2241 | + */ | |
2242 | + case Float: | |
2243 | + return GL20.GL_FLOAT; | |
2244 | +// case Double: | |
2245 | +// return GLES20.GL_DOUBLE; | |
2246 | + default: | |
2247 | + throw new RuntimeException("Unknown buffer format."); | |
2248 | + | |
2249 | + } | |
2250 | + } | |
2251 | + | |
2252 | + public void updateBufferData(VertexBuffer vb) { | |
2253 | + | |
2254 | + if (verboseLogging) { | |
2255 | + logger.info("updateBufferData(" + vb + ")"); | |
2256 | + } | |
2257 | + | |
2258 | + int bufId = vb.getId(); | |
2259 | + boolean created = false; | |
2260 | + if (bufId == -1) { | |
2261 | + // create buffer | |
2262 | + | |
2263 | + if (verboseLogging) { | |
2264 | + logger.info("GLES20.glGenBuffers(" + 1 + ", buffer)"); | |
2265 | + } | |
2266 | + | |
2267 | + Gdx.gl20.glGenBuffers(1, intBuf1); | |
2268 | + bufId = intBuf1.get(0); | |
2269 | + vb.setId(bufId); | |
2270 | + objManager.registerForCleanup(vb); | |
2271 | + | |
2272 | + created = true; | |
2273 | + } | |
2274 | + | |
2275 | + // bind buffer | |
2276 | + int target; | |
2277 | + if (vb.getBufferType() == Type.Index) { | |
2278 | + target = GL20.GL_ELEMENT_ARRAY_BUFFER; | |
2279 | + | |
2280 | + if (verboseLogging) { | |
2281 | + logger.info("vb.getBufferType() == VertexBuffer.Type.Index"); | |
2282 | + } | |
2283 | + | |
2284 | + if (context.boundElementArrayVBO != bufId) { | |
2285 | + | |
2286 | + if (verboseLogging) { | |
2287 | + logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); | |
2288 | + } | |
2289 | + | |
2290 | + Gdx.gl20.glBindBuffer(target, bufId); | |
2291 | + context.boundElementArrayVBO = bufId; | |
2292 | + } | |
2293 | + } else { | |
2294 | + if (verboseLogging) { | |
2295 | + logger.info("vb.getBufferType() != VertexBuffer.Type.Index"); | |
2296 | + } | |
2297 | + | |
2298 | + target = GL20.GL_ARRAY_BUFFER; | |
2299 | + | |
2300 | + if (context.boundArrayVBO != bufId) { | |
2301 | + | |
2302 | + if (verboseLogging) { | |
2303 | + logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); | |
2304 | + } | |
2305 | + | |
2306 | + Gdx.gl20.glBindBuffer(target, bufId); | |
2307 | + context.boundArrayVBO = bufId; | |
2308 | + } | |
2309 | + } | |
2310 | + | |
2311 | + int usage = convertUsage(vb.getUsage()); | |
2312 | + vb.getData().clear(); | |
2313 | + | |
2314 | + if (created || vb.hasDataSizeChanged()) { | |
2315 | + // upload data based on format | |
2316 | + int size = vb.getData().capacity() * vb.getFormat().getComponentSize(); | |
2317 | + | |
2318 | + switch (vb.getFormat()) { | |
2319 | + case Byte: | |
2320 | + case UnsignedByte: | |
2321 | + | |
2322 | + if (verboseLogging) { | |
2323 | + logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); | |
2324 | + } | |
2325 | + | |
2326 | + Gdx.gl20.glBufferData(target, size, (ByteBuffer) vb.getData(), usage); | |
2327 | + break; | |
2328 | + // case Half: | |
2329 | + case Short: | |
2330 | + case UnsignedShort: | |
2331 | + | |
2332 | + if (verboseLogging) { | |
2333 | + logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); | |
2334 | + } | |
2335 | + | |
2336 | + Gdx.gl20.glBufferData(target, size, (ShortBuffer) vb.getData(), usage); | |
2337 | + break; | |
2338 | + case Int: | |
2339 | + case UnsignedInt: | |
2340 | + | |
2341 | + if (verboseLogging) { | |
2342 | + logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); | |
2343 | + } | |
2344 | + | |
2345 | + Gdx.gl20.glBufferData(target, size, (IntBuffer) vb.getData(), usage); | |
2346 | + break; | |
2347 | + case Float: | |
2348 | + if (verboseLogging) { | |
2349 | + logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); | |
2350 | + } | |
2351 | + | |
2352 | + Gdx.gl20.glBufferData(target, size, (FloatBuffer) vb.getData(), usage); | |
2353 | + break; | |
2354 | + case Double: | |
2355 | + if (verboseLogging) { | |
2356 | + logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); | |
2357 | + } | |
2358 | + | |
2359 | + Gdx.gl20.glBufferData(target, size, (DoubleBuffer) vb.getData(), usage); | |
2360 | + break; | |
2361 | + default: | |
2362 | + throw new RuntimeException("Unknown buffer format."); | |
2363 | + } | |
2364 | + } else { | |
2365 | + int size = vb.getData().capacity() * vb.getFormat().getComponentSize(); | |
2366 | + | |
2367 | + switch (vb.getFormat()) { | |
2368 | + case Byte: | |
2369 | + case UnsignedByte: | |
2370 | + if (verboseLogging) { | |
2371 | + logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); | |
2372 | + } | |
2373 | + | |
2374 | + Gdx.gl20.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData()); | |
2375 | + break; | |
2376 | + case Short: | |
2377 | + case UnsignedShort: | |
2378 | + if (verboseLogging) { | |
2379 | + logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); | |
2380 | + } | |
2381 | + | |
2382 | + Gdx.gl20.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData()); | |
2383 | + break; | |
2384 | + case Int: | |
2385 | + case UnsignedInt: | |
2386 | + if (verboseLogging) { | |
2387 | + logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); | |
2388 | + } | |
2389 | + | |
2390 | + Gdx.gl20.glBufferSubData(target, 0, size, (IntBuffer) vb.getData()); | |
2391 | + break; | |
2392 | + case Float: | |
2393 | + if (verboseLogging) { | |
2394 | + logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); | |
2395 | + } | |
2396 | + | |
2397 | + Gdx.gl20.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData()); | |
2398 | + break; | |
2399 | + case Double: | |
2400 | + if (verboseLogging) { | |
2401 | + logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); | |
2402 | + } | |
2403 | + | |
2404 | + Gdx.gl20.glBufferSubData(target, 0, size, (DoubleBuffer) vb.getData()); | |
2405 | + break; | |
2406 | + default: | |
2407 | + throw new RuntimeException("Unknown buffer format."); | |
2408 | + } | |
2409 | + } | |
2410 | +// }else{ | |
2411 | +// if (created || vb.hasDataSizeChanged()){ | |
2412 | +// glBufferData(target, vb.getData().capacity() * vb.getFormat().getComponentSize(), usage); | |
2413 | +// } | |
2414 | +// | |
2415 | +// ByteBuffer buf = glMapBuffer(target, | |
2416 | +// GL_WRITE_ONLY, | |
2417 | +// vb.getMappedData()); | |
2418 | +// | |
2419 | +// if (buf != vb.getMappedData()){ | |
2420 | +// buf = buf.order(ByteOrder.nativeOrder()); | |
2421 | +// vb.setMappedData(buf); | |
2422 | +// } | |
2423 | +// | |
2424 | +// buf.clear(); | |
2425 | +// | |
2426 | +// switch (vb.getFormat()){ | |
2427 | +// case Byte: | |
2428 | +// case UnsignedByte: | |
2429 | +// buf.put( (ByteBuffer) vb.getData() ); | |
2430 | +// break; | |
2431 | +// case Short: | |
2432 | +// case UnsignedShort: | |
2433 | +// buf.asShortBuffer().put( (ShortBuffer) vb.getData() ); | |
2434 | +// break; | |
2435 | +// case Int: | |
2436 | +// case UnsignedInt: | |
2437 | +// buf.asIntBuffer().put( (IntBuffer) vb.getData() ); | |
2438 | +// break; | |
2439 | +// case Float: | |
2440 | +// buf.asFloatBuffer().put( (FloatBuffer) vb.getData() ); | |
2441 | +// break; | |
2442 | +// case Double: | |
2443 | +// break; | |
2444 | +// default: | |
2445 | +// throw new RuntimeException("Unknown buffer format."); | |
2446 | +// } | |
2447 | +// | |
2448 | +// glUnmapBuffer(target); | |
2449 | +// } | |
2450 | + | |
2451 | + vb.clearUpdateNeeded(); | |
2452 | + } | |
2453 | + | |
2454 | + public void deleteBuffer(VertexBuffer vb) { | |
2455 | + int bufId = vb.getId(); | |
2456 | + if (bufId != -1) { | |
2457 | + // delete buffer | |
2458 | + intBuf1.put(0, bufId); | |
2459 | + intBuf1.position(0).limit(1); | |
2460 | + if (verboseLogging) { | |
2461 | + logger.info("GLES20.glDeleteBuffers(1, buffer)"); | |
2462 | + } | |
2463 | + | |
2464 | + Gdx.gl20.glDeleteBuffers(1, intBuf1); | |
2465 | + vb.resetObject(); | |
2466 | + } | |
2467 | + } | |
2468 | + | |
2469 | + public void clearVertexAttribs() { | |
2470 | + IDList attribList = context.attribIndexList; | |
2471 | + int oldLen = attribList.oldLen; | |
2472 | + for (int i = 0; i < oldLen; i++) { | |
2473 | + int idx = attribList.oldList[i]; | |
2474 | + | |
2475 | + if (verboseLogging) { | |
2476 | + logger.info("GLES20.glDisableVertexAttribArray(" + idx + ")"); | |
2477 | + } | |
2478 | + if (idx != -1) { | |
2479 | + Gdx.gl20.glDisableVertexAttribArray(idx); | |
2480 | + context.boundAttribs[idx] = null; | |
2481 | + } | |
2482 | + } | |
2483 | + context.attribIndexList.copyNewToOld(); | |
2484 | + } | |
2485 | + | |
2486 | + public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { | |
2487 | + if (verboseLogging) { | |
2488 | + logger.info("setVertexAttrib(" + vb + ", " + idb + ")"); | |
2489 | + } | |
2490 | + | |
2491 | + if (vb.getBufferType() == Type.Index) { | |
2492 | + throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); | |
2493 | + } | |
2494 | + | |
2495 | + if (vb.isUpdateNeeded() && idb == null) { | |
2496 | + updateBufferData(vb); | |
2497 | + } | |
2498 | + | |
2499 | + int programId = context.boundShaderProgram; | |
2500 | + if (programId > 0) { | |
2501 | + Attribute attrib = boundShader.getAttribute(vb.getBufferType()); | |
2502 | + int loc = attrib.getLocation(); | |
2503 | + if (loc == -1) { | |
2504 | + | |
2505 | + if (verboseLogging) { | |
2506 | + logger.warning("location is invalid for attrib: [" + vb.getBufferType().name() + "]"); | |
2507 | + } | |
2508 | + | |
2509 | + return; // not defined | |
2510 | + } | |
2511 | + | |
2512 | + if (loc == -2) { | |
2513 | +// stringBuf.setLength(0); | |
2514 | +// stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); | |
2515 | +// updateNameBuffer(); | |
2516 | + | |
2517 | + String attributeName = "in" + vb.getBufferType().name(); | |
2518 | + | |
2519 | + if (verboseLogging) { | |
2520 | + logger.info("GLES20.glGetAttribLocation(" + programId + ", " + attributeName + ")"); | |
2521 | + } | |
2522 | + | |
2523 | + loc = Gdx.gl20.glGetAttribLocation(programId, attributeName); | |
2524 | + | |
2525 | + // not really the name of it in the shader (inPosition\0) but | |
2526 | + // the internal name of the enum (Position). | |
2527 | + if (loc < 0) { | |
2528 | + attrib.setLocation(-1); | |
2529 | + | |
2530 | + if (verboseLogging) { | |
2531 | + logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]"); | |
2532 | + } | |
2533 | + | |
2534 | + return; // not available in shader. | |
2535 | + } else { | |
2536 | + attrib.setLocation(loc); | |
2537 | + } | |
2538 | + } | |
2539 | + | |
2540 | + VertexBuffer[] attribs = context.boundAttribs; | |
2541 | + if (!context.attribIndexList.moveToNew(loc)) { | |
2542 | + if (verboseLogging) { | |
2543 | + logger.info("GLES20.glEnableVertexAttribArray(" + loc + ")"); | |
2544 | + } | |
2545 | + | |
2546 | + Gdx.gl20.glEnableVertexAttribArray(loc); | |
2547 | + //System.out.println("Enabled ATTRIB IDX: "+loc); | |
2548 | + } | |
2549 | + if (attribs[loc] != vb) { | |
2550 | + // NOTE: Use id from interleaved buffer if specified | |
2551 | + int bufId = idb != null ? idb.getId() : vb.getId(); | |
2552 | + assert bufId != -1; | |
2553 | + | |
2554 | + if (bufId == -1) { | |
2555 | + logger.warning("invalid buffer id"); | |
2556 | + } | |
2557 | + | |
2558 | + if (context.boundArrayVBO != bufId) { | |
2559 | + if (verboseLogging) { | |
2560 | + logger.info("GLES20.glBindBuffer(" + GL20.GL_ARRAY_BUFFER + ", " + bufId + ")"); | |
2561 | + } | |
2562 | + Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, bufId); | |
2563 | + context.boundArrayVBO = bufId; | |
2564 | + } | |
2565 | + | |
2566 | +// vb.getData().clear(); | |
2567 | + | |
2568 | + if (verboseLogging) { | |
2569 | + logger.info("GLES20.glVertexAttribPointer(" | |
2570 | + + "location=" + loc + ", " | |
2571 | + + "numComponents=" + vb.getNumComponents() + ", " | |
2572 | + + "format=" + vb.getFormat() + ", " | |
2573 | + + "isNormalized=" + vb.isNormalized() + ", " | |
2574 | + + "stride=" + vb.getStride() + ", " | |
2575 | + + "data.capacity=" + vb.getData().capacity() + ")"); | |
2576 | + } | |
2577 | + | |
2578 | + Gdx.gl20.glVertexAttribPointer(loc, | |
2579 | + vb.getNumComponents(), | |
2580 | + convertFormat(vb.getFormat()), | |
2581 | + vb.isNormalized(), | |
2582 | + vb.getStride(), | |
2583 | + vb.getOffset()); | |
2584 | + | |
2585 | + attribs[loc] = vb; | |
2586 | + } | |
2587 | + } else { | |
2588 | + throw new IllegalStateException("Cannot render mesh without shader bound"); | |
2589 | + } | |
2590 | + } | |
2591 | + | |
2592 | + public void setVertexAttrib(VertexBuffer vb) { | |
2593 | + setVertexAttrib(vb, null); | |
2594 | + } | |
2595 | + | |
2596 | + public void drawTriangleArray(Mode mode, int count, int vertCount) { | |
2597 | + /* if (count > 1){ | |
2598 | + ARBDrawInstanced.glDrawArraysInstancedARB(convertElementMode(mode), 0, | |
2599 | + vertCount, count); | |
2600 | + }else{*/ | |
2601 | + if (verboseLogging) { | |
2602 | + logger.info("GLES20.glDrawArrays(" + vertCount + ")"); | |
2603 | + } | |
2604 | + | |
2605 | + Gdx.gl20.glDrawArrays(convertElementMode(mode), 0, vertCount); | |
2606 | + /* | |
2607 | + }*/ | |
2608 | + } | |
2609 | + | |
2610 | + public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { | |
2611 | + | |
2612 | + if (verboseLogging) { | |
2613 | + logger.info("drawTriangleList(" + count + ")"); | |
2614 | + } | |
2615 | + | |
2616 | + if (indexBuf.getBufferType() != Type.Index) { | |
2617 | + throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); | |
2618 | + } | |
2619 | + | |
2620 | + if (indexBuf.isUpdateNeeded()) { | |
2621 | + if (verboseLogging) { | |
2622 | + logger.info("updateBufferData for indexBuf."); | |
2623 | + } | |
2624 | + updateBufferData(indexBuf); | |
2625 | + } | |
2626 | + | |
2627 | + int bufId = indexBuf.getId(); | |
2628 | + assert bufId != -1; | |
2629 | + | |
2630 | + if (bufId == -1) { | |
2631 | + logger.info("invalid buffer id!"); | |
2632 | + } | |
2633 | + | |
2634 | + if (context.boundElementArrayVBO != bufId) { | |
2635 | + if (verboseLogging) { | |
2636 | + logger.log(Level.INFO, "GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, {0})", bufId); | |
2637 | + } | |
2638 | + | |
2639 | + Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, bufId); | |
2640 | + context.boundElementArrayVBO = bufId; | |
2641 | + } | |
2642 | + | |
2643 | + int vertCount = mesh.getVertexCount(); | |
2644 | + boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); | |
2645 | + | |
2646 | + Buffer indexData = indexBuf.getData(); | |
2647 | + | |
2648 | + if (mesh.getMode() == Mode.Hybrid) { | |
2649 | + int[] modeStart = mesh.getModeStart(); | |
2650 | + int[] elementLengths = mesh.getElementLengths(); | |
2651 | + | |
2652 | + int elMode = convertElementMode(Mode.Triangles); | |
2653 | + int fmt = convertFormat(indexBuf.getFormat()); | |
2654 | + int elSize = indexBuf.getFormat().getComponentSize(); | |
2655 | + int listStart = modeStart[0]; | |
2656 | + int stripStart = modeStart[1]; | |
2657 | + int fanStart = modeStart[2]; | |
2658 | + int curOffset = 0; | |
2659 | + for (int i = 0; i < elementLengths.length; i++) { | |
2660 | + if (i == stripStart) { | |
2661 | + elMode = convertElementMode(Mode.TriangleStrip); | |
2662 | + } else if (i == fanStart) { | |
2663 | + elMode = convertElementMode(Mode.TriangleStrip); | |
2664 | + } | |
2665 | + int elementLength = elementLengths[i]; | |
2666 | + | |
2667 | + if (useInstancing) { | |
2668 | + //ARBDrawInstanced. | |
2669 | + throw new IllegalArgumentException("instancing is not supported."); | |
2670 | + /* | |
2671 | + GLES20.glDrawElementsInstancedARB(elMode, | |
2672 | + elementLength, | |
2673 | + fmt, | |
2674 | + curOffset, | |
2675 | + count); | |
2676 | + */ | |
2677 | + } else { | |
2678 | + indexBuf.getData().position(curOffset); | |
2679 | + if (verboseLogging) { | |
2680 | + logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); | |
2681 | + } | |
2682 | + | |
2683 | + Gdx.gl20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); | |
2684 | + /* | |
2685 | + glDrawRangeElements(elMode, | |
2686 | + 0, | |
2687 | + vertCount, | |
2688 | + elementLength, | |
2689 | + fmt, | |
2690 | + curOffset); | |
2691 | + */ | |
2692 | + } | |
2693 | + | |
2694 | + curOffset += elementLength * elSize; | |
2695 | + } | |
2696 | + } else { | |
2697 | + if (useInstancing) { | |
2698 | + throw new IllegalArgumentException("instancing is not supported."); | |
2699 | + //ARBDrawInstanced. | |
2700 | +/* | |
2701 | + GLES20.glDrawElementsInstancedARB(convertElementMode(mesh.getMode()), | |
2702 | + indexBuf.getData().capacity(), | |
2703 | + convertFormat(indexBuf.getFormat()), | |
2704 | + 0, | |
2705 | + count); | |
2706 | + */ | |
2707 | + } else { | |
2708 | + indexData.clear(); | |
2709 | + | |
2710 | + if (verboseLogging) { | |
2711 | + logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); | |
2712 | + } | |
2713 | + | |
2714 | + Gdx.gl20.glDrawElements( | |
2715 | + convertElementMode(mesh.getMode()), | |
2716 | + indexBuf.getData().capacity(), | |
2717 | + convertFormat(indexBuf.getFormat()), | |
2718 | + 0); | |
2719 | + } | |
2720 | + } | |
2721 | + } | |
2722 | + | |
2723 | + /*********************************************************************\ | |
2724 | + |* Render Calls *| | |
2725 | + \*********************************************************************/ | |
2726 | + public int convertElementMode(Mode mode) { | |
2727 | + switch (mode) { | |
2728 | + case Points: | |
2729 | + return GL20.GL_POINTS; | |
2730 | + case Lines: | |
2731 | + return GL20.GL_LINES; | |
2732 | + case LineLoop: | |
2733 | + return GL20.GL_LINE_LOOP; | |
2734 | + case LineStrip: | |
2735 | + return GL20.GL_LINE_STRIP; | |
2736 | + case Triangles: | |
2737 | + return GL20.GL_TRIANGLES; | |
2738 | + case TriangleFan: | |
2739 | + return GL20.GL_TRIANGLE_FAN; | |
2740 | + case TriangleStrip: | |
2741 | + return GL20.GL_TRIANGLE_STRIP; | |
2742 | + default: | |
2743 | + throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode); | |
2744 | + } | |
2745 | + } | |
2746 | + | |
2747 | + public void updateVertexArray(Mesh mesh) { | |
2748 | + logger.log(Level.INFO, "updateVertexArray({0})", mesh); | |
2749 | + int id = mesh.getId(); | |
2750 | + /* | |
2751 | + if (id == -1){ | |
2752 | + IntBuffer temp = intBuf1; | |
2753 | + // ARBVertexArrayObject.glGenVertexArrays(temp); | |
2754 | + GLES20.glGenVertexArrays(temp); | |
2755 | + id = temp.get(0); | |
2756 | + mesh.setId(id); | |
2757 | + } | |
2758 | + | |
2759 | + if (context.boundVertexArray != id){ | |
2760 | + // ARBVertexArrayObject.glBindVertexArray(id); | |
2761 | + GLES20.glBindVertexArray(id); | |
2762 | + context.boundVertexArray = id; | |
2763 | + } | |
2764 | + */ | |
2765 | + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); | |
2766 | + if (interleavedData != null && interleavedData.isUpdateNeeded()) { | |
2767 | + updateBufferData(interleavedData); | |
2768 | + } | |
2769 | + | |
2770 | + SafeArrayList<VertexBuffer> buffersList = mesh.getBufferList(); | |
2771 | + for (int i = 0; i < buffersList.size(); i++) { | |
2772 | + VertexBuffer vb = buffersList.get(i); | |
2773 | + | |
2774 | + if (vb.getBufferType() == Type.InterleavedData | |
2775 | + || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers | |
2776 | + || vb.getBufferType() == Type.Index) { | |
2777 | + continue; | |
2778 | + } | |
2779 | + | |
2780 | + if (vb.getStride() == 0) { | |
2781 | + // not interleaved | |
2782 | + setVertexAttrib(vb); | |
2783 | + } else { | |
2784 | + // interleaved | |
2785 | + setVertexAttrib(vb, interleavedData); | |
2786 | + } | |
2787 | + } | |
2788 | + } | |
2789 | + | |
2790 | + /** | |
2791 | + * renderMeshVertexArray renders a mesh using vertex arrays | |
2792 | + * @param mesh | |
2793 | + * @param lod | |
2794 | + * @param count | |
2795 | + */ | |
2796 | + private void renderMeshVertexArray(Mesh mesh, int lod, int count) { | |
2797 | + if (verboseLogging) { | |
2798 | + logger.info("renderMeshVertexArray"); | |
2799 | + } | |
2800 | + | |
2801 | + // IntMap<VertexBuffer> buffers = mesh.getBuffers(); | |
2802 | + IntMap<VertexBuffer> buffers = mesh.getBuffers(); | |
2803 | + IntMap.Entry<VertexBuffer> table[] = buffers.getTable(); | |
2804 | + for (IntMap.Entry<VertexBuffer> entry : table) { | |
2805 | + if (entry == null) { | |
2806 | + continue; | |
2807 | + } | |
2808 | + VertexBuffer vb = entry.getValue(); | |
2809 | + | |
2810 | + if (vb.getBufferType() == Type.InterleavedData | |
2811 | + || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers | |
2812 | + || vb.getBufferType() == Type.Index) { | |
2813 | + continue; | |
2814 | + } | |
2815 | + | |
2816 | + if (vb.getStride() == 0) { | |
2817 | + // not interleaved | |
2818 | + setVertexAttrib_Array(vb); | |
2819 | + } else { | |
2820 | + // interleaved | |
2821 | + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); | |
2822 | + setVertexAttrib_Array(vb, interleavedData); | |
2823 | + } | |
2824 | + } | |
2825 | + | |
2826 | + VertexBuffer indices = null; | |
2827 | + if (mesh.getNumLodLevels() > 0) { | |
2828 | + indices = mesh.getLodLevel(lod); | |
2829 | + } else { | |
2830 | + indices = mesh.getBuffer(Type.Index);//buffers.get(Type.Index.ordinal()); | |
2831 | + } | |
2832 | + clearVertexAttribs(); | |
2833 | +// clearTextureUnits(); | |
2834 | + if (indices != null) { | |
2835 | + drawTriangleList_Array(indices, mesh, count); | |
2836 | + } else { | |
2837 | + if (verboseLogging) { | |
2838 | + logger.log(Level.INFO, "GLES20.glDrawArrays({0}, {1}, {2})", | |
2839 | + new Object[]{mesh.getMode(), 0, mesh.getVertexCount()}); | |
2840 | + } | |
2841 | + | |
2842 | + Gdx.gl20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); | |
2843 | + } | |
2844 | + } | |
2845 | + | |
2846 | + private void renderMeshDefault(Mesh mesh, int lod, int count) { | |
2847 | + if (verboseLogging) { | |
2848 | + logger.log(Level.INFO, "renderMeshDefault({0}, {1}, {2})", | |
2849 | + new Object[]{mesh, lod, count}); | |
2850 | + } | |
2851 | + VertexBuffer indices = null; | |
2852 | + | |
2853 | + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); | |
2854 | + if (interleavedData != null && interleavedData.isUpdateNeeded()) { | |
2855 | + updateBufferData(interleavedData); | |
2856 | + } | |
2857 | + | |
2858 | + //IntMap<VertexBuffer> buffers = mesh.getBuffers(); ; | |
2859 | + if (mesh.getNumLodLevels() > 0) { | |
2860 | + indices = mesh.getLodLevel(lod); | |
2861 | + } else { | |
2862 | + indices = mesh.getBuffer(Type.Index);// buffers.get(Type.Index.ordinal()); | |
2863 | + } | |
2864 | + SafeArrayList<VertexBuffer> buffersList = mesh.getBufferList(); | |
2865 | + for (int i = 0; i < buffersList.size(); i++) { | |
2866 | + VertexBuffer vb = buffersList.get(i); | |
2867 | + | |
2868 | + if (vb.getBufferType() == Type.InterleavedData | |
2869 | + || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers | |
2870 | + || vb.getBufferType() == Type.Index) { | |
2871 | + continue; | |
2872 | + } | |
2873 | + | |
2874 | + if (vb.getStride() == 0) { | |
2875 | + // not interleaved | |
2876 | + setVertexAttrib(vb); | |
2877 | + } else { | |
2878 | + // interleaved | |
2879 | + setVertexAttrib(vb, interleavedData); | |
2880 | + } | |
2881 | + } | |
2882 | + clearVertexAttribs(); | |
2883 | +// clearTextureUnits(); | |
2884 | + if (indices != null) { | |
2885 | + drawTriangleList(indices, mesh, count); | |
2886 | + } else { | |
2887 | +// throw new UnsupportedOperationException("Cannot render without index buffer"); | |
2888 | + if (verboseLogging) { | |
2889 | + logger.log(Level.INFO, "GLES20.glDrawArrays({0}, 0, {1})", | |
2890 | + new Object[]{convertElementMode(mesh.getMode()), mesh.getVertexCount()}); | |
2891 | + } | |
2892 | + | |
2893 | + Gdx.gl20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); | |
2894 | + } | |
2895 | + } | |
2896 | + | |
2897 | + public void renderMesh(Mesh mesh, int lod, int count) { | |
2898 | + if (context.pointSize != mesh.getPointSize()) { | |
2899 | + | |
2900 | + if (verboseLogging) { | |
2901 | + logger.log(Level.INFO, "GLES10.glPointSize({0})", mesh.getPointSize()); | |
2902 | + } | |
2903 | + // TODO | |
2904 | + Gdx.gl10.glPointSize(mesh.getPointSize()); | |
2905 | + context.pointSize = mesh.getPointSize(); | |
2906 | + } | |
2907 | + if (context.lineWidth != mesh.getLineWidth()) { | |
2908 | + | |
2909 | + if (verboseLogging) { | |
2910 | + logger.log(Level.INFO, "GLES20.glLineWidth({0})", mesh.getLineWidth()); | |
2911 | + } | |
2912 | + | |
2913 | + Gdx.gl20.glLineWidth(mesh.getLineWidth()); | |
2914 | + context.lineWidth = mesh.getLineWidth(); | |
2915 | + } | |
2916 | + | |
2917 | + statistics.onMeshDrawn(mesh, lod); | |
2918 | +// if (GLContext.getCapabilities().GL_ARB_vertex_array_object){ | |
2919 | +// renderMeshVertexArray(mesh, lod, count); | |
2920 | +// }else{ | |
2921 | + | |
2922 | + if (useVBO) { | |
2923 | + if (verboseLogging) { | |
2924 | + logger.info("RENDERING A MESH USING VertexBufferObject"); | |
2925 | + } | |
2926 | + | |
2927 | + renderMeshDefault(mesh, lod, count); | |
2928 | + } else { | |
2929 | + if (verboseLogging) { | |
2930 | + logger.info("RENDERING A MESH USING VertexArray"); | |
2931 | + } | |
2932 | + | |
2933 | + renderMeshVertexArray(mesh, lod, count); | |
2934 | + } | |
2935 | + | |
2936 | +// } | |
2937 | + } | |
2938 | + | |
2939 | + private void checkGLError() { | |
2940 | + } | |
2941 | + | |
2942 | + private void checkGLError2() { | |
2943 | + int error; | |
2944 | + while ((error = Gdx.gl20.glGetError()) != GL20.GL_NO_ERROR) { | |
2945 | + logger.log(Level.WARNING, "glError {0}", error); | |
2946 | + // throw new RuntimeException("glError " + error); | |
2947 | + } | |
2948 | + } | |
2949 | + | |
2950 | + private boolean log(String message) { | |
2951 | + logger.info(message); | |
2952 | + return true; | |
2953 | + } | |
2954 | + | |
2955 | + /** | |
2956 | + * drawTriangleList_Array uses Vertex Array | |
2957 | + * @param indexBuf | |
2958 | + * @param mesh | |
2959 | + * @param count | |
2960 | + */ | |
2961 | + public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count) { | |
2962 | + if (verboseLogging) { | |
2963 | + logger.log(Level.INFO, "drawTriangleList_Array(Count = {0})", count); | |
2964 | + } | |
2965 | + | |
2966 | + if (indexBuf.getBufferType() != Type.Index) { | |
2967 | + throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); | |
2968 | + } | |
2969 | + | |
2970 | + boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); | |
2971 | + if (useInstancing) { | |
2972 | + throw new IllegalArgumentException("Caps.MeshInstancing is not supported."); | |
2973 | + } | |
2974 | + | |
2975 | + int vertCount = mesh.getVertexCount(); | |
2976 | + Buffer indexData = indexBuf.getData(); | |
2977 | + indexData.clear(); | |
2978 | + | |
2979 | + if (mesh.getMode() == Mode.Hybrid) { | |
2980 | + int[] modeStart = mesh.getModeStart(); | |
2981 | + int[] elementLengths = mesh.getElementLengths(); | |
2982 | + | |
2983 | + int elMode = convertElementMode(Mode.Triangles); | |
2984 | + int fmt = convertFormat(indexBuf.getFormat()); | |
2985 | + int elSize = indexBuf.getFormat().getComponentSize(); | |
2986 | + int listStart = modeStart[0]; | |
2987 | + int stripStart = modeStart[1]; | |
2988 | + int fanStart = modeStart[2]; | |
2989 | + int curOffset = 0; | |
2990 | + for (int i = 0; i < elementLengths.length; i++) { | |
2991 | + if (i == stripStart) { | |
2992 | + elMode = convertElementMode(Mode.TriangleStrip); | |
2993 | + } else if (i == fanStart) { | |
2994 | + elMode = convertElementMode(Mode.TriangleStrip); | |
2995 | + } | |
2996 | + int elementLength = elementLengths[i]; | |
2997 | + | |
2998 | + indexBuf.getData().position(curOffset); | |
2999 | + if (verboseLogging) { | |
3000 | + logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); | |
3001 | + } | |
3002 | + | |
3003 | + Gdx.gl20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); | |
3004 | + | |
3005 | + curOffset += elementLength * elSize; | |
3006 | + } | |
3007 | + } else { | |
3008 | + if (verboseLogging) { | |
3009 | + logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); | |
3010 | + } | |
3011 | + | |
3012 | + Gdx.gl20.glDrawElements( | |
3013 | + convertElementMode(mesh.getMode()), | |
3014 | + indexBuf.getData().capacity(), | |
3015 | + convertFormat(indexBuf.getFormat()), | |
3016 | + indexBuf.getData()); | |
3017 | + } | |
3018 | + } | |
3019 | + | |
3020 | + /** | |
3021 | + * setVertexAttrib_Array uses Vertex Array | |
3022 | + * @param vb | |
3023 | + * @param idb | |
3024 | + */ | |
3025 | + public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb) { | |
3026 | + if (verboseLogging) { | |
3027 | + logger.log(Level.INFO, "setVertexAttrib_Array({0}, {1})", new Object[]{vb, idb}); | |
3028 | + } | |
3029 | + | |
3030 | + if (vb.getBufferType() == Type.Index) { | |
3031 | + throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); | |
3032 | + } | |
3033 | + | |
3034 | + // Get shader | |
3035 | + int programId = context.boundShaderProgram; | |
3036 | + if (programId > 0) { | |
3037 | + VertexBuffer[] attribs = context.boundAttribs; | |
3038 | + | |
3039 | + Attribute attrib = boundShader.getAttribute(vb.getBufferType()); | |
3040 | + int loc = attrib.getLocation(); | |
3041 | + if (loc == -1) { | |
3042 | + //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]"); | |
3043 | + if (verboseLogging) { | |
3044 | + logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); | |
3045 | + } | |
3046 | + return; | |
3047 | + } else if (loc == -2) { | |
3048 | + String attributeName = "in" + vb.getBufferType().name(); | |
3049 | + | |
3050 | + if (verboseLogging) { | |
3051 | + logger.log(Level.INFO, "GLES20.glGetAttribLocation({0}, {1})", new Object[]{programId, attributeName}); | |
3052 | + } | |
3053 | + | |
3054 | + loc = Gdx.gl20.glGetAttribLocation(programId, attributeName); | |
3055 | + if (loc < 0) { | |
3056 | + attrib.setLocation(-1); | |
3057 | + if (verboseLogging) { | |
3058 | + logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); | |
3059 | + } | |
3060 | + return; // not available in shader. | |
3061 | + } else { | |
3062 | + attrib.setLocation(loc); | |
3063 | + } | |
3064 | + | |
3065 | + } // if (loc == -2) | |
3066 | + | |
3067 | + if ((attribs[loc] != vb) || vb.isUpdateNeeded()) { | |
3068 | + System.err.println("isUpdateNeeded "+vb.isUpdateNeeded()); | |
3069 | + vb.clearUpdateNeeded(); | |
3070 | + // NOTE: Use data from interleaved buffer if specified | |
3071 | + VertexBuffer avb = idb != null ? idb : vb; | |
3072 | + avb.getData().clear(); | |
3073 | + avb.getData().position(vb.getOffset()); | |
3074 | + | |
3075 | + if (verboseLogging) { | |
3076 | + logger.log(Level.INFO, | |
3077 | + "GLES20.glVertexAttribPointer(" | |
3078 | + + "location={0}, " | |
3079 | + + "numComponents={1}, " | |
3080 | + + "format={2}, " | |
3081 | + + "isNormalized={3}, " | |
3082 | + + "stride={4}, " | |
3083 | + + "data.capacity={5})", | |
3084 | + new Object[]{loc, vb.getNumComponents(), | |
3085 | + vb.getFormat(), | |
3086 | + vb.isNormalized(), | |
3087 | + vb.getStride(), | |
3088 | + avb.getData().capacity()}); | |
3089 | + } | |
3090 | + | |
3091 | + | |
3092 | + // Upload attribute data | |
3093 | + | |
3094 | + Gdx.gl20.glVertexAttribPointer(loc, | |
3095 | + vb.getNumComponents(), | |
3096 | + convertFormat(vb.getFormat()), | |
3097 | + vb.isNormalized(), | |
3098 | + vb.getStride(), | |
3099 | + convBuffer(avb.getData())); | |
3100 | + checkGLError(); | |
3101 | + | |
3102 | + Gdx.gl20.glEnableVertexAttribArray(loc); | |
3103 | + | |
3104 | + attribs[loc] = vb; | |
3105 | + } // if (attribs[loc] != vb) | |
3106 | + } else { | |
3107 | + throw new IllegalStateException("Cannot render mesh without shader bound"); | |
3108 | + } | |
3109 | + } | |
3110 | + private ByteBuffer convBuffer(Buffer buf) { | |
3111 | + System.err.println("convBuffer"); | |
3112 | + if (buf instanceof FloatBuffer) { | |
3113 | + System.err.println("FloatBuffer"); | |
3114 | + FloatBuffer fb = (FloatBuffer)buf; | |
3115 | + ByteBuffer bb = BufferUtils.createByteBuffer(buf.capacity() * 4); | |
3116 | + FloatBuffer fb2 = bb.asFloatBuffer(); | |
3117 | + fb2.put(fb); | |
3118 | + return bb; | |
3119 | + } else if (buf instanceof ShortBuffer) { | |
3120 | + System.err.println("ShortBuffer"); | |
3121 | + | |
3122 | + ShortBuffer sb = (ShortBuffer)buf; | |
3123 | + ByteBuffer bb = BufferUtils.createByteBuffer(buf.capacity() * 2); | |
3124 | + ShortBuffer sb2 = bb.asShortBuffer(); | |
3125 | + sb2.put(sb); | |
3126 | + return bb; | |
3127 | + } else { | |
3128 | + return (ByteBuffer)buf; | |
3129 | + //throw new RuntimeException("type = "+buf.getClass().getName()); | |
3130 | + } | |
3131 | + } | |
3132 | + | |
3133 | + /** | |
3134 | + * setVertexAttrib_Array uses Vertex Array | |
3135 | + * @param vb | |
3136 | + */ | |
3137 | + public void setVertexAttrib_Array(VertexBuffer vb) { | |
3138 | + setVertexAttrib_Array(vb, null); | |
3139 | + } | |
3140 | + | |
3141 | + public void setAlphaToCoverage(boolean value) { | |
3142 | + if (value) { | |
3143 | + Gdx.gl20.glEnable(GL20.GL_SAMPLE_ALPHA_TO_COVERAGE); | |
3144 | + } else { | |
3145 | + Gdx.gl20.glDisable(GL20.GL_SAMPLE_ALPHA_TO_COVERAGE); | |
3146 | + } | |
3147 | + } | |
3148 | + | |
3149 | + @Override | |
3150 | + public void invalidateState() { | |
3151 | + context.reset(); | |
3152 | + boundShader = null; | |
3153 | + lastFb = null; | |
3154 | + } | |
3155 | + | |
3156 | + public void resetBoundsTexture() { | |
3157 | + context.boundTextures[0] = null; | |
3158 | + if (context.boundTextureUnit != 0) { | |
3159 | + Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE0); | |
3160 | + context.boundTextureUnit = 0; | |
3161 | + } | |
3162 | +// GLES20.glDisable(GLES20.GL_TEXTURE_2D); | |
3163 | + Gdx.gl20.glBindTexture(GL20.GL_TEXTURE_2D, 0); | |
3164 | + // context.boundTextureUnit = -2; | |
3165 | +// context.boundElementArrayVBO = -2; | |
3166 | +// context.boundShaderProgram = -1; | |
3167 | +// context.boundArrayVBO = -1; | |
3168 | +// context.boundElementArrayVBO = -1; | |
3169 | + | |
3170 | + if (context.boundElementArrayVBO != 0) { | |
3171 | + | |
3172 | + | |
3173 | + Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0); | |
3174 | + context.boundElementArrayVBO = 0; | |
3175 | + } | |
3176 | + if (context.boundArrayVBO != 0) { | |
3177 | + Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0); | |
3178 | + context.boundArrayVBO = 0; | |
3179 | + } | |
3180 | + if (context.boundShaderProgram != 0) { | |
3181 | + Gdx.gl20.glUseProgram(0); | |
3182 | + checkGLError(); | |
3183 | + boundShader = null; | |
3184 | + context.boundShaderProgram = 0; | |
3185 | + } | |
3186 | + } | |
3187 | +} |
@@ -0,0 +1,499 @@ | ||
1 | +package com.jme3.renderer.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.Gdx; | |
4 | +import com.badlogic.gdx.graphics.GL10; | |
5 | +import com.badlogic.gdx.graphics.GL20; | |
6 | +import com.jme3.asset.DesktopAssetManager; | |
7 | +import com.jme3.math.FastMath; | |
8 | +import com.jme3.system.JmeSystem; | |
9 | +import com.jme3.texture.Image; | |
10 | +import com.jme3.texture.Image.Format; | |
11 | +import java.nio.ByteBuffer; | |
12 | +import java.util.logging.Logger; | |
13 | + | |
14 | +public class TextureUtilGdx { | |
15 | + public static boolean ENABLE_COMPRESSION = true; | |
16 | + private static boolean NPOT = false; | |
17 | + private static boolean ETC1support = false; | |
18 | + private static boolean DXT1 = false; | |
19 | + private static boolean DEPTH24_STENCIL8 = false; | |
20 | + private static boolean DEPTH_TEXTURE = true; | |
21 | + private static boolean RGBA8 = false; | |
22 | + | |
23 | + // Same constant used by both GL_ARM_rgba8 and GL_OES_rgb8_rgba8. | |
24 | + private static final int GL_RGBA8 = 0x8058; | |
25 | + | |
26 | + private static final int GL_DXT1 = 0x83F0; | |
27 | + private static final int GL_DXT1A = 0x83F1; | |
28 | + | |
29 | + private static final int GL_DEPTH_STENCIL_OES = 0x84F9; | |
30 | + private static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; | |
31 | + private static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; | |
32 | + | |
33 | + public static int convertTextureFormat(Format fmt){ | |
34 | + switch (fmt){ | |
35 | + case Alpha16: | |
36 | + case Alpha8: | |
37 | + return GL10.GL_ALPHA; | |
38 | + case Luminance8Alpha8: | |
39 | + case Luminance16Alpha16: | |
40 | + return GL10.GL_LUMINANCE_ALPHA; | |
41 | + case Luminance8: | |
42 | + case Luminance16: | |
43 | + return GL10.GL_LUMINANCE; | |
44 | + case RGB10: | |
45 | + case RGB16: | |
46 | + case BGR8: | |
47 | + case RGB8: | |
48 | + case RGB565: | |
49 | + return GL10.GL_RGB; | |
50 | + case RGB5A1: | |
51 | + case RGBA16: | |
52 | + case RGBA8: | |
53 | + return GL10.GL_RGBA; | |
54 | + | |
55 | + case Depth: | |
56 | + return Gdx.gl20.GL_DEPTH_COMPONENT; | |
57 | + case Depth16: | |
58 | + return Gdx.gl20.GL_DEPTH_COMPONENT16; | |
59 | + case Depth24: | |
60 | + case Depth32: | |
61 | + case Depth32F: | |
62 | + throw new UnsupportedOperationException("Unsupported depth format: " + fmt); | |
63 | + | |
64 | + case DXT1A: | |
65 | + throw new UnsupportedOperationException("Unsupported format: " + fmt); | |
66 | + default: | |
67 | + throw new UnsupportedOperationException("Unrecognized format: " + fmt); | |
68 | + } | |
69 | + } | |
70 | + // TODO | |
71 | +// private static void buildMipmap(Bitmap bitmap) { | |
72 | +// int level = 0; | |
73 | +// int height = bitmap.getHeight(); | |
74 | +// int width = bitmap.getWidth(); | |
75 | +// | |
76 | +// while (height >= 1 || width >= 1) { | |
77 | +// //First of all, generate the texture from our bitmap and set it to the according level | |
78 | +// | |
79 | +// GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0); | |
80 | +////checkGLError(); | |
81 | +// if (height == 1 || width == 1) { | |
82 | +// break; | |
83 | +// } | |
84 | +// | |
85 | +// //Increase the mipmap level | |
86 | +// level++; | |
87 | +// | |
88 | +// height /= 2; | |
89 | +// width /= 2; | |
90 | +// Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); | |
91 | +// | |
92 | +// bitmap.recycle(); | |
93 | +// bitmap = bitmap2; | |
94 | +// } | |
95 | +// }bitmap2 | |
96 | +// // TODO | |
97 | +// /** | |
98 | +// * <code>uploadTextureBitmap</code> uploads a native android bitmap | |
99 | +// * @param target | |
100 | +// * @param bitmap | |
101 | +// * @param generateMips | |
102 | +// * @param powerOf2 | |
103 | +// */ | |
104 | +// public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2) { | |
105 | +// int MAX_RETRY_COUNT = 1; | |
106 | +// for(int retryCount = 0;retryCount<MAX_RETRY_COUNT;retryCount++) { | |
107 | +// try { | |
108 | +// uploadTextureBitmap2(target, bitmap, generateMips, powerOf2); | |
109 | +// }catch(OutOfMemoryError ex) { | |
110 | +// if (!(retryCount < MAX_RETRY_COUNT)){ | |
111 | +// throw ex; | |
112 | +// } | |
113 | +// DesktopAssetManager assetManager = | |
114 | +// (DesktopAssetManager)((AndroidHarness)JmeSystem.getActivity()) | |
115 | +// .getJmeApplication().getAssetManager(); | |
116 | +// assetManager.clearCache(); | |
117 | +// System.gc(); | |
118 | +// System.runFinalization(); | |
119 | +// } | |
120 | +// } | |
121 | +// } | |
122 | +// /** | |
123 | +// * <code>uploadTextureBitmap</code> uploads a native android bitmap | |
124 | +// * @param target | |
125 | +// * @param bitmap | |
126 | +// * @param generateMips | |
127 | +// * @param powerOf2 | |
128 | +// */ | |
129 | +// private static void uploadTextureBitmap2(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2) | |
130 | +// { | |
131 | +// if (bitmap.isRecycled()) { | |
132 | +// throw new RuntimeException("bitmap is recycled."); | |
133 | +// } | |
134 | +// if (!powerOf2) | |
135 | +// { | |
136 | +// int width = bitmap.getWidth(); | |
137 | +// int height = bitmap.getHeight(); | |
138 | +// if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height) | |
139 | +// /*|| width >= 512 || height >= 512*/) | |
140 | +// { | |
141 | +// // scale to power of two | |
142 | +// width = FastMath.nearestPowerOfTwo(width); | |
143 | +// height = FastMath.nearestPowerOfTwo(height); | |
144 | +//// while(width >= 512) { | |
145 | +//// width = width / 2; | |
146 | +//// } | |
147 | +//// while(height >= 512) { | |
148 | +//// height = height / 2; | |
149 | +//// } | |
150 | +// Logger.getLogger(TextureUtil.class.getName()).warning("texture size changed."); | |
151 | +// Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); | |
152 | +// bitmap.recycle(); | |
153 | +// bitmap = bitmap2; | |
154 | +// } | |
155 | +// } | |
156 | +// | |
157 | +// if (generateMips) | |
158 | +// { | |
159 | +// buildMipmap(bitmap); | |
160 | +// } | |
161 | +// else | |
162 | +// { | |
163 | +// // TODO | |
164 | +// GLUtils.texImage2D(target, 0, bitmap, 0); | |
165 | +////checkGLError(); | |
166 | +////bitmap.recycle(); | |
167 | +// } | |
168 | +// } | |
169 | + private static void unsupportedFormat(Format fmt) { | |
170 | + throw new UnsupportedOperationException("The image format '" + fmt + "' is unsupported by the video hardware."); | |
171 | + } | |
172 | + | |
173 | + public static AndroidGLImageFormat getImageFormat(Format fmt) throws UnsupportedOperationException { | |
174 | + AndroidGLImageFormat imageFormat = new AndroidGLImageFormat(); | |
175 | + switch (fmt) { | |
176 | + case RGBA16: | |
177 | + case RGB16: | |
178 | + case RGB10: | |
179 | + case Luminance16: | |
180 | + case Luminance16Alpha16: | |
181 | + case Alpha16: | |
182 | + case Depth32: | |
183 | + case Depth32F: | |
184 | + throw new UnsupportedOperationException("The image format '" | |
185 | + + fmt + "' is not supported by OpenGL ES 2.0 specification."); | |
186 | + case Alpha8: | |
187 | + imageFormat.format = GL20.GL_ALPHA; | |
188 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
189 | + if (RGBA8) { | |
190 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
191 | + } else { | |
192 | + // Highest precision alpha supported by vanilla OGLES2 | |
193 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGBA4; | |
194 | + } | |
195 | + break; | |
196 | + case Luminance8: | |
197 | + imageFormat.format = GL20.GL_LUMINANCE; | |
198 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
199 | + if (RGBA8) { | |
200 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
201 | + } else { | |
202 | + // Highest precision luminance supported by vanilla OGLES2 | |
203 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGB565; | |
204 | + } | |
205 | + break; | |
206 | + case Luminance8Alpha8: | |
207 | + imageFormat.format = GL20.GL_LUMINANCE_ALPHA; | |
208 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
209 | + if (RGBA8) { | |
210 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
211 | + } else { | |
212 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGBA4; | |
213 | + } | |
214 | + break; | |
215 | + case RGB565: | |
216 | + imageFormat.format = GL20.GL_RGB; | |
217 | + imageFormat.dataType = GL20.GL_UNSIGNED_SHORT_5_6_5; | |
218 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGB565; | |
219 | + break; | |
220 | + case ARGB4444: | |
221 | + imageFormat.format = GL20.GL_RGBA4; | |
222 | + imageFormat.dataType = GL20.GL_UNSIGNED_SHORT_4_4_4_4; | |
223 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGBA4; | |
224 | + break; | |
225 | + case RGB5A1: | |
226 | + imageFormat.format = GL20.GL_RGBA; | |
227 | + imageFormat.dataType = GL20.GL_UNSIGNED_SHORT_5_5_5_1; | |
228 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGB5_A1; | |
229 | + break; | |
230 | + case RGB8: | |
231 | + imageFormat.format = GL20.GL_RGB; | |
232 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
233 | + if (RGBA8) { | |
234 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
235 | + } else { | |
236 | + // Fallback: Use RGB565 if RGBA8 is not available. | |
237 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGB565; | |
238 | + } | |
239 | + break; | |
240 | + case BGR8: | |
241 | + imageFormat.format = GL20.GL_RGB; | |
242 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
243 | + if (RGBA8) { | |
244 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
245 | + } else { | |
246 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGB565; | |
247 | + } | |
248 | + break; | |
249 | + case RGBA8: | |
250 | + imageFormat.format = GL20.GL_RGBA; | |
251 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
252 | + if (RGBA8) { | |
253 | + imageFormat.renderBufferStorageFormat = GL_RGBA8; | |
254 | + } else { | |
255 | + imageFormat.renderBufferStorageFormat = GL20.GL_RGBA4; | |
256 | + } | |
257 | + break; | |
258 | + case Depth: | |
259 | + case Depth16: | |
260 | + if (!DEPTH_TEXTURE) { | |
261 | + unsupportedFormat(fmt); | |
262 | + } | |
263 | + imageFormat.format = GL20.GL_DEPTH_COMPONENT; | |
264 | + imageFormat.dataType = GL20.GL_UNSIGNED_SHORT; | |
265 | + imageFormat.renderBufferStorageFormat = GL20.GL_DEPTH_COMPONENT16; | |
266 | + break; | |
267 | + case Depth24: | |
268 | +// case Depth24Stencil8: | |
269 | +// if (!DEPTH_TEXTURE) { | |
270 | +// unsupportedFormat(fmt); | |
271 | +// } | |
272 | +// if (DEPTH24_STENCIL8) { | |
273 | +// // NEW: True Depth24 + Stencil8 format. | |
274 | +// imageFormat.format = GL_DEPTH_STENCIL_OES; | |
275 | +// imageFormat.dataType = GL_UNSIGNED_INT_24_8_OES; | |
276 | +// imageFormat.renderBufferStorageFormat = GL_DEPTH24_STENCIL8_OES; | |
277 | +// } else { | |
278 | +// // Vanilla OGLES2, only Depth16 available. | |
279 | +// imageFormat.format = GLES20.GL_DEPTH_COMPONENT; | |
280 | +// imageFormat.dataType = GLES20.GL_UNSIGNED_SHORT; | |
281 | +// imageFormat.renderBufferStorageFormat = GLES20.GL_DEPTH_COMPONENT16; | |
282 | +// } | |
283 | +// break; | |
284 | + case DXT1: | |
285 | + if (!DXT1) { | |
286 | + unsupportedFormat(fmt); | |
287 | + } | |
288 | + imageFormat.format = GL_DXT1; | |
289 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
290 | + imageFormat.compress = true; | |
291 | + break; | |
292 | + case DXT1A: | |
293 | + if (!DXT1) { | |
294 | + unsupportedFormat(fmt); | |
295 | + } | |
296 | + imageFormat.format = GL_DXT1A; | |
297 | + imageFormat.dataType = GL20.GL_UNSIGNED_BYTE; | |
298 | + imageFormat.compress = true; | |
299 | + break; | |
300 | + default: | |
301 | + throw new UnsupportedOperationException("Unrecognized format: " + fmt); | |
302 | + } | |
303 | + return imageFormat; | |
304 | + } | |
305 | + public static class AndroidGLImageFormat { | |
306 | + | |
307 | + boolean compress = false; | |
308 | + int format = -1; | |
309 | + int renderBufferStorageFormat = -1; | |
310 | + int dataType = -1; | |
311 | + } | |
312 | + public static void uploadTexture( | |
313 | + Image img, | |
314 | + int target, | |
315 | + int index, | |
316 | + int border, | |
317 | + boolean tdc, | |
318 | + boolean generateMips, | |
319 | + boolean powerOf2){ | |
320 | + // TODO | |
321 | +// if (img.getEfficentData() instanceof Bitmap){ | |
322 | +// Bitmap bitmap = (Bitmap) img.getEfficentData(); | |
323 | +// uploadTextureBitmap(target, bitmap, generateMips, powerOf2); | |
324 | +// return; | |
325 | +// } | |
326 | + | |
327 | + Format fmt = img.getFormat(); | |
328 | + ByteBuffer data; | |
329 | + if (index >= 0 || img.getData() != null && img.getData().size() > 0){ | |
330 | + data = img.getData(index); | |
331 | + }else{ | |
332 | + data = null; | |
333 | + } | |
334 | + | |
335 | + int width = img.getWidth(); | |
336 | + int height = img.getHeight(); | |
337 | + int depth = img.getDepth(); | |
338 | + | |
339 | + boolean compress = false; | |
340 | + int internalFormat = -1; | |
341 | + int format = -1; | |
342 | + int dataType = -1; | |
343 | + | |
344 | + switch (fmt){ | |
345 | + case Alpha16: | |
346 | + case Alpha8: | |
347 | + format = GL20.GL_ALPHA; | |
348 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
349 | + break; | |
350 | + case Luminance8: | |
351 | + format = GL20.GL_LUMINANCE; | |
352 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
353 | + break; | |
354 | + case Luminance8Alpha8: | |
355 | + format = GL20.GL_LUMINANCE_ALPHA; | |
356 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
357 | + break; | |
358 | + case Luminance16Alpha16: | |
359 | + format = GL20.GL_LUMINANCE_ALPHA; | |
360 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
361 | + break; | |
362 | + case Luminance16: | |
363 | + format = GL20.GL_LUMINANCE; | |
364 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
365 | + break; | |
366 | + case RGB565: | |
367 | + format = GL20.GL_RGB; | |
368 | + internalFormat = GL20.GL_RGB565; | |
369 | + dataType = GL20.GL_UNSIGNED_SHORT_5_6_5; | |
370 | + break; | |
371 | + case ARGB4444: | |
372 | + format = GL20.GL_RGBA; | |
373 | + dataType = GL20.GL_UNSIGNED_SHORT_4_4_4_4; | |
374 | + break; | |
375 | + case RGB10: | |
376 | + format = GL20.GL_RGB; | |
377 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
378 | + break; | |
379 | + case RGB16: | |
380 | + format = GL20.GL_RGB; | |
381 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
382 | + break; | |
383 | + case RGB5A1: | |
384 | + format = GL20.GL_RGBA; | |
385 | + internalFormat = GL20.GL_RGB5_A1; | |
386 | + dataType = GL20.GL_UNSIGNED_SHORT_5_5_5_1; | |
387 | + break; | |
388 | + case RGB8: | |
389 | + format = GL20.GL_RGB; | |
390 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
391 | + break; | |
392 | + case BGR8: | |
393 | + format = GL20.GL_RGB; | |
394 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
395 | + break; | |
396 | + case RGBA16: | |
397 | + format = GL20.GL_RGBA; | |
398 | + internalFormat = GL20.GL_RGBA4; | |
399 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
400 | + break; | |
401 | + case RGBA8: | |
402 | + format = GL20.GL_RGBA; | |
403 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
404 | + break; | |
405 | + case DXT1A: | |
406 | + format = GL20.GL_COMPRESSED_TEXTURE_FORMATS; | |
407 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
408 | + case Depth: | |
409 | + format = GL20.GL_DEPTH_COMPONENT; | |
410 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
411 | + break; | |
412 | + case Depth16: | |
413 | + format = GL20.GL_DEPTH_COMPONENT; | |
414 | + internalFormat = GL20.GL_DEPTH_COMPONENT16; | |
415 | + dataType = GL20.GL_UNSIGNED_BYTE; | |
416 | + break; | |
417 | + case Depth24: | |
418 | + case Depth32: | |
419 | + case Depth32F: | |
420 | + throw new UnsupportedOperationException("Unsupported depth format: " + fmt); | |
421 | + default: | |
422 | + throw new UnsupportedOperationException("Unrecognized format: " + fmt); | |
423 | + } | |
424 | + | |
425 | + if (internalFormat == -1) | |
426 | + { | |
427 | + internalFormat = format; | |
428 | + } | |
429 | + | |
430 | + if (data != null) | |
431 | + Gdx.gl20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 1); | |
432 | + | |
433 | + int[] mipSizes = img.getMipMapSizes(); | |
434 | + int pos = 0; | |
435 | + if (mipSizes == null){ | |
436 | + if (data != null) | |
437 | + mipSizes = new int[]{ data.capacity() }; | |
438 | + else | |
439 | + mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 }; | |
440 | + } | |
441 | + | |
442 | + // XXX: might want to change that when support | |
443 | + // of more than paletted compressions is added.. | |
444 | + if (compress){ | |
445 | + data.clear(); | |
446 | + Gdx.gl20.glCompressedTexImage2D(GL20.GL_TEXTURE_2D, | |
447 | + 1 - mipSizes.length, | |
448 | + format, | |
449 | + width, | |
450 | + height, | |
451 | + 0, | |
452 | + data.capacity(), | |
453 | + data); | |
454 | +//checkGLError(); | |
455 | +return; | |
456 | + } | |
457 | + | |
458 | + for (int i = 0; i < mipSizes.length; i++){ | |
459 | + int mipWidth = Math.max(1, width >> i); | |
460 | + int mipHeight = Math.max(1, height >> i); | |
461 | + int mipDepth = Math.max(1, depth >> i); | |
462 | + | |
463 | + if (data != null){ | |
464 | + data.position(pos); | |
465 | + data.limit(pos + mipSizes[i]); | |
466 | + } | |
467 | + | |
468 | + if (compress && data != null){ | |
469 | + Gdx.gl20.glCompressedTexImage2D(GL20.GL_TEXTURE_2D, | |
470 | + i, | |
471 | + format, | |
472 | + mipWidth, | |
473 | + mipHeight, | |
474 | + 0, | |
475 | + data.remaining(), | |
476 | + data); | |
477 | +//checkGLError(); | |
478 | + }else{ | |
479 | + Gdx.gl20.glTexImage2D(GL20.GL_TEXTURE_2D, | |
480 | + i, | |
481 | + internalFormat, | |
482 | + mipWidth, | |
483 | + mipHeight, | |
484 | + 0, | |
485 | + format, | |
486 | + dataType, | |
487 | + data); | |
488 | + } | |
489 | +//checkGLError(); | |
490 | + pos += mipSizes[i]; | |
491 | + } | |
492 | + } | |
493 | +// private static void checkGLError() { | |
494 | +// int error; | |
495 | +// while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { | |
496 | +// throw new RuntimeException("glError " + error); | |
497 | +// } | |
498 | +// } | |
499 | +} |
@@ -0,0 +1,133 @@ | ||
1 | +package com.jme3.system; | |
2 | + | |
3 | +import com.jme3.app.Application; | |
4 | +import com.jme3.asset.*; | |
5 | +import com.jme3.asset.gdx.GdxAssetManager; | |
6 | +import com.jme3.audio.*; | |
7 | +import com.jme3.system.gdx.GdxAudioRenderer; | |
8 | +import com.jme3.system.gdx.GdxContext; | |
9 | +//import com.jme3.audio.DummyAudioRenderer; | |
10 | +import com.jme3.system.JmeContext.Type; | |
11 | +import com.jme3.util.JmeFormatter; | |
12 | + | |
13 | +import java.io.InputStream; | |
14 | +import java.util.logging.Handler; | |
15 | +import java.util.logging.Level; | |
16 | +import java.util.logging.Logger; | |
17 | + | |
18 | +import java.net.URL; | |
19 | + | |
20 | +public class JmeSystemDelegateImpl implements JmeSystemDelegate { | |
21 | + | |
22 | + private static final Logger logger = Logger.getLogger(JmeSystemDelegateImpl.class.getName()); | |
23 | + private boolean initialized = false; | |
24 | + private boolean lowPermissions = false; | |
25 | + private static ThreadLocal<Application> app = new ThreadLocal<Application>(); | |
26 | + | |
27 | + public void initialize(AppSettings settings) { | |
28 | + if (initialized) { | |
29 | + return; | |
30 | + } | |
31 | + | |
32 | + initialized = true; | |
33 | + try { | |
34 | + JmeFormatter formatter = new JmeFormatter(); | |
35 | + | |
36 | +// Handler consoleHandler = new AndroidLogHandler(); | |
37 | +// consoleHandler.setFormatter(formatter); | |
38 | + } catch (SecurityException ex) { | |
39 | + logger.log(Level.SEVERE, "Security error in creating log file", ex); | |
40 | + } | |
41 | + logger.log(Level.INFO, "Running on {0}", getFullName()); | |
42 | + } | |
43 | + | |
44 | + public String getFullName() { | |
45 | + return "MikuMikuStudio gdx 1.0.0"; | |
46 | + } | |
47 | + | |
48 | + public void setLowPermissions(boolean lowPerm) { | |
49 | + lowPermissions = lowPerm; | |
50 | + } | |
51 | + | |
52 | + public boolean isLowPermissions() { | |
53 | + return lowPermissions; | |
54 | + } | |
55 | + | |
56 | + public JmeContext newContext(AppSettings settings, Type contextType) { | |
57 | + initialize(settings); | |
58 | + if (settings.getRenderer().startsWith("LiveWallpaper")) { | |
59 | + | |
60 | + } | |
61 | + return new GdxContext(); | |
62 | + } | |
63 | + | |
64 | + // TODO | |
65 | + public AudioRenderer newAudioRenderer(AppSettings settings) { | |
66 | + return new GdxAudioRenderer(); | |
67 | + } | |
68 | + | |
69 | +// public static void setResources(Resources res) { | |
70 | +// JmeSystem.res = res; | |
71 | +// } | |
72 | + | |
73 | +// public static Resources getResources() { | |
74 | +// return res; | |
75 | +// } | |
76 | + | |
77 | +// public static void setActivity(Context activity) { | |
78 | +// JmeSystem.activity = activity; | |
79 | +// | |
80 | +// } | |
81 | + public void setApplication(Application app) { | |
82 | + JmeSystem.app.set(app); | |
83 | + } | |
84 | + public Application getApplication() { | |
85 | + return app.get(); | |
86 | + } | |
87 | + | |
88 | +// public static Context getActivity() { | |
89 | +// return activity; | |
90 | +// } | |
91 | + | |
92 | + public AssetManager newAssetManager() { | |
93 | + logger.log(Level.INFO, "newAssetManager()"); | |
94 | + AssetManager am = new GdxAssetManager(); | |
95 | + | |
96 | + return am; | |
97 | + } | |
98 | + | |
99 | + public AssetManager newAssetManager(URL url) { | |
100 | + logger.log(Level.INFO, "newAssetManager({0})", url); | |
101 | + AssetManager am = new GdxAssetManager(); | |
102 | + | |
103 | + return am; | |
104 | + } | |
105 | + | |
106 | + public boolean showSettingsDialog(AppSettings settings, boolean loadSettings) { | |
107 | + return true; | |
108 | + } | |
109 | + | |
110 | + public Platform getPlatform() { | |
111 | + String arch = System.getProperty("os.arch").toLowerCase(); | |
112 | + if (arch.contains("arm")){ | |
113 | + if (arch.contains("v5")){ | |
114 | + return Platform.Android_ARM5; | |
115 | + }else if (arch.contains("v6")){ | |
116 | + return Platform.Android_ARM6; | |
117 | + }else if (arch.contains("v7")){ | |
118 | + return Platform.Android_ARM7; | |
119 | + }else{ | |
120 | + return Platform.Android_ARM5; // unknown ARM | |
121 | + } | |
122 | + }else{ | |
123 | + throw new UnsupportedOperationException("Unsupported Android Platform"); | |
124 | + } | |
125 | + } | |
126 | + public InputStream getResourceAsStream(String name) { | |
127 | + return JmeSystem.class.getResourceAsStream(name); | |
128 | + } | |
129 | + | |
130 | + public URL getResource(String name) { | |
131 | + return JmeSystem.class.getResource(name); | |
132 | + } | |
133 | +} |
@@ -0,0 +1,27 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.Gdx; | |
4 | +import com.badlogic.gdx.files.FileHandle; | |
5 | + | |
6 | +import java.io.File; | |
7 | +import java.io.IOException; | |
8 | +import java.io.InputStream; | |
9 | + | |
10 | +/** | |
11 | + * Created by kobayasi on 2013/12/29. | |
12 | + */ | |
13 | +public class GdxAssetCache { | |
14 | + public static FileHandle getFileHandle(String path) { | |
15 | + FileHandle fileHandle = Gdx.files.local("gdxtemp/"+path); | |
16 | + if (!fileHandle.exists()) { | |
17 | + InputStream is = GdxAssetCache.class.getClassLoader().getResourceAsStream(path); | |
18 | + fileHandle.write(is, false); | |
19 | + try { | |
20 | + is.close(); | |
21 | + } catch (IOException e) { | |
22 | + e.printStackTrace(); | |
23 | + } | |
24 | + } | |
25 | + return fileHandle; | |
26 | + } | |
27 | +} |
@@ -0,0 +1,64 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.jme3.asset.AssetKey; | |
4 | +import com.jme3.audio.AudioData; | |
5 | +import com.jme3.audio.AudioRenderer; | |
6 | +import com.jme3.util.NativeObject; | |
7 | + | |
8 | +/** | |
9 | + * Created by kobayasi on 2013/12/29. | |
10 | + */ | |
11 | +public class GdxAudioData extends AudioData{ | |
12 | + protected AssetKey assetKey; | |
13 | + protected float currentVolume = 0f; | |
14 | + | |
15 | + public GdxAudioData(){ | |
16 | + super(); | |
17 | + } | |
18 | + | |
19 | + protected GdxAudioData(int id){ | |
20 | + super(id); | |
21 | + } | |
22 | + | |
23 | + public AssetKey getAssetKey() { | |
24 | + return assetKey; | |
25 | + } | |
26 | + | |
27 | + public void setAssetKey(AssetKey assetKey) { | |
28 | + this.assetKey = assetKey; | |
29 | + } | |
30 | + | |
31 | + @Override | |
32 | + public DataType getDataType() { | |
33 | + return DataType.Buffer; | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + public float getDuration() { | |
38 | + return 0; // TODO: ??? | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + public void resetObject() { | |
43 | + this.id = -1; | |
44 | + setUpdateNeeded(); | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + public void deleteObject(Object rendererObject) { | |
49 | + ((AudioRenderer)rendererObject).deleteAudioData(this); | |
50 | + } | |
51 | + | |
52 | + public float getCurrentVolume() { | |
53 | + return currentVolume; | |
54 | + } | |
55 | + | |
56 | + public void setCurrentVolume(float currentVolume) { | |
57 | + this.currentVolume = currentVolume; | |
58 | + } | |
59 | + | |
60 | + @Override | |
61 | + public NativeObject createDestructableClone() { | |
62 | + return new GdxAudioData(id); | |
63 | + } | |
64 | +} |
@@ -0,0 +1,26 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.jme3.asset.AssetInfo; | |
4 | +import com.jme3.asset.AssetLoader; | |
5 | + | |
6 | +import java.io.IOException; | |
7 | +import java.io.InputStream; | |
8 | + | |
9 | +/** | |
10 | + * Created by kobayasi on 2013/12/29. | |
11 | + */ | |
12 | +public class GdxAudioLoader implements AssetLoader { | |
13 | + @Override | |
14 | + public Object load(AssetInfo assetInfo) throws IOException | |
15 | + { | |
16 | + | |
17 | + InputStream in = assetInfo.openStream(); | |
18 | + if (in != null) | |
19 | + { | |
20 | + in.close(); | |
21 | + } | |
22 | + GdxAudioData result = new GdxAudioData(); | |
23 | + result.setAssetKey( assetInfo.getKey() ); | |
24 | + return result; | |
25 | + } | |
26 | +} |
@@ -0,0 +1,193 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.Application; | |
4 | +import com.badlogic.gdx.Gdx; | |
5 | +import com.badlogic.gdx.audio.Music; | |
6 | +import com.jme3.audio.*; | |
7 | + | |
8 | +import java.util.HashMap; | |
9 | + | |
10 | +/** | |
11 | + * Created by kobayasi on 2013/12/28. | |
12 | + */ | |
13 | +public class GdxAudioRenderer implements AudioRenderer{ | |
14 | + private boolean audioDisabled = false; | |
15 | + private Listener listener; | |
16 | + private final HashMap<AudioNode, Music> musicMap = new HashMap<AudioNode, Music>(); | |
17 | + @Override | |
18 | + public void setListener(Listener listener) { | |
19 | + Gdx.app.log("GdxAudioRenderer", "setListener"); | |
20 | + if (audioDisabled) { | |
21 | + return; | |
22 | + } | |
23 | + | |
24 | + if (this.listener != null) { | |
25 | + // previous listener no longer associated with current | |
26 | + // renderer | |
27 | + this.listener.setRenderer(null); | |
28 | + } | |
29 | + | |
30 | + this.listener = listener; | |
31 | + this.listener.setRenderer(this); | |
32 | + | |
33 | + } | |
34 | + @Override | |
35 | + public void setEnvironment(Environment environment) { | |
36 | + Gdx.app.log("GdxAudioRenderer", "setEnvironment"); | |
37 | + } | |
38 | + | |
39 | + @Override | |
40 | + public void playSourceInstance(AudioNode audioNode) { | |
41 | + Gdx.app.log("GdxAudioRenderer", "playSourceInstance"); | |
42 | + GdxAudioData audioData; | |
43 | + audioData = (GdxAudioData) audioNode.getAudioData(); | |
44 | + Music music = musicMap.get(audioNode); | |
45 | + if (Gdx.app.getType() == Application.ApplicationType.iOS && audioData.getAssetKey().getName().endsWith(".ogg")) { | |
46 | + return; | |
47 | + } | |
48 | + if (music == null) { | |
49 | + music = Gdx.audio.newMusic(GdxAssetCache.getFileHandle(audioData.getAssetKey().getName())); | |
50 | + musicMap.put(audioNode, music); | |
51 | + } | |
52 | + music.stop(); | |
53 | + music.play(); | |
54 | + audioNode.setStatus(AudioNode.Status.Playing); | |
55 | + } | |
56 | + | |
57 | + @Override | |
58 | + public void playSource(AudioNode audioNode) { | |
59 | + Gdx.app.log("GdxAudioRenderer", "playSource"); | |
60 | + if (audioNode.getStatus() == AudioNode.Status.Playing) { | |
61 | + stopSource(audioNode); | |
62 | + playSourceInstance(audioNode); | |
63 | + } else if (audioNode.getStatus() == AudioNode.Status.Stopped) { | |
64 | + playSourceInstance(audioNode); | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + @Override | |
69 | + public void pauseSource(AudioNode src) { | |
70 | + Gdx.app.log("GdxAudioRenderer", "pauseSource"); | |
71 | + if (src.getStatus() == AudioNode.Status.Playing) { | |
72 | + if (src.getAudioData() instanceof GdxAudioData) { | |
73 | + GdxAudioData audioData = (GdxAudioData) src.getAudioData(); | |
74 | + if (audioData.getAssetKey() instanceof AudioKey) { | |
75 | + AudioKey assetKey = (AudioKey) audioData.getAssetKey(); | |
76 | + | |
77 | + if (assetKey.isStream()) { | |
78 | + Music mp; | |
79 | + if (musicMap.containsKey(src)) { | |
80 | + mp = musicMap.get(src); | |
81 | + mp.pause(); | |
82 | + src.setStatus(AudioNode.Status.Paused); | |
83 | + } | |
84 | + } else { | |
85 | + assert src.getChannel() != -1; | |
86 | + | |
87 | + if (src.getChannel() > 0) { | |
88 | +// soundPool.pause(src.getChannel()); | |
89 | + src.setStatus(AudioNode.Status.Paused); | |
90 | + } | |
91 | + } | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + } | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public void stopSource(AudioNode src) { | |
100 | + Gdx.app.log("GdxAudioRenderer", "stopSource"); | |
101 | + if (src.getStatus() != AudioNode.Status.Stopped) { | |
102 | + if (src.getAudioData() instanceof GdxAudioData) { | |
103 | + GdxAudioData audioData = (GdxAudioData) src.getAudioData(); | |
104 | + if (audioData.getAssetKey() instanceof AudioKey) { | |
105 | + AudioKey assetKey = (AudioKey) audioData.getAssetKey(); | |
106 | + if (assetKey.isStream()) { | |
107 | + Music mp; | |
108 | + if (musicMap.containsKey(src)) { | |
109 | + mp = musicMap.get(src); | |
110 | + mp.stop(); | |
111 | + src.setStatus(AudioNode.Status.Stopped); | |
112 | + src.setChannel(-1); | |
113 | + } | |
114 | + } else { | |
115 | + int chan = src.getChannel(); | |
116 | + assert chan != -1; // if it's not stopped, must have id | |
117 | + | |
118 | + if (src.getChannel() > 0) { | |
119 | +// soundPool.stop(src.getChannel()); | |
120 | + src.setChannel(-1); | |
121 | + } | |
122 | + | |
123 | + src.setStatus(AudioNode.Status.Stopped); | |
124 | + | |
125 | + if (audioData.getId() > 0) { | |
126 | +// soundPool.unload(audioData.getId()); | |
127 | + } | |
128 | + audioData.setId(-1); | |
129 | + | |
130 | + | |
131 | + | |
132 | + } | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + } | |
137 | + | |
138 | + } | |
139 | + | |
140 | + @Override | |
141 | + public void updateSourceParam(AudioNode audioNode, AudioParam audioParam) { | |
142 | + Gdx.app.log("GdxAudioRenderer", "updateSourceParam"); | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public void updateListenerParam(Listener listener, ListenerParam listenerParam) { | |
147 | + Gdx.app.log("GdxAudioRenderer", "updateListenerParam"); | |
148 | + | |
149 | + } | |
150 | + | |
151 | + @Override | |
152 | + public void deleteFilter(Filter filter) { | |
153 | + Gdx.app.log("GdxAudioRenderer", "deleteFilter"); | |
154 | + | |
155 | + } | |
156 | + | |
157 | + @Override | |
158 | + public void deleteAudioData(AudioData audioData) { | |
159 | + Gdx.app.log("GdxAudioRenderer", "deleteAudioData"); | |
160 | + | |
161 | + } | |
162 | + | |
163 | + @Override | |
164 | + public void initialize() { | |
165 | + Gdx.app.log("GdxAudioRenderer", "initialize"); | |
166 | + | |
167 | + } | |
168 | + | |
169 | + @Override | |
170 | + public void update(float v) { | |
171 | +// Gdx.app.log("GdxAudioRenderer", "update"); | |
172 | + for(AudioNode src : musicMap.keySet()) { | |
173 | + Music music = musicMap.get(src); | |
174 | + if (src.getStatus() == AudioNode.Status.Playing) { | |
175 | + if (!music.isPlaying()) { | |
176 | + Gdx.app.log("GdxAudioRenderer","music Stopped"); | |
177 | + src.setStatus(AudioNode.Status.Stopped); | |
178 | + } else { | |
179 | + } | |
180 | + } | |
181 | + } | |
182 | + | |
183 | + } | |
184 | + | |
185 | + @Override | |
186 | + public void cleanup() { | |
187 | + Gdx.app.log("GdxAudioRenderer", "cleanup"); | |
188 | + for(Music music : musicMap.values()) { | |
189 | + music.dispose(); | |
190 | + } | |
191 | + musicMap.clear(); | |
192 | + } | |
193 | +} |
@@ -0,0 +1,145 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.Gdx; | |
4 | +import com.badlogic.gdx.input.GestureDetector; | |
5 | +import com.jme3.input.*; | |
6 | +import com.jme3.input.dummy.DummyKeyInput; | |
7 | +import com.jme3.input.dummy.DummyMouseInput; | |
8 | +import com.jme3.renderer.Renderer; | |
9 | +import com.jme3.renderer.gdx.GdxRenderer; | |
10 | +import com.jme3.system.AppSettings; | |
11 | +import com.jme3.system.JmeContext; | |
12 | +import com.jme3.system.SystemListener; | |
13 | +import com.jme3.system.Timer; | |
14 | + | |
15 | +/** | |
16 | + * Created with IntelliJ IDEA. | |
17 | + * User: kobayasi | |
18 | + * Date: 13/10/07 | |
19 | + * Time: 20:59 | |
20 | + * To change this template use File | Settings | File Templates. | |
21 | + */ | |
22 | +public class GdxContext implements JmeContext { | |
23 | + private SystemListener systemListener; | |
24 | + private AppSettings settings; | |
25 | + private GdxRenderer renderer; | |
26 | + private boolean created = false; | |
27 | + private boolean renderable = false; | |
28 | + private boolean autoFlush = true; | |
29 | + private GdxTimer timer; | |
30 | + private boolean needInitialize = true; | |
31 | + | |
32 | + public GdxContext() { | |
33 | + timer = new GdxTimer(); | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + public Type getType() { | |
38 | + return Type.Display; | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + public void setSettings(AppSettings appSettings) { | |
43 | + System.out.println("GdxContext.setSettings"); | |
44 | + if (appSettings == null) { | |
45 | + throw new RuntimeException("GdxContext.setSettings appSettings == null"); | |
46 | + } | |
47 | + this.settings = appSettings; | |
48 | + } | |
49 | + | |
50 | + @Override | |
51 | + public void setSystemListener(SystemListener systemListener) { | |
52 | + System.out.println("setSystemListener"); | |
53 | + this.systemListener = systemListener; | |
54 | + } | |
55 | + | |
56 | + @Override | |
57 | + public AppSettings getSettings() { | |
58 | + return settings; | |
59 | + } | |
60 | + | |
61 | + @Override | |
62 | + public Renderer getRenderer() { | |
63 | + return renderer; //To change body of implemented methods use File | Settings | File Templates. | |
64 | + } | |
65 | + | |
66 | + @Override | |
67 | + public MouseInput getMouseInput() { | |
68 | + return new DummyMouseInput(); | |
69 | + } | |
70 | + | |
71 | + @Override | |
72 | + public KeyInput getKeyInput() { | |
73 | + return new DummyKeyInput(); | |
74 | + } | |
75 | + | |
76 | + @Override | |
77 | + public JoyInput getJoyInput() { | |
78 | + return null; //To change body of implemented methods use File | Settings | File Templates. | |
79 | + } | |
80 | + | |
81 | + @Override | |
82 | + public TouchInput getTouchInput() { | |
83 | + GdxInput input = new GdxInput(); | |
84 | + Gdx.input.setInputProcessor(new GestureDetector(input)); | |
85 | + return input; | |
86 | + //return null; //To change body of implemented methods use File | Settings | File Templates. | |
87 | + } | |
88 | + | |
89 | + @Override | |
90 | + public Timer getTimer() { | |
91 | + return timer; | |
92 | + } | |
93 | + | |
94 | + @Override | |
95 | + public void setTitle(String s) { | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public boolean isCreated() { | |
100 | + return created; | |
101 | + } | |
102 | + | |
103 | + @Override | |
104 | + public boolean isRenderable() { | |
105 | + return renderable; | |
106 | + } | |
107 | + | |
108 | + @Override | |
109 | + public void setAutoFlushFrames(boolean b) { | |
110 | + this.autoFlush = b; | |
111 | + } | |
112 | + | |
113 | + @Override | |
114 | + public void create(boolean b) { | |
115 | + System.out.println("GdxContext.create()"); | |
116 | + renderer = new GdxRenderer(); | |
117 | + renderable = true; | |
118 | + created = true; | |
119 | + } | |
120 | + | |
121 | + @Override | |
122 | + public void restart() { | |
123 | + } | |
124 | + | |
125 | + @Override | |
126 | + public void destroy(boolean b) { | |
127 | + renderable = false; | |
128 | + } | |
129 | + | |
130 | + public void onDrawFrame() { | |
131 | + if (needInitialize) { | |
132 | + renderer.initialize(); | |
133 | + systemListener.initialize(); | |
134 | + needInitialize = false; | |
135 | + } | |
136 | + if (isRenderable()) { | |
137 | + if (systemListener != null) { | |
138 | + systemListener.update(); | |
139 | + } | |
140 | + if (autoFlush) { | |
141 | + renderer.onFrame(); | |
142 | + } | |
143 | + } | |
144 | + } | |
145 | +} |
@@ -0,0 +1,426 @@ | ||
1 | +package com.jme3.system.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.Gdx; | |
4 | +import com.badlogic.gdx.InputProcessor; | |
5 | +import com.badlogic.gdx.input.GestureDetector; | |
6 | +import com.badlogic.gdx.math.Vector2; | |
7 | +import com.jme3.input.RawInputListener; | |
8 | +import com.jme3.input.TouchInput; | |
9 | +import com.jme3.input.event.MouseButtonEvent; | |
10 | +import com.jme3.input.event.MouseMotionEvent; | |
11 | +import com.jme3.input.event.TouchEvent; | |
12 | +import com.jme3.math.Vector2f; | |
13 | +import com.jme3.util.RingBuffer; | |
14 | + | |
15 | +import java.util.HashMap; | |
16 | +import java.util.logging.Logger; | |
17 | + | |
18 | +/** | |
19 | + * Created by kobayasi on 2013/12/27. | |
20 | + */ | |
21 | +public class GdxInput implements TouchInput, InputProcessor, GestureDetector.GestureListener { | |
22 | + private static final Logger logger = Logger.getLogger(GdxInput.class.getName()); | |
23 | + final private static int MAX_EVENTS = 1024; | |
24 | + | |
25 | + public boolean mouseEventsEnabled = true; | |
26 | + public boolean mouseEventsInvertX = false; | |
27 | + public boolean mouseEventsInvertY = false; | |
28 | + public boolean keyboardEventsEnabled = false; | |
29 | + public boolean dontSendHistory = false; | |
30 | + private RawInputListener listener = null; | |
31 | + final private RingBuffer<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS); | |
32 | + final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS); | |
33 | + final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS); | |
34 | + final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); | |
35 | + private int lastX = -1; | |
36 | + private int lastY = -1; | |
37 | + private boolean isInitialized = false; | |
38 | + | |
39 | + @Override | |
40 | + public void setSimulateMouse(boolean b) { | |
41 | + mouseEventsEnabled = b; | |
42 | + } | |
43 | + | |
44 | + @Override | |
45 | + public void setSimulateKeyboard(boolean b) { | |
46 | + keyboardEventsEnabled = b; | |
47 | + } | |
48 | + | |
49 | + @Override | |
50 | + public void setOmitHistoricEvents(boolean b) { | |
51 | + dontSendHistory = b; | |
52 | + } | |
53 | + | |
54 | + @Override | |
55 | + public void initialize() { | |
56 | + TouchEvent item; | |
57 | + for (int i = 0; i < MAX_EVENTS; i++) | |
58 | + { | |
59 | + item = new TouchEvent(); | |
60 | + eventPool.push(item); | |
61 | + } | |
62 | + isInitialized = true; | |
63 | + } | |
64 | + | |
65 | + @Override | |
66 | + public void update() { | |
67 | + if (listener != null) { | |
68 | + TouchEvent event; | |
69 | + MouseButtonEvent btn; | |
70 | + int newX; | |
71 | + int newY; | |
72 | + while (!eventQueue.isEmpty()) { | |
73 | + synchronized (eventQueue) { | |
74 | + event = eventQueue.pop(); | |
75 | + } | |
76 | + if (event != null) { | |
77 | + listener.onTouchEvent(event); | |
78 | + if (mouseEventsEnabled) { | |
79 | + if (mouseEventsInvertX) | |
80 | + newX = Gdx.graphics.getWidth() - (int) event.getX(); | |
81 | + else | |
82 | + newX = (int) event.getX(); | |
83 | + | |
84 | + if (mouseEventsInvertY) | |
85 | + newY = Gdx.graphics.getHeight() - (int) event.getY(); | |
86 | + else | |
87 | + newY = (int) event.getY(); | |
88 | + switch (event.getType()) { | |
89 | + case DOWN: | |
90 | + // Handle mouse down event | |
91 | + btn = new MouseButtonEvent(0, true, newX, newY); | |
92 | + btn.setTime(event.getTime()); | |
93 | + listener.onMouseButtonEvent(btn); | |
94 | + // Store current pos | |
95 | + lastX = -1; | |
96 | + lastY = -1; | |
97 | + //lastX = newX; | |
98 | + //lastY = newY; | |
99 | +// System.err.println("DOWN x = " + btn.getX() + " y = " + btn.getY()); | |
100 | + break; | |
101 | + | |
102 | + case UP: | |
103 | + // Handle mouse up event | |
104 | + btn = new MouseButtonEvent(0, false, newX, newY); | |
105 | + btn.setTime(event.getTime()); | |
106 | + listener.onMouseButtonEvent(btn); | |
107 | + // Store current pos | |
108 | + lastX = -1; | |
109 | + lastY = -1; | |
110 | + //lastX = newX; | |
111 | + //lastY = newY; | |
112 | +// System.err.println("UP x = " + btn.getX() + " y = " + btn.getY()); | |
113 | + break; | |
114 | + | |
115 | + case MOVE: | |
116 | + int dx; | |
117 | + int dy; | |
118 | + if (lastX != -1) { | |
119 | + dx = newX - lastX; | |
120 | + dy = newY - lastY; | |
121 | + } else { | |
122 | + dx = 1; | |
123 | + dy = 0; | |
124 | + } | |
125 | + MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0); | |
126 | + mot.setTime(event.getTime()); | |
127 | + listener.onMouseMotionEvent(mot); | |
128 | + lastX = newX; | |
129 | + lastY = newY; | |
130 | + break; | |
131 | + } | |
132 | + } | |
133 | + } | |
134 | + if (event.isConsumed() == false) { | |
135 | + synchronized (eventPoolUnConsumed) { | |
136 | + try { | |
137 | + eventPoolUnConsumed.push(event); | |
138 | + } catch(Exception ex) { | |
139 | + ex.printStackTrace(); | |
140 | + } | |
141 | + } | |
142 | + | |
143 | + } else { | |
144 | + synchronized (eventPool) { | |
145 | + try { | |
146 | + eventPool.push(event); | |
147 | + } catch(Exception ex) { | |
148 | + ex.printStackTrace(); | |
149 | + } | |
150 | + } | |
151 | + } | |
152 | + } | |
153 | + } | |
154 | + | |
155 | + } | |
156 | + | |
157 | + @Override | |
158 | + public void destroy() { | |
159 | + | |
160 | + } | |
161 | + | |
162 | + @Override | |
163 | + public boolean isInitialized() { | |
164 | + return isInitialized; | |
165 | + } | |
166 | + | |
167 | + @Override | |
168 | + public void setInputListener(RawInputListener rawInputListener) { | |
169 | + this.listener = rawInputListener; | |
170 | + } | |
171 | + | |
172 | + @Override | |
173 | + public long getInputTimeNanos() { | |
174 | + return System.nanoTime(); | |
175 | + } | |
176 | + | |
177 | + private void processEvent(TouchEvent event) { | |
178 | + synchronized (eventQueue) { | |
179 | + try { | |
180 | + eventQueue.push(event); | |
181 | + } catch(Exception ex) { | |
182 | + ex.printStackTrace(); | |
183 | + } | |
184 | + } | |
185 | + } | |
186 | + | |
187 | + private TouchEvent getNextFreeTouchEvent() { | |
188 | + return getNextFreeTouchEvent(false); | |
189 | + } | |
190 | + private TouchEvent getNextFreeTouchEvent(boolean wait) | |
191 | + { | |
192 | + TouchEvent evt = null; | |
193 | + synchronized(eventPoolUnConsumed) | |
194 | + { | |
195 | + int size = eventPoolUnConsumed.size(); | |
196 | + while (size > 0) | |
197 | + { | |
198 | + evt = eventPoolUnConsumed.pop(); | |
199 | + if (!evt.isConsumed()) | |
200 | + { | |
201 | + eventPoolUnConsumed.push(evt); | |
202 | + evt = null; | |
203 | + } | |
204 | + else | |
205 | + { | |
206 | + break; | |
207 | + } | |
208 | + size--; | |
209 | + } | |
210 | + } | |
211 | + | |
212 | + | |
213 | + if (evt == null) | |
214 | + { | |
215 | + if (eventPool.isEmpty() && wait) | |
216 | + { | |
217 | + logger.warning("eventPool buffer underrun"); | |
218 | + boolean isEmpty; | |
219 | + do | |
220 | + { | |
221 | + synchronized(eventPool) | |
222 | + { | |
223 | + isEmpty = eventPool.isEmpty(); | |
224 | + } | |
225 | + try { Thread.sleep(50); } catch (InterruptedException e) { } | |
226 | + } | |
227 | + while (isEmpty); | |
228 | + synchronized(eventPool) | |
229 | + { | |
230 | + evt = eventPool.pop(); | |
231 | + } | |
232 | + } | |
233 | + else if (eventPool.isEmpty()) | |
234 | + { | |
235 | + evt = new TouchEvent(); | |
236 | + logger.warning("eventPool buffer underrun"); | |
237 | + } | |
238 | + else | |
239 | + { | |
240 | + synchronized(eventPool) | |
241 | + { | |
242 | + evt = eventPool.pop(); | |
243 | + } | |
244 | + } | |
245 | + } | |
246 | + return evt; | |
247 | + } | |
248 | + | |
249 | + // InputProcessor methods. | |
250 | + | |
251 | + @Override | |
252 | + public boolean keyDown(int keycode) { | |
253 | + return false; | |
254 | + } | |
255 | + | |
256 | + @Override | |
257 | + public boolean keyUp(int keycode) { | |
258 | + return false; | |
259 | + } | |
260 | + | |
261 | + @Override | |
262 | + public boolean keyTyped(char character) { | |
263 | + return false; | |
264 | + } | |
265 | + | |
266 | + @Override | |
267 | + public boolean touchDown(int screenX, int screenY, int pointer, int button) { | |
268 | + //mouseMoved2(screenX, screenY); | |
269 | + TouchEvent event = getNextFreeTouchEvent(); | |
270 | + //event.set(TouchEvent.Type.MOVE, screenX, Gdx.graphics.getHeight() - screenY, 0, 0); | |
271 | + //event.setPointerId(0); | |
272 | + //event.setTime(System.nanoTime()); | |
273 | + //processEvent(event); | |
274 | + | |
275 | + //event = getNextFreeTouchEvent(); | |
276 | + event.set(TouchEvent.Type.DOWN, screenX, Gdx.graphics.getHeight() - screenY, 0, 0); | |
277 | + event.setPointerId(0); | |
278 | + event.setTime(System.nanoTime()); | |
279 | + processEvent(event); | |
280 | + | |
281 | + Vector2f lastPos = lastPositions.get(pointer); | |
282 | + if (lastPos == null) | |
283 | + { | |
284 | + lastPos = new Vector2f(screenX, Gdx.graphics.getHeight() - screenY); | |
285 | + lastPositions.put(pointer, lastPos); | |
286 | + } | |
287 | + lastPos.set(screenX, Gdx.graphics.getHeight() - screenY); | |
288 | + | |
289 | + System.err.println("touchDown x = " + screenX + " y = " + screenY); | |
290 | + return false; | |
291 | + } | |
292 | + | |
293 | + @Override | |
294 | + public boolean touchUp(int screenX, int screenY, int pointer, int button) { | |
295 | + TouchEvent event = getNextFreeTouchEvent(); | |
296 | + event.set(TouchEvent.Type.UP, screenX, Gdx.graphics.getHeight() - screenY, 0, 0); | |
297 | + event.setPointerId(pointer); | |
298 | + event.setTime(System.nanoTime()); | |
299 | + processEvent(event); | |
300 | + System.err.println("touchUp x = " + screenX + " y = " + screenY); | |
301 | + return false; | |
302 | + } | |
303 | + | |
304 | + @Override | |
305 | + public boolean touchDragged(int screenX, int screenY, int pointer) { | |
306 | + if (screenX < 0 || screenY < 0) { | |
307 | + return false; | |
308 | + } | |
309 | + Vector2f lastPos = lastPositions.get(pointer); | |
310 | + if (lastPos == null) | |
311 | + { | |
312 | + lastPos = new Vector2f(screenX, Gdx.graphics.getHeight() - screenY); | |
313 | + lastPositions.put(pointer, lastPos); | |
314 | + } | |
315 | + TouchEvent event = getNextFreeTouchEvent(); | |
316 | + event.set(TouchEvent.Type.MOVE, screenX, Gdx.graphics.getHeight() - screenY, screenX - lastPos.x, Gdx.graphics.getHeight() - screenY - lastPos.y); | |
317 | + event.setPointerId(pointer); | |
318 | + event.setTime(System.nanoTime()); | |
319 | + processEvent(event); | |
320 | + System.err.println("touchDragged x = " + screenX + " y = " + screenY); | |
321 | + lastPos.set(screenX, Gdx.graphics.getHeight() - screenY); | |
322 | + return false; | |
323 | + } | |
324 | + | |
325 | + @Override | |
326 | + public boolean mouseMoved(int screenX, int screenY) { | |
327 | + return mouseMoved2(screenX, screenY); | |
328 | + } | |
329 | + public boolean mouseMoved2(int screenX, int screenY) { | |
330 | + if (screenX < 0 || screenY < 0) { | |
331 | + return false; | |
332 | + } | |
333 | + Vector2f lastPos = lastPositions.get(0); | |
334 | + if (lastPos == null) | |
335 | + { | |
336 | + lastPos = new Vector2f(screenX, Gdx.graphics.getHeight() - screenY); | |
337 | + lastPositions.put(0, lastPos); | |
338 | + } | |
339 | + | |
340 | + | |
341 | + TouchEvent event = getNextFreeTouchEvent(); | |
342 | + event.set(TouchEvent.Type.MOVE, screenX, Gdx.graphics.getHeight() - screenY, screenX - lastPos.x, Gdx.graphics.getHeight() - screenY - lastPos.y); | |
343 | + event.setPointerId(0); | |
344 | + event.setTime(System.nanoTime()); | |
345 | + processEvent(event); | |
346 | +// System.err.println("mouseMoved x = " + screenX + " y = " + screenY); | |
347 | + lastPos.set(screenX, Gdx.graphics.getHeight() - screenY); | |
348 | + return false; | |
349 | + } | |
350 | + | |
351 | + @Override | |
352 | + public boolean scrolled(int amount) { | |
353 | +// System.err.println("scrolled amount = " + amount); | |
354 | + return false; | |
355 | + } | |
356 | + public boolean isMouseEventsInvertY() { | |
357 | + return mouseEventsInvertY; | |
358 | + } | |
359 | + | |
360 | + public void setMouseEventsInvertY(boolean mouseEventsInvertY) { | |
361 | + this.mouseEventsInvertY = mouseEventsInvertY; | |
362 | + } | |
363 | + | |
364 | + public boolean isMouseEventsInvertX() { | |
365 | + return mouseEventsInvertX; | |
366 | + } | |
367 | + | |
368 | + public void setMouseEventsInvertX(boolean mouseEventsInvertX) { | |
369 | + this.mouseEventsInvertX = mouseEventsInvertX; | |
370 | + } | |
371 | + | |
372 | + // GestureListener | |
373 | + | |
374 | + @Override | |
375 | + public boolean touchDown(float x, float y, int pointer, int button) { | |
376 | + System.err.println("touchDown2"); | |
377 | + return touchDown((int)x, (int)y, pointer, button); | |
378 | + } | |
379 | + | |
380 | + @Override | |
381 | + public boolean tap(float x, float y, int count, int button) { | |
382 | + System.err.println("tap"); | |
383 | + return touchUp((int)x, (int)y, count, button); | |
384 | + } | |
385 | + | |
386 | + @Override | |
387 | + public boolean longPress(float x, float y) { | |
388 | + System.err.println("longPress"); | |
389 | + return false; | |
390 | + } | |
391 | + | |
392 | + @Override | |
393 | + public boolean fling(float velocityX, float velocityY, int button) { | |
394 | + System.err.println("fling"); | |
395 | + return false; | |
396 | + } | |
397 | + | |
398 | + @Override | |
399 | + public boolean pan(float x, float y, float deltaX, float deltaY) { | |
400 | + System.err.println("pan"); | |
401 | + return touchDragged((int)x, (int)y, 0); | |
402 | + } | |
403 | + | |
404 | + @Override | |
405 | + public boolean panStop(float x, float y, int pointer, int button) { | |
406 | + System.err.println("panStop"); | |
407 | + return touchUp((int)x,(int)y,pointer, button); | |
408 | + } | |
409 | + | |
410 | + @Override | |
411 | + public boolean zoom(float initialDistance, float distance) { | |
412 | + System.err.println("zoom "+initialDistance+" "+distance); | |
413 | + TouchEvent event = getNextFreeTouchEvent(); | |
414 | + event.set(TouchEvent.Type.SCALE_MOVE, initialDistance, distance, 0, 0); | |
415 | + event.setPointerId(0); | |
416 | + event.setTime(System.nanoTime()); | |
417 | + processEvent(event); | |
418 | + return false; | |
419 | + } | |
420 | + | |
421 | + @Override | |
422 | + public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) { | |
423 | + System.err.println("pinch"); | |
424 | + return false; | |
425 | + } | |
426 | +} |
@@ -0,0 +1,97 @@ | ||
1 | +/* | |
2 | + * Copyright (c) 2003-2009 jMonkeyEngine | |
3 | + * All rights reserved. | |
4 | + * | |
5 | + * Redistribution and use in source and binary forms, with or without | |
6 | + * modification, are permitted provided that the following conditions are | |
7 | + * met: | |
8 | + * | |
9 | + * * Redistributions of source code must retain the above copyright | |
10 | + * notice, this list of conditions and the following disclaimer. | |
11 | + * | |
12 | + * * Redistributions in binary form must reproduce the above copyright | |
13 | + * notice, this list of conditions and the following disclaimer in the | |
14 | + * documentation and/or other materials provided with the distribution. | |
15 | + * | |
16 | + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | |
17 | + * may be used to endorse or promote products derived from this software | |
18 | + * without specific prior written permission. | |
19 | + * | |
20 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 | + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 | + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
24 | + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
25 | + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
26 | + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
27 | + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
28 | + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
29 | + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | + */ | |
32 | + | |
33 | +package com.jme3.system.gdx; | |
34 | + | |
35 | +import com.jme3.system.Timer; | |
36 | + | |
37 | +/** | |
38 | + * <code>GdxTimer</code> is a System.nanoTime implementation of <code>Timer</code>. | |
39 | + */ | |
40 | +public class GdxTimer extends Timer { | |
41 | + | |
42 | + //private static final long TIMER_RESOLUTION = 1000L; | |
43 | + //private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L; | |
44 | + private static final long TIMER_RESOLUTION = 1000000000L; | |
45 | + private static final float INVERSE_TIMER_RESOLUTION = 1f/1000000000L; | |
46 | + | |
47 | + private long startTime; | |
48 | + private float previousTime; | |
49 | + private float tpf; | |
50 | + private float fps; | |
51 | + | |
52 | + public GdxTimer() { | |
53 | + //startTime = System.currentTimeMillis(); | |
54 | + startTime = System.nanoTime(); | |
55 | + } | |
56 | + | |
57 | + /** | |
58 | + * Returns the time in seconds. The timer starts | |
59 | + * at 0.0 seconds. | |
60 | + * | |
61 | + * @return the current time in seconds | |
62 | + */ | |
63 | + @Override | |
64 | + public float getTimeInSeconds() { | |
65 | + return getTime() * INVERSE_TIMER_RESOLUTION; | |
66 | + } | |
67 | + | |
68 | + public long getTime() { | |
69 | + //return System.currentTimeMillis() - startTime; | |
70 | + return System.nanoTime() - startTime; | |
71 | + } | |
72 | + | |
73 | + public long getResolution() { | |
74 | + return TIMER_RESOLUTION; | |
75 | + } | |
76 | + | |
77 | + public float getFrameRate() { | |
78 | + return fps; | |
79 | + } | |
80 | + | |
81 | + public float getTimePerFrame() { | |
82 | + return tpf; | |
83 | + } | |
84 | + | |
85 | + public void update() { | |
86 | + long timeNow = getTime(); | |
87 | + tpf = (timeNow) * (1.0f / TIMER_RESOLUTION) - previousTime; | |
88 | + fps = 1.0f / tpf; | |
89 | + previousTime = previousTime += tpf; | |
90 | + } | |
91 | + | |
92 | + public void reset() { | |
93 | + //startTime = System.currentTimeMillis(); | |
94 | + startTime = System.nanoTime(); | |
95 | + previousTime = 0;//getTime(); | |
96 | + } | |
97 | +} |
@@ -0,0 +1,140 @@ | ||
1 | +package com.jme3.texture.plugins.gdx; | |
2 | + | |
3 | +import com.badlogic.gdx.graphics.GL20; | |
4 | +import com.badlogic.gdx.graphics.Pixmap; | |
5 | +import com.jme3.asset.AssetInfo; | |
6 | +import com.jme3.asset.AssetLoader; | |
7 | +import com.jme3.asset.AssetNotFoundException; | |
8 | +import com.jme3.math.FastMath; | |
9 | +import com.jme3.texture.Image; | |
10 | +import com.jme3.util.BufferUtils; | |
11 | + | |
12 | +import java.io.IOException; | |
13 | +import java.io.InputStream; | |
14 | +import java.nio.ByteBuffer; | |
15 | + | |
16 | +/** | |
17 | + * Created with IntelliJ IDEA. | |
18 | + * User: kobayasi | |
19 | + * Date: 13/10/10 | |
20 | + * Time: 23:54 | |
21 | + * To change this template use File | Settings | File Templates. | |
22 | + */ | |
23 | +public class GdxImageLoader implements AssetLoader{ | |
24 | + public GdxImageLoader() { | |
25 | + } | |
26 | + | |
27 | + @Override | |
28 | + public Object load(AssetInfo assetInfo) throws IOException { | |
29 | + Pixmap pixmap = null; | |
30 | + InputStream is = null; | |
31 | + | |
32 | + try { | |
33 | + is = assetInfo.openStream(); | |
34 | + byte[] buf = new byte[is.available()]; | |
35 | + System.err.println(assetInfo.getKey()+" buf length = "+buf.length); | |
36 | + int i = 0; | |
37 | + while ( i < buf.length) { | |
38 | + int len = is.read(buf, i, buf.length - i); | |
39 | + if (len < 0) { | |
40 | + throw new IOException(); | |
41 | + } | |
42 | + i += len; | |
43 | + } | |
44 | + is.close(); | |
45 | + is = null; | |
46 | + pixmap = new Pixmap(buf, 0, buf.length); | |
47 | + Image.Format format; | |
48 | + ByteBuffer bb = BufferUtils.clone(pixmap.getPixels()); | |
49 | + int height = pixmap.getHeight(); | |
50 | + int width = pixmap.getWidth(); | |
51 | + switch(pixmap.getGLFormat()) { | |
52 | + case GL20.GL_RGBA: | |
53 | + format = Image.Format.RGBA8; | |
54 | + ByteBuffer bb2 = pixmap.getPixels(); | |
55 | + for(int y = 0;y<height;y++) { | |
56 | + bb.position((y * width)*4); | |
57 | + bb2.position(((height - y - 1) * width)*4); | |
58 | + for(int i2=0;i2<width * 4;i2++) { | |
59 | + bb.put(bb2.get()); | |
60 | + } | |
61 | + } | |
62 | + break; | |
63 | + case GL20.GL_RGB: | |
64 | + format = Image.Format.RGB8; | |
65 | + bb2 = pixmap.getPixels(); | |
66 | + for(int y = 0;y<height;y++) { | |
67 | + bb.position((y * width)*3); | |
68 | + bb2.position(((height - y-1) * width)*3); | |
69 | + for(int i2=0;i2<width * 3;i2++) { | |
70 | + bb.put(bb2.get()); | |
71 | + } | |
72 | + } | |
73 | + break; | |
74 | + default: | |
75 | + throw new IOException("Invalid format "+pixmap.getGLFormat()); | |
76 | + } | |
77 | + if (pixmap.getWidth() != FastMath.nearestPowerOfTwo(pixmap.getWidth()) | |
78 | + || pixmap.getHeight() != FastMath.nearestPowerOfTwo(pixmap.getHeight())) { | |
79 | + if (pixmap.getGLFormat() == GL20.GL_RGBA) { | |
80 | + bb = resize(pixmap.getWidth(), pixmap.getHeight(), FastMath.nearestPowerOfTwo(pixmap.getWidth()),FastMath.nearestPowerOfTwo(pixmap.getHeight()),bb); | |
81 | + } else { | |
82 | + bb = resize2(pixmap.getWidth(), pixmap.getHeight(), FastMath.nearestPowerOfTwo(pixmap.getWidth()),FastMath.nearestPowerOfTwo(pixmap.getHeight()),bb); | |
83 | + } | |
84 | + } | |
85 | + Image image = new Image(format, FastMath.nearestPowerOfTwo(pixmap.getWidth()),FastMath.nearestPowerOfTwo(pixmap.getHeight()), bb, null); | |
86 | + return image; //To change body of implemented methods use File | Settings | File Templates. | |
87 | + } finally { | |
88 | + if (pixmap != null) { | |
89 | + pixmap.dispose(); | |
90 | + } | |
91 | + if (is != null) { | |
92 | + is.close(); | |
93 | + } | |
94 | + } | |
95 | + } | |
96 | + private static ByteBuffer resize(int w1,int h1, int w2, int h2, ByteBuffer bb) { | |
97 | +// w2 = w1; | |
98 | +// h2 = h1; | |
99 | + if (w1 == w2 && h1 == h2) { | |
100 | + return bb; | |
101 | + } | |
102 | + ByteBuffer out = BufferUtils.createByteBuffer(w2 * h2 * 4); | |
103 | + float f1 = ((float)w1) / (float)w2; | |
104 | + float f2 = ((float)h1) / (float)h2; | |
105 | + for(int x = 0;x<w2;x++) { | |
106 | + for(int y = 0;y<h2;y++) { | |
107 | + int index = (int)(((int)(f2 * (float)y)) * (float)w1 + f1 * (float)x); | |
108 | + if (index >= w1 * h1) { | |
109 | + index = 0; | |
110 | + } | |
111 | + for(int i=0;i<4;i++) { | |
112 | + out.put((x + y * w2)*4+i,bb.get(index * 4 + i)); | |
113 | + } | |
114 | + } | |
115 | + } | |
116 | + return out; | |
117 | + } | |
118 | + private static ByteBuffer resize2(int w1,int h1, int w2, int h2, ByteBuffer bb) { | |
119 | +// w2 = w1; | |
120 | +// h2 = h1; | |
121 | + if (w1 == w2 && h1 == h2) { | |
122 | + //return buf; | |
123 | + } | |
124 | + ByteBuffer out = BufferUtils.createByteBuffer(w2 * h2 * 3); | |
125 | + float f1 = ((float)w1) / (float)w2; | |
126 | + float f2 = ((float)h1) / (float)h2; | |
127 | + for(int x = 0;x<w2;x++) { | |
128 | + for(int y = 0;y<h2;y++) { | |
129 | + int index = (int)(((int)(f2 * (float)y)) * (float)w1 + f1 * (float)x); | |
130 | + if (index >= w1 * h1) { | |
131 | + index = 0; | |
132 | + } | |
133 | + for(int i=0;i<3;i++) { | |
134 | + out.put((x + y * w2)*3+i,bb.get(index * 3 + i)); | |
135 | + } | |
136 | + } | |
137 | + } | |
138 | + return out; | |
139 | + } | |
140 | +} |
@@ -0,0 +1,572 @@ | ||
1 | +/* | |
2 | + * Copyright (c) 2009-2010 jMonkeyEngine | |
3 | + * All rights reserved. | |
4 | + * | |
5 | + * Redistribution and use in source and binary forms, with or without | |
6 | + * modification, are permitted provided that the following conditions are | |
7 | + * met: | |
8 | + * | |
9 | + * * Redistributions of source code must retain the above copyright | |
10 | + * notice, this list of conditions and the following disclaimer. | |
11 | + * | |
12 | + * * Redistributions in binary form must reproduce the above copyright | |
13 | + * notice, this list of conditions and the following disclaimer in the | |
14 | + * documentation and/or other materials provided with the distribution. | |
15 | + * | |
16 | + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | |
17 | + * may be used to endorse or promote products derived from this software | |
18 | + * without specific prior written permission. | |
19 | + * | |
20 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 | + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 | + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
24 | + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
25 | + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
26 | + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
27 | + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
28 | + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
29 | + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | + */ | |
32 | + | |
33 | +package com.jme3.texture.plugins.gdx; | |
34 | + | |
35 | +import com.jme3.math.FastMath; | |
36 | +import com.jme3.asset.AssetLoader; | |
37 | +import com.jme3.texture.Image; | |
38 | +import com.jme3.util.BufferUtils; | |
39 | +import com.jme3.asset.AssetInfo; | |
40 | +import com.jme3.asset.TextureKey; | |
41 | +import com.jme3.texture.Image.Format; | |
42 | +import java.io.BufferedInputStream; | |
43 | +import java.io.DataInputStream; | |
44 | +import java.io.IOException; | |
45 | +import java.io.InputStream; | |
46 | +import java.nio.ByteBuffer; | |
47 | + | |
48 | +/** | |
49 | + * <code>TextureManager</code> provides static methods for building a | |
50 | + * <code>Texture</code> object. Typically, the information supplied is the | |
51 | + * filename and the texture properties. | |
52 | + * | |
53 | + * @author Mark Powell | |
54 | + * @author Joshua Slack - cleaned, commented, added ability to read 16bit true color and color-mapped TGAs. | |
55 | + * @author Kirill Vainer - ported to jME3 | |
56 | + * @version $Id: TGALoader.java 4131 2009-03-19 20:15:28Z blaine.dev $ | |
57 | + */ | |
58 | +public final class GdxTGALoader implements AssetLoader { | |
59 | + | |
60 | + // 0 - no image data in file | |
61 | + public static final int TYPE_NO_IMAGE = 0; | |
62 | + | |
63 | + // 1 - uncompressed, color-mapped image | |
64 | + public static final int TYPE_COLORMAPPED = 1; | |
65 | + | |
66 | + // 2 - uncompressed, true-color image | |
67 | + public static final int TYPE_TRUECOLOR = 2; | |
68 | + | |
69 | + // 3 - uncompressed, black and white image | |
70 | + public static final int TYPE_BLACKANDWHITE = 3; | |
71 | + | |
72 | + // 9 - run-length encoded, color-mapped image | |
73 | + public static final int TYPE_COLORMAPPED_RLE = 9; | |
74 | + | |
75 | + // 10 - run-length encoded, true-color image | |
76 | + public static final int TYPE_TRUECOLOR_RLE = 10; | |
77 | + | |
78 | + // 11 - run-length encoded, black and white image | |
79 | + public static final int TYPE_BLACKANDWHITE_RLE = 11; | |
80 | + | |
81 | + public Object load(AssetInfo info) throws IOException{ | |
82 | + if (!(info.getKey() instanceof TextureKey)) | |
83 | + throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey"); | |
84 | + | |
85 | + boolean flip = ((TextureKey)info.getKey()).isFlipY(); | |
86 | + InputStream in = null; | |
87 | + try { | |
88 | + in = info.openStream(); | |
89 | + Image img = load(in, flip); | |
90 | + return img; | |
91 | + } finally { | |
92 | + if (in != null){ | |
93 | + in.close(); | |
94 | + } | |
95 | + } | |
96 | + } | |
97 | + | |
98 | + /** | |
99 | + * <code>loadImage</code> is a manual image loader which is entirely | |
100 | + * independent of AWT. OUT: RGB888 or RGBA8888 Image object | |
101 | + * | |
102 | + * @return <code>Image</code> object that contains the | |
103 | + * image, either as a RGB888 or RGBA8888 | |
104 | + * @param flip | |
105 | + * Flip the image vertically | |
106 | + * @param exp32 | |
107 | + * Add a dummy Alpha channel to 24b RGB image. | |
108 | + * @param fis | |
109 | + * InputStream of an uncompressed 24b RGB or 32b RGBA TGA | |
110 | + * @throws java.io.IOException | |
111 | + */ | |
112 | + public static Image load(InputStream in, boolean flip) throws IOException { | |
113 | + boolean flipH = false; | |
114 | + | |
115 | + // open a stream to the file | |
116 | + DataInputStream dis = new DataInputStream(new BufferedInputStream(in)); | |
117 | + | |
118 | + // ---------- Start Reading the TGA header ---------- // | |
119 | + // length of the image id (1 byte) | |
120 | + int idLength = dis.readUnsignedByte(); | |
121 | + | |
122 | + // Type of color map (if any) included with the image | |
123 | + // 0 - no color map data is included | |
124 | + // 1 - a color map is included | |
125 | + int colorMapType = dis.readUnsignedByte(); | |
126 | + | |
127 | + // Type of image being read: | |
128 | + int imageType = dis.readUnsignedByte(); | |
129 | + | |
130 | + // Read Color Map Specification (5 bytes) | |
131 | + // Index of first color map entry (if we want to use it, uncomment and remove extra read.) | |
132 | +// short cMapStart = flipEndian(dis.readShort()); | |
133 | + dis.readShort(); | |
134 | + // number of entries in the color map | |
135 | + short cMapLength = flipEndian(dis.readShort()); | |
136 | + // number of bits per color map entry | |
137 | + int cMapDepth = dis.readUnsignedByte(); | |
138 | + | |
139 | + // Read Image Specification (10 bytes) | |
140 | + // horizontal coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.) | |
141 | +// int xOffset = flipEndian(dis.readShort()); | |
142 | + dis.readShort(); | |
143 | + // vertical coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.) | |
144 | +// int yOffset = flipEndian(dis.readShort()); | |
145 | + dis.readShort(); | |
146 | + // width of image - in pixels | |
147 | + int width = flipEndian(dis.readShort()); | |
148 | + // height of image - in pixels | |
149 | + int height = flipEndian(dis.readShort()); | |
150 | + // bits per pixel in image. | |
151 | + int pixelDepth = dis.readUnsignedByte(); | |
152 | + int imageDescriptor = dis.readUnsignedByte(); | |
153 | + if ((imageDescriptor & 32) != 0) // bit 5 : if 1, flip top/bottom ordering | |
154 | + flip = !flip; | |
155 | + if ((imageDescriptor & 16) != 0) // bit 4 : if 1, flip left/right ordering | |
156 | + flipH = !flipH; | |
157 | + | |
158 | + // ---------- Done Reading the TGA header ---------- // | |
159 | + | |
160 | + // Skip image ID | |
161 | + if (idLength > 0) | |
162 | + in.skip(idLength); | |
163 | + | |
164 | + ColorMapEntry[] cMapEntries = null; | |
165 | + if (colorMapType != 0) { | |
166 | + // read the color map. | |
167 | + int bytesInColorMap = (cMapDepth * cMapLength) >> 3; | |
168 | + int bitsPerColor = Math.min(cMapDepth/3 , 8); | |
169 | + | |
170 | + byte[] cMapData = new byte[bytesInColorMap]; | |
171 | + in.read(cMapData); | |
172 | + | |
173 | + // Only go to the trouble of constructing the color map | |
174 | + // table if this is declared a color mapped image. | |
175 | + if (imageType == TYPE_COLORMAPPED || imageType == TYPE_COLORMAPPED_RLE) { | |
176 | + cMapEntries = new ColorMapEntry[cMapLength]; | |
177 | + int alphaSize = cMapDepth - (3*bitsPerColor); | |
178 | + float scalar = 255f / (FastMath.pow(2, bitsPerColor) - 1); | |
179 | + float alphaScalar = 255f / (FastMath.pow(2, alphaSize) - 1); | |
180 | + for (int i = 0; i < cMapLength; i++) { | |
181 | + ColorMapEntry entry = new ColorMapEntry(); | |
182 | + int offset = cMapDepth * i; | |
183 | + entry.red = (byte)(int)(getBitsAsByte(cMapData, offset, bitsPerColor) * scalar); | |
184 | + entry.green = (byte)(int)(getBitsAsByte(cMapData, offset+bitsPerColor, bitsPerColor) * scalar); | |
185 | + entry.blue = (byte)(int)(getBitsAsByte(cMapData, offset+(2*bitsPerColor), bitsPerColor) * scalar); | |
186 | + if (alphaSize <= 0) | |
187 | + entry.alpha = (byte)255; | |
188 | + else | |
189 | + entry.alpha = (byte)(int)(getBitsAsByte(cMapData, offset+(3*bitsPerColor), alphaSize) * alphaScalar); | |
190 | + | |
191 | + cMapEntries[i] = entry; | |
192 | + } | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + | |
197 | + // Allocate image data array | |
198 | + Format format; | |
199 | + byte[] rawData = null; | |
200 | + int dl; | |
201 | + if (pixelDepth == 32) { | |
202 | + rawData = new byte[width * height * 4]; | |
203 | + dl = 4; | |
204 | + } else { | |
205 | + rawData = new byte[width * height * 3]; | |
206 | + dl = 3; | |
207 | + } | |
208 | + int rawDataIndex = 0; | |
209 | + | |
210 | + if (imageType == TYPE_TRUECOLOR) { | |
211 | + byte red = 0; | |
212 | + byte green = 0; | |
213 | + byte blue = 0; | |
214 | + byte alpha = 0; | |
215 | + | |
216 | + // Faster than doing a 16-or-24-or-32 check on each individual pixel, | |
217 | + // just make a seperate loop for each. | |
218 | + if (pixelDepth == 16) { | |
219 | + byte[] data = new byte[2]; | |
220 | + float scalar = 255f/31f; | |
221 | + for (int i = 0; i <= (height - 1); i++) { | |
222 | + if (!flip) | |
223 | + rawDataIndex = (height - 1 - i) * width * dl; | |
224 | + for (int j = 0; j < width; j++) { | |
225 | + data[1] = dis.readByte(); | |
226 | + data[0] = dis.readByte(); | |
227 | + rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 1, 5) * scalar); | |
228 | + rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 6, 5) * scalar); | |
229 | + rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 11, 5) * scalar); | |
230 | + if (dl == 4) { | |
231 | + // create an alpha channel | |
232 | + alpha = getBitsAsByte(data, 0, 1); | |
233 | + if (alpha == 1) alpha = (byte)255; | |
234 | + rawData[rawDataIndex++] = alpha; | |
235 | + } else { | |
236 | + rawData[rawDataIndex++] = (byte)0xff; | |
237 | + } | |
238 | + } | |
239 | + } | |
240 | + | |
241 | + format = dl == 4 ? Format.RGBA8 : Format.RGB8; | |
242 | + } else if (pixelDepth == 24){ | |
243 | + for (int y = 0; y < height; y++) { | |
244 | + if (!flip) | |
245 | + rawDataIndex = (height - 1 - y) * width * dl; | |
246 | + else | |
247 | + rawDataIndex = y * width * dl; | |
248 | + | |
249 | +// dis.readFully(rawData, rawDataIndex, width * dl); | |
250 | + for (int x = 0; x < width; x++) { | |
251 | +// read scanline | |
252 | + blue = dis.readByte(); | |
253 | + green = dis.readByte(); | |
254 | + red = dis.readByte(); | |
255 | + rawData[rawDataIndex++] = red; | |
256 | + rawData[rawDataIndex++] = green; | |
257 | + rawData[rawDataIndex++] = blue; | |
258 | + } | |
259 | + } | |
260 | + format = Format.RGB8; | |
261 | + } else if (pixelDepth == 32){ | |
262 | + for (int i = 0; i <= (height - 1); i++) { | |
263 | + if (!flip) | |
264 | + rawDataIndex = (height - 1 - i) * width * dl; | |
265 | + | |
266 | + for (int j = 0; j < width; j++) { | |
267 | + blue = dis.readByte(); | |
268 | + green = dis.readByte(); | |
269 | + red = dis.readByte(); | |
270 | + alpha = dis.readByte(); | |
271 | + rawData[rawDataIndex++] = red; | |
272 | + rawData[rawDataIndex++] = green; | |
273 | + rawData[rawDataIndex++] = blue; | |
274 | + rawData[rawDataIndex++] = alpha; | |
275 | + } | |
276 | + } | |
277 | + format = Format.RGBA8; | |
278 | + }else{ | |
279 | + throw new IOException("Unsupported TGA true color depth: "+pixelDepth); | |
280 | + } | |
281 | + } else if( imageType == TYPE_TRUECOLOR_RLE ) { | |
282 | + byte red = 0; | |
283 | + byte green = 0; | |
284 | + byte blue = 0; | |
285 | + byte alpha = 0; | |
286 | + // Faster than doing a 16-or-24-or-32 check on each individual pixel, | |
287 | + // just make a seperate loop for each. | |
288 | + if( pixelDepth == 32 ){ | |
289 | + for( int i = 0; i <= ( height - 1 ); ++i ){ | |
290 | + if( !flip ){ | |
291 | + rawDataIndex = ( height - 1 - i ) * width * dl; | |
292 | + } | |
293 | + | |
294 | + for( int j = 0; j < width; ++j ){ | |
295 | + // Get the number of pixels the next chunk covers (either packed or unpacked) | |
296 | + int count = dis.readByte(); | |
297 | + if( ( count & 0x80 ) != 0 ){ | |
298 | + // Its an RLE packed block - use the following 1 pixel for the next <count> pixels | |
299 | + count &= 0x07f; | |
300 | + j += count; | |
301 | + blue = dis.readByte(); | |
302 | + green = dis.readByte(); | |
303 | + red = dis.readByte(); | |
304 | + alpha = dis.readByte(); | |
305 | + while( count-- >= 0 ){ | |
306 | + rawData[rawDataIndex++] = red; | |
307 | + rawData[rawDataIndex++] = green; | |
308 | + rawData[rawDataIndex++] = blue; | |
309 | + rawData[rawDataIndex++] = alpha; | |
310 | + } | |
311 | + } else{ | |
312 | + // Its not RLE packed, but the next <count> pixels are raw. | |
313 | + j += count; | |
314 | + while( count-- >= 0 ){ | |
315 | + blue = dis.readByte(); | |
316 | + green = dis.readByte(); | |
317 | + red = dis.readByte(); | |
318 | + alpha = dis.readByte(); | |
319 | + rawData[rawDataIndex++] = red; | |
320 | + rawData[rawDataIndex++] = green; | |
321 | + rawData[rawDataIndex++] = blue; | |
322 | + rawData[rawDataIndex++] = alpha; | |
323 | + } | |
324 | + } | |
325 | + } | |
326 | + } | |
327 | + format = Format.RGBA8; | |
328 | + } else if( pixelDepth == 24 ){ | |
329 | + for( int i = 0; i <= ( height - 1 ); i++ ){ | |
330 | + if( !flip ){ | |
331 | + rawDataIndex = ( height - 1 - i ) * width * dl; | |
332 | + } | |
333 | + for( int j = 0; j < width; ++j ){ | |
334 | + // Get the number of pixels the next chunk covers (either packed or unpacked) | |
335 | + int count = dis.readByte(); | |
336 | + if( ( count & 0x80 ) != 0 ){ | |
337 | + // Its an RLE packed block - use the following 1 pixel for the next <count> pixels | |
338 | + count &= 0x07f; | |
339 | + j += count; | |
340 | + blue = dis.readByte(); | |
341 | + green = dis.readByte(); | |
342 | + red = dis.readByte(); | |
343 | + while( count-- >= 0 ){ | |
344 | + rawData[rawDataIndex++] = red; | |
345 | + rawData[rawDataIndex++] = green; | |
346 | + rawData[rawDataIndex++] = blue; | |
347 | + } | |
348 | + } else{ | |
349 | + // Its not RLE packed, but the next <count> pixels are raw. | |
350 | + j += count; | |
351 | + while( count-- >= 0 ){ | |
352 | + blue = dis.readByte(); | |
353 | + green = dis.readByte(); | |
354 | + red = dis.readByte(); | |
355 | + rawData[rawDataIndex++] = red; | |
356 | + rawData[rawDataIndex++] = green; | |
357 | + rawData[rawDataIndex++] = blue; | |
358 | + } | |
359 | + } | |
360 | + } | |
361 | + } | |
362 | + format = Format.RGB8; | |
363 | + } else if( pixelDepth == 16 ){ | |
364 | + byte[] data = new byte[ 2 ]; | |
365 | + float scalar = 255f / 31f; | |
366 | + for( int i = 0; i <= ( height - 1 ); i++ ){ | |
367 | + if( !flip ){ | |
368 | + rawDataIndex = ( height - 1 - i ) * width * dl; | |
369 | + } | |
370 | + for( int j = 0; j < width; j++ ){ | |
371 | + // Get the number of pixels the next chunk covers (either packed or unpacked) | |
372 | + int count = dis.readByte(); | |
373 | + if( ( count & 0x80 ) != 0 ){ | |
374 | + // Its an RLE packed block - use the following 1 pixel for the next <count> pixels | |
375 | + count &= 0x07f; | |
376 | + j += count; | |
377 | + data[1] = dis.readByte(); | |
378 | + data[0] = dis.readByte(); | |
379 | + blue = (byte) (int) ( getBitsAsByte( data, 1, 5 ) * scalar ); | |
380 | + green = (byte) (int) ( getBitsAsByte( data, 6, 5 ) * scalar ); | |
381 | + red = (byte) (int) ( getBitsAsByte( data, 11, 5 ) * scalar ); | |
382 | + while( count-- >= 0 ){ | |
383 | + rawData[rawDataIndex++] = red; | |
384 | + rawData[rawDataIndex++] = green; | |
385 | + rawData[rawDataIndex++] = blue; | |
386 | + } | |
387 | + } else{ | |
388 | + // Its not RLE packed, but the next <count> pixels are raw. | |
389 | + j += count; | |
390 | + while( count-- >= 0 ){ | |
391 | + data[1] = dis.readByte(); | |
392 | + data[0] = dis.readByte(); | |
393 | + blue = (byte) (int) ( getBitsAsByte( data, 1, 5 ) * scalar ); | |
394 | + green = (byte) (int) ( getBitsAsByte( data, 6, 5 ) * scalar ); | |
395 | + red = (byte) (int) ( getBitsAsByte( data, 11, 5 ) * scalar ); | |
396 | + rawData[rawDataIndex++] = red; | |
397 | + rawData[rawDataIndex++] = green; | |
398 | + rawData[rawDataIndex++] = blue; | |
399 | + } | |
400 | + } | |
401 | + } | |
402 | + } | |
403 | + format = Format.RGB8; | |
404 | + } else{ | |
405 | + throw new IOException( "Unsupported TGA true color depth: " + pixelDepth ); | |
406 | + } | |
407 | + | |
408 | + } else if( imageType == TYPE_COLORMAPPED ){ | |
409 | + int bytesPerIndex = pixelDepth / 8; | |
410 | + | |
411 | + if (bytesPerIndex == 1) { | |
412 | + for (int i = 0; i <= (height - 1); i++) { | |
413 | + if (!flip) | |
414 | + rawDataIndex = (height - 1 - i) * width * dl; | |
415 | + for (int j = 0; j < width; j++) { | |
416 | + int index = dis.readUnsignedByte(); | |
417 | + if (index >= cMapEntries.length || index < 0) | |
418 | + throw new IOException("TGA: Invalid color map entry referenced: "+index); | |
419 | + | |
420 | + ColorMapEntry entry = cMapEntries[index]; | |
421 | + rawData[rawDataIndex++] = entry.red; | |
422 | + rawData[rawDataIndex++] = entry.green; | |
423 | + rawData[rawDataIndex++] = entry.blue; | |
424 | + if (dl == 4) { | |
425 | + rawData[rawDataIndex++] = entry.alpha; | |
426 | + } else { | |
427 | + rawData[rawDataIndex++] = (byte)0xff; | |
428 | + } | |
429 | + } | |
430 | + } | |
431 | + } else if (bytesPerIndex == 2) { | |
432 | + for (int i = 0; i <= (height - 1); i++) { | |
433 | + if (!flip) | |
434 | + rawDataIndex = (height - 1 - i) * width * dl; | |
435 | + for (int j = 0; j < width; j++) { | |
436 | + int index = flipEndian(dis.readShort()); | |
437 | + if (index >= cMapEntries.length || index < 0) | |
438 | + throw new IOException("TGA: Invalid color map entry referenced: "+index); | |
439 | + | |
440 | + ColorMapEntry entry = cMapEntries[index]; | |
441 | + rawData[rawDataIndex++] = entry.red; | |
442 | + rawData[rawDataIndex++] = entry.green; | |
443 | + rawData[rawDataIndex++] = entry.blue; | |
444 | + if (dl == 4) { | |
445 | + rawData[rawDataIndex++] = entry.alpha; | |
446 | + } else { | |
447 | + rawData[rawDataIndex++] = (byte)0xff; | |
448 | + } | |
449 | + } | |
450 | + } | |
451 | + } else { | |
452 | + throw new IOException("TGA: unknown colormap indexing size used: "+bytesPerIndex); | |
453 | + } | |
454 | + | |
455 | + format = dl == 4 ? Format.RGBA8 : Format.RGB8; | |
456 | + } else { | |
457 | + throw new IOException("Grayscale TGA not supported"); | |
458 | + } | |
459 | + | |
460 | + | |
461 | + in.close(); | |
462 | + Image textureImage = new Image(); | |
463 | + textureImage.setFormat(format); | |
464 | + textureImage.setWidth(FastMath.nearestPowerOfTwo(width)); | |
465 | + textureImage.setHeight(FastMath.nearestPowerOfTwo(height)); | |
466 | + if (format != Format.RGBA8) { | |
467 | + rawData = resize2(width, height, FastMath.nearestPowerOfTwo(width), FastMath.nearestPowerOfTwo(height), rawData); | |
468 | + //textureImage.setFormat(Format.RGBA8); | |
469 | + } else { | |
470 | + rawData = resize(width, height, FastMath.nearestPowerOfTwo(width), FastMath.nearestPowerOfTwo(height), rawData); | |
471 | + } | |
472 | + ByteBuffer bb = BufferUtils.createByteBuffer(rawData.length); | |
473 | + for(int i=0;i<rawData.length;i++) { | |
474 | + bb.put(rawData[i]); | |
475 | + } | |
476 | + bb.position(0); | |
477 | + textureImage.setData(bb); | |
478 | + System.out.println("pixelDepth = "+pixelDepth); | |
479 | + return textureImage; | |
480 | + } | |
481 | + | |
482 | + private static byte getBitsAsByte(byte[] data, int offset, int length) { | |
483 | + int offsetBytes = offset / 8; | |
484 | + int indexBits = offset % 8; | |
485 | + int rVal = 0; | |
486 | + | |
487 | + // start at data[offsetBytes]... spill into next byte as needed. | |
488 | + for (int i = length; --i >=0;) { | |
489 | + byte b = data[offsetBytes]; | |
490 | + int test = indexBits == 7 ? 1 : 2 << (6-indexBits); | |
491 | + if ((b & test) != 0) { | |
492 | + if (i == 0) | |
493 | + rVal++; | |
494 | + else | |
495 | + rVal += (2 << i-1); | |
496 | + } | |
497 | + indexBits++; | |
498 | + if (indexBits == 8) { | |
499 | + indexBits = 0; | |
500 | + offsetBytes++; | |
501 | + } | |
502 | + } | |
503 | + | |
504 | + return (byte)rVal; | |
505 | + } | |
506 | + | |
507 | + /** | |
508 | + * <code>flipEndian</code> is used to flip the endian bit of the header | |
509 | + * file. | |
510 | + * | |
511 | + * @param signedShort | |
512 | + * the bit to flip. | |
513 | + * @return the flipped bit. | |
514 | + */ | |
515 | + private static short flipEndian(short signedShort) { | |
516 | + int input = signedShort & 0xFFFF; | |
517 | + return (short) (input << 8 | (input & 0xFF00) >>> 8); | |
518 | + } | |
519 | + | |
520 | + static class ColorMapEntry { | |
521 | + byte red, green, blue, alpha; | |
522 | + | |
523 | + @Override | |
524 | + public String toString() { | |
525 | + return "entry: "+red+","+green+","+blue+","+alpha; | |
526 | + } | |
527 | + } | |
528 | + private static byte[] resize(int w1,int h1, int w2, int h2, byte[] buf) { | |
529 | +// w2 = w1; | |
530 | +// h2 = h1; | |
531 | + if (w1 == w2 && h1 == h2) { | |
532 | + return buf; | |
533 | + } | |
534 | + byte[] out = new byte[w2 * h2 * 4]; | |
535 | + float f1 = ((float)w1) / (float)w2; | |
536 | + float f2 = ((float)h1) / (float)h2; | |
537 | + for(int x = 0;x<w2;x++) { | |
538 | + for(int y = 0;y<h2;y++) { | |
539 | + int index = (int)(((int)(f2 * (float)y)) * (float)w1 + f1 * (float)x); | |
540 | + if (index >= w1 * h1) { | |
541 | + index = 0; | |
542 | + } | |
543 | + for(int i=0;i<4;i++) { | |
544 | + out[(x + y * w2)*4+i] = buf[index * 4 + i]; | |
545 | + } | |
546 | + } | |
547 | + } | |
548 | + return out; | |
549 | + } | |
550 | + private static byte[] resize2(int w1,int h1, int w2, int h2, byte[] buf) { | |
551 | +// w2 = w1; | |
552 | +// h2 = h1; | |
553 | + if (w1 == w2 && h1 == h2) { | |
554 | + //return buf; | |
555 | + } | |
556 | + byte[] out = new byte[w2 * h2 * 3]; | |
557 | + float f1 = ((float)w1) / (float)w2; | |
558 | + float f2 = ((float)h1) / (float)h2; | |
559 | + for(int x = 0;x<w2;x++) { | |
560 | + for(int y = 0;y<h2;y++) { | |
561 | + int index = (int)(((int)(f2 * (float)y)) * (float)w1 + f1 * (float)x); | |
562 | + if (index >= w1 * h1) { | |
563 | + index = 0; | |
564 | + } | |
565 | + for(int i=0;i<3;i++) { | |
566 | + out[(x + y * w2)*3+i] = buf[index * 3 + i]; | |
567 | + } | |
568 | + } | |
569 | + } | |
570 | + return out; | |
571 | + } | |
572 | +} |
@@ -0,0 +1,75 @@ | ||
1 | +package com.jme3.util; | |
2 | + | |
3 | +import java.util.Iterator; | |
4 | +import java.util.NoSuchElementException; | |
5 | + | |
6 | +/** | |
7 | + * Ring buffer (fixed size queue) implementation using a circular array (array with wrap-around). | |
8 | + */ | |
9 | +// suppress unchecked warnings in Java 1.5.0_6 and later | |
10 | +@SuppressWarnings("unchecked") | |
11 | +public class RingBuffer<Item> implements Iterable<Item> { | |
12 | + | |
13 | + private Item[] buffer; // queue elements | |
14 | + private int count = 0; // number of elements on queue | |
15 | + private int indexOut = 0; // index of first element of queue | |
16 | + private int indexIn = 0; // index of next available slot | |
17 | + | |
18 | + // cast needed since no generic array creation in Java | |
19 | + public RingBuffer(int capacity) { | |
20 | + buffer = (Item[]) new Object[capacity]; | |
21 | + } | |
22 | + | |
23 | + public boolean isEmpty() { | |
24 | + return count == 0; | |
25 | + } | |
26 | + | |
27 | + public int size() { | |
28 | + return count; | |
29 | + } | |
30 | + | |
31 | + public void push(Item item) { | |
32 | + if (count == buffer.length) { | |
33 | + throw new RuntimeException("Ring buffer overflow"); | |
34 | + } | |
35 | + buffer[indexIn] = item; | |
36 | + indexIn = (indexIn + 1) % buffer.length; // wrap-around | |
37 | + count++; | |
38 | + } | |
39 | + | |
40 | + public Item pop() { | |
41 | + if (isEmpty()) { | |
42 | + throw new RuntimeException("Ring buffer underflow"); | |
43 | + } | |
44 | + Item item = buffer[indexOut]; | |
45 | + buffer[indexOut] = null; // to help with garbage collection | |
46 | + count--; | |
47 | + indexOut = (indexOut + 1) % buffer.length; // wrap-around | |
48 | + return item; | |
49 | + } | |
50 | + | |
51 | + public Iterator<Item> iterator() { | |
52 | + return new RingBufferIterator(); | |
53 | + } | |
54 | + | |
55 | + // an iterator, doesn't implement remove() since it's optional | |
56 | + private class RingBufferIterator implements Iterator<Item> { | |
57 | + | |
58 | + private int i = 0; | |
59 | + | |
60 | + public boolean hasNext() { | |
61 | + return i < count; | |
62 | + } | |
63 | + | |
64 | + public void remove() { | |
65 | + throw new UnsupportedOperationException(); | |
66 | + } | |
67 | + | |
68 | + public Item next() { | |
69 | + if (!hasNext()) { | |
70 | + throw new NoSuchElementException(); | |
71 | + } | |
72 | + return buffer[i++]; | |
73 | + } | |
74 | + } | |
75 | +} |
@@ -0,0 +1,22 @@ | ||
1 | +LOCATOR / com.jme3.asset.plugins.ClasspathLocator | |
2 | + | |
3 | +LOADER com.jme3.audio.plugins.WAVLoader : wav | |
4 | +LOADER com.jme3.audio.plugins.OGGLoader : ogg | |
5 | +LOADER com.jme3.material.plugins.J3MLoader : j3m | |
6 | +LOADER com.jme3.material.plugins.J3MLoader : j3md | |
7 | +LOADER com.jme3.font.plugins.BitmapFontLoader : fnt | |
8 | +LOADER com.jme3.texture.plugins.DDSLoader : dds | |
9 | +LOADER com.jme3.texture.plugins.PFMLoader : pfm | |
10 | +LOADER com.jme3.texture.plugins.HDRLoader : hdr | |
11 | +LOADER com.jme3.texture.plugins.TGALoader : tga | |
12 | +LOADER com.jme3.export.binary.BinaryImporter : j3o | |
13 | +LOADER com.jme3.export.binary.BinaryImporter : j3f | |
14 | +LOADER com.jme3.scene.plugins.OBJLoader : obj | |
15 | +LOADER com.jme3.scene.plugins.MTLLoader : mtl | |
16 | +LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml | |
17 | +LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml | |
18 | +LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material | |
19 | +LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene | |
20 | +LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib | |
21 | +LOADER projectkyoto.jme3.mmd.PMDLoaderGLSLSkinning2 : pmd | |
22 | +LOADER projectkyoto.jme3.mmd.VMDLoader : vmd | |
\ No newline at end of file |