Converted ShatteredPD to Build from Gradle

Major Changes:
- Shattered now builds effortlessly either from gradle CLI or android studio
- Much better dependency management through gradle (although it's not really used atm)
- Separate PD-classes repo is now SPD-classes module within main repo
This commit is contained in:
Evan Debenham 2016-08-13 02:11:29 -04:00
parent 188523b2a5
commit 36e44340a8
954 changed files with 8530 additions and 14 deletions

15
.gitignore vendored
View File

@ -1,11 +1,5 @@
.classpath
.project
project.properties
proguard.cfg
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
@ -13,10 +7,6 @@ proguard.cfg
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
@ -24,9 +14,6 @@ build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
#intellij project files
*.iml
*.idea
*.idea

6
SPD-classes/build.gradle Normal file
View File

@ -0,0 +1,6 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "24.0.0"
}

View File

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.watabou">
<application
android:label="@string/app_name"
>
</application>
</manifest>

View File

@ -0,0 +1,86 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.glscripts;
import java.util.HashMap;
import com.watabou.glwrap.Program;
import com.watabou.glwrap.Shader;
public class Script extends Program {
private static final HashMap<Class<? extends Script>,Script> all =
new HashMap<Class<? extends Script>, Script>();
private static Script curScript = null;
private static Class<? extends Script> curScriptClass = null;
@SuppressWarnings("unchecked")
public static<T extends Script> T use( Class<T> c ) {
if (c != curScriptClass) {
Script script = all.get( c );
if (script == null) {
try {
script = c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
all.put( c, script );
}
if (curScript != null) {
curScript.unuse();
}
curScript = script;
curScriptClass = c;
curScript.use();
}
return (T)curScript;
}
public static void reset() {
for (Script script:all.values()) {
script.delete();
}
all.clear();
curScript = null;
curScriptClass = null;
}
public void compile( String src ) {
String[] srcShaders = src.split( "//\n" );
attach( Shader.createCompiled( Shader.VERTEX, srcShaders[0] ) );
attach( Shader.createCompiled( Shader.FRAGMENT, srcShaders[1] ) );
link();
}
public void unuse() {
}
}

View File

@ -0,0 +1,99 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.gltextures;
import java.util.HashMap;
import android.graphics.RectF;
public class Atlas {
public SmartTexture tx;
protected HashMap<Object,RectF> namedFrames;
protected float uvLeft;
protected float uvTop;
protected float uvWidth;
protected float uvHeight;
protected int cols;
public Atlas( SmartTexture tx ) {
this.tx = tx;
tx.atlas = this;
namedFrames = new HashMap<Object, RectF>();
}
public void add( Object key, int left, int top, int right, int bottom ) {
add( key, uvRect( tx, left, top, right, bottom ) );
}
public void add( Object key, RectF rect ) {
namedFrames.put( key, rect );
}
public void grid( int width ) {
grid( width, tx.height );
}
public void grid( int width, int height ) {
grid( 0, 0, width, height, tx.width / width );
}
public void grid( int left, int top, int width, int height, int cols ) {
uvLeft = (float)left / tx.width;
uvTop = (float)top / tx.height;
uvWidth = (float)width / tx.width;
uvHeight= (float)height / tx.height;
this.cols = cols;
}
public RectF get( int index ) {
float x = index % cols;
float y = index / cols;
float l = uvLeft + x * uvWidth;
float t = uvTop + y * uvHeight;
return new RectF( l, t, l + uvWidth, t + uvHeight );
}
public RectF get( Object key ) {
return namedFrames.get( key );
}
public float width( RectF rect ) {
return rect.width() * tx.width;
}
public float height( RectF rect ) {
return rect.height() * tx.height;
}
public static RectF uvRect( SmartTexture tx, int left, int top, int right, int bottom ) {
return new RectF(
(float)left / tx.width,
(float)top / tx.height,
(float)right / tx.width,
(float)bottom / tx.height );
}
}

View File

@ -0,0 +1,42 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.gltextures;
import android.graphics.Bitmap;
public class Gradient extends SmartTexture {
public Gradient( int colors[] ) {
super( Bitmap.createBitmap( colors.length, 1, Bitmap.Config.ARGB_8888 ) );
for (int i=0; i < colors.length; i++) {
bitmap.setPixel( i, 0, colors[i] );
}
bitmap( bitmap );
filter( LINEAR, LINEAR );
wrap( CLAMP, CLAMP );
TextureCache.add( Gradient.class, this );
}
}

View File

@ -0,0 +1,107 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.gltextures;
import android.graphics.Bitmap;
import android.graphics.RectF;
import com.watabou.glwrap.Texture;
public class SmartTexture extends Texture {
public int width;
public int height;
public int fModeMin;
public int fModeMax;
public int wModeH;
public int wModeV;
public Bitmap bitmap;
public Atlas atlas;
public SmartTexture( Bitmap bitmap ) {
this( bitmap, NEAREST, CLAMP, false );
}
public SmartTexture( Bitmap bitmap, int filtering, int wrapping, boolean premultiplied ) {
super();
bitmap( bitmap, premultiplied );
filter( filtering, filtering );
wrap( wrapping, wrapping );
}
@Override
public void filter(int minMode, int maxMode) {
super.filter( fModeMin = minMode, fModeMax = maxMode);
}
@Override
public void wrap( int s, int t ) {
super.wrap( wModeH = s, wModeV = t );
}
@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 );
}
this.bitmap = bitmap;
width = bitmap.getWidth();
height = bitmap.getHeight();
}
public void reload() {
id = new SmartTexture( bitmap, NEAREST, CLAMP, premultiplied ).id;
filter( fModeMin, fModeMax );
wrap( wModeH, wModeV );
}
@Override
public void delete() {
super.delete();
bitmap.recycle();
bitmap = null;
}
public RectF uvRect( int left, int top, int right, int bottom ) {
return new RectF(
(float)left / width,
(float)top / height,
(float)right / width,
(float)bottom / height );
}
}

View File

@ -0,0 +1,164 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.gltextures;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import com.watabou.glwrap.Texture;
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 static SmartTexture createSolid( int color ) {
final String key = "1x1:" + color;
if (all.containsKey( key )) {
return all.get( key );
} else {
Bitmap bmp = Bitmap.createBitmap( 1, 1, Bitmap.Config.ARGB_8888 );
bmp.eraseColor( color );
SmartTexture tx = new SmartTexture( bmp );
all.put( key, tx );
return tx;
}
}
public static SmartTexture createGradient( int width, int height, int... colors ) {
final String key = "" + width + "x" + height + ":" + colors;
if (all.containsKey( key )) {
return all.get( key );
} else {
Bitmap bmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
Canvas canvas = new Canvas( bmp );
Paint paint = new Paint();
paint.setShader( new LinearGradient( 0, 0, 0, height, colors, null, TileMode.CLAMP ) );
canvas.drawPaint( paint );
SmartTexture tx = new SmartTexture( bmp );
all.put( key, tx );
return tx;
}
}
public static void add( Object key, SmartTexture tx ) {
all.put( key, tx );
}
public static SmartTexture get( Object src ) {
if (all.containsKey( src )) {
return all.get( src );
} else if (src instanceof SmartTexture) {
return (SmartTexture)src;
} else {
SmartTexture tx = new SmartTexture( getBitmap( src ) );
all.put( src, tx );
return tx;
}
}
public static void clear() {
for (Texture txt:all.values()) {
txt.delete();
}
all.clear();
}
public static void reload() {
for (SmartTexture tx:all.values()) {
tx.reload();
}
}
public static Bitmap getBitmap( Object src ) {
try {
if (src instanceof Integer){
return BitmapFactory.decodeResource(
context.getResources(), (Integer)src, bitmapOptions );
} else if (src instanceof String) {
return BitmapFactory.decodeStream(
context.getAssets().open( (String)src ), null, bitmapOptions );
} else if (src instanceof Bitmap) {
return (Bitmap)src;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static boolean contains( Object key ) {
return all.containsKey( key );
}
}

View File

@ -0,0 +1,51 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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 java.nio.FloatBuffer;
import android.opengl.GLES20;
public class Attribute {
private int location;
public Attribute( int location ) {
this.location = location;
}
public int location() {
return location;
}
public void enable() {
GLES20.glEnableVertexAttribArray( location );
}
public void disable() {
GLES20.glDisableVertexAttribArray( location );
}
public void vertexPointer( int size, int stride, FloatBuffer ptr ) {
GLES20.glVertexAttribPointer( location, size, GLES20.GL_FLOAT, false, stride * Float.SIZE / 8, ptr );
}
}

View File

@ -0,0 +1,69 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.GLES20;
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 Framebuffer system = new Framebuffer( 0 );
private int id;
public Framebuffer() {
int[] buffers = new int[1];
GLES20.glGenBuffers( 1, buffers, 0 );
id = buffers[0];
}
private Framebuffer( int n ) {
}
public void bind() {
GLES20.glBindFramebuffer( GLES20.GL_FRAMEBUFFER, id );
}
public void delete() {
int[] buffers = {id};
GLES20.glDeleteFramebuffers( 1, buffers, 0 );
}
public void attach( int point, Texture tex ) {
bind();
GLES20.glFramebufferTexture2D( GLES20.GL_FRAMEBUFFER, point, GLES20.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() );
}
public boolean status() {
bind();
return GLES20.glCheckFramebufferStatus( GLES20.GL_FRAMEBUFFER ) == GLES20.GL_FRAMEBUFFER_COMPLETE;
}
}

View File

@ -0,0 +1,103 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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;
public class Matrix {
public static final float G2RAD = 0.01745329251994329576923690768489f;
public static float[] clone( float[] m ) {
int n = m.length;
float[] res = new float[n];
do {
res[--n] = m[n];
} while (n > 0);
return res;
}
public static void copy( float[] src, float[] dst ) {
int n = src.length;
do {
dst[--n] = src[n];
} while (n > 0);
}
public static void setIdentity( float[] m ) {
for (int i=0 ; i < 16 ; i++) {
m[i] = 0f;
}
for (int i = 0; i < 16; i += 5) {
m[i] = 1f;
}
}
public static void rotate( float[] m, float a ) {
a *= G2RAD;
float sin = (float)Math.sin( a );
float cos = (float)Math.cos( a );
float m0 = m[0];
float m1 = m[1];
float m4 = m[4];
float m5 = m[5];
m[0] = m0 * cos + m4 * sin;
m[1] = m1 * cos + m5 * sin;
m[4] = -m0 * sin + m4 * cos;
m[5] = -m1 * sin + m5 * cos;
}
public static void skewX( float[] m, float a ) {
double t = Math.tan( a * G2RAD );
m[4] += -m[0] * t;
m[5] += -m[1] * t;
}
public static void skewY( float[] m, float a ) {
double t = Math.tan( a * G2RAD );
m[0] += m[4] * t;
m[1] += m[5] * t;
}
public static void scale( float[] m, float x, float y ) {
m[0] *= x;
m[1] *= x;
m[2] *= x;
m[3] *= x;
m[4] *= y;
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 ) {
m[12] += m[0] * x + m[4] * y;
m[13] += m[1] * x + m[5] * y;
}
public static void multiply( float[] left, float right[], float[] result ) {
android.opengl.Matrix.multiplyMM( result, 0, left, 0, right, 0 );
}
}

View File

@ -0,0 +1,76 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.GLES20;
public class Program {
private int handle;
public Program() {
handle = GLES20.glCreateProgram();
}
public int handle() {
return handle;
}
public void attach( Shader shader ) {
GLES20.glAttachShader( handle, shader.handle() );
}
public void link() {
GLES20.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 ) );
}
}
public Attribute attribute( String name ) {
return new Attribute( GLES20.glGetAttribLocation( handle, name ) );
}
public Uniform uniform( String name ) {
return new Uniform( GLES20.glGetUniformLocation( handle, name ) );
}
public void use() {
GLES20.glUseProgram( handle );
}
public void delete() {
GLES20.glDeleteProgram( handle );
}
public static Program create( Shader ...shaders ) {
Program program = new Program();
for (int i=0; i < shaders.length; i++) {
program.attach( shaders[i] );
}
program.link();
return program;
}
}

View File

@ -0,0 +1,140 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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 java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
public class Quad {
// 0---1
// | \ |
// 3---2
public static final short[] VALUES = {0, 1, 2, 0, 2, 3};
public static final int SIZE = VALUES.length;
private static ShortBuffer indices;
private static int indexSize = 0;
public static FloatBuffer create() {
return ByteBuffer.
allocateDirect( 16 * Float.SIZE / 8 ).
order( ByteOrder.nativeOrder() ).
asFloatBuffer();
}
public static FloatBuffer createSet( int size ) {
return ByteBuffer.
allocateDirect( size * 16 * Float.SIZE / 8 ).
order( ByteOrder.nativeOrder() ).
asFloatBuffer();
}
public static ShortBuffer getIndices( int size ) {
if (size > indexSize) {
// TODO: Optimize it!
indexSize = size;
indices = ByteBuffer.
allocateDirect( size * SIZE * Short.SIZE / 8 ).
order( ByteOrder.nativeOrder() ).
asShortBuffer();
short[] values = new short[size * 6];
int pos = 0;
int limit = size * 4;
for (int ofs=0; ofs < limit; ofs += 4) {
values[pos++] = (short)(ofs + 0);
values[pos++] = (short)(ofs + 1);
values[pos++] = (short)(ofs + 2);
values[pos++] = (short)(ofs + 0);
values[pos++] = (short)(ofs + 2);
values[pos++] = (short)(ofs + 3);
}
indices.put( values );
indices.position( 0 );
}
return indices;
}
public static void fill( float[] v,
float x1, float x2, float y1, float y2,
float u1, float u2, float v1, float v2 ) {
v[0] = x1;
v[1] = y1;
v[2] = u1;
v[3] = v1;
v[4] = x2;
v[5] = y1;
v[6] = u2;
v[7] = v1;
v[8] = x2;
v[9] = y2;
v[10]= u2;
v[11]= v2;
v[12]= x1;
v[13]= y2;
v[14]= u1;
v[15]= v2;
}
public static void fillXY( float[] v, float x1, float x2, float y1, float y2 ) {
v[0] = x1;
v[1] = y1;
v[4] = x2;
v[5] = y1;
v[8] = x2;
v[9] = y2;
v[12]= x1;
v[13]= y2;
}
public static void fillUV( float[] v, float u1, float u2, float v1, float v2 ) {
v[2] = u1;
v[3] = v1;
v[6] = u2;
v[7] = v1;
v[10]= u2;
v[11]= v2;
v[14]= u1;
v[15]= v2;
}
}

View File

@ -0,0 +1,56 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.GLES20;
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;
private int id;
public Renderbuffer() {
int[] buffers = new int[1];
GLES20.glGenRenderbuffers( 1, buffers, 0 );
id = buffers[0];
}
public int id() {
return id;
}
public void bind() {
GLES20.glBindRenderbuffer( GLES20.GL_RENDERBUFFER, id );
}
public void delete() {
int[] buffers = {id};
GLES20.glDeleteRenderbuffers( 1, buffers, 0 );
}
public void storage( int format, int width, int height ) {
GLES20.glRenderbufferStorage( GLES20.GL_RENDERBUFFER, format , width, height );
}
}

View File

@ -0,0 +1,65 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.GLES20;
public class Shader {
public static final int VERTEX = GLES20.GL_VERTEX_SHADER;
public static final int FRAGMENT = GLES20.GL_FRAGMENT_SHADER;
private int handle;
public Shader( int type ) {
handle = GLES20.glCreateShader( type );
}
public int handle() {
return handle;
}
public void source( String src ) {
GLES20.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 ) );
}
}
public void delete() {
GLES20.glDeleteShader( handle );
}
public static Shader createCompiled( int type, String src ) {
Shader shader = new Shader( type );
shader.source( src );
shader.compile();
return shader;
}
}

View File

@ -0,0 +1,183 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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 java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
public class Texture {
public static final int NEAREST = GLES20.GL_NEAREST;
public static final int LINEAR = GLES20.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 int id;
private static int bound_id = 0; //id of the currently bound texture
public boolean premultiplied = false;
public Texture() {
int[] ids = new int[1];
GLES20.glGenTextures( 1, ids, 0 );
id = ids[0];
bind();
}
public static void activate( int index ) {
GLES20.glActiveTexture( GLES20.GL_TEXTURE0 + index );
}
public void bind() {
if (id != bound_id) {
GLES20.glBindTexture( GLES20.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 );
}
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 );
}
public void delete() {
if (bound_id == id) bound_id = 0;
int[] ids = {id};
GLES20.glDeleteTextures( 1, ids, 0 );
}
public void bitmap( Bitmap bitmap ) {
bind();
GLUtils.texImage2D( GLES20.GL_TEXTURE_2D, 0, bitmap, 0 );
premultiplied = true;
}
public void pixels( int w, int h, int[] pixels ) {
bind();
IntBuffer imageBuffer = ByteBuffer.
allocateDirect( w * h * 4 ).
order( ByteOrder.nativeOrder() ).
asIntBuffer();
imageBuffer.put( pixels );
imageBuffer.position( 0 );
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_RGBA,
w,
h,
0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
imageBuffer );
}
public void pixels( int w, int h, byte[] pixels ) {
bind();
ByteBuffer imageBuffer = ByteBuffer.
allocateDirect( w * h ).
order( ByteOrder.nativeOrder() );
imageBuffer.put( pixels );
imageBuffer.position( 0 );
GLES20.glPixelStorei( GLES20.GL_UNPACK_ALIGNMENT, 1 );
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_ALPHA,
w,
h,
0,
GLES20.GL_ALPHA,
GLES20.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 ) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pixels = new int[w * h];
bitmap.getPixels( pixels, 0, w, 0, 0, w, h );
// recode - components reordering is needed
if (recode) {
for (int i=0; i < pixels.length; i++) {
int color = pixels[i];
int ag = color & 0xFF00FF00;
int r = (color >> 16) & 0xFF;
int b = color & 0xFF;
pixels[i] = ag | (b << 16) | r;
}
}
pixels( w, h, pixels );
premultiplied = false;
}
public static Texture create( Bitmap bmp ) {
Texture tex = new Texture();
tex.bitmap( bmp );
return tex;
}
public static Texture create( int width, int height, int[] pixels ) {
Texture tex = new Texture();
tex.pixels( width, height, pixels );
return tex;
}
public static Texture create( int width, int height, byte[] pixels ) {
Texture tex = new Texture();
tex.pixels( width, height, pixels );
return tex;
}
}

View File

@ -0,0 +1,69 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.GLES20;
public class Uniform {
private int location;
public Uniform( int location ) {
this.location = location;
}
public int location() {
return location;
}
public void enable() {
GLES20.glEnableVertexAttribArray( location );
}
public void disable() {
GLES20.glDisableVertexAttribArray( location );
}
public void value( int value ) {
GLES20.glUniform1i( location, value );
}
public void value1f( float value ) {
GLES20.glUniform1f( location, value );
}
public void value2f( float v1, float v2 ) {
GLES20.glUniform2f( location, v1, v2 );
}
public void value4f( float v1, float v2, float v3, float v4 ) {
GLES20.glUniform4f( location, v1, v2, v3, v4 );
}
public void valueM3( float[] value ) {
GLES20.glUniformMatrix3fv( location, 1, false, value, 0 );
}
public void valueM4( float[] value ) {
GLES20.glUniformMatrix4fv( location, 1, false, value, 0 );
}
}

View File

@ -0,0 +1,65 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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 java.util.ArrayList;
import com.watabou.utils.Signal;
import android.view.KeyEvent;
public class Keys {
public static final int BACK = KeyEvent.KEYCODE_BACK;
public static final int MENU = KeyEvent.KEYCODE_MENU;
public static Signal<Key> event = new Signal<Key>( 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 class Key {
public int code;
public boolean pressed;
public Key( int code, boolean pressed ) {
this.code = code;
this.pressed = pressed;
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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 java.util.ArrayList;
import java.util.HashMap;
import com.watabou.utils.PointF;
import com.watabou.utils.Signal;
import android.view.MotionEvent;
public class Touchscreen {
public static Signal<Touch> event = new Signal<Touch>( true );
public static HashMap<Integer,Touch> pointers = new HashMap<Integer, Touch>();
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++) {
pointers.get( e.getPointerId( j ) ).update( e, j );
}
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;
}
e.recycle();
}
}
public static class Touch {
public PointF start;
public PointF current;
public boolean down;
public Touch( MotionEvent e, int index ) {
float x = e.getX( index );
float y = e.getY( index );
start = new PointF( x, y );
current = new PointF( x, y );
down = true;
}
public void update( MotionEvent e, int index ) {
current.set( e.getX( index ), e.getY( index ) );
}
public Touch up() {
down = false;
return this;
}
}
}

View File

@ -0,0 +1,353 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.nio.FloatBuffer;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Matrix;
import com.watabou.glwrap.Quad;
import android.graphics.Bitmap;
import android.graphics.RectF;
public class BitmapText extends Visual {
protected String text;
protected Font font;
protected float[] vertices = new float[16];
protected FloatBuffer quads;
public int realLength;
protected boolean dirty = true;
public BitmapText() {
this( "", null );
}
public BitmapText( Font font ) {
this( "", font );
}
public BitmapText( String text, Font font ) {
super( 0, 0, 0, 0 );
this.text = text;
this.font = font;
}
@Override
public void destroy() {
text = null;
font = null;
vertices = null;
quads = null;
super.destroy();
}
@Override
protected void updateMatrix() {
// "origin" field is ignored
Matrix.setIdentity( matrix );
Matrix.translate( matrix, x, y );
Matrix.scale( matrix, scale.x, scale.y );
Matrix.rotate( matrix, angle );
}
@Override
public void draw() {
super.draw();
NoosaScript script = NoosaScript.get();
font.texture.bind();
if (dirty) {
updateVertices();
}
script.camera( camera() );
script.uModel.valueM4( matrix );
script.lighting(
rm, gm, bm, am,
ra, ga, ba, aa );
script.drawQuadSet( quads, realLength );
}
protected void updateVertices() {
width = 0;
height = 0;
if (text == null) {
text = "";
}
quads = Quad.createSet( text.length() );
realLength = 0;
int length = text.length();
for (int i=0; i < length; i++) {
RectF rect = font.get( text.charAt( i ) );
if (rect == null) {
rect=null;
}
float w = font.width( rect );
float h = font.height( rect );
vertices[0] = width;
vertices[1] = 0;
vertices[2] = rect.left;
vertices[3] = rect.top;
vertices[4] = width + w;
vertices[5] = 0;
vertices[6] = rect.right;
vertices[7] = rect.top;
vertices[8] = width + w;
vertices[9] = h;
vertices[10] = rect.right;
vertices[11] = rect.bottom;
vertices[12] = width;
vertices[13] = h;
vertices[14] = rect.left;
vertices[15] = rect.bottom;
quads.put( vertices );
realLength++;
width += w + font.tracking;
if (h > height) {
height = h;
}
}
if (length > 0) {
width -= font.tracking;
}
dirty = false;
}
public void measure() {
width = 0;
height = 0;
if (text == null) {
text = "";
}
int length = text.length();
for (int i=0; i < length; i++) {
RectF rect = font.get( text.charAt( i ) );
float w = font.width( rect );
float h = font.height( rect );
width += w + font.tracking;
if (h > height) {
height = h;
}
}
if (length > 0) {
width -= font.tracking;
}
}
public float baseLine() {
return font.baseLine * scale.y;
}
public Font font() {
return font;
}
public void font( Font value ) {
font = value;
}
public String text() {
return text;
}
public void text( String str ) {
text = str;
dirty = true;
}
public static class Font extends TextureFilm {
public static final String LATIN_FULL =
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007F";
public SmartTexture texture;
public float tracking = 0;
public float baseLine;
public float lineHeight;
protected Font( SmartTexture tx ) {
super( tx );
texture = tx;
}
public Font( SmartTexture tx, int width, String chars ) {
this( tx, width, tx.height, chars );
}
public Font( SmartTexture tx, int width, int height, String chars ) {
super( tx );
texture = tx;
int length = chars.length();
float uw = (float)width / tx.width;
float vh = (float)height / tx.height;
float left = 0;
float top = 0;
float bottom = vh;
for (int i=0; i < length; i++) {
RectF rect = new RectF( left, top, left += uw, bottom );
add( chars.charAt( i ), rect );
if (left >= 1) {
left = 0;
top = bottom;
bottom += vh;
}
}
lineHeight = baseLine = height;
}
protected void splitBy( Bitmap bitmap, int height, int color, String chars ) {
int length = chars.length();
int width = bitmap.getWidth();
float vHeight = (float)height / bitmap.getHeight();
int pos;
int line = 0;
spaceMeasuring:
for (pos=0; pos < width; pos++) {
for (int j=0; j < height; j++) {
if (bitmap.getPixel( pos, j ) != color) {
break spaceMeasuring;
}
}
}
add( ' ', new RectF( 0, 0, (float)pos / width, vHeight-0.01f ) );
int separator = pos;
for (int i=0; i < length; i++) {
char ch = chars.charAt( i );
if (ch == ' ') {
continue;
} else {
boolean found;
do{
if (separator >= width) {
line += height;
separator = 0;
}
found = false;
for (int j=line; j < line + height; j++) {
if (bitmap.getPixel( separator, j ) != color) {
found = true;
break;
}
}
if (!found) separator++;
} while (!found);
int start = separator;
do {
if (++separator >= width) {
line += height;
separator = start = 0;
if (line + height >= bitmap.getHeight())
break;
}
found = true;
for (int j=line; j < line + height; j++) {
if (bitmap.getPixel( separator, j ) != color) {
found = false;
break;
}
}
} while (!found);
add( ch, new RectF( (float)start / width, (float)line / bitmap.getHeight(), (float)separator / width, (float)line / bitmap.getHeight() + vHeight) );
separator++;
}
}
lineHeight = baseLine = height( frames.get( chars.charAt( 0 ) ) );
}
public static Font colorMarked( Bitmap 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 ) {
Font font = new Font( TextureCache.get( bmp ) );
font.splitBy( bmp, height, color, chars );
return font;
}
public RectF get( char ch ) {
if (frames.containsKey( ch )){
return super.get( ch );
} else {
return super.get( '?' );
}
}
}
}

View File

@ -0,0 +1,325 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.util.ArrayList;
import java.util.regex.Pattern;
import android.graphics.RectF;
import com.watabou.glwrap.Quad;
import com.watabou.utils.PointF;
public class BitmapTextMultiline extends BitmapText {
public int maxWidth = Integer.MAX_VALUE;
protected static final Pattern PARAGRAPH = Pattern.compile( "\n" );
protected static final Pattern WORD = Pattern.compile( "\\s+" );
protected float spaceSize;
public int nLines = 0;
public boolean[] mask;
public BitmapTextMultiline( Font font ) {
this( "", font );
}
public BitmapTextMultiline( String text, Font font ) {
super( text, font );
spaceSize = font.width( font.get( ' ' ) );
}
@Override
protected void updateVertices() {
if (text == null) {
text = "";
}
quads = Quad.createSet( text.length() );
realLength = 0;
// This object controls lines breaking
SymbolWriter writer = new SymbolWriter();
// Word size
PointF metrics = new PointF();
String paragraphs[] = PARAGRAPH.split( text );
// Current character (used in masking)
int pos = 0;
for (int i=0; i < paragraphs.length; i++) {
String[] words = WORD.split( paragraphs[i] );
for (int j=0; j < words.length; j++) {
String word = words[j];
if (word.length() == 0) {
// This case is possible when there are
// several spaces coming along
continue;
}
getWordMetrics( word, metrics );
writer.addSymbol( metrics.x, metrics.y );
int length = word.length();
float shift = 0; // Position in pixels relative to the beginning of the word
for (int k=0; k < length; k++) {
RectF rect = font.get( word.charAt( k ) );
float w = font.width( rect );
float h = font.height( rect );
if (mask == null || mask[pos]) {
vertices[0] = writer.x + shift;
vertices[1] = writer.y;
vertices[2] = rect.left;
vertices[3] = rect.top;
vertices[4] = writer.x + shift + w;
vertices[5] = writer.y;
vertices[6] = rect.right;
vertices[7] = rect.top;
vertices[8] = writer.x + shift + w;
vertices[9] = writer.y + h;
vertices[10] = rect.right;
vertices[11] = rect.bottom;
vertices[12] = writer.x + shift;
vertices[13] = writer.y + h;
vertices[14] = rect.left;
vertices[15] = rect.bottom;
quads.put( vertices );
realLength++;
}
shift += w + font.tracking;
pos++;
}
writer.addSpace( spaceSize );
}
writer.newLine( 0, font.lineHeight );
}
nLines = writer.nLines();
dirty = false;
}
private void getWordMetrics( String word, PointF metrics ) {
float w = 0;
float h = 0;
int length = word.length();
for (int i=0; i < length; i++) {
RectF rect = font.get( word.charAt( i ) );
w += font.width( rect ) + (w > 0 ? font.tracking : 0);
h = Math.max( h, font.height( rect ) );
}
metrics.set( w, h );
}
@Override
public void measure() {
SymbolWriter writer = new SymbolWriter();
PointF metrics = new PointF();
String paragraphs[] = PARAGRAPH.split( text );
for (int i=0; i < paragraphs.length; i++) {
String[] words = WORD.split( paragraphs[i] );
for (int j=0; j < words.length; j++) {
if (j > 0) {
writer.addSpace( spaceSize );
}
String word = words[j];
if (word.length() == 0) {
continue;
}
getWordMetrics( word, metrics );
writer.addSymbol( metrics.x, metrics.y );
}
writer.newLine( 0, font.lineHeight );
}
width = writer.width;
height = writer.height;
nLines = writer.nLines();
}
@Override
public float baseLine() {
return (height - font.lineHeight + font.baseLine) * scale.y;
}
private class SymbolWriter {
public float width = 0;
public float height = 0;
public int nLines = 0;
public float lineWidth = 0;
public float lineHeight = 0;
public float x = 0;
public float y = 0;
public void addSymbol( float w, float h ) {
if (lineWidth > 0 && lineWidth + font.tracking + w > maxWidth / scale.x) {
newLine( w, h );
} else {
x = lineWidth;
lineWidth += (lineWidth > 0 ? font.tracking : 0) + w;
if (h > lineHeight) {
lineHeight = h;
}
}
}
public void addSpace( float w ) {
if (lineWidth > 0 && lineWidth + font.tracking + w > maxWidth / scale.x) {
newLine( 0, 0 );
} else {
x = lineWidth;
lineWidth += (lineWidth > 0 ? font.tracking : 0) + w;
}
}
public void newLine( float w, float h ) {
height += lineHeight;
if (width < lineWidth) {
width = lineWidth;
}
lineWidth = w;
lineHeight = h;
x = 0;
y = height;
nLines++;
}
public int nLines() {
return x == 0 ? nLines : nLines+1;
}
}
public class LineSplitter {
private ArrayList<BitmapText> lines;
private StringBuilder curLine;
private float curLineWidth;
private PointF metrics = new PointF();
private void newLine( String str, float width ) {
BitmapText txt = new BitmapText( curLine.toString(), font );
txt.scale.set( scale.x );
lines.add( txt );
curLine = new StringBuilder( str );
curLineWidth = width;
}
private void append( String str, float width ) {
curLineWidth += (curLineWidth > 0 ? font.tracking : 0) + width;
curLine.append( str );
}
public ArrayList<BitmapText> split() {
lines = new ArrayList<>();
curLine = new StringBuilder();
curLineWidth = 0;
String paragraphs[] = PARAGRAPH.split( text );
for (int i=0; i < paragraphs.length; i++) {
String[] words = WORD.split( paragraphs[i] );
for (int j=0; j < words.length; j++) {
String word = words[j];
if (word.length() == 0) {
continue;
}
getWordMetrics( word, metrics );
if (curLineWidth > 0 && curLineWidth + font.tracking + metrics.x > maxWidth / scale.x) {
newLine( word, metrics.x );
} else {
append( word, metrics.x );
}
if (curLineWidth > 0 && curLineWidth + font.tracking + spaceSize > maxWidth / scale.x) {
newLine( "", 0 );
} else {
append( " ", spaceSize );
}
}
newLine( "", 0 );
}
return lines;
}
}
}

View File

@ -0,0 +1,236 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.util.ArrayList;
import com.watabou.glwrap.Matrix;
import com.watabou.utils.Point;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class Camera extends Gizmo {
protected static ArrayList<Camera> all = new ArrayList<Camera>();
protected static float invW2;
protected static float invH2;
public static Camera main;
public float zoom;
public int x;
public int y;
public int width;
public int height;
int screenWidth;
int screenHeight;
public float[] matrix;
public PointF scroll;
public Visual target;
private float shakeMagX = 10f;
private float shakeMagY = 10f;
private float shakeTime = 0f;
private float shakeDuration = 1f;
protected float shakeX;
protected float shakeY;
public static Camera reset() {
return reset( createFullscreen( 1 ) );
}
public static Camera reset( Camera newCamera ) {
invW2 = 2f / Game.width;
invH2 = 2f / Game.height;
int length = all.size();
for (int i=0; i < length; i++) {
all.get( i ).destroy();
}
all.clear();
return main = add( newCamera );
}
public static Camera add( Camera camera ) {
all.add( camera );
return camera;
}
public static Camera remove( Camera camera ) {
all.remove( camera );
return camera;
}
public static void updateAll() {
int length = all.size();
for (int i=0; i < length; i++) {
Camera c = all.get( i );
if (c.exists && c.active) {
c.update();
}
}
}
public static Camera createFullscreen( float zoom ) {
int w = (int)Math.ceil( Game.width / zoom );
int h = (int)Math.ceil( Game.height / zoom );
return new Camera(
(int)(Game.width - w * zoom) / 2,
(int)(Game.height - h * zoom) / 2,
w, h, zoom );
}
public Camera( int x, int y, int width, int height, float zoom ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.zoom = zoom;
screenWidth = (int)(width * zoom);
screenHeight = (int)(height * zoom);
scroll = new PointF();
matrix = new float[16];
Matrix.setIdentity( matrix );
}
@Override
public void destroy() {
target = null;
matrix = null;
}
public void zoom( float value ) {
zoom( value,
scroll.x + width / 2,
scroll.y + height / 2 );
}
public void zoom( float value, float fx, float fy ) {
zoom = value;
width = (int)(screenWidth / zoom);
height = (int)(screenHeight / zoom);
focusOn( fx, fy );
}
public void resize( int width, int height ) {
this.width = width;
this.height = height;
screenWidth = (int)(width * zoom);
screenHeight = (int)(height * zoom);
}
@Override
public void update() {
super.update();
if (target != null) {
focusOn( target );
}
if ((shakeTime -= Game.elapsed) > 0) {
float damping = shakeTime / shakeDuration;
shakeX = Random.Float( -shakeMagX, +shakeMagX ) * damping;
shakeY = Random.Float( -shakeMagY, +shakeMagY ) * damping;
} else {
shakeX = 0;
shakeY = 0;
}
updateMatrix();
}
public PointF center() {
return new PointF( width / 2, height / 2 );
}
public boolean hitTest( float x, float y ) {
return x >= this.x && y >= this.y && x < this.x + screenWidth && y < this.y + screenHeight;
}
public void focusOn( float x, float y ) {
scroll.set( x - width / 2, y - height / 2 );
}
public void focusOn( PointF point ) {
focusOn( point.x, point.y );
}
public void focusOn( Visual visual ) {
focusOn( visual.center() );
}
public PointF screenToCamera( int x, int y ) {
return new PointF(
(x - this.x) / zoom + scroll.x,
(y - this.y) / zoom + scroll.y );
}
public Point cameraToScreen( float x, float y ) {
return new Point(
(int)((x - scroll.x) * zoom + this.x),
(int)((y - scroll.y) * zoom + this.y));
}
public float screenWidth() {
return width * zoom;
}
public float screenHeight() {
return height * zoom;
}
protected void updateMatrix() {
/* Matrix.setIdentity( matrix );
Matrix.translate( matrix, -1, +1 );
Matrix.scale( matrix, 2f / G.width, -2f / G.height );
Matrix.translate( matrix, x, y );
Matrix.scale( matrix, zoom, zoom );
Matrix.translate( matrix, scroll.x, scroll.y );*/
matrix[0] = +zoom * invW2;
matrix[5] = -zoom * invH2;
matrix[12] = -1 + x * invW2 - (scroll.x + shakeX) * matrix[0];
matrix[13] = +1 - y * invH2 - (scroll.y + shakeY) * matrix[5];
}
public void shake( float magnitude, float duration ) {
shakeMagX = shakeMagY = magnitude;
shakeTime = shakeDuration = duration;
}
}

View File

@ -0,0 +1,48 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.gltextures.TextureCache;
public class ColorBlock extends Image implements Resizable {
public ColorBlock( float width, float height, int color ) {
super( TextureCache.createSolid( color ) );
scale.set( width, height );
origin.set( 0, 0 );
}
@Override
public void size( float width, float height ) {
scale.set( width, height );
}
@Override
public float width() {
return scale.x;
}
@Override
public float height() {
return scale.y;
}
}

View File

@ -0,0 +1,342 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.watabou.glscripts.Script;
import com.watabou.gltextures.TextureCache;
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.SystemTime;
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.Bundle;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTouchListener {
public static Game instance;
// Actual size of the screen
public static int width;
public static int height;
// Density: mdpi=1, hdpi=1.5, xhdpi=2...
public static float density = 1;
public static String version;
public static int versionCode;
// Current scene
protected Scene scene;
// New scene we are going to switch to
protected Scene requestedScene;
// true if scene switch is requested
protected boolean requestedReset = true;
// callback to perform logic during scene change
protected SceneChangeCallback onChange;
// New scene class
protected Class<? extends Scene> sceneClass;
// Current time in milliseconds
protected long now;
// Milliseconds passed since previous update
protected long step;
public static float timeScale = 1f;
public static float elapsed = 0f;
public static float timeTotal = 0f;
protected GLSurfaceView view;
protected SurfaceHolder holder;
// Accumulated touch events
protected ArrayList<MotionEvent> motionEvents = new ArrayList<MotionEvent>();
// Accumulated key events
protected ArrayList<KeyEvent> keysEvents = new ArrayList<KeyEvent>();
public Game( Class<? extends Scene> c ) {
super();
sceneClass = c;
}
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
BitmapCache.context = TextureCache.context = instance = this;
DisplayMetrics m = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics( m );
density = m.density;
try {
version = getPackageManager().getPackageInfo( getPackageName(), 0 ).versionName;
} catch (NameNotFoundException e) {
version = "???";
}
try {
versionCode = getPackageManager().getPackageInfo( getPackageName(), 0 ).versionCode;
} catch (NameNotFoundException e) {
versionCode = 0;
}
setVolumeControlStream( AudioManager.STREAM_MUSIC );
view = new GLSurfaceView( this );
view.setEGLContextClientVersion( 2 );
view.setEGLConfigChooser( 5, 6, 5, 0, 0, 0 );
view.setRenderer( this );
view.setOnTouchListener( this );
setContentView( view );
}
@Override
public void onResume() {
super.onResume();
now = 0;
view.onResume();
Music.INSTANCE.resume();
Sample.INSTANCE.resume();
}
@Override
public void onPause() {
super.onPause();
if (scene != null) {
scene.pause();
}
view.onPause();
Script.reset();
Music.INSTANCE.pause();
Sample.INSTANCE.pause();
}
@Override
public void onDestroy() {
super.onDestroy();
destroyGame();
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;
}
@Override
public boolean onKeyDown( int keyCode, KeyEvent event ) {
if (keyCode != Keys.BACK &&
keyCode != Keys.MENU) {
return false;
}
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;
}
SystemTime.tick();
long rightNow = SystemTime.now;
step = (now == 0 ? 0 : rightNow - now);
now = rightNow;
step();
NoosaScript.get().resetCamera();
GLES20.glScissor( 0, 0, width, height );
GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT );
draw();
}
@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();
}
}
@Override
public void onSurfaceCreated( GL10 gl, EGLConfig config ) {
GLES20.glEnable( GL10.GL_BLEND );
// For premultiplied alpha:
// GLES20.glBlendFunc( GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA );
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
GLES20.glEnable( GL10.GL_SCISSOR_TEST );
TextureCache.reload();
RenderedText.reloadCache();
}
protected void destroyGame() {
if (scene != null) {
scene.destroy();
scene = null;
}
//instance = null;
}
public static void resetScene() {
switchScene( instance.sceneClass );
}
public static void switchScene(Class<? extends Scene> c) {
switchScene(c, null);
}
public static void switchScene(Class<? extends Scene> c, SceneChangeCallback callback) {
instance.sceneClass = c;
instance.requestedReset = true;
instance.onChange = callback;
}
public static Scene scene() {
return instance.scene;
}
protected void step() {
if (requestedReset) {
requestedReset = false;
try {
requestedScene = sceneClass.newInstance();
switchScene();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
update();
}
protected void draw() {
scene.draw();
}
protected void switchScene() {
Camera.reset();
if (scene != null) {
scene.destroy();
}
scene = requestedScene;
if (onChange != null) onChange.beforeCreate();
scene.create();
if (onChange != null) onChange.afterCreate();
onChange = null;
Game.elapsed = 0f;
Game.timeScale = 1f;
Game.timeTotal = 0f;
}
protected void update() {
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();
}
scene.update();
Camera.updateAll();
}
public static void vibrate( int milliseconds ) {
((Vibrator)instance.getSystemService( VIBRATOR_SERVICE )).vibrate( milliseconds );
}
public interface SceneChangeCallback{
void beforeCreate();
void afterCreate();
}
}

View File

@ -0,0 +1,101 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
public class Gizmo {
public boolean exists;
public boolean alive;
public boolean active;
public boolean visible;
public Group parent;
public Camera camera;
public Gizmo() {
exists = true;
alive = true;
active = true;
visible = true;
}
public void destroy() {
parent = null;
}
public void update() {
}
public void draw() {
}
public void kill() {
alive = false;
exists = false;
}
// Not exactly opposite to "kill" method
public void revive() {
alive = true;
exists = true;
}
public Camera camera() {
if (camera != null) {
return camera;
} else if (parent != null) {
return parent.camera();
} else {
return null;
}
}
public boolean isVisible() {
if (parent == null) {
return visible;
} else {
return visible && parent.isVisible();
}
}
public boolean isActive() {
if (parent == null) {
return active;
} else {
return active && parent.isActive();
}
}
public void killAndErase() {
kill();
if (parent != null) {
parent.erase( this );
}
}
public void remove() {
if (parent != null) {
parent.remove( this );
}
}
}

View File

@ -0,0 +1,314 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.noosa.particles.Emitter;
import java.util.ArrayList;
public class Group extends Gizmo {
protected ArrayList<Gizmo> members;
// Accessing it is a little faster,
// than calling members.getSize()
public int length;
public static boolean freezeEmitters = false;
public Group() {
members = new ArrayList<Gizmo>();
length = 0;
}
@Override
public void destroy() {
super.destroy();
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null) {
g.destroy();
}
}
members.clear();
members = null;
length = 0;
}
@Override
public void update() {
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && g.exists && g.active
//functionality for the freezing of emitters(particle effects), effects are given a second
//from load to get started so they aren't frozen before anything is generated.
&& !(freezeEmitters && Game.timeTotal > 1f && g instanceof Emitter)) {
g.update();
}
}
}
@Override
public void draw() {
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && g.exists && g.visible) {
g.draw();
}
}
}
@Override
public void kill() {
// A killed group keeps all its members,
// but they get killed too
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && g.exists) {
g.kill();
}
}
super.kill();
}
public int indexOf( Gizmo g ) {
return members.indexOf( g );
}
public Gizmo add( Gizmo g ) {
if (g.parent == this) {
return g;
}
if (g.parent != null) {
g.parent.remove( g );
}
// Trying to find an empty space for a new member
for (int i=0; i < length; i++) {
if (members.get( i ) == null) {
members.set( i, g );
g.parent = this;
return g;
}
}
members.add( g );
g.parent = this;
length++;
return g;
}
public Gizmo addToFront( Gizmo g){
if (g.parent == this) {
return g;
}
if (g.parent != null) {
g.parent.remove( g );
}
// Trying to find an empty space for a new member
// starts from the front and never goes over a none-null element
for (int i=length-1; i >= 0; i--) {
if (members.get( i ) == null) {
if (i == 0 || members.get(i - 1) != null) {
members.set(i, g);
g.parent = this;
return g;
}
} else {
break;
}
}
members.add( g );
g.parent = this;
length++;
return g;
}
public Gizmo addToBack( Gizmo g ) {
if (g.parent == this) {
sendToBack( g );
return g;
}
if (g.parent != null) {
g.parent.remove( g );
}
if (members.get( 0 ) == null) {
members.set( 0, g );
g.parent = this;
return g;
}
members.add( 0, g );
g.parent = this;
length++;
return g;
}
public Gizmo recycle( Class<? extends Gizmo> c ) {
Gizmo g = getFirstAvailable( c );
if (g != null) {
return g;
} else if (c == null) {
return null;
} else {
try {
return add( c.newInstance() );
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
// Fast removal - replacing with null
public Gizmo erase( Gizmo g ) {
int index = members.indexOf( g );
if (index != -1) {
members.set( index, null );
g.parent = null;
return g;
} else {
return null;
}
}
// Real removal
public Gizmo remove( Gizmo g ) {
if (members.remove( g )) {
length--;
g.parent = null;
return g;
} else {
return null;
}
}
public Gizmo replace( Gizmo oldOne, Gizmo newOne ) {
int index = members.indexOf( oldOne );
if (index != -1) {
members.set( index, newOne );
newOne.parent = this;
oldOne.parent = null;
return newOne;
} else {
return null;
}
}
public Gizmo getFirstAvailable( Class<? extends Gizmo> c ) {
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && !g.exists && ((c == null) || g.getClass() == c)) {
return g;
}
}
return null;
}
public int countLiving() {
int count = 0;
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && g.exists && g.alive) {
count++;
}
}
return count;
}
public int countDead() {
int count = 0;
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null && !g.alive) {
count++;
}
}
return count;
}
public Gizmo random() {
if (length > 0) {
return members.get( (int)(Math.random() * length) );
} else {
return null;
}
}
public void clear() {
for (int i=0; i < length; i++) {
Gizmo g = members.get( i );
if (g != null) {
g.parent = null;
}
}
members.clear();
length = 0;
}
public Gizmo bringToFront( Gizmo g ) {
if (members.contains( g )) {
members.remove( g );
members.add( g );
return g;
} else {
return null;
}
}
public Gizmo sendToBack( Gizmo g ) {
if (members.contains( g )) {
members.remove( g );
members.add( 0, g );
return g;
} else {
return null;
}
}
}

View File

@ -0,0 +1,171 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.nio.FloatBuffer;
import android.graphics.RectF;
import com.watabou.gltextures.TextureCache;
import com.watabou.gltextures.SmartTexture;
import com.watabou.glwrap.Quad;
public class Image extends Visual {
public SmartTexture texture;
protected RectF frame;
public boolean flipHorizontal;
public boolean flipVertical;
protected float[] vertices;
protected FloatBuffer verticesBuffer;
protected boolean dirty;
public Image() {
super( 0, 0, 0, 0 );
vertices = new float[16];
verticesBuffer = Quad.create();
}
public Image( Image src ) {
this();
copy( src );
}
public Image( Object tx ) {
this();
texture( tx );
}
public Image( Object tx, int left, int top, int width, int height ) {
this( tx );
frame( texture.uvRect( left, top, left + width, top + height ) );
}
public void texture( Object tx ) {
texture = tx instanceof SmartTexture ? (SmartTexture)tx : TextureCache.get( tx );
frame( new RectF( 0, 0, 1, 1 ) );
}
public void frame( RectF frame ) {
this.frame = frame;
width = frame.width() * texture.width;
height = frame.height() * texture.height;
updateFrame();
updateVertices();
}
public void frame( int left, int top, int width, int height ) {
frame( texture.uvRect( left, top, left + width, top + height ) );
}
public RectF frame() {
return new RectF( frame );
}
public void copy( Image other ) {
texture = other.texture;
frame = new RectF( other.frame );
width = other.width;
height = other.height;
updateFrame();
updateVertices();
}
protected void updateFrame() {
if (flipHorizontal) {
vertices[2] = frame.right;
vertices[6] = frame.left;
vertices[10] = frame.left;
vertices[14] = frame.right;
} else {
vertices[2] = frame.left;
vertices[6] = frame.right;
vertices[10] = frame.right;
vertices[14] = frame.left;
}
if (flipVertical) {
vertices[3] = frame.bottom;
vertices[7] = frame.bottom;
vertices[11] = frame.top;
vertices[15] = frame.top;
} else {
vertices[3] = frame.top;
vertices[7] = frame.top;
vertices[11] = frame.bottom;
vertices[15] = frame.bottom;
}
dirty = true;
}
protected void updateVertices() {
vertices[0] = 0;
vertices[1] = 0;
vertices[4] = width;
vertices[5] = 0;
vertices[8] = width;
vertices[9] = height;
vertices[12] = 0;
vertices[13] = height;
dirty = true;
}
@Override
public void draw() {
super.draw();
NoosaScript script = NoosaScript.get();
texture.bind();
script.camera( camera() );
script.uModel.valueM4( matrix );
script.lighting(
rm, gm, bm, am,
ra, ga, ba, aa );
if (dirty) {
verticesBuffer.position( 0 );
verticesBuffer.put( vertices );
dirty = false;
}
script.drawQuad( verticesBuffer );
}
}

View File

@ -0,0 +1,143 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import android.graphics.RectF;
public class MovieClip extends Image {
protected Animation curAnim;
protected int curFrame;
protected float frameTimer;
protected boolean finished;
public boolean paused = false;
public Listener listener;
public MovieClip() {
super();
}
public MovieClip( Object tx ) {
super( tx );
}
@Override
public void update() {
super.update();
if (!paused) {
updateAnimation();
}
}
public boolean looping(){
return curAnim != null && curAnim.looped;
}
protected void updateAnimation() {
if (curAnim != null && curAnim.delay > 0 && (curAnim.looped || !finished)) {
int lastFrame = curFrame;
frameTimer += Game.elapsed;
while (frameTimer > curAnim.delay) {
frameTimer -= curAnim.delay;
if (curFrame == curAnim.frames.length - 1) {
if (curAnim.looped) {
curFrame = 0;
}
finished = true;
if (listener != null) {
listener.onComplete( curAnim );
// This check can probably be removed
if (curAnim == null) {
return;
}
}
} else {
curFrame++;
}
}
if (curFrame != lastFrame) {
frame( curAnim.frames[curFrame] );
}
}
}
public void play( Animation anim ) {
play( anim, false );
}
public void play( Animation anim, boolean force ) {
if (!force && (curAnim != null) && (curAnim == anim) && (curAnim.looped || !finished)) {
return;
}
curAnim = anim;
curFrame = 0;
finished = false;
frameTimer = 0;
if (anim != null) {
frame( anim.frames[curFrame] );
}
}
public static class Animation {
public float delay;
public RectF[] frames;
public boolean looped;
public Animation( int fps, boolean looped ) {
this.delay = 1f / fps;
this.looped = looped;
}
public Animation frames( RectF... frames ) {
this.frames = frames;
return this;
}
public Animation frames( TextureFilm film, Object... frames ) {
this.frames = new RectF[frames.length];
for (int i=0; i < frames.length; i++) {
this.frames[i] = film.get( frames[i] );
}
return this;
}
public Animation clone() {
return new Animation( Math.round( 1 / delay ), looped ).frames( frames );
}
}
public interface Listener {
void onComplete( Animation anim );
}
}

View File

@ -0,0 +1,212 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.nio.FloatBuffer;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Quad;
import android.graphics.RectF;
public class NinePatch extends Visual {
public SmartTexture texture;
protected float[] vertices;
protected FloatBuffer verticesBuffer;
protected RectF outterF;
protected RectF innerF;
protected int marginLeft;
protected int marginRight;
protected int marginTop;
protected int marginBottom;
protected float nWidth;
protected float nHeight;
protected boolean flipHorizontal;
protected boolean flipVertical;
public NinePatch( Object tx, int margin ) {
this( tx, margin, margin, margin, margin );
}
public NinePatch( Object tx, int left, int top, int right, int bottom ) {
this( tx, 0, 0, 0, 0, left, top, right, bottom );
}
public NinePatch( Object tx, int x, int y, int w, int h, int margin ) {
this( tx, x, y, w, h, margin, margin, margin, margin );
}
public NinePatch( Object tx, int x, int y, int w, int h, int left, int top, int right, int bottom ) {
super( 0, 0, 0, 0 );
texture = TextureCache.get( tx );
w = w == 0 ? texture.width : w;
h = h == 0 ? texture.height : h;
nWidth = width = w;
nHeight = height = h;
vertices = new float[16];
verticesBuffer = Quad.createSet( 9 );
marginLeft = left;
marginRight = right;
marginTop = top;
marginBottom= bottom;
outterF = texture.uvRect( x, y, x + w, y + h );
innerF = texture.uvRect( x + left, y + top, x + w - right, y + h - bottom );
updateVertices();
}
protected void updateVertices() {
verticesBuffer.position( 0 );
float right = width - marginRight;
float bottom = height - marginBottom;
float outleft = flipHorizontal ? outterF.right : outterF.left;
float outright = flipHorizontal ? outterF.left : outterF.right;
float outtop = flipVertical ? outterF.bottom : outterF.top;
float outbottom = flipVertical ? outterF.top : outterF.bottom;
float inleft = flipHorizontal ? innerF.right : innerF.left;
float inright = flipHorizontal ? innerF.left : innerF.right;
float intop = flipVertical ? innerF.bottom : innerF.top;
float inbottom = flipVertical ? innerF.top : innerF.bottom;
Quad.fill( vertices,
0, marginLeft, 0, marginTop, outleft, inleft, outtop, intop );
verticesBuffer.put( vertices );
Quad.fill( vertices,
marginLeft, right, 0, marginTop, inleft, inright, outtop, intop );
verticesBuffer.put( vertices );
Quad.fill( vertices,
right, width, 0, marginTop, inright, outright, outtop, intop );
verticesBuffer.put( vertices );
Quad.fill( vertices,
0, marginLeft, marginTop, bottom, outleft, inleft, intop, inbottom );
verticesBuffer.put( vertices );
Quad.fill( vertices,
marginLeft, right, marginTop, bottom, inleft, inright, intop, inbottom );
verticesBuffer.put( vertices );
Quad.fill( vertices,
right, width, marginTop, bottom, inright, outright, intop, inbottom );
verticesBuffer.put( vertices );
Quad.fill( vertices,
0, marginLeft, bottom, height, outleft, inleft, inbottom, outbottom );
verticesBuffer.put( vertices );
Quad.fill( vertices,
marginLeft, right, bottom, height, inleft, inright, inbottom, outbottom );
verticesBuffer.put( vertices );
Quad.fill( vertices,
right, width, bottom, height, inright, outright, inbottom, outbottom );
verticesBuffer.put( vertices );
}
public int marginLeft() {
return marginLeft;
}
public int marginRight() {
return marginRight;
}
public int marginTop() {
return marginTop;
}
public int marginBottom() {
return marginBottom;
}
public int marginHor() {
return marginLeft + marginRight;
}
public int marginVer() {
return marginTop + marginBottom;
}
public float innerWidth() {
return width - marginLeft - marginRight;
}
public float innerHeight() {
return height - marginTop - marginBottom;
}
public float innerRight() {
return width - marginRight;
}
public float innerBottom() {
return height - marginBottom;
}
public void flipHorizontal(boolean value) {
flipHorizontal = value;
updateVertices();
}
public void flipVertical(boolean value) {
flipVertical = value;
updateVertices();
}
public void size( float width, float height ) {
this.width = width;
this.height = height;
updateVertices();
}
@Override
public void draw() {
super.draw();
NoosaScript script = NoosaScript.get();
texture.bind();
script.camera( camera() );
script.uModel.valueM4( matrix );
script.lighting(
rm, gm, bm, am,
ra, ga, ba, aa );
script.drawQuadSet( verticesBuffer, 9 );
}
}

View File

@ -0,0 +1,171 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import android.opengl.GLES20;
import com.watabou.glscripts.Script;
import com.watabou.glwrap.Attribute;
import com.watabou.glwrap.Quad;
import com.watabou.glwrap.Uniform;
public class NoosaScript extends Script {
public Uniform uCamera;
public Uniform uModel;
public Uniform uTex;
public Uniform uColorM;
public Uniform uColorA;
public Attribute aXY;
public Attribute aUV;
private Camera lastCamera;
public NoosaScript() {
super();
compile( shader() );
uCamera = uniform( "uCamera" );
uModel = uniform( "uModel" );
uTex = uniform( "uTex" );
uColorM = uniform( "uColorM" );
uColorA = uniform( "uColorA" );
aXY = attribute( "aXYZW" );
aUV = attribute( "aUV" );
}
@Override
public void use() {
super.use();
aXY.enable();
aUV.enable();
}
public void drawElements( FloatBuffer vertices, ShortBuffer indices, int size ) {
vertices.position( 0 );
aXY.vertexPointer( 2, 4, vertices );
vertices.position( 2 );
aUV.vertexPointer( 2, 4, vertices );
GLES20.glDrawElements( GLES20.GL_TRIANGLES, size, GLES20.GL_UNSIGNED_SHORT, indices );
}
public void drawQuad( FloatBuffer vertices ) {
vertices.position( 0 );
aXY.vertexPointer( 2, 4, vertices );
vertices.position( 2 );
aUV.vertexPointer( 2, 4, vertices );
GLES20.glDrawElements( GLES20.GL_TRIANGLES, Quad.SIZE, GLES20.GL_UNSIGNED_SHORT, Quad.getIndices( 1 ) );
}
public void drawQuadSet( FloatBuffer vertices, int size ) {
if (size == 0) {
return;
}
vertices.position( 0 );
aXY.vertexPointer( 2, 4, vertices );
vertices.position( 2 );
aUV.vertexPointer( 2, 4, vertices );
GLES20.glDrawElements(
GLES20.GL_TRIANGLES,
Quad.SIZE * size,
GLES20.GL_UNSIGNED_SHORT,
Quad.getIndices( size ) );
}
public void lighting( float rm, float gm, float bm, float am, float ra, float ga, float ba, float aa ) {
uColorM.value4f( rm, gm, bm, am );
uColorA.value4f( ra, ga, ba, aa );
}
public void resetCamera() {
lastCamera = null;
}
public void camera( Camera camera ) {
if (camera == null) {
camera = Camera.main;
}
if (camera != lastCamera && camera.matrix != null) {
lastCamera = camera;
uCamera.valueM4( camera.matrix );
GLES20.glScissor(
camera.x,
Game.height - camera.screenHeight - camera.y,
camera.screenWidth,
camera.screenHeight );
}
}
public static NoosaScript get() {
return Script.use( NoosaScript.class );
}
protected String shader() {
return SHADER;
}
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" +
"precision mediump float;" +
"varying vec2 vUV;" +
"uniform sampler2D uTex;" +
"uniform vec4 uColorM;" +
"uniform vec4 uColorA;" +
"void main() {" +
" gl_FragColor = texture2D( uTex, vUV ) * uColorM + uColorA;" +
"}";
}

View File

@ -0,0 +1,48 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.gltextures.TextureCache;
public class PseudoPixel extends Image {
public PseudoPixel() {
super( TextureCache.createSolid( 0xFFFFFFFF ) );
}
public PseudoPixel( float x, float y, int color ) {
this();
this.x = x;
this.y = y;
color( color );
}
public void size( float w, float h ) {
scale.set( w, h );
}
public void size( float value ) {
scale.set( value );
}
}

View File

@ -0,0 +1,229 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import com.watabou.gltextures.SmartTexture;
import com.watabou.glwrap.Matrix;
import com.watabou.glwrap.Texture;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class RenderedText extends Image {
private static Canvas canvas = new Canvas();
private static Paint painter = new Paint();
private static Typeface font;
//this is basically a LRU cache. capacity is determined by character count, not entry count.
//will attempt to clear oldest, not in use entires until there are 500 characters stored.
//FIXME: Caching based on words is very inefficient for every language but chinese.
private static LinkedHashMap<String, CachedText> textCache =
new LinkedHashMap<String, CachedText>(700, 0.75f, true){
private int cachedChars = 0;
private final int MAX_CACHED = 500;
@Override
public CachedText put(String key, CachedText value) {
cachedChars += value.length;
CachedText added = super.put(key, value);
runGC();
return added;
}
@Override
public CachedText remove(Object key) {
CachedText removed = super.remove(key);
if (removed != null) {
cachedChars-= removed.length;
removed.texture.delete();
}
return removed;
}
@Override
public void clear() {
super.clear();
cachedChars = 0;
}
private void runGC(){
Iterator<Map.Entry<String, CachedText>> it = this.entrySet().iterator();
while (cachedChars > MAX_CACHED && it.hasNext()){
CachedText cached = it.next().getValue();
if (cached.activeTexts.isEmpty()) it.remove();
}
}
};
private int size;
private String text;
private CachedText cache;
public RenderedText( ){
text = null;
}
public RenderedText( int size ){
text = null;
this.size = size;
}
public RenderedText(String text, int size){
this.text = text;
this.size = size;
render();
}
public void text( String text ){
this.text = text;
render();
}
public String text(){
return text;
}
public void size( int size ){
this.size = size;
render();
}
public float baseLine(){
return size * scale.y;
}
private void render(){
if ( text == null || text.equals("") ) {
text = "";
width=height=0;
visible = false;
return;
} else {
visible = true;
}
if (cache != null)
cache.activeTexts.remove(this);
String key = "text:" + size + " " + text;
if (textCache.containsKey(key)){
cache = textCache.get(key);
texture = cache.texture;
frame(cache.rect);
cache.activeTexts.add(this);
} else {
painter.setTextSize(size);
painter.setAntiAlias(true);
if (font != null) {
painter.setTypeface(font);
} else {
painter.setTypeface(Typeface.DEFAULT);
}
//paint outer strokes
painter.setARGB(0xff, 0, 0, 0);
painter.setStyle(Paint.Style.STROKE);
painter.setStrokeWidth(size / 5f);
int right = (int)(painter.measureText(text)+ (size/5f));
int bottom = (int)(-painter.ascent() + painter.descent()+ (size/5f));
//bitmap has to be in a power of 2 for some devices (as we're using openGL methods to render to texture)
Bitmap bitmap = Bitmap.createBitmap(Integer.highestOneBit(right)*2, Integer.highestOneBit(bottom)*2, Bitmap.Config.ARGB_4444);
bitmap.eraseColor(0x00000000);
canvas.setBitmap(bitmap);
canvas.drawText(text, (size/10f), size, painter);
//paint inner text
painter.setARGB(0xff, 0xff, 0xff, 0xff);
painter.setStyle(Paint.Style.FILL);
canvas.drawText(text, (size/10f), size, painter);
texture = new SmartTexture(bitmap, Texture.NEAREST, Texture.CLAMP, true);
RectF rect = texture.uvRect(0, 0, right, bottom);
frame(rect);
cache = new CachedText();
cache.rect = rect;
cache.texture = texture;
cache.length = text.length();
cache.activeTexts = new HashSet<>();
cache.activeTexts.add(this);
textCache.put("text:" + size + " " + text, cache);
}
}
@Override
protected void updateMatrix() {
super.updateMatrix();
//the y value is set at the top of the character, not at the top of accents.
Matrix.translate( matrix, 0, -Math.round((baseLine()*0.15f)/scale.y) );
}
@Override
public void destroy() {
if (cache != null)
cache.activeTexts.remove(this);
super.destroy();
}
public static void clearCache(){
for (CachedText cached : textCache.values()){
cached.texture.delete();
}
textCache.clear();
}
public static void reloadCache(){
for (CachedText txt : textCache.values()){
txt.texture.reload();
}
}
public static void setFont(String asset){
font = Typeface.createFromAsset(Game.instance.getAssets(), asset);
clearCache();
}
private class CachedText{
public SmartTexture texture;
public RectF rect;
public int length;
public HashSet<RenderedText> activeTexts;
}
}

View File

@ -0,0 +1,30 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
public interface Resizable {
public void size( float width, float height );
public float width();
public float height();
}

View File

@ -0,0 +1,81 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.input.Keys;
import com.watabou.utils.Signal;
public class Scene extends Group {
private Signal.Listener<Keys.Key> keyListener;
public void create() {
Keys.event.add( keyListener = new Signal.Listener<Keys.Key>() {
@Override
public void onSignal( Keys.Key key ) {
if (Game.instance != null && key.pressed) {
switch (key.code) {
case Keys.BACK:
onBackPressed();
break;
case Keys.MENU:
onMenuPressed();
break;
}
}
}
} );
}
@Override
public void destroy() {
Keys.event.remove( keyListener );
super.destroy();
}
public void pause() {
}
public void resume() {
}
@Override
public void update() {
super.update();
}
@Override
public Camera camera() {
return Camera.main;
}
protected void onBackPressed() {
Game.instance.finish();
}
protected void onMenuPressed() {
}
}

View File

@ -0,0 +1,130 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.glwrap.Texture;
import android.graphics.RectF;
public class SkinnedBlock extends Image {
protected float scaleX;
protected float scaleY;
protected float offsetX;
protected float offsetY;
public boolean autoAdjust = false;
public SkinnedBlock( float width, float height, Object tx ) {
super( tx );
texture.wrap( Texture.REPEAT, Texture.REPEAT );
size( width, height );
}
@Override
public void frame( RectF frame ) {
scaleX = 1;
scaleY = 1;
offsetX = 0;
offsetY = 0;
super.frame( new RectF( 0, 0, 1, 1 ) );
}
@Override
protected void updateFrame() {
if (autoAdjust) {
while (offsetX > texture.width) {
offsetX -= texture.width;
}
while (offsetX < -texture.width) {
offsetX += texture.width;
}
while (offsetY > texture.height) {
offsetY -= texture.height;
}
while (offsetY < -texture.height) {
offsetY += texture.height;
}
}
float tw = 1f / texture.width;
float th = 1f / texture.height;
float u0 = offsetX * tw;
float v0 = offsetY * th;
float u1 = u0 + width * tw / scaleX;
float v1 = v0 + height * th / scaleY;
vertices[2] = u0;
vertices[3] = v0;
vertices[6] = u1;
vertices[7] = v0;
vertices[10] = u1;
vertices[11] = v1;
vertices[14] = u0;
vertices[15] = v1;
dirty = true;
}
public void offsetTo( float x, float y ) {
offsetX = x;
offsetY = y;
updateFrame();
}
public void offset( float x, float y ) {
offsetX += x;
offsetY += y;
updateFrame();
}
public float offsetX() {
return offsetX;
}
public float offsetY() {
return offsetY;
}
public void scale( float x, float y ) {
scaleX = x;
scaleY = y;
updateFrame();
}
public void size( float w, float h ) {
this.width = w;
this.height = h;
updateFrame();
updateVertices();
}
}

View File

@ -0,0 +1,110 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.util.HashMap;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
import android.graphics.RectF;
public class TextureFilm {
private static final RectF FULL = new RectF( 0, 0, 1, 1 );
private int texWidth;
private int texHeight;
protected HashMap<Object,RectF> frames = new HashMap<Object, RectF>();
public TextureFilm( Object tx ) {
SmartTexture texture = TextureCache.get( tx );
texWidth = texture.width;
texHeight = texture.height;
add( null, FULL );
}
public TextureFilm( SmartTexture texture, int width ) {
this( texture, width, texture.height );
}
public TextureFilm( Object tx, int width, int height ) {
SmartTexture texture = TextureCache.get( tx );
texWidth = texture.width;
texHeight = texture.height;
float uw = (float)width / texWidth;
float vh = (float)height / texHeight;
int cols = texWidth / width;
int rows = texHeight / height;
for (int i=0; i < rows; i++) {
for (int j=0; j < cols; j++) {
RectF rect = new RectF( j * uw, i * vh, (j+1) * uw, (i+1) * vh );
add( i * cols + j, rect );
}
}
}
public TextureFilm( TextureFilm atlas, Object key, int width, int height ) {
texWidth = atlas.texWidth;
texHeight = atlas.texHeight;
RectF patch = atlas.get( key );
float uw = (float)width / texWidth;
float vh = (float)height / texHeight;
int cols = (int)(width( patch ) / width);
int rows = (int)(height( patch ) / height);
for (int i=0; i < rows; i++) {
for (int j=0; j < cols; j++) {
RectF rect = new RectF( j * uw, i * vh, (j+1) * uw, (i+1) * vh );
rect.offset( patch.left, patch.top );
add( i * cols + j, rect );
}
}
}
public void add( Object id, RectF rect ) {
frames.put( id, rect );
}
public RectF get( Object id ) {
return frames.get( id );
}
public float width( RectF frame ) {
return frame.width() * texWidth;
}
public float height( RectF frame ) {
return frame.height() * texHeight;
}
}

View File

@ -0,0 +1,160 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import java.nio.FloatBuffer;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Quad;
import com.watabou.utils.Rect;
import android.graphics.RectF;
public class Tilemap extends Visual {
protected SmartTexture texture;
protected TextureFilm tileset;
protected int[] data;
protected int mapWidth;
protected int mapHeight;
protected int size;
private float cellW;
private float cellH;
protected float[] vertices;
protected FloatBuffer quads;
public Rect updated;
public Tilemap( Object tx, TextureFilm tileset ) {
super( 0, 0, 0, 0 );
this.texture = TextureCache.get( tx );
this.tileset = tileset;
RectF r = tileset.get( 0 );
cellW = tileset.width( r );
cellH = tileset.height( r );
vertices = new float[16];
updated = new Rect();
}
public void map( int[] data, int cols ) {
this.data = data;
mapWidth = cols;
mapHeight = data.length / cols;
size = mapWidth * mapHeight;
width = cellW * mapWidth;
height = cellH * mapHeight;
quads = Quad.createSet( size );
updated.set( 0, 0, mapWidth, mapHeight );
}
protected void updateVertices() {
float y1 = cellH * updated.top;
float y2 = y1 + cellH;
for (int i=updated.top; i < updated.bottom; i++) {
float x1 = cellW * updated.left;
float x2 = x1 + cellW;
int pos = i * mapWidth + updated.left;
quads.position( 16 * pos );
for (int j=updated.left; j < updated.right; j++) {
RectF uv = tileset.get( data[pos++] );
vertices[0] = x1;
vertices[1] = y1;
vertices[2] = uv.left;
vertices[3] = uv.top;
vertices[4] = x2;
vertices[5] = y1;
vertices[6] = uv.right;
vertices[7] = uv.top;
vertices[8] = x2;
vertices[9] = y2;
vertices[10] = uv.right;
vertices[11] = uv.bottom;
vertices[12] = x1;
vertices[13] = y2;
vertices[14] = uv.left;
vertices[15] = uv.bottom;
quads.put( vertices );
x1 = x2;
x2 += cellW;
}
y1 = y2;
y2 += cellH;
}
updated.setEmpty();
}
@Override
public void draw() {
super.draw();
NoosaScript script = NoosaScript.get();
texture.bind();
script.uModel.valueM4( matrix );
script.lighting(
rm, gm, bm, am,
ra, ga, ba, aa );
if (!updated.isEmpty()) {
updateVertices();
}
script.camera( camera );
script.drawQuadSet( quads, size );
}
}

View File

@ -0,0 +1,121 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.input.Touchscreen;
import com.watabou.input.Touchscreen.Touch;
import com.watabou.utils.Signal;
public class TouchArea extends Visual implements Signal.Listener<Touchscreen.Touch> {
// Its target can be toucharea itself
public Visual target;
protected Touchscreen.Touch touch = null;
//if true, this TouchArea will always block input, even when it is inactive
public boolean blockWhenInactive = false;
public TouchArea( Visual target ) {
super( 0, 0, 0, 0 );
this.target = target;
Touchscreen.event.add( this );
}
public TouchArea( float x, float y, float width, float height ) {
super( x, y, width, height );
this.target = this;
visible = false;
Touchscreen.event.add( this );
}
@Override
public void onSignal( Touch touch ) {
boolean hit = touch != null && target.overlapsScreenPoint( (int)touch.current.x, (int)touch.current.y );
if (!isActive()) {
if (hit && blockWhenInactive) Touchscreen.event.cancel();
return;
}
if (hit) {
if (touch.down || touch == this.touch) Touchscreen.event.cancel();
if (touch.down) {
if (this.touch == null) {
this.touch = touch;
}
onTouchDown( touch );
} else {
onTouchUp( touch );
if (this.touch == touch) {
this.touch = null;
onClick( touch );
}
}
} else {
if (touch == null && this.touch != null) {
onDrag( this.touch );
}
else if (this.touch != null && !touch.down) {
onTouchUp( touch );
this.touch = null;
}
}
}
protected void onTouchDown( Touch touch ) {
}
protected void onTouchUp( Touch touch ) {
}
protected void onClick( Touch touch ) {
}
protected void onDrag( Touch touch ) {
}
public void reset() {
touch = null;
}
@Override
public void destroy() {
Touchscreen.event.remove( this );
super.destroy();
}
}

View File

@ -0,0 +1,246 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa;
import com.watabou.glwrap.Matrix;
import com.watabou.utils.GameMath;
import com.watabou.utils.Point;
import com.watabou.utils.PointF;
public class Visual extends Gizmo {
public float x;
public float y;
public float width;
public float height;
public PointF scale;
public PointF origin;
protected float[] matrix;
public float rm;
public float gm;
public float bm;
public float am;
public float ra;
public float ga;
public float ba;
public float aa;
public PointF speed;
public PointF acc;
public float angle;
public float angularSpeed;
public Visual( float x, float y, float width, float height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
scale = new PointF( 1, 1 );
origin = new PointF();
matrix = new float[16];
resetColor();
speed = new PointF();
acc = new PointF();
}
@Override
public void update() {
updateMotion();
}
@Override
public void draw() {
updateMatrix();
}
protected void updateMatrix() {
Matrix.setIdentity( matrix );
Matrix.translate( matrix, x, y );
Matrix.translate( matrix, origin.x, origin.y );
if (angle != 0) {
Matrix.rotate( matrix, angle );
}
if (scale.x != 1 || scale.y != 1) {
Matrix.scale( matrix, scale.x, scale.y );
}
Matrix.translate( matrix, -origin.x, -origin.y );
}
public PointF point() {
return new PointF( x, y );
}
public PointF point( PointF p ) {
x = p.x;
y = p.y;
return p;
}
public Point point( Point p ) {
x = p.x;
y = p.y;
return p;
}
public PointF center() {
return new PointF( x + width / 2, y + height / 2 );
}
public PointF center( PointF p ) {
x = p.x - width / 2;
y = p.y - height / 2;
return p;
}
public float width() {
return width * scale.x;
}
public float height() {
return height * scale.y;
}
protected void updateMotion() {
float elapsed = Game.elapsed;
float d = (GameMath.speed( speed.x, acc.x ) - speed.x) / 2;
speed.x += d;
x += speed.x * elapsed;
speed.x += d;
d = (GameMath.speed( speed.y, acc.y ) - speed.y) / 2;
speed.y += d;
y += speed.y * elapsed;
speed.y += d;
angle += angularSpeed * elapsed;
}
public void alpha( float value ) {
am = value;
aa = 0;
}
public float alpha() {
return am + aa;
}
public void invert() {
rm = gm = bm = -1f;
ra = ga = ba = +1f;
}
public void lightness( float value ) {
if (value < 0.5f) {
rm = gm = bm = value * 2f;
ra = ga = ba = 0;
} else {
rm = gm = bm = 2f - value * 2f;
ra = ga = ba = value * 2f - 1f;
}
}
public void brightness( float value ) {
rm = gm = bm = value;
}
public void tint( float r, float g, float b, float strength ) {
rm = gm = bm = 1f - strength;
ra = r * strength;
ga = g * strength;
ba = b * strength;
}
public void tint( int color, float strength ) {
rm = gm = bm = 1f - strength;
ra = ((color >> 16) & 0xFF) / 255f * strength;
ga = ((color >> 8) & 0xFF) / 255f * strength;
ba = (color & 0xFF) / 255f * strength;
}
//color must include an alpha component (e.g. 0x80FF0000 for red at 0.5 strength)
public void tint( int color ) {
tint( color & 0xFFFFFF, ((color >> 24) & 0xFF) / (float)0xFF);
}
public void color( float r, float g, float b ) {
rm = gm = bm = 0;
ra = r;
ga = g;
ba = b;
}
public void color( int color ) {
color( ((color >> 16) & 0xFF) / 255f, ((color >> 8) & 0xFF) / 255f, (color & 0xFF) / 255f );
}
public void hardlight( float r, float g, float b ) {
ra = ga = ba = 0;
rm = r;
gm = g;
bm = b;
}
public void hardlight( int color ) {
hardlight( (color >> 16) / 255f, ((color >> 8) & 0xFF) / 255f, (color & 0xFF) / 255f );
}
public void resetColor() {
rm = gm = bm = am = 1;
ra = ga = ba = aa = 0;
}
public boolean overlapsPoint( float x, float y ) {
return x >= this.x && x < this.x + width * scale.x && y >= this.y && y < this.y + height * scale.y;
}
public boolean overlapsScreenPoint( int x, int y ) {
Camera c = camera();
if (c == null) return false;
PointF p = c.screenToCamera( x, y );
return overlapsPoint( p.x, p.y );
}
// true if its bounding box intersects its camera's bounds
public boolean isVisible() {
Camera c = camera();
if (c == null) return false;
float cx = c.scroll.x;
float cy = c.scroll.y;
float w = width();
float h = height();
return x + w >= cx && y + h >= cy && x < cx + c.width && y < cy + c.height;
}
}

View File

@ -0,0 +1,141 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.audio;
import java.io.IOException;
import com.watabou.noosa.Game;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
public enum Music implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
INSTANCE;
private MediaPlayer player;
private String lastPlayed;
private boolean looping;
private boolean enabled = true;
public void play( String assetName, boolean looping ) {
if (isPlaying() && lastPlayed.equals( assetName )) {
return;
}
stop();
lastPlayed = assetName;
this.looping = looping;
if (!enabled || assetName == null) {
return;
}
try {
AssetFileDescriptor afd = Game.instance.getAssets().openFd( assetName );
player = new MediaPlayer();
player.setAudioStreamType( AudioManager.STREAM_MUSIC );
player.setDataSource( afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength() );
player.setOnPreparedListener( this );
player.setOnErrorListener( this );
player.prepareAsync();
} catch (IOException e) {
player.release();
player = null;
}
}
public void mute() {
lastPlayed = null;
stop();
}
@Override
public void onPrepared( MediaPlayer player ) {
player.start();
player.setLooping(looping);
}
@Override
public boolean onError( MediaPlayer mp, int what, int extra ) {
if (player != null) {
player.release();
player = null;
}
return true;
}
public void pause() {
if (player != null) {
player.pause();
}
}
public void resume() {
if (player != null) {
player.start();
player.setLooping(looping);
}
}
public void stop() {
if (player != null) {
player.stop();
player.release();
player = null;
}
}
public void volume( float value ) {
if (player != null) {
player.setVolume( value, value );
}
}
public boolean isPlaying() {
return player != null && player.isPlaying();
}
public void enable( boolean value ) {
enabled = value;
if (isPlaying() && !value) {
stop();
} else
if (!isPlaying() && value) {
play( lastPlayed, looping );
}
}
public boolean isEnabled() {
return enabled;
}
}

View File

@ -0,0 +1,151 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.audio;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import com.watabou.noosa.Game;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
public enum Sample implements SoundPool.OnLoadCompleteListener {
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<>();
private boolean enabled = true;
private float volume = 1f;
private LinkedList<String> loadingQueue = new LinkedList<>();
public void reset() {
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();
}
}
public void resume() {
if (pool != null) {
pool.autoResume();
}
}
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();
}
}
}
public void unload( Object src ) {
if (ids.containsKey( src )) {
pool.unload( ids.get( src ) );
ids.remove( src );
}
}
public int play( Object id ) {
return play( id, 1 );
}
public int play( Object id, float volume ) {
return play( id, volume, volume, 1 );
}
public int play( Object id, float leftVolume, float rightVolume, float rate ) {
if (enabled && ids.containsKey( id )) {
return pool.play( ids.get( id ), leftVolume*volume, rightVolume*volume, 0, 0, rate );
} else {
return -1;
}
}
public void enable( boolean value ) {
enabled = value;
}
public void volume( float value ) {
this.volume = value;
}
public boolean isEnabled() {
return enabled;
}
@Override
public void onLoadComplete( SoundPool soundPool, int sampleId, int status ) {
}
}

View File

@ -0,0 +1,66 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.particles;
import android.graphics.RectF;
import com.watabou.gltextures.SmartTexture;
import com.watabou.noosa.Image;
import com.watabou.noosa.particles.Emitter;
import com.watabou.utils.Random;
public class BitmaskEmitter extends Emitter {
// DON'T USE WITH COMPLETELY TRANSPARENT IMAGES!!!
private SmartTexture map;
private int mapW;
private int mapH;
public BitmaskEmitter( Image target ) {
super();
this.target = target;
map = target.texture;
mapW = map.bitmap.getWidth();
mapH = map.bitmap.getHeight();
}
@Override
protected void emit( int index ) {
RectF frame = ((Image)target).frame();
float ofsX = frame.left * mapW;
float ofsY = frame.top * mapH;
float x, y;
do {
x = Random.Float( frame.width() ) * mapW;
y = Random.Float( frame.height() ) * mapH;
} while ((map.bitmap.getPixel( (int)(x + ofsX), (int)(y + ofsY) ) & 0x000000FF) == 0);
factory.emit( this, index,
target.x + x * target.scale.x,
target.y + y * target.scale.y );
}
}

View File

@ -0,0 +1,169 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.particles;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import com.watabou.noosa.Game;
import com.watabou.noosa.Group;
import com.watabou.noosa.Visual;
import com.watabou.utils.PointF;
import com.watabou.utils.Random;
public class Emitter extends Group {
protected boolean lightMode = false;
public float x;
public float y;
public float width;
public float height;
protected Visual target;
public boolean fillTarget = true;
protected float interval;
protected int quantity;
public boolean on = false;
public boolean autoKill = true;
protected int count;
protected float time;
protected Factory factory;
public void pos( float x, float y ) {
pos( x, y, 0, 0 );
}
public void pos( PointF p ) {
pos( p.x, p.y, 0, 0 );
}
public void pos( float x, float y, float width, float height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
target = null;
}
public void pos( Visual target ) {
this.target = target;
}
public void pos( Visual target, float x, float y, float width, float height ) {
pos(x, y, width, height);
pos(target);
}
public void burst( Factory factory, int quantity ) {
start( factory, 0, quantity );
}
public void pour( Factory factory, float interval ) {
start( factory, interval, 0 );
}
public void start( Factory factory, float interval, int quantity ) {
this.factory = factory;
this.lightMode = factory.lightMode();
this.interval = interval;
this.quantity = quantity;
count = 0;
time = Random.Float( interval );
on = true;
}
@Override
public void update() {
if (on) {
time += Game.elapsed;
while (time > interval) {
time -= interval;
emit( count++ );
if (quantity > 0 && count >= quantity) {
on = false;
break;
}
}
} else if (autoKill && countLiving() == 0) {
kill();
}
super.update();
}
protected void emit( int index ) {
if (target == null) {
factory.emit(
this,
index,
x + Random.Float( width ),
y + Random.Float( height ) );
} else {
if (fillTarget) {
factory.emit(
this,
index,
target.x + Random.Float( target.width ),
target.y + Random.Float( target.height ) );
} else {
factory.emit(
this,
index,
target.x + x + Random.Float( width ),
target.y + y + Random.Float( height ) );
}
}
}
@Override
public void draw() {
if (lightMode) {
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE );
super.draw();
GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
} else {
super.draw();
}
}
abstract public static class Factory {
abstract public void emit( Emitter emitter, int index, float x, float y );
public boolean lightMode() {
return false;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.particles;
import com.watabou.noosa.Game;
import com.watabou.noosa.PseudoPixel;
public class PixelParticle extends PseudoPixel {
protected float size;
protected float lifespan;
protected float left;
public PixelParticle() {
super();
origin.set( +0.5f );
}
public void reset( float x, float y, int color, float size, float lifespan ) {
revive();
this.x = x;
this.y = y;
color( color );
size( this.size = size );
this.left = this.lifespan = lifespan;
}
@Override
public void update() {
super.update();
if ((left -= Game.elapsed) <= 0) {
kill();
}
}
public static class Shrinking extends PixelParticle {
@Override
public void update() {
super.update();
size( size * left / lifespan );
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
import com.watabou.noosa.Visual;
public class AlphaTweener extends Tweener {
public Visual image;
public float start;
public float delta;
public AlphaTweener( Visual image, float alpha, float time ) {
super( image, time );
this.image = image;
start = image.alpha();
delta = alpha - start;
}
@Override
protected void updateValues( float progress ) {
image.alpha( start + delta * progress );
}
}

View File

@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
import com.watabou.noosa.Camera;
import com.watabou.utils.PointF;
public class CameraScrollTweener extends Tweener {
public Camera camera;
public PointF start;
public PointF end;
public CameraScrollTweener( Camera camera, PointF pos, float time ) {
super( camera, time );
this.camera = camera;
start = camera.scroll;
end = pos;
}
@Override
protected void updateValues( float progress ) {
camera.scroll = PointF.inter( start, end, progress );
}
}

View File

@ -0,0 +1,37 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
public class Delayer extends Tweener {
public Delayer() {
super( null, 0 );
}
public Delayer( float time ) {
super( null, time );
}
@Override
protected void updateValues( float progress ) {
}
}

View File

@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
import com.watabou.noosa.Visual;
import com.watabou.utils.PointF;
public class PosTweener extends Tweener {
public Visual visual;
public PointF start;
public PointF end;
public PosTweener( Visual visual, PointF pos, float time ) {
super( visual, time );
this.visual = visual;
start = visual.point();
end = pos;
}
@Override
protected void updateValues( float progress ) {
visual.point( PointF.inter( start, end, progress ) );
}
}

View File

@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
import com.watabou.noosa.Visual;
import com.watabou.utils.PointF;
public class ScaleTweener extends Tweener {
public Visual visual;
public PointF start;
public PointF end;
public ScaleTweener( Visual visual, PointF scale, float time ) {
super( visual, time );
this.visual = visual;
start = visual.scale;
end = scale;
}
@Override
protected void updateValues( float progress ) {
visual.scale = PointF.inter( start, end, progress );
}
}

View File

@ -0,0 +1,68 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.tweeners;
import com.watabou.noosa.Game;
import com.watabou.noosa.Gizmo;
abstract public class Tweener extends Gizmo {
public Gizmo target;
public float interval;
public float elapsed;
public Listener listener;
public Tweener( Gizmo target, float interval ) {
super();
this.target = target;
this.interval = interval;
elapsed = 0;
}
@Override
public void update() {
elapsed += Game.elapsed;
if (elapsed >= interval) {
updateValues( 1 );
onComplete();
kill();
} else {
updateValues( elapsed / interval );
}
}
protected void onComplete() {
if (listener != null) {
listener.onComplete( this );
}
}
abstract protected void updateValues( float progress );
public static interface Listener {
void onComplete( Tweener tweener );
}
}

View File

@ -0,0 +1,100 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.ui;
import com.watabou.input.Touchscreen.Touch;
import com.watabou.noosa.Game;
import com.watabou.noosa.TouchArea;
public class Button extends Component {
public static float longClick = 1f;
protected TouchArea hotArea;
protected boolean pressed;
protected float pressTime;
protected boolean processed;
@Override
protected void createChildren() {
hotArea = new TouchArea( 0, 0, 0, 0 ) {
@Override
protected void onTouchDown(Touch touch) {
pressed = true;
pressTime = 0;
processed = false;
Button.this.onTouchDown();
};
@Override
protected void onTouchUp(Touch touch) {
pressed = false;
Button.this.onTouchUp();
};
@Override
protected void onClick( Touch touch ) {
if (!processed) {
Button.this.onClick();
}
};
};
add( hotArea );
}
@Override
public void update() {
super.update();
hotArea.active = visible;
if (pressed) {
if ((pressTime += Game.elapsed) >= longClick) {
pressed = false;
if (onLongClick()) {
hotArea.reset();
processed = true;
onTouchUp();
Game.vibrate( 50 );
}
}
}
}
protected void onTouchDown() {};
protected void onTouchUp() {};
protected void onClick() {};
protected boolean onLongClick() {
return false;
};
@Override
protected void layout() {
hotArea.x = x;
hotArea.y = y;
hotArea.width = width;
hotArea.height = height;
}
}

View File

@ -0,0 +1,51 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.ui;
public class CheckBox extends Button {
protected boolean checked;
public boolean checked() {
return checked;
}
public void checked( boolean value ) {
if (checked != value) {
checked = value;
updateState();
}
}
protected void updateState() {
}
@Override
protected void onClick() {
checked( !checked );
onChange();
}
protected void onChange() {
}
}

View File

@ -0,0 +1,109 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.noosa.ui;
import com.watabou.noosa.Group;
public class Component extends Group {
protected float x;
protected float y;
protected float width;
protected float height;
public Component() {
super();
createChildren();
}
public Component setPos( float x, float y ) {
this.x = x;
this.y = y;
layout();
return this;
}
public Component setSize( float width, float height ) {
this.width = width;
this.height = height;
layout();
return this;
}
public Component setRect( float x, float y, float width, float height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
layout();
return this;
}
public boolean inside( float x, float y ) {
return x >= this.x && y >= this.y && x < this.x + width && y < this.y + height;
}
public void fill( Component c ) {
setRect( c.x, c.y, c.width, c.height );
}
public float left() {
return x;
}
public float right() {
return x + width;
}
public float centerX() {
return x + width / 2;
}
public float top() {
return y;
}
public float bottom() {
return y + height;
}
public float centerY() {
return y + height / 2;
}
public float width() {
return width;
}
public float height() {
return height;
}
protected void createChildren() {
}
protected void layout() {
}
}

View File

@ -0,0 +1,125 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class BitmapCache {
private static final String DEFAULT = "__default";
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 ) {
return get( DEFAULT, assetName );
}
public static Bitmap get( String layerName, String assetName ) {
Layer layer;
if (!layers.containsKey( layerName )) {
layer = new Layer();
layers.put( layerName, layer );
} else {
layer = layers.get( layerName );
}
if (layer.containsKey( assetName )) {
return layer.get( assetName );
} else {
try {
InputStream stream = context.getResources().getAssets().open( assetName );
Bitmap bmp = BitmapFactory.decodeStream( stream, null, opts );
layer.put( assetName, bmp );
return bmp;
} catch (IOException e) {
return null;
}
}
}
public static Bitmap get( int resID ) {
return get( DEFAULT, resID );
}
public static Bitmap get( String layerName, int resID ) {
Layer layer;
if (!layers.containsKey( layerName )) {
layer = new Layer();
layers.put( layerName, layer );
} else {
layer = layers.get( layerName );
}
if (layer.containsKey( resID )) {
return layer.get( resID );
} else {
Bitmap bmp = BitmapFactory.decodeResource( context.getResources(), resID );
layer.put( resID, bmp );
return bmp;
}
}
public static void clear( String layerName ) {
if (layers.containsKey( layerName )) {
layers.get( layerName ).clear();
layers.remove( layerName );
}
}
public static void clear() {
for (Layer layer:layers.values()) {
layer.clear();
}
layers.clear();
}
@SuppressWarnings("serial")
private static class Layer extends HashMap<Object,Bitmap> {
@Override
public void clear() {
for (Bitmap bmp:values()) {
bmp.recycle();
}
super.clear();
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.HashMap;
import android.graphics.Bitmap;
import android.graphics.Rect;
public class BitmapFilm {
public Bitmap bitmap;
protected HashMap<Object,Rect> frames = new HashMap<Object, Rect>();
public BitmapFilm( Bitmap bitmap ) {
this.bitmap = bitmap;
add( null, new Rect( 0, 0, bitmap.getWidth(), bitmap.getHeight() ) );
}
public BitmapFilm( Bitmap bitmap, int width ) {
this( bitmap, width, bitmap.getHeight() );
}
public BitmapFilm( Bitmap bitmap, int width, int height ) {
this.bitmap = bitmap;
int cols = bitmap.getWidth() / width;
int rows = bitmap.getHeight() / height;
for (int i=0; i < rows; i++) {
for (int j=0; j < cols; j++) {
Rect rect = new Rect( j * width, i * height, (j+1) * width, (i+1) * height );
add( i * cols + j, rect );
}
}
}
public void add( Object id, Rect rect ) {
frames.put( id, rect );
}
public Rect get( Object id ) {
return frames.get( id );
}
}

View File

@ -0,0 +1,29 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
public interface Bundlable {
void restoreFromBundle( Bundle bundle );
void storeInBundle( Bundle bundle );
}

View File

@ -0,0 +1,411 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public class Bundle {
private static final String CLASS_NAME = "__className";
private static HashMap<String,String> aliases = new HashMap<String, String>();
private JSONObject data;
public Bundle() {
this( new JSONObject() );
}
public String toString() {
return data.toString();
}
private Bundle( JSONObject data ) {
this.data = data;
}
public boolean isNull() {
return data == null;
}
public boolean contains( String key ) {
return !data.isNull( key );
}
public boolean getBoolean( String key ) {
return data.optBoolean( key );
}
public int getInt( String key ) {
return data.optInt( key );
}
public float getFloat( String key ) {
return (float)data.optDouble( key, 0.0 );
}
public String getString( String key ) {
return data.optString( key );
}
public Class getClass( String key ) {
String clName = getString(key).replace("class ", "");;
if (clName != null){
if (aliases.containsKey( clName )) {
clName = aliases.get( clName );
}
try {
Class cl = Class.forName( clName );
return cl;
} catch (ClassNotFoundException e) {
return null;
}
}
return null;
}
public Bundle getBundle( String key ) {
return new Bundle( data.optJSONObject( key ) );
}
private Bundlable get() {
if (data == null) return null;
try {
String clName = getString( CLASS_NAME );
if (aliases.containsKey( clName )) {
clName = aliases.get( clName );
}
Class<?> cl = Class.forName( clName );
if (cl != null) {
Bundlable object = (Bundlable)cl.newInstance();
object.restoreFromBundle( this );
return object;
} else {
return null;
}
} catch (ClassNotFoundException e ) {
return null;
} catch (InstantiationException e ) {
return null;
} catch (IllegalAccessException e ) {
return null;
}
}
public Bundlable get( String key ) {
return getBundle( key ).get();
}
public <E extends Enum<E>> E getEnum( String key, Class<E> enumClass ) {
try {
return Enum.valueOf( enumClass, data.getString( key ) );
} catch (JSONException e) {
return enumClass.getEnumConstants()[0];
}
}
public int[] getIntArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
int[] result = new int[length];
for (int i=0; i < length; i++) {
result[i] = array.getInt( i );
}
return result;
} catch (JSONException e) {
return null;
}
}
public boolean[] getBooleanArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
boolean[] result = new boolean[length];
for (int i=0; i < length; i++) {
result[i] = array.getBoolean( i );
}
return result;
} catch (JSONException e) {
return null;
}
}
public String[] getStringArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
String[] result = new String[length];
for (int i=0; i < length; i++) {
result[i] = array.getString( i );
}
return result;
} catch (JSONException e) {
return null;
}
}
public Class[] getClassArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
Class[] result = new Class[length];
for (int i=0; i < length; i++) {
String clName = array.getString( i ).replace("class ", "");
if (aliases.containsKey( clName )) {
clName = aliases.get( clName );
}
try {
Class cl = Class.forName( clName );
result[i] = cl;
} catch (ClassNotFoundException e) {
result[i] = null;
}
}
return result;
} catch (JSONException e) {
return null;
}
}
public Collection<Bundlable> getCollection( String key ) {
ArrayList<Bundlable> list = new ArrayList<Bundlable>();
try {
JSONArray array = data.getJSONArray( key );
for (int i=0; i < array.length(); i++) {
Bundlable O = new Bundle( array.getJSONObject( i ) ).get();
if (O != null) list.add( O );
}
} catch (JSONException e) {
}
return list;
}
public void put( String key, boolean value ) {
try {
data.put( key, value );
} catch (JSONException e) {
}
}
public void put( String key, int value ) {
try {
data.put( key, value );
} catch (JSONException e) {
}
}
public void put( String key, float value ) {
try {
data.put( key, value );
} catch (JSONException e) {
}
}
public void put( String key, String value ) {
try {
data.put( key, value );
} catch (JSONException e) {
}
}
public void put( String key, Class value ){
try {
data.put( key, value );
} catch (JSONException e) {
}
}
public void put( String key, Bundle bundle ) {
try {
data.put( key, bundle.data );
} catch (JSONException e) {
}
}
public void put( String key, Bundlable object ) {
if (object != null) {
try {
Bundle bundle = new Bundle();
bundle.put( CLASS_NAME, object.getClass().getName() );
object.storeInBundle( bundle );
data.put( key, bundle.data );
} catch (JSONException e) {
}
}
}
public void put( String key, Enum<?> value ) {
if (value != null) {
try {
data.put( key, value.name() );
} catch (JSONException e) {
}
}
}
public void put( String key, int[] array ) {
try {
JSONArray jsonArray = new JSONArray();
for (int i=0; i < array.length; i++) {
jsonArray.put( i, array[i] );
}
data.put( key, jsonArray );
} catch (JSONException e) {
}
}
public void put( String key, boolean[] array ) {
try {
JSONArray jsonArray = new JSONArray();
for (int i=0; i < array.length; i++) {
jsonArray.put( i, array[i] );
}
data.put( key, jsonArray );
} catch (JSONException e) {
}
}
public void put( String key, String[] array ) {
try {
JSONArray jsonArray = new JSONArray();
for (int i=0; i < array.length; i++) {
jsonArray.put( i, array[i] );
}
data.put( key, jsonArray );
} catch (JSONException e) {
}
}
public void put( String key, Class[] array ){
try {
JSONArray jsonArray = new JSONArray();
for (int i=0; i < array.length; i++) {
jsonArray.put( i, array[i] );
}
data.put( key, jsonArray );
} catch (JSONException e) {
}
}
public void put( String key, Collection<? extends Bundlable> collection ) {
JSONArray array = new JSONArray();
for (Bundlable object : collection) {
if (object != null) {
Bundle bundle = new Bundle();
bundle.put(CLASS_NAME, object.getClass().getName());
object.storeInBundle(bundle);
array.put(bundle.data);
}
}
try {
data.put( key, array );
} catch (JSONException e) {
}
}
//useful to turn this off for save data debugging.
private static final boolean compressByDefault = true;
private static final int GZIP_BUFFER = 1024*4; //4 kb
public static Bundle read( InputStream stream ) throws IOException {
try {
BufferedReader reader;
//determines if we're reading a regular, or compressed file
PushbackInputStream pb = new PushbackInputStream( stream, 2 );
byte[] header = new byte[2];
pb.unread(header, 0, pb.read(header));
//GZIP header is 0x1f8b
if( header[ 0 ] == (byte) 0x1f && header[ 1 ] == (byte) 0x8b )
reader = new BufferedReader( new InputStreamReader( new GZIPInputStream( pb, GZIP_BUFFER ) ) );
else
reader = new BufferedReader( new InputStreamReader( pb ) );
JSONObject json = (JSONObject)new JSONTokener( reader.readLine() ).nextValue();
reader.close();
return new Bundle( json );
} catch (Exception e) {
throw new IOException();
}
}
public static boolean write( Bundle bundle, OutputStream stream ){
return write(bundle, stream, compressByDefault);
}
public static boolean write( Bundle bundle, OutputStream stream, boolean compressed ) {
try {
BufferedWriter writer;
if (compressed) writer = new BufferedWriter( new OutputStreamWriter( new GZIPOutputStream(stream, GZIP_BUFFER ) ) );
else writer = new BufferedWriter( new OutputStreamWriter( stream ) );
writer.write( bundle.data.toString() );
writer.close();
return true;
} catch (IOException e) {
return false;
}
}
public static void addAlias( Class<?> cl, String alias ) {
aliases.put( alias, cl.getName() );
}
}

View File

@ -0,0 +1,28 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
public interface Callback {
void call();
}

View File

@ -0,0 +1,65 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
public class ColorMath {
public static int interpolate( int A, int B, float p ) {
if (p <= 0) {
return A;
} else if (p >= 1) {
return B;
}
int ra = A >> 16;
int ga = (A >> 8) & 0xFF;
int ba = A & 0xFF;
int rb = B >> 16;
int gb = (B >> 8) & 0xFF;
int bb = B & 0xFF;
float p1 = 1 - p;
int r = (int)(p1 * ra + p * rb);
int g = (int)(p1 * ga + p * gb);
int b = (int)(p1 * ba + p * bb);
return (r << 16) + (g << 8) + b;
}
public static int interpolate( float p, int... colors ) {
if (p <= 0) {
return colors[0];
} else if (p >= 1) {
return colors[colors.length-1];
}
int segment = (int)(colors.length * p);
return interpolate( colors[segment], colors[segment+1], (p * (colors.length - 1)) % 1 );
}
public static int random( int a, int b ) {
return interpolate( a, b, Random.Float() );
}
}

View File

@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import com.watabou.noosa.Game;
public class GameMath {
public static float speed( float speed, float acc ) {
if (acc != 0) {
speed += acc * Game.elapsed;
}
return speed;
}
public static float gate( float min, float value, float max ) {
if (value < min) {
return min;
} else if (value > max) {
return max;
} else {
return value;
}
}
}

View File

@ -0,0 +1,107 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class Graph {
public static <T extends Node> void setPrice( List<T> nodes, int value ) {
for (T node : nodes) {
node.price( value );
}
}
public static <T extends Node> void buildDistanceMap( Collection<T> nodes, Node focus ) {
for (T node : nodes) {
node.distance( Integer.MAX_VALUE );
}
LinkedList<Node> queue = new LinkedList<Node>();
focus.distance( 0 );
queue.add( focus );
while (!queue.isEmpty()) {
Node node = queue.poll();
int distance = node.distance();
int price = node.price();
for (Node edge : node.edges()) {
if (edge.distance() > distance + price) {
queue.add( edge );
edge.distance( distance + price );
}
}
}
}
@SuppressWarnings("unchecked")
public static <T extends Node> List<T> buildPath( Collection<T> nodes, T from, T to ) {
List<T> path = new ArrayList<T>();
T room = from;
while (room != to) {
int min = room.distance();
T next = null;
Collection<? extends Node> edges = room.edges();
for (Node edge : edges) {
int distance = edge.distance();
if (distance < min) {
min = distance;
next = (T)edge;
}
}
if (next == null) {
return null;
}
path.add( next );
room = next;
}
return path;
}
public interface Node {
int distance();
void distance( int value );
int price();
void price( int value );
Collection<? extends Node> edges();
}
}

View File

@ -0,0 +1,81 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Highlighter {
private static final Pattern HIGHLIGHTER = Pattern.compile( "_(.*?)_" );
private static final Pattern STRIPPER = Pattern.compile( "[ \n]" );
public String text;
public boolean[] mask;
public Highlighter( String text ) {
String stripped = STRIPPER.matcher( text ).replaceAll( "" );
mask = new boolean[stripped.length()];
Matcher m = HIGHLIGHTER.matcher( stripped );
int pos = 0;
int lastMatch = 0;
while (m.find()) {
pos += (m.start() - lastMatch);
int groupLen = m.group( 1 ).length();
for (int i=pos; i < pos + groupLen; i++) {
mask[i] = true;
}
pos += groupLen;
lastMatch = m.end();
}
m.reset( text );
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement( sb, m.group( 1 ) );
}
m.appendTail( sb );
this.text = sb.toString();
}
public boolean[] inverted() {
boolean[] result = new boolean[mask.length];
for (int i=0; i < result.length; i++) {
result[i] = !mask[i];
}
return result;
}
public boolean isHighlighted() {
for (int i=0; i < mask.length; i++) {
if (mask[i]) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,340 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.Arrays;
import java.util.LinkedList;
public class PathFinder {
public static int[] distance;
private static boolean[] goals;
private static int[] queue;
private static int size = 0;
private static int[] dir;
public static void setMapSize( int width, int height ) {
int size = width * height;
if (PathFinder.size != size) {
PathFinder.size = size;
distance = new int[size];
goals = new boolean[size];
queue = new int[size];
dir = new int[]{-1, +1, -width, +width, -width-1, -width+1, +width-1, +width+1};
}
}
public static Path find( int from, int to, boolean[] passable ) {
if (!buildDistanceMap( from, to, passable )) {
return null;
}
Path result = new Path();
int s = from;
// From the starting position we are moving downwards,
// until we reach the ending point
do {
int minD = distance[s];
int mins = s;
for (int i=0; i < dir.length; i++) {
int n = s + dir[i];
int thisD = distance[n];
if (thisD < minD) {
minD = thisD;
mins = n;
}
}
s = mins;
result.add( s );
} while (s != to);
return result;
}
public static int getStep( int from, int to, boolean[] passable ) {
if (!buildDistanceMap( from, to, passable )) {
return -1;
}
// From the starting position we are making one step downwards
int minD = distance[from];
int best = from;
int step, stepD;
for (int i=0; i < dir.length; i++) {
if ((stepD = distance[step = from + dir[i]]) < minD) {
minD = stepD;
best = step;
}
}
return best;
}
public static int getStepBack( int cur, int from, boolean[] passable ) {
int d = buildEscapeDistanceMap( cur, from, 2f, passable );
for (int i=0; i < size; i++) {
goals[i] = distance[i] == d;
}
if (!buildDistanceMap( cur, goals, passable )) {
return -1;
}
int s = cur;
// From the starting position we are making one step downwards
int minD = distance[s];
int mins = s;
for (int i=0; i < dir.length; i++) {
int n = s + dir[i];
int thisD = distance[n];
if (thisD < minD) {
minD = thisD;
mins = n;
}
}
return mins;
}
private static boolean buildDistanceMap( int from, int to, boolean[] passable ) {
if (from == to) {
return false;
}
Arrays.fill( distance, Integer.MAX_VALUE );
boolean pathFound = false;
int head = 0;
int tail = 0;
// Add to queue
queue[tail++] = to;
distance[to] = 0;
while (head < tail) {
// Remove from queue
int step = queue[head++];
if (step == from) {
pathFound = true;
break;
}
int nextDistance = distance[step] + 1;
for (int i=0; i < dir.length; i++) {
int n = step + dir[i];
if (n == from || (n >= 0 && n < size && passable[n] && (distance[n] > nextDistance))) {
// Add to queue
queue[tail++] = n;
distance[n] = nextDistance;
}
}
}
return pathFound;
}
public static void buildDistanceMap( int to, boolean[] passable, int limit ) {
Arrays.fill( distance, Integer.MAX_VALUE );
int head = 0;
int tail = 0;
// Add to queue
queue[tail++] = to;
distance[to] = 0;
while (head < tail) {
// Remove from queue
int step = queue[head++];
int nextDistance = distance[step] + 1;
if (nextDistance > limit) {
return;
}
for (int i=0; i < dir.length; i++) {
int n = step + dir[i];
if (n >= 0 && n < size && passable[n] && (distance[n] > nextDistance)) {
// Add to queue
queue[tail++] = n;
distance[n] = nextDistance;
}
}
}
}
private static boolean buildDistanceMap( int from, boolean[] to, boolean[] passable ) {
if (to[from]) {
return false;
}
Arrays.fill( distance, Integer.MAX_VALUE );
boolean pathFound = false;
int head = 0;
int tail = 0;
// Add to queue
for (int i=0; i < size; i++) {
if (to[i]) {
queue[tail++] = i;
distance[i] = 0;
}
}
while (head < tail) {
// Remove from queue
int step = queue[head++];
if (step == from) {
pathFound = true;
break;
}
int nextDistance = distance[step] + 1;
for (int i=0; i < dir.length; i++) {
int n = step + dir[i];
if (n == from || (n >= 0 && n < size && passable[n] && (distance[n] > nextDistance))) {
// Add to queue
queue[tail++] = n;
distance[n] = nextDistance;
}
}
}
return pathFound;
}
private static int buildEscapeDistanceMap( int cur, int from, float factor, boolean[] passable ) {
Arrays.fill( distance, Integer.MAX_VALUE );
int destDist = Integer.MAX_VALUE;
int head = 0;
int tail = 0;
// Add to queue
queue[tail++] = from;
distance[from] = 0;
int dist = 0;
while (head < tail) {
// Remove from queue
int step = queue[head++];
dist = distance[step];
if (dist > destDist) {
return destDist;
}
if (step == cur) {
destDist = (int)(dist * factor) + 1;
}
int nextDistance = dist + 1;
for (int i=0; i < dir.length; i++) {
int n = step + dir[i];
if (n >= 0 && n < size && passable[n] && distance[n] > nextDistance) {
// Add to queue
queue[tail++] = n;
distance[n] = nextDistance;
}
}
}
return dist;
}
@SuppressWarnings("unused")
private static void buildDistanceMap( int to, boolean[] passable ) {
Arrays.fill( distance, Integer.MAX_VALUE );
int head = 0;
int tail = 0;
// Add to queue
queue[tail++] = to;
distance[to] = 0;
while (head < tail) {
// Remove from queue
int step = queue[head++];
int nextDistance = distance[step] + 1;
for (int i=0; i < dir.length; i++) {
int n = step + dir[i];
if (n >= 0 && n < size && passable[n] && (distance[n] > nextDistance)) {
// Add to queue
queue[tail++] = n;
distance[n] = nextDistance;
}
}
}
}
@SuppressWarnings("serial")
public static class Path extends LinkedList<Integer> {
}
}

View File

@ -0,0 +1,85 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
public class Point {
public int x;
public int y;
public Point() {
}
public Point( int x, int y ) {
this.x = x;
this.y = y;
}
public Point( Point p ) {
this.x = p.x;
this.y = p.y;
}
public Point set( int x, int y ) {
this.x = x;
this.y = y;
return this;
}
public Point set( Point p ) {
x = p.x;
y = p.y;
return this;
}
public Point clone() {
return new Point( this );
}
public Point scale( float f ) {
this.x *= f;
this.y *= f;
return this;
}
public Point offset( int dx, int dy ) {
x += dx;
y += dy;
return this;
}
public Point offset( Point d ) {
x += d.x;
y += d.y;
return this;
}
@Override
public boolean equals( Object obj ) {
if (obj instanceof Point) {
Point p = (Point)obj;
return p.x == x && p.y == y;
} else {
return false;
}
}
}

View File

@ -0,0 +1,154 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import android.annotation.SuppressLint;
import android.util.FloatMath;
@SuppressLint("FloatMath")
public class PointF {
public static final float PI = 3.1415926f;
public static final float PI2 = PI * 2;
public static final float G2R = PI / 180;
public float x;
public float y;
public PointF() {
}
public PointF( float x, float y ) {
this.x = x;
this.y = y;
}
public PointF( PointF p ) {
this.x = p.x;
this.y = p.y;
}
public PointF( Point p ) {
this.x = p.x;
this.y = p.y;
}
public PointF clone() {
return new PointF( this );
}
public PointF scale( float f ) {
this.x *= f;
this.y *= f;
return this;
}
public PointF invScale( float f ) {
this.x /= f;
this.y /= f;
return this;
}
public PointF set( float x, float y ) {
this.x = x;
this.y = y;
return this;
}
public PointF set( PointF p ) {
this.x = p.x;
this.y = p.y;
return this;
}
public PointF set( float v ) {
this.x = v;
this.y = v;
return this;
}
public PointF polar( float a, float l ) {
this.x = l * (float)Math.cos( a );
this.y = l * (float)Math.sin( a );
return this;
}
public PointF offset( float dx, float dy ) {
x += dx;
y += dy;
return this;
}
public PointF offset( PointF p ) {
x += p.x;
y += p.y;
return this;
}
public PointF negate() {
x = -x;
y = -y;
return this;
}
public PointF normalize() {
float l = length();
x /= l;
y /= l;
return this;
}
public Point floor() {
return new Point( (int)x, (int)y );
}
public float length() {
return (float)Math.sqrt( x * x + y * y );
}
public static PointF sum( PointF a, PointF b ) {
return new PointF( a.x + b.x, a.y + b.y );
}
public static PointF diff( PointF a, PointF b ) {
return new PointF( a.x - b.x, a.y - b.y );
}
public static PointF inter( PointF a, PointF b, float d ) {
return new PointF( a.x + (b.x - a.x) * d, a.y + (b.y - a.y) * d );
}
public static float distance( PointF a, PointF b ) {
float dx = a.x - b.x;
float dy = a.y - b.y;
return (float)Math.sqrt( dx * dx + dy * dy );
}
public static float angle( PointF start, PointF end ) {
return (float)Math.atan2( end.y - start.y, end.x - start.x );
}
@Override
public String toString() {
return "" + x + ", " + y;
}
}

View File

@ -0,0 +1,154 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.Collection;
import java.util.HashMap;
public class Random {
public static float Float( float min, float max ) {
return (float)(min + Math.random() * (max - min));
}
public static float Float( float max ) {
return (float)(Math.random() * max);
}
public static float Float() {
return (float)Math.random();
}
public static int Int( int max ) {
return max > 0 ? (int)(Math.random() * max) : 0;
}
public static int Int( int min, int max ) {
return min + (int)(Math.random() * (max - min));
}
public static int IntRange( int min, int max ) {
return min + (int)(Math.random() * (max - min + 1));
}
public static int NormalIntRange( int min, int max ) {
return min + (int)((Math.random() + Math.random()) * (max - min + 1) / 2f);
}
public static int chances( float[] chances ) {
int length = chances.length;
float sum = 0;
for (int i=0; i < length; i++) {
sum += chances[i];
}
float value = Float( sum );
sum = 0;
for (int i=0; i < length; i++) {
sum += chances[i];
if (value < sum) {
return i;
}
}
return -1;
}
@SuppressWarnings("unchecked")
public static <K> K chances( HashMap<K,Float> chances ) {
int size = chances.size();
Object[] values = chances.keySet().toArray();
float[] probs = new float[size];
float sum = 0;
for (int i=0; i < size; i++) {
probs[i] = chances.get( values[i] );
sum += probs[i];
}
float value = Float( sum );
sum = probs[0];
for (int i=0; i < size; i++) {
if (value < sum) {
return (K)values[i];
}
sum += probs[i + 1];
}
return null;
}
public static int index( Collection<?> collection ) {
return (int)(Math.random() * collection.size());
}
@SafeVarargs
public static<T> T oneOf( T... array ) {
return array[(int)(Math.random() * array.length)];
}
public static<T> T element( T[] array ) {
return element( array, array.length );
}
public static<T> T element( T[] array, int max ) {
return array[(int)(Math.random() * max)];
}
@SuppressWarnings("unchecked")
public static<T> T element( Collection<? extends T> collection ) {
int size = collection.size();
return size > 0 ?
(T)collection.toArray()[Int( size )] :
null;
}
public static<T> void shuffle( T[] array ) {
for (int i=0; i < array.length - 1; i++) {
int j = Int( i, array.length );
if (j != i) {
T t = array[i];
array[i] = array[j];
array[j] = t;
}
}
}
public static<U,V> void shuffle( U[] u, V[]v ) {
for (int i=0; i < u.length - 1; i++) {
int j = Int( i, u.length );
if (j != i) {
U ut = u[i];
u[i] = u[j];
u[j] = ut;
V vt = v[i];
v[i] = v[j];
v[j] = vt;
}
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.HashSet;
public class Rect {
public int left;
public int top;
public int right;
public int bottom;
public Rect() {
this( 0, 0, 0, 0 );
}
public Rect( Rect rect ) {
this( rect.left, rect.top, rect.right, rect.bottom );
}
public Rect( int left, int top, int right, int bottom ) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public int width() {
return right - left;
}
public int height() {
return bottom - top;
}
public int square() {
return (right - left) * (bottom - top);
}
public Rect set( int left, int top, int right, int bottom ) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
return this;
}
public Rect set( Rect rect ) {
return set( rect.left, rect.top, rect.right, rect.bottom );
}
public boolean isEmpty() {
return right <= left || bottom <= top;
}
public Rect setEmpty() {
left = right = top = bottom = 0;
return this;
}
public Rect intersect( Rect other ) {
Rect result = new Rect();
result.left = Math.max( left, other.left );
result.right = Math.min( right, other.right );
result.top = Math.max( top, other.top );
result.bottom = Math.min( bottom, other.bottom );
return result;
}
public Rect union( int x, int y ) {
if (isEmpty()) {
return set( x, y, x + 1, y + 1 );
} else {
if (x < left) {
left = x;
} else if (x >= right) {
right = x + 1;
}
if (y < top) {
top = y;
} else if (y >= bottom) {
bottom = y + 1;
}
return this;
}
}
public Rect union( Point p ) {
return union( p.x, p.y );
}
public boolean inside( Point p ) {
return p.x >= left && p.x < right && p.y >= top && p.y < bottom;
}
public Rect shrink( int d ) {
return new Rect( left + d, top + d, right - d, bottom - d );
}
public Rect shrink() {
return shrink( 1 );
}
public HashSet<Point> getPoints() {
HashSet<Point> points = new HashSet<>(square()*2);
for (int i = left; i <= right; i++)
for (int j = top; j <= bottom; j++)
points.add(new Point(i, j));
return points;
}
}

View File

@ -0,0 +1,96 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.LinkedList;
public class Signal<T> {
private LinkedList<Listener<T>> listeners = new LinkedList<Signal.Listener<T>>();
private boolean canceled;
private boolean stackMode;
public Signal() {
this( false );
}
public Signal( boolean stackMode ) {
this.stackMode = stackMode;
}
public void add( Listener<T> listener ) {
if (!listeners.contains( listener )) {
if (stackMode) {
listeners.addFirst( listener );
} else {
listeners.addLast( listener );
}
}
}
public void remove( Listener<T> listener ) {
listeners.remove( listener );
}
public void removeAll() {
listeners.clear();
}
public void replace( Listener<T> listener ) {
removeAll();
add( listener );
}
public int numListeners() {
return listeners.size();
}
public void dispatch( T t ) {
@SuppressWarnings("unchecked")
Listener<T>[] list = listeners.toArray( new Listener[0] );
canceled = false;
for (int i=0; i < list.length; i++) {
Listener<T> listener = list[i];
if (listeners.contains( listener )) {
listener.onSignal( t );
if (canceled) {
return;
}
}
}
}
public void cancel() {
canceled = true;
}
public static interface Listener<T> {
public void onSignal( T t );
}
}

View File

@ -0,0 +1,46 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
import java.util.ArrayList;
import java.util.List;
public class SparseArray<T> extends android.util.SparseArray<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;
}
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;
}
}

View File

@ -0,0 +1,32 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 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.utils;
public class SystemTime {
public static long now;
public static void tick() {
now = System.currentTimeMillis();
}
}

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">SPD-Classes</string>
</resources>

14
build.gradle Normal file
View File

@ -0,0 +1,14 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
}
}
allprojects {
repositories {
jcenter()
}
}

17
core/build.gradle Normal file
View File

@ -0,0 +1,17 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "24.0.0"
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile project(':SPD-classes')
}

21
core/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Program Files (x86)\Android\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-dontwarn **
-keep class com.shatteredpixel.** { *; }
-keep class com.watabou.** { *; }

View File

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 516 B

After

Width:  |  Height:  |  Size: 516 B

View File

Before

Width:  |  Height:  |  Size: 482 B

After

Width:  |  Height:  |  Size: 482 B

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1020 B

After

Width:  |  Height:  |  Size: 1020 B

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 123 B

After

Width:  |  Height:  |  Size: 123 B

Some files were not shown because too many files have changed in this diff Show More