v0.7.4b: Initial LibGDX commit! more details below:

Large sections of game logic are now working through libgdx instead of
android libraries. There is still work to do but this is the first
major step. Big changes include:
- Graphics code is now through LibGDX (except for text rendering)
- Initialization and screen-handling logic is now mostly through LibGDX
- Audio is now through LibGDX
- Input handling is now through LibGDX
- Most misc functions are now through LibGDX
This commit is contained in:
Evan Debenham 2019-07-30 16:50:40 -04:00
parent f10be84a10
commit 2a523f2ea2
42 changed files with 828 additions and 972 deletions

View File

@ -6,5 +6,54 @@ android {
defaultConfig {
//noinspection MinSdkTooLow
minSdkVersion appAndroidMinSDK
consumerProguardFiles 'proguard-rules.pro'
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
configurations { natives }
dependencies {
//TODO migrate this to implementation from api
//in order to do this I have to remove 100% of libGDX API access from core
api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi"
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
implementation "com.badlogicgames.gdx:gdx-controllers:$gdxVersion"
implementation "com.badlogicgames.gdx:gdx-controllers-android:$gdxVersion"
}
// called every time gradle gets executed, takes the native dependencies of
// the natives configuration, and extracts them to the proper libs/ folders
// so they get packed with the APK.
task copyAndroidNatives() {
file("libs/armeabi/").mkdirs()
file("libs/armeabi-v7a/").mkdirs()
file("libs/arm64-v8a/").mkdirs()
file("libs/x86_64/").mkdirs()
file("libs/x86/").mkdirs()
configurations.natives.files.each { jar ->
def outputDir = null
if(jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
if(jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
if(jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi")
if(jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64")
if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
if(outputDir != null) {
copy {
from zipTree(jar)
into outputDir
include "*.so"
}
}
}
}

19
SPD-classes/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,19 @@
-dontwarn android.support.**
-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication
-dontwarn com.badlogic.gdx.utils.GdxBuild
-dontwarn com.badlogic.gdx.physics.box2d.utils.Box2DBuild
-dontwarn com.badlogic.gdx.jnigen.BuildTarget*
-keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* {
<init>(com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration);
}
-keepclassmembers class com.badlogic.gdx.physics.box2d.World {
boolean contactFilter(long, long);
void beginContact(long);
void endContact(long);
void preSolve(long, long);
void postSolve(long, long);
boolean reportFixture(long);
float reportRayFixture(long, float, float, float, float, float);
}

View File

@ -21,15 +21,15 @@
package com.watabou.gltextures;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import com.watabou.glwrap.Texture;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
//provides a native intbuffer implementation because android.graphics.bitmap is too slow
//provides a native intbuffer implementation because pixmap is too slow
//TODO: should evaluate this again, seeing as I've moved to LibGDX
public class BufferTexture extends SmartTexture {
public IntBuffer pixels;
@ -46,9 +46,7 @@ public class BufferTexture extends SmartTexture {
@Override
protected void generate() {
int[] ids = new int[1];
GLES20.glGenTextures( 1, ids, 0 );
id = ids[0];
id = Gdx.gl.glGenTexture();
}
@Override
@ -62,15 +60,15 @@ public class BufferTexture extends SmartTexture {
filter( Texture.LINEAR, Texture.LINEAR );
wrap( Texture.CLAMP, Texture.CLAMP);
pixels.position(0);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
Gdx.gl.glTexImage2D(
Gdx.gl.GL_TEXTURE_2D,
0,
GLES20.GL_RGBA,
Gdx.gl.GL_RGBA,
width,
height,
0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
Gdx.gl.GL_RGBA,
Gdx.gl.GL_UNSIGNED_BYTE,
pixels );
}
@ -80,14 +78,14 @@ public class BufferTexture extends SmartTexture {
filter( Texture.LINEAR, Texture.LINEAR );
wrap( Texture.CLAMP, Texture.CLAMP);
pixels.position(top*width);
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D,
Gdx.gl.glTexSubImage2D(Gdx.gl.GL_TEXTURE_2D,
0,
0,
top,
width,
bottom - top,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
Gdx.gl.GL_RGBA,
Gdx.gl.GL_UNSIGNED_BYTE,
pixels);
}
}

View File

@ -21,8 +21,7 @@
package com.watabou.gltextures;
import android.graphics.Bitmap;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.glwrap.Texture;
import com.watabou.utils.RectF;
@ -37,22 +36,22 @@ public class SmartTexture extends Texture {
public int wModeH;
public int wModeV;
public Bitmap bitmap;
public Pixmap bitmap;
public Atlas atlas;
protected SmartTexture( ) {
//useful for subclasses which want to manage their own texture data
// in cases where android.graphics.bitmap isn't fast enough.
// in cases where pixmaps isn't fast enough.
//subclasses which use this MUST also override some mix of reload/generate/bind
}
public SmartTexture( Bitmap bitmap ) {
public SmartTexture( Pixmap bitmap ) {
this( bitmap, NEAREST, CLAMP, false );
}
public SmartTexture( Bitmap bitmap, int filtering, int wrapping, boolean premultiplied ) {
public SmartTexture( Pixmap bitmap, int filtering, int wrapping, boolean premultiplied ) {
this.bitmap = bitmap;
width = bitmap.getWidth();
@ -66,7 +65,7 @@ public class SmartTexture extends Texture {
@Override
protected void generate() {
super.generate();
bitmap( bitmap, premultiplied );
bitmap( bitmap );
filter( fModeMin, fModeMax );
wrap( wModeH, wModeV );
}
@ -88,16 +87,8 @@ public class SmartTexture extends Texture {
}
@Override
public void bitmap( Bitmap bitmap ) {
bitmap( bitmap, false );
}
public void bitmap( Bitmap bitmap, boolean premultiplied ) {
if (premultiplied) {
super.bitmap( bitmap );
} else {
handMade( bitmap, true );
}
public void bitmap( Pixmap bitmap ) {
super.bitmap( bitmap );
this.bitmap = bitmap;
width = bitmap.getWidth();
@ -119,7 +110,7 @@ public class SmartTexture extends Texture {
super.delete();
if (bitmap != null)
bitmap.recycle();
bitmap.dispose();
bitmap = null;
}

View File

@ -21,28 +21,16 @@
package com.watabou.gltextures;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.glwrap.Texture;
import com.watabou.noosa.Game;
import java.util.HashMap;
public class TextureCache {
public static Context context;
private static HashMap<Object,SmartTexture> all = new HashMap<>();
// No dithering, no scaling, 32 bits per pixel
private static BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
static {
bitmapOptions.inScaled = false;
bitmapOptions.inDither = false;
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
}
public synchronized static SmartTexture createSolid( int color ) {
final String key = "1x1:" + color;
@ -52,11 +40,13 @@ public class TextureCache {
return all.get( key );
} else {
Bitmap bmp = Bitmap.createBitmap( 1, 1, Bitmap.Config.ARGB_8888 );
bmp.eraseColor( color );
SmartTexture tx = new SmartTexture( bmp );
Pixmap pixmap =new Pixmap( 1, 1, Pixmap.Format.RGBA8888 );
// In the rest of the code ARGB is used
pixmap.setColor( (color << 8) | (color >>> 24) );
pixmap.fill();
SmartTexture tx = new SmartTexture( pixmap );
all.put( key, tx );
return tx;
@ -72,12 +62,13 @@ public class TextureCache {
return all.get( key );
} else {
Bitmap bmp = Bitmap.createBitmap( colors.length, 1, Bitmap.Config.ARGB_8888 );
Pixmap pixmap = new Pixmap( colors.length, 1, Pixmap.Format.RGBA8888);
for (int i=0; i < colors.length; i++) {
bmp.setPixel( i, 0, colors[i] );
// In the rest of the code ARGB is used
pixmap.drawPixel( i, 0, (colors[i] << 8) | (colors[i] >>> 24) );
}
SmartTexture tx = new SmartTexture( bmp );
SmartTexture tx = new SmartTexture( pixmap );
tx.filter( Texture.LINEAR, Texture.LINEAR );
tx.wrap( Texture.CLAMP, Texture.CLAMP );
@ -134,22 +125,22 @@ public class TextureCache {
}
}
public static Bitmap getBitmap( Object src ) {
public static Pixmap getBitmap( Object src ) {
try {
if (src instanceof Integer){
return BitmapFactory.decodeResource(
context.getResources(), (Integer)src, bitmapOptions );
//LibGDX does not support android resource integer handles, and they were
//never used by the game anyway, should probably remove this entirely
return null;
} else if (src instanceof String) {
return BitmapFactory.decodeStream(
context.getAssets().open( (String)src ), null, bitmapOptions );
return new Pixmap(Gdx.files.internal((String)src));
} else if (src instanceof Bitmap) {
} else if (src instanceof Pixmap) {
return (Bitmap)src;
return (Pixmap)src;
} else {

View File

@ -21,8 +21,7 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import android.os.Build;
import com.badlogic.gdx.Gdx;
import java.nio.FloatBuffer;
@ -39,18 +38,18 @@ public class Attribute {
}
public void enable() {
GLES20.glEnableVertexAttribArray( location );
Gdx.gl.glEnableVertexAttribArray( location );
}
public void disable() {
GLES20.glDisableVertexAttribArray( location );
Gdx.gl.glDisableVertexAttribArray( location );
}
public void vertexPointer( int size, int stride, FloatBuffer ptr ) {
GLES20.glVertexAttribPointer( location, size, GLES20.GL_FLOAT, false, stride * 4, ptr );
Gdx.gl.glVertexAttribPointer( location, size, Gdx.gl.GL_FLOAT, false, stride * 4, ptr );
}
public void vertexBuffer( int size, int stride, int offset) {
GLES20.glVertexAttribPointer(location, size, GLES20.GL_FLOAT, false, stride * 4, offset * 4);
Gdx.gl.glVertexAttribPointer(location, size, Gdx.gl.GL_FLOAT, false, stride * 4, offset * 4);
}
}

View File

@ -21,7 +21,7 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import javax.microedition.khronos.opengles.GL10;
@ -33,21 +33,21 @@ public class Blending {
}
public static void enable(){
GLES20.glEnable( GL10.GL_BLEND );
Gdx.gl.glEnable( GL10.GL_BLEND );
}
public static void disable(){
GLES20.glDisable( GL10.GL_BLEND );
Gdx.gl.glDisable( GL10.GL_BLEND );
}
//in this mode colors overwrite eachother, based on alpha value
public static void setNormalMode(){
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
Gdx.gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
}
//in this mode colors add to eachother, eventually reaching pure white
public static void setLightMode(){
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE );
Gdx.gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE );
}
}

View File

@ -21,22 +21,20 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
public class Framebuffer {
public static final int COLOR = GLES20.GL_COLOR_ATTACHMENT0;
public static final int DEPTH = GLES20.GL_DEPTH_ATTACHMENT;
public static final int STENCIL = GLES20.GL_STENCIL_ATTACHMENT;
public static final int COLOR = Gdx.gl.GL_COLOR_ATTACHMENT0;
public static final int DEPTH = Gdx.gl.GL_DEPTH_ATTACHMENT;
public static final int STENCIL = Gdx.gl.GL_STENCIL_ATTACHMENT;
public static final Framebuffer system = new Framebuffer( 0 );
private int id;
public Framebuffer() {
int[] buffers = new int[1];
GLES20.glGenBuffers( 1, buffers, 0 );
id = buffers[0];
id = Gdx.gl.glGenBuffer();
}
private Framebuffer( int n ) {
@ -44,26 +42,25 @@ public class Framebuffer {
}
public void bind() {
GLES20.glBindFramebuffer( GLES20.GL_FRAMEBUFFER, id );
Gdx.gl.glBindFramebuffer( Gdx.gl.GL_FRAMEBUFFER, id );
}
public void delete() {
int[] buffers = {id};
GLES20.glDeleteFramebuffers( 1, buffers, 0 );
Gdx.gl.glDeleteBuffer(id);
}
public void attach( int point, Texture tex ) {
bind();
GLES20.glFramebufferTexture2D( GLES20.GL_FRAMEBUFFER, point, GLES20.GL_TEXTURE_2D, tex.id, 0 );
Gdx.gl.glFramebufferTexture2D( Gdx.gl.GL_FRAMEBUFFER, point, Gdx.gl.GL_TEXTURE_2D, tex.id, 0 );
}
public void attach( int point, Renderbuffer buffer ) {
bind();
GLES20.glFramebufferRenderbuffer( GLES20.GL_RENDERBUFFER, point, GLES20.GL_TEXTURE_2D, buffer.id() );
Gdx.gl.glFramebufferRenderbuffer( Gdx.gl.GL_RENDERBUFFER, point, Gdx.gl.GL_TEXTURE_2D, buffer.id() );
}
public boolean status() {
bind();
return GLES20.glCheckFramebufferStatus( GLES20.GL_FRAMEBUFFER ) == GLES20.GL_FRAMEBUFFER_COMPLETE;
return Gdx.gl.glCheckFramebufferStatus( Gdx.gl.GL_FRAMEBUFFER ) == Gdx.gl.GL_FRAMEBUFFER_COMPLETE;
}
}

View File

@ -21,6 +21,8 @@
package com.watabou.glwrap;
//TODO LibGDX offer matrix classes as well, which might give better performance.
//should investigate using them
public class Matrix {
public static final float G2RAD = 0.01745329251994329576923690768489f;
@ -91,7 +93,6 @@ public class Matrix {
m[5] *= y;
m[6] *= y;
m[7] *= y;
// android.opengl.Matrix.scaleM( m, 0, x, y, 1 );
}
public static void translate( float[] m, float x, float y ) {
@ -100,6 +101,64 @@ public class Matrix {
}
public static void multiply( float[] left, float right[], float[] result ) {
android.opengl.Matrix.multiplyMM( result, 0, left, 0, right, 0 );
final float ax1 = left[0];
final float ay1 = left[1];
final float az1 = left[2];
final float aw1 = left[3];
final float ax2 = left[4];
final float ay2 = left[5];
final float az2 = left[6];
final float aw2 = left[7];
final float ax3 = left[8];
final float ay3 = left[9];
final float az3 = left[10];
final float aw3 = left[11];
final float ax4 = left[12];
final float ay4 = left[13];
final float az4 = left[14];
final float aw4 = left[15];
final float bx1 = right[0];
final float by1 = right[1];
final float bz1 = right[2];
final float bw1 = right[3];
final float bx2 = right[4];
final float by2 = right[5];
final float bz2 = right[6];
final float bw2 = right[7];
final float bx3 = right[8];
final float by3 = right[9];
final float bz3 = right[10];
final float bw3 = right[11];
final float bx4 = right[12];
final float by4 = right[13];
final float bz4 = right[14];
final float bw4 = right[15];
result[0] = ax1 * bx1 + ax2 * by1 + ax3 * bz1 + ax4 * bw1;
result[1] = ay1 * bx1 + ay2 * by1 + ay3 * bz1 + ay4 * bw1;
result[2] = az1 * bx1 + az2 * by1 + az3 * bz1 + az4 * bw1;
result[3] = aw1 * bx1 + aw2 * by1 + aw3 * bz1 + aw4 * bw1;
result[4] = ax1 * bx2 + ax2 * by2 + ax3 * bz2 + ax4 * bw2;
result[5] = ay1 * bx2 + ay2 * by2 + ay3 * bz2 + ay4 * bw2;
result[6] = az1 * bx2 + az2 * by2 + az3 * bz2 + az4 * bw2;
result[7] = aw1 * bx2 + aw2 * by2 + aw3 * bz2 + aw4 * bw2;
result[8] = ax1 * bx3 + ax2 * by3 + ax3 * bz3 + ax4 * bw3;
result[9] = ay1 * bx3 + ay2 * by3 + ay3 * bz3 + ay4 * bw3;
result[10] = az1 * bx3 + az2 * by3 + az3 * bz3 + az4 * bw3;
result[11] = aw1 * bx3 + aw2 * by3 + aw3 * bz3 + aw4 * bw3;
result[12] = ax1 * bx4 + ax2 * by4 + ax3 * bz4 + ax4 * bw4;
result[13] = ay1 * bx4 + ay2 * by4 + ay3 * bz4 + ay4 * bw4;
result[14] = az1 * bx4 + az2 * by4 + az3 * bz4 + az4 * bw4;
result[15] = aw1 * bx4 + aw2 * by4 + aw3 * bz4 + aw4 * bw4;
}
}

View File

@ -21,14 +21,17 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.BufferUtils;
import java.nio.IntBuffer;
public class Program {
private int handle;
public Program() {
handle = GLES20.glCreateProgram();
handle = Gdx.gl.glCreateProgram();
}
public int handle() {
@ -36,33 +39,33 @@ public class Program {
}
public void attach( Shader shader ) {
GLES20.glAttachShader( handle, shader.handle() );
Gdx.gl.glAttachShader( handle, shader.handle() );
}
public void link() {
GLES20.glLinkProgram( handle );
Gdx.gl.glLinkProgram( handle );
int[] status = new int[1];
GLES20.glGetProgramiv( handle, GLES20.GL_LINK_STATUS, status, 0 );
if (status[0] == GLES20.GL_FALSE) {
throw new Error( GLES20.glGetProgramInfoLog( handle ) );
IntBuffer status = BufferUtils.newIntBuffer(1);
Gdx.gl.glGetProgramiv( handle, Gdx.gl.GL_LINK_STATUS, status );
if (status.get() == Gdx.gl.GL_FALSE) {
throw new Error( Gdx.gl.glGetProgramInfoLog( handle ) );
}
}
public Attribute attribute( String name ) {
return new Attribute( GLES20.glGetAttribLocation( handle, name ) );
return new Attribute( Gdx.gl.glGetAttribLocation( handle, name ) );
}
public Uniform uniform( String name ) {
return new Uniform( GLES20.glGetUniformLocation( handle, name ) );
return new Uniform( Gdx.gl.glGetUniformLocation( handle, name ) );
}
public void use() {
GLES20.glUseProgram( handle );
Gdx.gl.glUseProgram( handle );
}
public void delete() {
GLES20.glDeleteProgram( handle );
Gdx.gl.glDeleteProgram( handle );
}
public static Program create( Shader ...shaders ) {

View File

@ -21,7 +21,7 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@ -59,21 +59,19 @@ public class Quad {
public static void setupIndices(){
ShortBuffer indices = getIndices( Short.MAX_VALUE );
if (bufferIndex == -1){
int[] buf = new int[1];
GLES20.glGenBuffers(1, buf, 0);
bufferIndex = buf[0];
bufferIndex = Gdx.gl.glGenBuffer();
}
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferIndex);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, (indices.capacity()*2), indices, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ELEMENT_ARRAY_BUFFER, bufferIndex);
Gdx.gl.glBufferData(Gdx.gl.GL_ELEMENT_ARRAY_BUFFER, (indices.capacity()*2), indices, Gdx.gl.GL_STATIC_DRAW);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ELEMENT_ARRAY_BUFFER, 0);
}
public static void bindIndices(){
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufferIndex);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ELEMENT_ARRAY_BUFFER, bufferIndex);
}
public static void releaseIndices(){
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ELEMENT_ARRAY_BUFFER, 0);
}
public static ShortBuffer getIndices( int size ) {

View File

@ -21,20 +21,18 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
public class Renderbuffer {
public static final int RGBA8 = GLES20.GL_RGBA; // ?
public static final int DEPTH16 = GLES20.GL_DEPTH_COMPONENT16;
public static final int STENCIL8 = GLES20.GL_STENCIL_INDEX8;
public static final int RGBA8 = Gdx.gl.GL_RGBA; // ?
public static final int DEPTH16 = Gdx.gl.GL_DEPTH_COMPONENT16;
public static final int STENCIL8 = Gdx.gl.GL_STENCIL_INDEX8;
private int id;
public Renderbuffer() {
int[] buffers = new int[1];
GLES20.glGenRenderbuffers( 1, buffers, 0 );
id = buffers[0];
id = Gdx.gl.glGenRenderbuffer();
}
public int id() {
@ -42,15 +40,14 @@ public class Renderbuffer {
}
public void bind() {
GLES20.glBindRenderbuffer( GLES20.GL_RENDERBUFFER, id );
Gdx.gl.glBindRenderbuffer( Gdx.gl.GL_RENDERBUFFER, id );
}
public void delete() {
int[] buffers = {id};
GLES20.glDeleteRenderbuffers( 1, buffers, 0 );
Gdx.gl.glDeleteRenderbuffer( id );
}
public void storage( int format, int width, int height ) {
GLES20.glRenderbufferStorage( GLES20.GL_RENDERBUFFER, format , width, height );
Gdx.gl.glRenderbufferStorage( Gdx.gl.GL_RENDERBUFFER, format , width, height );
}
}

View File

@ -1,183 +0,0 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.watabou.glwrap;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
public class ScreenConfigChooser implements GLSurfaceView.EGLConfigChooser {
//array of corresponding EGL attributes for each array index
private int[] attribEGLconsts = new int[]{
EGL10.EGL_RED_SIZE,
EGL10.EGL_GREEN_SIZE,
EGL10.EGL_BLUE_SIZE,
EGL10.EGL_ALPHA_SIZE,
EGL10.EGL_DEPTH_SIZE,
EGL10.EGL_STENCIL_SIZE
};
private int[] desiredAttribVals = new int[attribEGLconsts.length]; //desired attribute values
private int[] attribPrefs = new int[attribEGLconsts.length]; //attribute preferences types
private int[] prefWeights = new int[attribEGLconsts.length]; //weights for preferences
//attributes with this preference are ignored
public static final int DONT_CARE = 0;
//attributes with this preference must be present in the config at exactly the given value
public static final int EXACTLY = 1;
//attributes with this preference must be present in the config with at least the given value
// In the case of multiple valid configs, chooser will prefer lower values for these attributes
public static final int PREF_LOW = 2;
//attributes with this preference must be present in the config with at least the given value
// In the case of multiple valid configs, chooser will prefer higher values for these attributes
public static final int PREF_HIGH = 3;
private EGL10 egl;
private EGLDisplay display;
public ScreenConfigChooser(){
this( false );
}
public ScreenConfigChooser( boolean depth ){
this( false, depth );
}
//helper constructor for a basic config with or without depth
//and whether or not to prefer RGB565 for performance reasons
//On many devices RGB565 gives slightly better performance for a minimal quality tradeoff.
public ScreenConfigChooser( boolean prefRGB565, boolean depth ){
this(
new int[]{ 5 , 6 , 5 , 0 , depth ? 16 : 0, 0 } ,
prefRGB565 ?
new int[]{ PREF_LOW , PREF_LOW , PREF_LOW , EXACTLY , PREF_LOW , PREF_LOW } :
new int[]{ PREF_HIGH, PREF_HIGH, PREF_HIGH, EXACTLY , PREF_LOW , PREF_LOW },
new int[]{ 2 , 2 , 2 , 1 , 1 , 1 }
);
}
public ScreenConfigChooser( int[] vals, int[] prefs, int[] weights){
if (vals.length != desiredAttribVals.length
|| prefs.length != attribPrefs.length
|| weights.length != prefWeights.length)
throw new IllegalArgumentException("incorrect array lengths!");
desiredAttribVals = vals;
attribPrefs = prefs;
prefWeights = weights;
}
private int[] eglPrefs = new int[]{
EGL10.EGL_RENDERABLE_TYPE, 4, //same as EGL_OPENGL_ES2_BIT. config must support GLES 2.0
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_NONE
};
@Override
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
this.egl = egl;
this.display = display;
int[] num = new int[1];
if (!egl.eglChooseConfig(display, eglPrefs, null, 0, num)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
EGLConfig[] configs = new EGLConfig[num[0]];
if (!egl.eglChooseConfig(display, eglPrefs, configs, num[0], num)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
EGLConfig config = chooseConfig(configs);
if (config == null) {
throw new IllegalArgumentException("No config chosen");
}
return config;
}
private EGLConfig chooseConfig( EGLConfig[] configs ){
EGLConfig bestConfig = null;
int bestConfigValue = Integer.MIN_VALUE;
for (EGLConfig curConfig : configs){
int curConfigValue = 0;
for (int i = 0; i < attribEGLconsts.length; i++){
int val = findConfigAttrib(curConfig, attribEGLconsts[i]);
if (attribPrefs[i] == EXACTLY) {
if (desiredAttribVals[i] != val) {
curConfigValue = Integer.MIN_VALUE;
break;
}
} else if (attribPrefs[i] == PREF_HIGH) {
if (desiredAttribVals[i] > val) {
curConfigValue = Integer.MIN_VALUE;
break;
} else {
curConfigValue += prefWeights[i]*(val - desiredAttribVals[i]);
}
} else if (attribPrefs[i] == PREF_LOW) {
if (desiredAttribVals[i] > val) {
curConfigValue = Integer.MIN_VALUE;
break;
} else {
curConfigValue -= prefWeights[i]*(val - desiredAttribVals[i]);
}
}
}
if (curConfigValue > bestConfigValue){
bestConfigValue = curConfigValue;
bestConfig = curConfig;
}
}
return bestConfig;
}
private int[] value = new int[1];
private int findConfigAttrib(EGLConfig config, int attribute) {
if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
return value[0];
} else {
throw new IllegalArgumentException("eglGetConfigAttrib failed");
}
}
}

View File

@ -21,17 +21,20 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.BufferUtils;
import java.nio.IntBuffer;
public class Shader {
public static final int VERTEX = GLES20.GL_VERTEX_SHADER;
public static final int FRAGMENT = GLES20.GL_FRAGMENT_SHADER;
public static final int VERTEX = Gdx.gl.GL_VERTEX_SHADER;
public static final int FRAGMENT = Gdx.gl.GL_FRAGMENT_SHADER;
private int handle;
public Shader( int type ) {
handle = GLES20.glCreateShader( type );
handle = Gdx.gl.glCreateShader( type );
}
public int handle() {
@ -39,21 +42,21 @@ public class Shader {
}
public void source( String src ) {
GLES20.glShaderSource( handle, src );
Gdx.gl.glShaderSource( handle, src );
}
public void compile() {
GLES20.glCompileShader( handle );
int[] status = new int[1];
GLES20.glGetShaderiv( handle, GLES20.GL_COMPILE_STATUS, status, 0 );
if (status[0] == GLES20.GL_FALSE) {
throw new Error( GLES20.glGetShaderInfoLog( handle ) );
Gdx.gl.glCompileShader( handle );
IntBuffer status = BufferUtils.newIntBuffer(1);
Gdx.gl.glGetShaderiv( handle, Gdx.gl.GL_COMPILE_STATUS, status);
if (status.get() == Gdx.gl.GL_FALSE) {
throw new Error( Gdx.gl.glGetShaderInfoLog( handle ) );
}
}
public void delete() {
GLES20.glDeleteShader( handle );
Gdx.gl.glDeleteShader( handle );
}
public static Shader createCompiled( int type, String src ) {

View File

@ -21,9 +21,8 @@
package com.watabou.glwrap;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@ -31,12 +30,12 @@ import java.nio.IntBuffer;
public class Texture {
public static final int NEAREST = GLES20.GL_NEAREST;
public static final int LINEAR = GLES20.GL_LINEAR;
public static final int NEAREST = Gdx.gl.GL_NEAREST;
public static final int LINEAR = Gdx.gl.GL_LINEAR;
public static final int REPEAT = GLES20.GL_REPEAT;
public static final int MIRROR = GLES20.GL_MIRRORED_REPEAT;
public static final int CLAMP = GLES20.GL_CLAMP_TO_EDGE;
public static final int REPEAT = Gdx.gl.GL_REPEAT;
public static final int MIRROR = Gdx.gl.GL_MIRRORED_REPEAT;
public static final int CLAMP = Gdx.gl.GL_CLAMP_TO_EDGE;
public int id = -1;
private static int bound_id = 0; //id of the currently bound texture
@ -44,13 +43,11 @@ public class Texture {
public boolean premultiplied = false;
protected void generate(){
int[] ids = new int[1];
GLES20.glGenTextures( 1, ids, 0 );
id = ids[0];
id = Gdx.gl.glGenTexture();
}
public static void activate( int index ) {
GLES20.glActiveTexture( GLES20.GL_TEXTURE0 + index );
Gdx.gl.glActiveTexture( Gdx.gl.GL_TEXTURE0 + index );
}
public void bind() {
@ -58,32 +55,42 @@ public class Texture {
generate();
}
if (id != bound_id) {
GLES20.glBindTexture( GLES20.GL_TEXTURE_2D, id );
Gdx.gl.glBindTexture( Gdx.gl.GL_TEXTURE_2D, id );
bound_id = id;
}
}
public void filter( int minMode, int maxMode ) {
bind();
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, minMode );
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, maxMode );
Gdx.gl.glTexParameterf( Gdx.gl.GL_TEXTURE_2D, Gdx.gl.GL_TEXTURE_MIN_FILTER, minMode );
Gdx.gl.glTexParameterf( Gdx.gl.GL_TEXTURE_2D, Gdx.gl.GL_TEXTURE_MAG_FILTER, maxMode );
}
public void wrap( int s, int t ) {
bind();
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, s );
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, t );
Gdx.gl.glTexParameterf( Gdx.gl.GL_TEXTURE_2D, Gdx.gl.GL_TEXTURE_WRAP_S, s );
Gdx.gl.glTexParameterf( Gdx.gl.GL_TEXTURE_2D, Gdx.gl.GL_TEXTURE_WRAP_T, t );
}
public void delete() {
if (bound_id == id) bound_id = 0;
int[] ids = {id};
GLES20.glDeleteTextures( 1, ids, 0 );
Gdx.gl.glDeleteTexture( id );
}
public void bitmap( Bitmap bitmap ) {
public void bitmap( Pixmap pixmap ) {
bind();
GLUtils.texImage2D( GLES20.GL_TEXTURE_2D, 0, bitmap, 0 );
Gdx.gl.glTexImage2D(
Gdx.gl.GL_TEXTURE_2D,
0,
pixmap.getGLInternalFormat(),
pixmap.getWidth(),
pixmap.getHeight(),
0,
pixmap.getGLFormat(),
pixmap.getGLType(),
pixmap.getPixels()
);
premultiplied = true;
}
@ -99,15 +106,15 @@ public class Texture {
imageBuffer.put( pixels );
imageBuffer.position( 0 );
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
Gdx.gl.glTexImage2D(
Gdx.gl.GL_TEXTURE_2D,
0,
GLES20.GL_RGBA,
Gdx.gl.GL_RGBA,
w,
h,
0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
Gdx.gl.GL_RGBA,
Gdx.gl.GL_UNSIGNED_BYTE,
imageBuffer );
}
@ -121,23 +128,24 @@ public class Texture {
imageBuffer.put( pixels );
imageBuffer.position( 0 );
GLES20.glPixelStorei( GLES20.GL_UNPACK_ALIGNMENT, 1 );
Gdx.gl.glPixelStorei( Gdx.gl.GL_UNPACK_ALIGNMENT, 1 );
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
Gdx.gl.glTexImage2D(
Gdx.gl.GL_TEXTURE_2D,
0,
GLES20.GL_ALPHA,
Gdx.gl.GL_ALPHA,
w,
h,
0,
GLES20.GL_ALPHA,
GLES20.GL_UNSIGNED_BYTE,
Gdx.gl.GL_ALPHA,
Gdx.gl.GL_UNSIGNED_BYTE,
imageBuffer );
}
// If getConfig returns null (unsupported format?), GLUtils.texImage2D works
// incorrectly. In this case we need to load pixels manually
public void handMade( Bitmap bitmap, boolean recode ) {
//TODO this seems to be unused, and is dependant on android code, remove?
/*public void handMade( Bitmap bitmap, boolean recode ) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
@ -159,11 +167,11 @@ public class Texture {
pixels( w, h, pixels );
premultiplied = false;
}
}*/
public static Texture create( Bitmap bmp ) {
public static Texture create( Pixmap pix ) {
Texture tex = new Texture();
tex.bitmap( bmp );
tex.bitmap( pix );
return tex;
}

View File

@ -21,7 +21,7 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
public class Uniform {
@ -36,30 +36,30 @@ public class Uniform {
}
public void enable() {
GLES20.glEnableVertexAttribArray(location);
Gdx.gl.glEnableVertexAttribArray(location);
}
public void disable() {
GLES20.glDisableVertexAttribArray(location);
Gdx.gl.glDisableVertexAttribArray(location);
}
public void value1f(float value) {
GLES20.glUniform1f(location, value);
Gdx.gl.glUniform1f(location, value);
}
public void value2f(float v1, float v2) {
GLES20.glUniform2f(location, v1, v2);
Gdx.gl.glUniform2f(location, v1, v2);
}
public void value4f(float v1, float v2, float v3, float v4) {
GLES20.glUniform4f(location, v1, v2, v3, v4);
Gdx.gl.glUniform4f(location, v1, v2, v3, v4);
}
public void valueM3(float[] value) {
GLES20.glUniformMatrix3fv(location, 1, false, value, 0);
Gdx.gl.glUniformMatrix3fv(location, 1, false, value, 0);
}
public void valueM4(float[] value) {
GLES20.glUniformMatrix4fv(location, 1, false, value, 0);
Gdx.gl.glUniformMatrix4fv(location, 1, false, value, 0);
}
}

View File

@ -21,7 +21,7 @@
package com.watabou.glwrap;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import java.nio.FloatBuffer;
import java.util.ArrayList;
@ -36,9 +36,7 @@ public class Vertexbuffer {
public Vertexbuffer( FloatBuffer vertices ) {
synchronized (buffers) {
int[] ptr = new int[1];
GLES20.glGenBuffers(1, ptr, 0);
id = ptr[0];
id = Gdx.gl.glGenBuffer();
this.vertices = vertices;
buffers.add(this);
@ -80,9 +78,9 @@ public class Vertexbuffer {
bind();
if (updateStart == 0 && updateEnd == vertices.limit()){
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertices.limit()*4, vertices, GLES20.GL_DYNAMIC_DRAW);
Gdx.gl.glBufferData(Gdx.gl.GL_ARRAY_BUFFER, vertices.limit()*4, vertices, Gdx.gl.GL_DYNAMIC_DRAW);
} else {
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, updateStart*4, (updateEnd - updateStart)*4, vertices);
Gdx.gl.glBufferSubData(Gdx.gl.GL_ARRAY_BUFFER, updateStart*4, (updateEnd - updateStart)*4, vertices);
}
release();
@ -90,16 +88,16 @@ public class Vertexbuffer {
}
public void bind(){
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, id);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ARRAY_BUFFER, id);
}
public void release(){
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
Gdx.gl.glBindBuffer(Gdx.gl.GL_ARRAY_BUFFER, 0);
}
public void delete(){
synchronized (buffers) {
GLES20.glDeleteBuffers(1, new int[]{id}, 0);
Gdx.gl.glDeleteBuffer( id );
buffers.remove(this);
}
}

View File

@ -0,0 +1,120 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.watabou.input;
import com.badlogic.gdx.InputAdapter;
import com.watabou.noosa.Game;
import java.util.ArrayList;
public class InputHandler extends InputAdapter {
// Accumulated touch events
protected ArrayList<Touchscreen.Touch> touchEvents = new ArrayList<>();
// Accumulated key events
protected ArrayList<Keys.Key> keyEvents = new ArrayList<>();
@Override
public boolean keyDown( int keyCode ) {
if (keyCode != Keys.BACK &&
keyCode != Keys.MENU) {
return false;
}
synchronized (keyEvents) {
keyEvents.add( new Keys.Key(keyCode, true) );
}
return true;
}
@Override
public boolean keyUp( int keyCode ) {
if (keyCode != Keys.BACK &&
keyCode != Keys.MENU) {
return false;
}
synchronized (keyEvents) {
keyEvents.add( new Keys.Key(keyCode, false) );
}
return true;
}
@Override
public boolean keyTyped(char character) {
return false;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
screenX /= (Game.dispWidth / (float)Game.width);
screenY /= (Game.dispHeight / (float)Game.height);
synchronized (touchEvents) {
touchEvents.add(new Touchscreen.Touch(screenX, screenY, pointer, true));
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
screenX /= (Game.dispWidth / (float)Game.width);
screenY /= (Game.dispHeight / (float)Game.height);
synchronized (touchEvents) {
touchEvents.add(new Touchscreen.Touch(screenX, screenY, pointer, false));
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
screenX /= (Game.dispWidth / (float)Game.width);
screenY /= (Game.dispHeight / (float)Game.height);
synchronized (touchEvents) {
touchEvents.add(new Touchscreen.Touch(screenX, screenY, pointer, true));
}
return true;
}
@Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
@Override
public boolean scrolled(int amount) {
return false;
}
public void processAllEvents(){
synchronized (touchEvents) {
Touchscreen.processTouchEvents( touchEvents );
touchEvents.clear();
}
synchronized (keyEvents) {
Keys.processKeyEvents( keyEvents );
keyEvents.clear();
}
}
}

View File

@ -21,34 +21,22 @@
package com.watabou.input;
import android.view.KeyEvent;
import com.badlogic.gdx.Input;
import com.watabou.utils.Signal;
import java.util.ArrayList;
//TODO probably want to merge this into a central input processor class
public class Keys {
public static final int BACK = KeyEvent.KEYCODE_BACK;
public static final int MENU = KeyEvent.KEYCODE_MENU;
public static final int BACK = Input.Keys.BACK;
public static final int MENU = Input.Keys.MENU;
public static Signal<Key> event = new Signal<Key>( true );
public static Signal<Key> event = new Signal<>( true );
public static void processTouchEvents( ArrayList<KeyEvent> events ) {
int size = events.size();
for (int i=0; i < size; i++) {
KeyEvent e = events.get( i );
switch (e.getAction()) {
case KeyEvent.ACTION_DOWN:
event.dispatch( new Key( e.getKeyCode(), true ) );
break;
case KeyEvent.ACTION_UP:
event.dispatch( new Key( e.getKeyCode(), false ) );
break;
}
public static void processKeyEvents( ArrayList<Key> events ){
for (Key k : events){
event.dispatch(k);
}
}

View File

@ -21,71 +21,38 @@
package com.watabou.input;
import android.view.MotionEvent;
import com.watabou.noosa.Game;
import com.watabou.utils.PointF;
import com.watabou.utils.Signal;
import java.util.ArrayList;
import java.util.HashMap;
//TODO integrate into a central input handler class
public class Touchscreen {
public static Signal<Touch> event = new Signal<Touch>( true );
public static Signal<Touch> event = new Signal<>( true );
public static HashMap<Integer,Touch> pointers = new HashMap<Integer, Touch>();
public static HashMap<Integer,Touch> pointers = new HashMap<>();
public static float x;
public static float y;
public static boolean touched;
public static void processTouchEvents( ArrayList<MotionEvent> events ) {
int size = events.size();
for (int i=0; i < size; i++) {
MotionEvent e = events.get( i );
Touch touch;
switch (e.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
touched = true;
touch = new Touch( e, 0 );
pointers.put( e.getPointerId( 0 ), touch );
event.dispatch( touch );
break;
case MotionEvent.ACTION_POINTER_DOWN:
int index = e.getActionIndex();
touch = new Touch( e, index );
pointers.put( e.getPointerId( index ), touch );
event.dispatch( touch );
break;
case MotionEvent.ACTION_MOVE:
int count = e.getPointerCount();
for (int j=0; j < count; j++) {
if (pointers.containsKey(e.getPointerId(j))) {
pointers.get(e.getPointerId(j)).update(e, j);
}
public static void processTouchEvents( ArrayList<Touch> events ) {
for (Touch t : events){
if (pointers.containsKey(t.id)){
Touch existing = pointers.get(t.id);
existing.current = t.current;
if (existing.down == t.down){
event.dispatch( null );
} else if (t.down) {
event.dispatch( existing );
} else {
pointers.remove(existing.id);
event.dispatch(existing.up());
}
event.dispatch( null );
break;
case MotionEvent.ACTION_POINTER_UP:
event.dispatch( pointers.remove( e.getPointerId( e.getActionIndex() ) ).up() );
break;
case MotionEvent.ACTION_UP:
touched = false;
event.dispatch( pointers.remove( e.getPointerId( 0 ) ).up() );
break;
} else {
if (t.down) {
pointers.put(t.id, t);
}
event.dispatch(t);
}
e.recycle();
}
}
@ -93,29 +60,20 @@ public class Touchscreen {
public PointF start;
public PointF current;
public int id;
public boolean down;
public Touch( MotionEvent e, int index ) {
float x = e.getX( index );
float y = e.getY( index );
x /= (Game.dispWidth / (float)Game.width);
y /= (Game.dispHeight / (float)Game.height);
start = new PointF( x, y );
current = new PointF( x, y );
down = true;
public Touch( int x, int y, int id, boolean down){
start = current = new PointF(x, y);
this.id = id;
this.down = down;
}
public void update( MotionEvent e, int index ) {
float x = e.getX( index );
float y = e.getY( index );
x /= (Game.dispWidth / (float)Game.width);
y /= (Game.dispHeight / (float)Game.height);
public void update( Touch other ){
this.current = other.current;
}
public void update( int x, int y ){
current.set( x, y );
}

View File

@ -21,8 +21,7 @@
package com.watabou.noosa;
import android.graphics.Bitmap;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Matrix;
@ -264,8 +263,8 @@ public class BitmapText extends Visual {
lineHeight = baseLine = height;
}
protected void splitBy( Bitmap bitmap, int height, int color, String chars ) {
protected void splitBy( Pixmap bitmap, int height, int color, String chars ) {
int length = chars.length();
int width = bitmap.getWidth();
@ -302,7 +301,7 @@ public class BitmapText extends Visual {
}
found = false;
for (int j=line; j < line + height; j++) {
if (bitmap.getPixel( separator, j ) != color) {
if (colorNotMatch( bitmap, separator, j, color)) {
found = true;
break;
}
@ -320,7 +319,7 @@ public class BitmapText extends Visual {
}
found = true;
for (int j=line; j < line + height; j++) {
if (bitmap.getPixel( separator, j ) != color) {
if (colorNotMatch( bitmap, separator, j, color)) {
found = false;
break;
}
@ -335,13 +334,22 @@ public class BitmapText extends Visual {
lineHeight = baseLine = height( frames.get( chars.charAt( 0 ) ) );
}
public static Font colorMarked( Bitmap bmp, int color, String chars ) {
//FIXME
private boolean colorNotMatch(Pixmap pixmap, int x, int y, int color) {
int pixel = pixmap.getPixel(x, y);
if ((pixel & 0xFF) == 0) {
return color != 0;
}
return pixel != color;
}
public static Font colorMarked( Pixmap bmp, int color, String chars ) {
Font font = new Font( TextureCache.get( bmp ) );
font.splitBy( bmp, bmp.getHeight(), color, chars );
return font;
}
public static Font colorMarked( Bitmap bmp, int height, int color, String chars ) {
public static Font colorMarked( Pixmap bmp, int height, int color, String chars ) {
Font font = new Font( TextureCache.get( bmp ) );
font.splitBy( bmp, height, color, chars );
return font;

View File

@ -21,42 +21,30 @@
package com.watabou.noosa;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.watabou.glscripts.Script;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Blending;
import com.watabou.glwrap.ScreenConfigChooser;
import com.watabou.glwrap.Vertexbuffer;
import com.watabou.input.InputHandler;
import com.watabou.input.Keys;
import com.watabou.input.Touchscreen;
import com.watabou.noosa.audio.Music;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.BitmapCache;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.SystemTime;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTouchListener {
public class Game extends AndroidApplication implements ApplicationListener {
public static Game instance;
@ -95,13 +83,9 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
public static float timeTotal = 0f;
protected GLSurfaceView view;
protected SurfaceHolder holder;
//protected SurfaceHolder holder;
// Accumulated touch events
protected ArrayList<MotionEvent> motionEvents = new ArrayList<MotionEvent>();
// Accumulated key events
protected ArrayList<KeyEvent> keysEvents = new ArrayList<KeyEvent>();
protected InputHandler inputHandler;
public Game( Class<? extends Scene> c ) {
super();
@ -112,17 +96,9 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
BitmapCache.context = TextureCache.context = instance = this;
DisplayMetrics m = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
getWindowManager().getDefaultDisplay().getRealMetrics( m );
else
getWindowManager().getDefaultDisplay().getMetrics( m );
density = m.density;
dispHeight = m.heightPixels;
dispWidth = m.widthPixels;
instance = this;
//FIXME this should be moved into a separate class, once we start to move to multiplatform
try {
version = getPackageManager().getPackageInfo( getPackageName(), 0 ).versionName;
} catch (NameNotFoundException e) {
@ -134,20 +110,33 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
versionCode = 0;
}
setVolumeControlStream( AudioManager.STREAM_MUSIC );
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.depth = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
//use rgb888 on more modern devices for better visuals
config.r = config.g = config.b = 8;
} else {
//and rgb565 (default) on older ones for better performance
}
view = new GLSurfaceView( this );
view.setEGLContextClientVersion( 2 );
//Older devices are forced to RGB 565 for performance reasons.
//Otherwise try to use RGB888 for best quality, but use RGB565 if it is what's available.
view.setEGLConfigChooser( new ScreenConfigChooser(
DeviceCompat.legacyDevice(),
false ));
view.setRenderer( this );
view.setOnTouchListener( this );
setContentView( view );
config.useCompass = false;
config.useAccelerometer = false;
//TODO consider the following additional options, might be better than setting manually
//config.hideStatusBar
//config.useImmersiveMode
initialize(this, config);
//FIXME shouldn't have a reference to the view here, remove things which access this
view = (GLSurfaceView)graphics.getView();
inputHandler = new InputHandler();
Gdx.input.setInputProcessor(inputHandler);
Gdx.input.setCatchKey(Keys.BACK, true);
Gdx.input.setCatchKey(Keys.MENU, true);
//FIXME this doesn't seem to work quite right. That might not be due to LibGDX though.
Music.setMuteListener();
//so first call to onstart/onresume calls correct logic.
paused = true;
@ -155,138 +144,46 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
private boolean paused;
//Starting with honeycomb, android's lifecycle management changes slightly
@Override
public void onStart() {
super.onStart();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
resumeGame();
}
}
@Override
protected void onResume() {
super.onResume();
if (scene != null) {
scene.onResume();
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB){
resumeGame();
}
}
@Override
protected void onPause() {
super.onPause();
if (scene != null) {
scene.onPause();
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB){
pauseGame();
}
}
@Override
public void onStop() {
super.onStop();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
pauseGame();
}
}
public void pauseGame(){
if (paused) return;
paused = true;
view.onPause();
Script.reset();
Music.INSTANCE.pause();
Sample.INSTANCE.pause();
}
public void resumeGame(){
if (!paused) return;
now = 0;
paused = false;
view.onResume();
Music.INSTANCE.resume();
Sample.INSTANCE.resume();
}
public boolean isPaused(){
return paused;
}
@Override
public void onDestroy() {
super.onDestroy();
destroyGame();
public void create() {
density = Gdx.graphics.getDensity();
dispHeight = Gdx.graphics.getDisplayMode().height;
dispWidth = Gdx.graphics.getDisplayMode().width;
Music.INSTANCE.mute();
Sample.INSTANCE.reset();
}
@SuppressLint({ "Recycle", "ClickableViewAccessibility" })
@Override
public boolean onTouch( View view, MotionEvent event ) {
synchronized (motionEvents) {
motionEvents.add( MotionEvent.obtain( event ) );
}
return true;
Blending.useDefault();
//refreshes texture and vertex data stored on the gpu
TextureCache.reload();
RenderedText.reloadCache();
Vertexbuffer.refreshAllBuffers();
}
@Override
public boolean onKeyDown( int keyCode, KeyEvent event ) {
public void resize(int width, int height) {
Gdx.gl.glViewport(0, 0, width, height);
if (keyCode != Keys.BACK &&
keyCode != Keys.MENU) {
return false;
if (height != Game.height || width != Game.width) {
Game.width = width;
Game.height = height;
resetScene();
}
synchronized (motionEvents) {
keysEvents.add( event );
}
return true;
}
@Override
public boolean onKeyUp( int keyCode, KeyEvent event ) {
if (keyCode != Keys.BACK &&
keyCode != Keys.MENU) {
return false;
}
synchronized (motionEvents) {
keysEvents.add( event );
}
return true;
}
@Override
public void onDrawFrame( GL10 gl ) {
if (width == 0 || height == 0) {
return;
}
public void render() {
NoosaScript.get().resetCamera();
NoosaScriptNoLighting.get().resetCamera();
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glDisable(Gdx.gl.GL_SCISSOR_TEST);
Gdx.gl.glClear(Gdx.gl.GL_COLOR_BUFFER_BIT);
draw();
GLES20.glFlush();
Gdx.gl.glFlush();
SystemTime.tick();
long rightNow = SystemClock.elapsedRealtime();
@ -295,29 +192,39 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
step();
}
@Override
public void onSurfaceChanged( GL10 gl, int width, int height ) {
GLES20.glViewport(0, 0, width, height);
if (height != Game.height || width != Game.width) {
Game.width = width;
Game.height = height;
resetScene();
public void pause() {
paused = true;
if (scene != null) {
scene.onPause();
}
//view.onPause();
Script.reset();
//Music.INSTANCE.pause();
//Sample.INSTANCE.pause();
}
@Override
public void onSurfaceCreated( GL10 gl, EGLConfig config ) {
Blending.useDefault();
//refreshes texture and vertex data stored on the gpu
TextureCache.reload();
RenderedText.reloadCache();
Vertexbuffer.refreshAllBuffers();
public void resume() {
paused = false;
now = 0;
//view.onResume();
//Music.INSTANCE.resume();
//Sample.INSTANCE.resume();
}
@Override
public void dispose() {
destroyGame();
//Music.INSTANCE.mute();
//Sample.INSTANCE.reset();
}
protected void destroyGame() {
@ -392,14 +299,7 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
Game.elapsed = Game.timeScale * step * 0.001f;
Game.timeTotal += Game.elapsed;
synchronized (motionEvents) {
Touchscreen.processTouchEvents( motionEvents );
motionEvents.clear();
}
synchronized (keysEvents) {
Keys.processTouchEvents( keysEvents );
keysEvents.clear();
}
inputHandler.processAllEvents();
scene.update();
Camera.updateAll();
@ -410,11 +310,15 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
}
protected void logException( Throwable tr ){
Log.e("GAME", Log.getStackTraceString(tr));
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
pw.flush();
Gdx.app.error("GAME", sw.toString());
}
public static void vibrate( int milliseconds ) {
((Vibrator)instance.getSystemService( VIBRATOR_SERVICE )).vibrate( milliseconds );
Gdx.input.vibrate(milliseconds);
}
public interface SceneChangeCallback{

View File

@ -21,10 +21,7 @@
package com.watabou.noosa;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
@ -41,14 +38,12 @@ public class Halo extends Image {
super();
if (!TextureCache.contains( CACHE_KEY )) {
Bitmap bmp = Bitmap.createBitmap( RADIUS * 2, RADIUS * 2, Bitmap.Config.ARGB_8888 );
Canvas canvas = new Canvas( bmp );
Paint paint = new Paint();
paint.setColor( 0x0AFFFFFF );
Pixmap pixmap = new Pixmap(RADIUS * 2, RADIUS * 2, Pixmap.Format.RGBA8888);
pixmap.setColor( 0xFFFFFF0A );
for (int i = 0; i < 50; i++) {
canvas.drawCircle(RADIUS, RADIUS, RADIUS * (i+1)/50f, paint);
pixmap.fillCircle(RADIUS, RADIUS, (int)(RADIUS * (i+1)/50f));
}
TextureCache.add( CACHE_KEY, new SmartTexture( bmp ) );
TextureCache.add( CACHE_KEY, new SmartTexture( pixmap ) );
}
texture( CACHE_KEY );

View File

@ -21,8 +21,7 @@
package com.watabou.noosa;
import android.opengl.GLES20;
import com.badlogic.gdx.Gdx;
import com.watabou.glscripts.Script;
import com.watabou.glwrap.Attribute;
import com.watabou.glwrap.Quad;
@ -81,7 +80,7 @@ public class NoosaScript extends Script {
aUV.vertexPointer( 2, 4, vertices );
Quad.releaseIndices();
GLES20.glDrawElements( GLES20.GL_TRIANGLES, size, GLES20.GL_UNSIGNED_SHORT, indices );
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, size, Gdx.gl20.GL_UNSIGNED_SHORT, indices );
Quad.bindIndices();
}
@ -92,8 +91,8 @@ public class NoosaScript extends Script {
vertices.position( 2 );
aUV.vertexPointer( 2, 4, vertices );
GLES20.glDrawElements( GLES20.GL_TRIANGLES, Quad.SIZE, GLES20.GL_UNSIGNED_SHORT, 0 );
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
}
public void drawQuad( Vertexbuffer buffer ) {
@ -106,8 +105,8 @@ public class NoosaScript extends Script {
aUV.vertexBuffer( 2, 4, 2 );
buffer.release();
GLES20.glDrawElements( GLES20.GL_TRIANGLES, Quad.SIZE, GLES20.GL_UNSIGNED_SHORT, 0 );
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
}
public void drawQuadSet( FloatBuffer vertices, int size ) {
@ -121,8 +120,8 @@ public class NoosaScript extends Script {
vertices.position( 2 );
aUV.vertexPointer( 2, 4, vertices );
GLES20.glDrawElements( GLES20.GL_TRIANGLES, Quad.SIZE * size, GLES20.GL_UNSIGNED_SHORT, 0 );
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE * size, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
}
public void drawQuadSet( Vertexbuffer buffer, int length, int offset ){
@ -139,8 +138,8 @@ public class NoosaScript extends Script {
aUV.vertexBuffer( 2, 4, 2 );
buffer.release();
GLES20.glDrawElements( GLES20.GL_TRIANGLES, Quad.SIZE * length, GLES20.GL_UNSIGNED_SHORT, Quad.SIZE * Short.SIZE/8 * offset );
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE * length, Gdx.gl20.GL_UNSIGNED_SHORT, Quad.SIZE * Short.SIZE/8 * offset );
}
public void lighting( float rm, float gm, float bm, float am, float ra, float ga, float ba, float aa ) {
@ -161,14 +160,14 @@ public class NoosaScript extends Script {
uCamera.valueM4( camera.matrix );
if (!camera.fullScreen) {
GLES20.glEnable( GLES20.GL_SCISSOR_TEST );
GLES20.glScissor(
Gdx.gl20.glEnable( Gdx.gl20.GL_SCISSOR_TEST );
Gdx.gl20.glScissor(
camera.x,
Game.height - camera.screenHeight - camera.y,
camera.screenWidth,
camera.screenHeight);
} else {
GLES20.glDisable( GLES20.GL_SCISSOR_TEST );
Gdx.gl20.glDisable( Gdx.gl20.GL_SCISSOR_TEST );
}
}
}
@ -184,23 +183,34 @@ public class NoosaScript extends Script {
private static final String SHADER =
"uniform mat4 uCamera;" +
"uniform mat4 uModel;" +
"attribute vec4 aXYZW;" +
"attribute vec2 aUV;" +
"varying vec2 vUV;" +
"void main() {" +
" gl_Position = uCamera * uModel * aXYZW;" +
" vUV = aUV;" +
"}" +
//vertex shader
"uniform mat4 uCamera;\n" +
"uniform mat4 uModel;\n" +
"attribute vec4 aXYZW;\n" +
"attribute vec2 aUV;\n" +
"varying vec2 vUV;\n" +
"void main() {\n" +
" gl_Position = uCamera * uModel * aXYZW;\n" +
" vUV = aUV;\n" +
"}\n" +
//this symbol separates the vertex and fragment shaders (see Script.compile)
"//\n" +
"varying mediump vec2 vUV;" +
"uniform lowp sampler2D uTex;" +
"uniform lowp vec4 uColorM;" +
"uniform lowp vec4 uColorA;" +
"void main() {" +
" gl_FragColor = texture2D( uTex, vUV ) * uColorM + uColorA;" +
"}";
//fragment shader
//preprocessor directives let us define precision on GLES platforms, and ignore it elsewhere
"#ifdef GL_ES\n" +
" #define LOW lowp\n" +
" #define MED mediump\n" +
"#else\n" +
" #define LOW\n" +
" #define MED\n" +
"#endif\n" +
"varying MED vec2 vUV;\n" +
"uniform LOW sampler2D uTex;\n" +
"uniform LOW vec4 uColorM;\n" +
"uniform LOW vec4 uColorA;\n" +
"void main() {\n" +
" gl_FragColor = texture2D( uTex, vUV ) * uColorM + uColorA;\n" +
"}\n";
}

View File

@ -45,22 +45,33 @@ public class NoosaScriptNoLighting extends NoosaScript {
}
private static final String SHADER =
"uniform mat4 uCamera;" +
"uniform mat4 uModel;" +
"attribute vec4 aXYZW;" +
"attribute vec2 aUV;" +
"varying vec2 vUV;" +
"void main() {" +
" gl_Position = uCamera * uModel * aXYZW;" +
" vUV = aUV;" +
"}" +
"//\n" +
"varying mediump vec2 vUV;" +
"uniform lowp sampler2D uTex;" +
"void main() {" +
" gl_FragColor = texture2D( uTex, vUV );" +
"}";
//vertex shader
"uniform mat4 uCamera;\n" +
"uniform mat4 uModel;\n" +
"attribute vec4 aXYZW;\n" +
"attribute vec2 aUV;\n" +
"varying vec2 vUV;\n" +
"void main() {\n" +
" gl_Position = uCamera * uModel * aXYZW;\n" +
" vUV = aUV;\n" +
"}\n" +
//this symbol separates the vertex and fragment shaders (see Script.compile)
"//\n" +
//fragment shader
//preprocessor directives let us define precision on GLES platforms, and ignore it elsewhere
"#ifdef GL_ES\n" +
" #define LOW lowp\n" +
" #define MED mediump\n" +
"#else\n" +
" #define LOW\n" +
" #define MED\n" +
"#endif\n" +
"varying MED vec2 vUV;\n" +
"uniform LOW sampler2D uTex;\n" +
"void main() {\n" +
" gl_FragColor = texture2D( uTex, vUV );\n" +
"}\n";
}

View File

@ -26,6 +26,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.gltextures.SmartTexture;
import com.watabou.glwrap.Matrix;
import com.watabou.glwrap.Texture;
@ -169,7 +170,18 @@ public class RenderedText extends Image {
canvas.drawText(r.text, (r.size/10f), r.size, painter);
r.texture = new SmartTexture(bitmap, Texture.NEAREST, Texture.CLAMP, true);
//FIXME really ugly and slow conversion between android bitmap and gdx pixmap
int[] pixels = new int[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
// Convert from ARGB to RGBA
for (int i = 0; i< pixels.length; i++) {
int pixel = pixels[i];
pixels[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
}
Pixmap pixmap = new Pixmap(bitmap.getWidth(), bitmap.getHeight(), Pixmap.Format.RGBA8888);
pixmap.getPixels().asIntBuffer().put(pixels);
r.texture = new SmartTexture(pixmap, Texture.NEAREST, Texture.CLAMP, true);
bitmap.recycle();
RectF rect = r.texture.uvRect(0, 0, r.width, r.height);
r.frame(rect);

View File

@ -22,20 +22,18 @@
package com.watabou.noosa.audio;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import com.badlogic.gdx.Gdx;
import com.watabou.noosa.Game;
public enum Music {
INSTANCE;
private MediaPlayer player;
private com.badlogic.gdx.audio.Music player;
private String lastPlayed;
private boolean looping;
@ -58,25 +56,11 @@ public enum Music {
return;
}
try {
AssetFileDescriptor afd = Game.instance.getAssets().openFd( assetName );
MediaPlayer mp = new MediaPlayer();
mp.setAudioStreamType( AudioManager.STREAM_MUSIC );
mp.setDataSource( afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength() );
mp.prepare();
player = mp;
player.start();
player.setLooping(looping);
player.setVolume(volume, volume);
} catch (Exception e) {
Game.reportException(e);
player = null;
}
player = Gdx.audio.newMusic(Gdx.files.internal(assetName));
player.setLooping(looping);
player.setVolume(volume);
player.play();
}
public void mute() {
@ -92,19 +76,15 @@ public enum Music {
public void resume() {
if (player != null) {
player.start();
player.play();
player.setLooping(looping);
}
}
public void stop() {
if (player != null) {
try {
player.stop();
player.release();
} catch ( Exception e ){
Game.reportException(e);
}
player.stop();
player.dispose();
player = null;
}
}
@ -112,7 +92,7 @@ public enum Music {
public void volume( float value ) {
volume = value;
if (player != null) {
player.setVolume( value, value );
player.setVolume( value );
}
}
@ -134,30 +114,29 @@ public enum Music {
return enabled;
}
public static final PhoneStateListener callMute = new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber)
{
if( state == TelephonyManager.CALL_STATE_RINGING ) {
INSTANCE.pause();
} else if( state == TelephonyManager.CALL_STATE_IDLE ) {
if (!Game.instance.isPaused()) {
INSTANCE.resume();
}
}
super.onCallStateChanged(state, incomingNumber);
}
};
//FIXME android-specific code, that is also broken by being part of this class.
public static void setMuteListener(){
//versions lower than this require READ_PHONE_STATE permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TelephonyManager mgr =
(TelephonyManager) Game.instance.getSystemService(Activity.TELEPHONY_SERVICE);
mgr.listen(Music.callMute, PhoneStateListener.LISTEN_CALL_STATE);
mgr.listen(new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber)
{
if( state == TelephonyManager.CALL_STATE_RINGING ) {
INSTANCE.pause();
} else if( state == TelephonyManager.CALL_STATE_IDLE ) {
if (!Game.instance.isPaused()) {
INSTANCE.resume();
}
}
super.onCallStateChanged(state, incomingNumber);
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}
}
}

View File

@ -21,113 +21,79 @@
package com.watabou.noosa.audio;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.watabou.noosa.Game;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
public enum Sample implements SoundPool.OnLoadCompleteListener {
public enum Sample {
INSTANCE;
public static final int MAX_STREAMS = 8;
protected SoundPool pool =
new SoundPool( MAX_STREAMS, AudioManager.STREAM_MUSIC, 0 );
protected HashMap<Object, Integer> ids =
new HashMap<>();
protected HashMap<Object, Sound> ids = new HashMap<>();
private boolean enabled = true;
private float volume = 1f;
private LinkedList<String> loadingQueue = new LinkedList<>();
private float globalVolume = 1f;
public void reset() {
for (Sound sound : ids.values()){
sound.dispose();
}
ids.clear();
loadingQueue = new LinkedList<>();
pool.release();
pool = new SoundPool( MAX_STREAMS, AudioManager.STREAM_MUSIC, 0 );
pool.setOnLoadCompleteListener( this );
}
public void pause() {
if (pool != null) {
pool.autoPause();
for (Sound sound : ids.values()) {
sound.pause();
}
}
public void resume() {
if (pool != null) {
pool.autoResume();
for (Sound sound : ids.values()) {
sound.resume();
}
}
public void load( String... assets ) {
for (String asset : assets) {
loadingQueue.add( asset );
}
loadNext();
}
private void loadNext() {
final String asset = loadingQueue.poll();
if (asset != null) {
if (!ids.containsKey( asset )) {
try {
pool.setOnLoadCompleteListener( new SoundPool.OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
loadNext();
}
} );
AssetManager manager = Game.instance.getAssets();
AssetFileDescriptor fd = manager.openFd( asset );
int streamID = pool.load( fd, 1 ) ;
ids.put( asset, streamID );
fd.close();
} catch (IOException e) {
loadNext();
} catch (NullPointerException e) {
// Do nothing (stop loading sounds)
}
} else {
loadNext();
//FIXME there used to be a queue here so that assets were loaded async.
//This was to prevent hanging on specific android versions (implement in vanilla v1.7.5)
//Maybe LibGDX already handles this?
for (String asset : assets){
if (!ids.containsKey(asset)){
ids.put(asset, Gdx.audio.newSound(Gdx.files.internal(asset)));
}
}
}
public void unload( Object src ) {
if (ids.containsKey( src )) {
pool.unload( ids.get( src ) );
ids.get( src ).dispose();
ids.remove( src );
}
}
public int play( Object id ) {
public long play( Object id ) {
return play( id, 1 );
}
public int play( Object id, float volume ) {
public long play( Object id, float volume ) {
return play( id, volume, volume, 1 );
}
public int play( Object id, float leftVolume, float rightVolume, float rate ) {
public long play( Object id, float volume, float pitch ) {
return play( id, volume, volume, pitch );
}
public long play( Object id, float leftVolume, float rightVolume, float pitch ) {
float volume = Math.max(leftVolume, rightVolume);
float pan = rightVolume - leftVolume;
if (enabled && ids.containsKey( id )) {
return pool.play( ids.get( id ), leftVolume*volume, rightVolume*volume, 0, 0, rate );
return ids.get(id).play( globalVolume*volume, pitch, pan );
} else {
return -1;
}
@ -138,14 +104,11 @@ public enum Sample implements SoundPool.OnLoadCompleteListener {
}
public void volume( float value ) {
this.volume = value;
globalVolume = value;
}
public boolean isEnabled() {
return enabled;
}
@Override
public void onLoadComplete( SoundPool soundPool, int sampleId, int status ) {
}
}

View File

@ -21,12 +21,10 @@
package com.watabou.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import com.watabou.noosa.Game;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
public class BitmapCache {
@ -35,18 +33,11 @@ public class BitmapCache {
private static HashMap<String,Layer> layers = new HashMap<String, BitmapCache.Layer>();
private static BitmapFactory.Options opts = new BitmapFactory.Options();
static {
opts.inDither = false;
}
public static Context context;
public static Bitmap get( String assetName ) {
public static Pixmap get( String assetName ) {
return get( DEFAULT, assetName );
}
public static Bitmap get( String layerName, String assetName ) {
public static Pixmap get( String layerName, String assetName ) {
Layer layer;
if (!layers.containsKey( layerName )) {
@ -61,22 +52,24 @@ public class BitmapCache {
} else {
try {
InputStream stream = context.getResources().getAssets().open( assetName );
Bitmap bmp = BitmapFactory.decodeStream( stream, null, opts );
Pixmap bmp = new Pixmap( Gdx.files.internal(assetName) );
layer.put( assetName, bmp );
return bmp;
} catch (IOException e) {
} catch (Exception e) {
Game.reportException( e );
return null;
}
}
}
public static Bitmap get( int resID ) {
//Unused, LibGDX does not support resource Ids
/*
public static Pixmap get( int resID ) {
return get( DEFAULT, resID );
}
public static Bitmap get( String layerName, int resID ) {
public static Pixmap get( String layerName, int resID ) {
Layer layer;
if (!layers.containsKey( layerName )) {
@ -95,7 +88,7 @@ public class BitmapCache {
return bmp;
}
}
}*/
public static void clear( String layerName ) {
if (layers.containsKey( layerName )) {
@ -112,12 +105,12 @@ public class BitmapCache {
}
@SuppressWarnings("serial")
private static class Layer extends HashMap<Object,Bitmap> {
private static class Layer extends HashMap<Object,Pixmap> {
@Override
public void clear() {
for (Bitmap bmp:values()) {
bmp.recycle();
for (Pixmap bmp:values()) {
bmp.dispose();
}
super.clear();
}

View File

@ -21,27 +21,26 @@
package com.watabou.utils;
import android.graphics.Bitmap;
import android.graphics.Rect;
import com.badlogic.gdx.graphics.Pixmap;
import java.util.HashMap;
public class BitmapFilm {
public Bitmap bitmap;
public Pixmap bitmap;
protected HashMap<Object,Rect> frames = new HashMap<Object, Rect>();
public BitmapFilm( Bitmap bitmap ) {
public BitmapFilm( Pixmap bitmap ) {
this.bitmap = bitmap;
add( null, new Rect( 0, 0, bitmap.getWidth(), bitmap.getHeight() ) );
}
public BitmapFilm( Bitmap bitmap, int width ) {
public BitmapFilm( Pixmap bitmap, int width ) {
this( bitmap, width, bitmap.getHeight() );
}
public BitmapFilm( Bitmap bitmap, int width, int height ) {
public BitmapFilm( Pixmap bitmap, int width, int height ) {
this.bitmap = bitmap;
int cols = bitmap.getWidth() / width;
int rows = bitmap.getHeight() / height;

View File

@ -21,22 +21,31 @@
package com.watabou.utils;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import com.badlogic.gdx.Gdx;
import com.watabou.BuildConfig;
import com.watabou.noosa.Game;
public class DeviceCompat {
public static boolean supportsFullScreen(){
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
switch (Gdx.app.getType()){
case Android:
//Android 4.4 KitKat and later, this is for immersive mode
return Gdx.app.getVersion() >= 19;
default:
//TODO implement functionality for other platforms here
return false;
}
}
public static boolean legacyDevice(){
return Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN;
switch (Gdx.app.getType()){
case Android:
//Devices prior to Android 4.1 Jelly Bean
return Gdx.app.getVersion() < 16;
default:
//TODO implement functionality for other platforms here
return false;
}
}
public static boolean isDebug(){
@ -44,12 +53,11 @@ public class DeviceCompat {
}
public static void openURI( String URI ){
Intent intent = new Intent( Intent.ACTION_VIEW, Uri.parse( URI ) );
Game.instance.startActivity( intent );
Gdx.net.openURI( URI );
}
public static void log( String tag, String message ){
Log.i( tag, message );
Gdx.app.log( tag, message );
}
}

View File

@ -21,18 +21,17 @@
package com.watabou.utils;
import android.content.SharedPreferences;
import android.os.Build;
import com.watabou.noosa.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
public class GameSettings {
private static SharedPreferences prefs;
private static Preferences prefs;
private static SharedPreferences get() {
private static Preferences get() {
if (prefs == null) {
prefs = Game.instance.getPreferences( Game.MODE_PRIVATE );
//TODO might want to rename this file. this is the auto-generated name for android atm
prefs = Gdx.app.getPreferences("ShatteredPixelDungeon");
}
return prefs;
}
@ -47,7 +46,7 @@ public class GameSettings {
public static int getInt( String key, int defValue, int min, int max ) {
try {
int i = get().getInt( key, defValue );
int i = get().getInteger( key, defValue );
if (i < min || i > max){
int val = (int)GameMath.gate(min, i, max);
put(key, val);
@ -93,15 +92,18 @@ public class GameSettings {
}
public static void put( String key, int value ) {
get().edit().putInt(key, value).apply();
get().putInteger(key, value);
get().flush();
}
public static void put( String key, boolean value ) {
get().edit().putBoolean(key, value).apply();
get().putBoolean(key, value);
get().flush();
}
public static void put( String key, String value ) {
get().edit().putString(key, value).apply();
get().putString(key, value);
get().flush();
}
}

View File

@ -21,9 +21,6 @@
package com.watabou.utils;
import android.annotation.SuppressLint;
@SuppressLint("FloatMath")
public class PointF {
public static final float PI = 3.1415926f;

View File

@ -21,26 +21,18 @@
package com.watabou.utils;
import java.util.ArrayList;
import com.badlogic.gdx.utils.IntMap;
import java.util.Arrays;
import java.util.List;
public class SparseArray<T> extends android.util.SparseArray<T> {
public class SparseArray<T> extends IntMap<T> {
public int[] keyArray() {
int size = size();
int[] array = new int[size];
for (int i=0; i < size; i++) {
array[i] = keyAt( i );
}
return array;
return keys().toArray().toArray();
}
public List<T> values() {
int size = size();
ArrayList<T> list = new ArrayList<T>( size );
for (int i=0; i < size; i++) {
list.add( i, valueAt( i ) );
}
return list;
public List<T> toList() {
return Arrays.asList(values().toArray().toArray());
}
}

View File

@ -20,6 +20,8 @@ allprojects {
appAndroidCompileSDK = 28
appAndroidMinSDK = 9
appAndroidTargetSDK = 28
gdxVersion = '1.9.10'
}
version = appVersionName

View File

@ -25,7 +25,8 @@
<activity
android:label="${appName}"
android:name="com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon"
android:screenOrientation="nosensor">
android:screenOrientation="nosensor"
android:configChanges="keyboard|keyboardHidden|orientation">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

After

Width:  |  Height:  |  Size: 186 B

View File

@ -21,12 +21,14 @@
package com.shatteredpixel.shatteredpixeldungeon;
import android.annotation.SuppressLint;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.scenes.WelcomeScene;
import com.watabou.noosa.Game;
@ -35,8 +37,6 @@ import com.watabou.noosa.audio.Music;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.DeviceCompat;
import javax.microedition.khronos.opengles.GL10;
public class ShatteredPixelDungeon extends Game {
//variable constants for specific older versions of shattered, used for data conversion
@ -108,8 +108,8 @@ public class ShatteredPixelDungeon extends Game {
}
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
public void create() {
super.create();
updateSystemUI();
SPDSettings.landscape ( SPDSettings.landscape() );
@ -118,8 +118,6 @@ public class ShatteredPixelDungeon extends Game {
Music.INSTANCE.volume( SPDSettings.musicVol()/10f );
Sample.INSTANCE.enable( SPDSettings.soundFx() );
Sample.INSTANCE.volume( SPDSettings.SFXVol()/10f );
Music.setMuteListener();
Sample.INSTANCE.load(
Assets.SND_CLICK,
@ -179,27 +177,6 @@ public class ShatteredPixelDungeon extends Game {
}
@Override
protected void onSaveInstanceState(Bundle outState) {
if (scene instanceof PixelScene){
((PixelScene) scene).saveWindows();
}
super.onSaveInstanceState(outState);
}
@Override
public void onWindowFocusChanged( boolean hasFocus ) {
super.onWindowFocusChanged( hasFocus );
if (hasFocus) updateSystemUI();
}
@Override
@SuppressWarnings("deprecation")
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
updateSystemUI();
}
public static void switchNoFade(Class<? extends PixelScene> c){
switchNoFade(c, null);
}
@ -231,14 +208,14 @@ public class ShatteredPixelDungeon extends Game {
}
@Override
public void onSurfaceChanged( GL10 gl, int width, int height ) {
public void resize( int width, int height ) {
if (scene instanceof PixelScene &&
(height != Game.height || width != Game.width)) {
((PixelScene) scene).saveWindows();
}
super.onSurfaceChanged( gl, width, height );
super.resize( width, height );
updateDisplaySize();
@ -302,31 +279,42 @@ public class ShatteredPixelDungeon extends Game {
}
public static void updateSystemUI() {
boolean fullscreen = Build.VERSION.SDK_INT < Build.VERSION_CODES.N
|| !instance.isInMultiWindowMode();
if (fullscreen){
instance.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
instance.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
if (DeviceCompat.supportsFullScreen()){
if (fullscreen && SPDSettings.fullscreen()) {
instance.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION );
} else {
instance.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
instance.runOnUiThread(new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
boolean fullscreen = Build.VERSION.SDK_INT < Build.VERSION_CODES.N
|| !instance.isInMultiWindowMode();
if (fullscreen){
instance.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
instance.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
if (DeviceCompat.supportsFullScreen()){
if (SPDSettings.fullscreen()) {
instance.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION );
} else {
instance.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
}
}
}
}
});
}
@Override
public void resume() {
super.resume();
updateSystemUI();
}
}

View File

@ -398,9 +398,9 @@ public abstract class Level implements Bundlable {
bundle.put( ENTRANCE, entrance );
bundle.put( EXIT, exit );
bundle.put( LOCKED, locked );
bundle.put( HEAPS, heaps.values() );
bundle.put( PLANTS, plants.values() );
bundle.put( TRAPS, traps.values() );
bundle.put( HEAPS, heaps.toList() );
bundle.put( PLANTS, plants.toList() );
bundle.put( TRAPS, traps.toList() );
bundle.put( CUSTOM_TILES, customTiles );
bundle.put( CUSTOM_WALLS, customWalls );
bundle.put( MOBS, mobs );

View File

@ -229,9 +229,8 @@ public class GameScene extends PixelScene {
heaps = new Group();
add( heaps );
int size = Dungeon.level.heaps.size();
for (int i=0; i < size; i++) {
addHeapSprite( Dungeon.level.heaps.valueAt( i ) );
for ( Heap heap : Dungeon.level.heaps.values() ) {
addHeapSprite( heap );
}
emitters = new Group();

View File

@ -431,9 +431,9 @@ public class DungeonTileSheet {
}
public static int getVisualWithAlts(int visual, int pos){
if (tileVariance[pos] >= 95 && rareAltVisuals.indexOfKey(visual) >= 0)
if (tileVariance[pos] >= 95 && rareAltVisuals.containsKey(visual))
return rareAltVisuals.get(visual);
else if (tileVariance[pos] >= 50 && commonAltVisuals.indexOfKey(visual) >= 0)
else if (tileVariance[pos] >= 50 && commonAltVisuals.containsKey(visual))
return commonAltVisuals.get(visual);
else
return visual;