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
@@ -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( '?' );
}
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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 );
}
}
}
@@ -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;
}
}
}
@@ -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 );
}
}
@@ -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 );
}
}
@@ -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 );
}
}
@@ -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;" +
"}";
}
@@ -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 );
}
}
@@ -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;
}
}
@@ -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();
}
@@ -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() {
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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 );
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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 ) {
}
}
@@ -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 );
}
}
@@ -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;
}
}
}
@@ -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 );
}
}
}
@@ -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 );
}
}
@@ -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 );
}
}
@@ -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 ) {
}
}
@@ -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 ) );
}
}
@@ -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 );
}
}
@@ -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 );
}
}
@@ -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;
}
}
@@ -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() {
}
}
@@ -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() {
}
}