progress on adding base layer
This commit is contained in:
17
old/core/.classpath
Normal file
17
old/core/.classpath
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="bin/main" path="src">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="main"/>
|
||||
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry exported="true" kind="con" path="org.springsource.ide.eclipse.gradle.classpathcontainer"/>
|
||||
<classpathentry kind="lib" path="Z:/Projects/RhythmBullet/core/lib/jaudiotagger-2.2.3.jar" sourcepath="lib/jaudiotagger-2.2.3-sources.jar">
|
||||
<attributes>
|
||||
<attribute name="javadoc_location" value="jar:file:/Z:/Projects/RhythmBullet/core/lib/jaudiotagger-2.2.3-javadoc.jar!/"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
</classpath>
|
18
old/core/.project
Normal file
18
old/core/.project
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>RhythmBullet-core</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.springsource.ide.eclipse.gradle.core.nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@@ -0,0 +1,4 @@
|
||||
#org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences
|
||||
#Mon Sep 10 00:40:41 CDT 2018
|
||||
org.springsource.ide.eclipse.gradle.linkedresources=
|
||||
org.springsource.ide.eclipse.gradle.rootprojectloc=..
|
@@ -0,0 +1,8 @@
|
||||
#org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences
|
||||
#Mon Sep 10 00:40:41 CDT 2018
|
||||
addResourceFilters=true
|
||||
afterTasks=afterEclipseImport;
|
||||
beforeTasks=cleanEclipse;eclipse;
|
||||
enableAfterTasks=true
|
||||
enableBeforeTasks=true
|
||||
useHierarchicalNames=false
|
11
old/core/.settings/org.eclipse.jdt.core.prefs
Normal file
11
old/core/.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,11 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
11
old/core/build.gradle
Normal file
11
old/core/build.gradle
Normal file
@@ -0,0 +1,11 @@
|
||||
apply plugin: "java"
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||
|
||||
sourceSets.main.java.srcDirs = [ "src/" ]
|
||||
|
||||
|
||||
eclipse.project {
|
||||
name = appName + "-core"
|
||||
}
|
BIN
old/core/lib/jaudiotagger-2.2.3-javadoc.jar
Normal file
BIN
old/core/lib/jaudiotagger-2.2.3-javadoc.jar
Normal file
Binary file not shown.
BIN
old/core/lib/jaudiotagger-2.2.3-sources.jar
Normal file
BIN
old/core/lib/jaudiotagger-2.2.3-sources.jar
Normal file
Binary file not shown.
BIN
old/core/lib/jaudiotagger-2.2.3.jar
Normal file
BIN
old/core/lib/jaudiotagger-2.2.3.jar
Normal file
Binary file not shown.
231
old/core/src/zero1hd/rhythmbullet/RhythmBullet.java
Normal file
231
old/core/src/zero1hd/rhythmbullet/RhythmBullet.java
Normal file
@@ -0,0 +1,231 @@
|
||||
package zero1hd.rhythmbullet;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.Game;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.assets.loaders.ParticleEffectLoader;
|
||||
import com.badlogic.gdx.assets.loaders.SoundLoader;
|
||||
import com.badlogic.gdx.assets.loaders.TextureAtlasLoader;
|
||||
import com.badlogic.gdx.assets.loaders.TextureLoader;
|
||||
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
|
||||
import com.badlogic.gdx.assets.loaders.resolvers.ResolutionFileResolver.Resolution;
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
|
||||
import zero1hd.rhythmbullet.util.AssetPack;
|
||||
import zero1hd.rhythmbullet.util.GenericFileTypeHandler;
|
||||
import zero1hd.rhythmbullet.util.InitialScreen;
|
||||
import zero1hd.rhythmbullet.util.RoundingResolutionHandler;
|
||||
import zero1hd.rhythmbullet.util.ScreenConfiguration;
|
||||
import zero1hd.rhythmbullet.util.ResizeReadyScreen;
|
||||
|
||||
|
||||
public class RhythmBullet extends Game {
|
||||
public static final int WORLD_WIDTH = 64;
|
||||
public static final int WORLD_HEIGHT = 48;
|
||||
public static final int SPAWN_CIRCLE_RADIUS = 6;
|
||||
public static int pixels_per_unit;
|
||||
private boolean initiated;
|
||||
private boolean resizing, simpleResizeOnce;
|
||||
private int screenWidth, screenHeight;
|
||||
public static final String VERSION = "(1.0.0) R1-PreAlpha";
|
||||
|
||||
private AssetManager assetManager = new AssetManager();
|
||||
private Skin skin;
|
||||
private Preferences preferences;
|
||||
private RoundingResolutionHandler rRHandler;
|
||||
private InitialScreen initialScreen;
|
||||
private AssetPack assetPack;
|
||||
private ScreenConfiguration screenConfiguration;
|
||||
/**
|
||||
* This should be called before passed to LWJGL. Setup for system-dependent items such as UI and assets.
|
||||
* @param initialScreen the first screen to go to.
|
||||
* @param assetPack the asset package to be used.
|
||||
*/
|
||||
public void setup(InitialScreen initialScreen, AssetPack assetPack, ScreenConfiguration screenConfiguration) {
|
||||
this.initialScreen = initialScreen;
|
||||
this.assetPack = assetPack;
|
||||
this.screenConfiguration = screenConfiguration;
|
||||
screenConfiguration.queueBorderless(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
setScreen(initialScreen);
|
||||
Gdx.app.setLogLevel(Application.LOG_DEBUG);
|
||||
screenWidth = Gdx.graphics.getWidth();
|
||||
screenHeight = Gdx.graphics.getHeight();
|
||||
initialScreen.init();
|
||||
initialLoad();
|
||||
}
|
||||
|
||||
private void initialLoad() {
|
||||
if (initiated) throw new IllegalStateException("Initiation cannot occur more than once.");
|
||||
|
||||
simpleResizeOnce = true;
|
||||
skin = new Skin();
|
||||
assetPack.initiate();
|
||||
|
||||
preferences = Gdx.app.getPreferences("RhythmBullet Preferences");
|
||||
|
||||
Resolution[] resolution = {
|
||||
new Resolution(1280, 720, "1280x720"),
|
||||
new Resolution(1366, 768, "1366x768"),
|
||||
new Resolution(1280, 800, "1280x800"),
|
||||
new Resolution(1920, 1080, "1920x1080"),
|
||||
new Resolution(1920, 1200, "1920x1200"),
|
||||
new Resolution(2560, 1440, "2560x1440"),
|
||||
new Resolution(3840, 2160, "3840x2160")
|
||||
};
|
||||
|
||||
InternalFileHandleResolver internalFileResolver = new InternalFileHandleResolver();
|
||||
rRHandler = new RoundingResolutionHandler(internalFileResolver, resolution);
|
||||
GenericFileTypeHandler genericFileFinder = new GenericFileTypeHandler(internalFileResolver);
|
||||
assetManager.setLoader(TextureAtlas.class, new TextureAtlasLoader(rRHandler));
|
||||
assetManager.setLoader(Texture.class, new TextureLoader(rRHandler));
|
||||
assetManager.setLoader(ParticleEffect.class, new ParticleEffectLoader(genericFileFinder));
|
||||
assetManager.setLoader(Sound.class, new SoundLoader(genericFileFinder));
|
||||
|
||||
rRHandler.setResolution(getPreferences().getInteger("screen-width"), getPreferences().getInteger("screen-height"));
|
||||
queueAssets();
|
||||
}
|
||||
|
||||
private void initialLoadComplete() {
|
||||
screenConfiguration.queueBorderless(preferences.getBoolean("borderless", false));
|
||||
|
||||
skin.addRegions(assetManager.get("uiskin.atlas", TextureAtlas.class));
|
||||
pixels_per_unit = (int) (Float.valueOf(screenHeight)/Float.valueOf(WORLD_HEIGHT));
|
||||
if (getPreferences().getBoolean("fullscreen", true)) {
|
||||
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
|
||||
} else {
|
||||
Gdx.graphics.setWindowedMode(getPreferences().getInteger("screen-width"), getPreferences().getInteger("screen-height"));
|
||||
}
|
||||
assetPack.generateFonts(skin);
|
||||
assetPack.setupSkin(skin);
|
||||
assetPack.complete(assetManager);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
checkAssetQueue();
|
||||
super.render();
|
||||
}
|
||||
|
||||
public boolean checkAssetQueue() {
|
||||
if (assetManager.update()) {
|
||||
if (resizing) {
|
||||
Gdx.app.debug("Resize", "Post resize is starting...");
|
||||
if (skin != null) skin.dispose();
|
||||
skin = new Skin();
|
||||
skin.addRegions(assetManager.get("uiskin.atlas", TextureAtlas.class));
|
||||
|
||||
assetPack.generateFonts(skin);
|
||||
assetPack.setupSkin(skin);
|
||||
assetPack.complete(assetManager);
|
||||
if (getScreen() instanceof ResizeReadyScreen) {
|
||||
((ResizeReadyScreen) getScreen()).postAssetLoad();
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot perform window resize on a screen that isn't resize ready.");
|
||||
}
|
||||
Gdx.app.debug("Resize", "Post resize has ended.");
|
||||
resizing = false;
|
||||
} else if (!initiated) {
|
||||
initiated = true;
|
||||
initialLoadComplete();
|
||||
setScreen(((InitialScreen) initialScreen).advance(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setScreen(Screen screen) {
|
||||
if (screen instanceof ResizeReadyScreen) {
|
||||
ResizeReadyScreen advancedResizeScreen = (ResizeReadyScreen) screen;
|
||||
try {
|
||||
advancedResizeScreen.preAssetLoad();
|
||||
} catch (NullPointerException cleanScreen) {
|
||||
Gdx.app.debug("Screen", "clean screen: " + advancedResizeScreen.getClass().getSimpleName());
|
||||
//Tried to perform pre-asset reload, but had uninitialized objects, meaning this is a new screen, or "clean" screen.
|
||||
} finally {
|
||||
advancedResizeScreen.postAssetLoad();
|
||||
}
|
||||
}
|
||||
super.setScreen(screen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
if (screenWidth != width || screenHeight != height) {
|
||||
Gdx.app.debug("resize", "Current size:" + screenWidth + "x" + screenHeight + " new size: " + width + "x" + height);
|
||||
screenWidth = width;
|
||||
screenHeight = height;
|
||||
pixels_per_unit = (int) (Float.valueOf(screenHeight)/Float.valueOf(WORLD_HEIGHT));
|
||||
rRHandler.setResolution(width, height);
|
||||
preferences.putInteger("screen-width", width);
|
||||
preferences.putInteger("screen-height", height);
|
||||
preferences.flush();
|
||||
|
||||
if (!simpleResizeOnce) {
|
||||
Gdx.app.debug("Resize", "complex pre-resize is happening. Resizing to " + width + "x" + height);
|
||||
if (getScreen() instanceof ResizeReadyScreen) {
|
||||
((ResizeReadyScreen) getScreen()).preAssetLoad();
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot perform window resize on a screen that isn't using a resize ready screen.");
|
||||
}
|
||||
|
||||
resizing = true;
|
||||
assetManager.clear();
|
||||
queueAssets();
|
||||
} else {
|
||||
simpleResizeOnce = false;
|
||||
}
|
||||
super.resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public void queueAssets() {
|
||||
assetPack.queueTextures(assetManager);
|
||||
assetPack.queueSFX(assetManager);
|
||||
assetPack.queueParticles(assetManager);
|
||||
}
|
||||
|
||||
public AssetManager getAssetManager() {
|
||||
return assetManager;
|
||||
}
|
||||
|
||||
public Skin getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
public Preferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Gdx.app.debug("Core", "disposing...");
|
||||
try {
|
||||
getScreen().dispose();
|
||||
getSkin().dispose();
|
||||
assetManager.dispose();
|
||||
assetPack.dispose();
|
||||
} catch (NullPointerException npe) {
|
||||
Gdx.app.debug("Core", "Disposal error occurred, possibly caused by failing to complete initialization.", npe);
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public ScreenConfiguration getScreenConfiguration() {
|
||||
return screenConfiguration;
|
||||
}
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.Sort;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.metadata.AudioMetadata;
|
||||
import zero1hd.rhythmbullet.audio.metadata.MP3Metadata;
|
||||
import zero1hd.rhythmbullet.audio.metadata.WAVMetadata;
|
||||
|
||||
public class AudioMetadataController extends Observable implements Disposable, Observer {
|
||||
private MusicList musicList;
|
||||
private volatile Array<AudioMetadata> metadataArray;
|
||||
private MetadataLoadingThread loadingThread;
|
||||
private volatile boolean searching;
|
||||
private Comparator<AudioMetadata> metadataComparer;
|
||||
|
||||
public AudioMetadataController(MusicList musicList) {
|
||||
this.musicList = musicList;
|
||||
metadataArray = new Array<>();
|
||||
loadingThread = new MetadataLoadingThread();
|
||||
musicList.addObserver(this);
|
||||
metadataComparer = new Comparator<AudioMetadata>() {
|
||||
@Override
|
||||
public int compare(AudioMetadata o1, AudioMetadata o2) {
|
||||
return o1.getTitle().compareToIgnoreCase(o2.getTitle());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public MusicList getMusicList() {
|
||||
return musicList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-blocking, loads on separate thread.
|
||||
*/
|
||||
public void loadAudioMetadata() {
|
||||
if (!loadingThread.start()) {
|
||||
loadingThread.stop();
|
||||
loadingThread = new MetadataLoadingThread();
|
||||
loadingThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if there is the same amount of metadata as there is music in the music list.
|
||||
* @return whether or not both sizes are equal.
|
||||
*/
|
||||
public boolean isSameSizeMusicList() {
|
||||
return (metadataArray.size == musicList.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
for (int i = 0; i < metadataArray.size; i++) {
|
||||
metadataArray.get(i).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return metadataArray.size;
|
||||
}
|
||||
|
||||
public AudioMetadata getAudioMetadata(int index) {
|
||||
return metadataArray.get(index);
|
||||
}
|
||||
|
||||
|
||||
public AudioMetadata getAudioMetadata(FileHandle filehandle) {
|
||||
for (int i = 0; i < metadataArray.size; i++) {
|
||||
if (metadataArray.get(i).getFileHandle() == filehandle) {
|
||||
return metadataArray.get(i);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Couldn't find file " + filehandle.name());
|
||||
}
|
||||
|
||||
public boolean isSearching() {
|
||||
return searching;
|
||||
}
|
||||
|
||||
private class MetadataLoadingThread implements Runnable {
|
||||
private Thread thread;
|
||||
private String name = "AudioMetadata-Load";
|
||||
private volatile boolean work = true;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Gdx.app.debug(name, "loading...");
|
||||
clear();
|
||||
synchronized (this) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
searching = true;
|
||||
Array<AudioMetadata> tempMetadataArray = new Array<>();
|
||||
for (int i = 0; i < musicList.getTotal() && work; i++) {
|
||||
FileHandle musicFile = musicList.getAudioFileHandle(i);
|
||||
if (musicFile == null) return;
|
||||
switch (SupportedFormats.valueOf(musicFile.extension().toUpperCase())) {
|
||||
case MP3:
|
||||
tempMetadataArray.add(new MP3Metadata(musicFile));
|
||||
break;
|
||||
case WAV:
|
||||
tempMetadataArray.add(new WAVMetadata(musicFile));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Sort.instance().sort(tempMetadataArray, metadataComparer);
|
||||
|
||||
if (work) {
|
||||
metadataArray = tempMetadataArray;
|
||||
searching = false;
|
||||
Gdx.app.debug(name, "load complete.");
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if (thread == null) {
|
||||
thread = new Thread(this, name);
|
||||
thread.start();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
work = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
if (o == musicList && arg == musicList.states.COMPLETE) {
|
||||
loadAudioMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Gdx.app.postRunnable(() -> {
|
||||
for (int i = 0; i < metadataArray.size; i++) {
|
||||
metadataArray.get(i).dispose();
|
||||
}
|
||||
metadataArray.clear();
|
||||
synchronized (loadingThread) {
|
||||
loadingThread.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.processor.AudioProcessor;
|
||||
|
||||
public interface AudioProcessorFactory {
|
||||
/**
|
||||
* @return a new {@link #zero1hd.rhythmbullet.audio.processor.AudioProcessor()} from the appropriate platform.
|
||||
*/
|
||||
public AudioProcessor newMP3AudioProcessor(FileHandle fileHandle);
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jaudiotagger.audio.AudioFile;
|
||||
import org.jaudiotagger.audio.AudioFileIO;
|
||||
import org.jaudiotagger.audio.AudioHeader;
|
||||
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
|
||||
import org.jaudiotagger.audio.mp3.MP3File;
|
||||
import org.jaudiotagger.tag.TagException;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
public class MinimalAudioHeader {
|
||||
private int sampleRate, channelCount;
|
||||
private SupportedFormats format;
|
||||
private FileHandle musicFile;
|
||||
public MinimalAudioHeader(FileHandle musicFile) {
|
||||
if (musicFile == null) throw new IllegalArgumentException("musicFile for minimal audio headers should not be null.");
|
||||
this.musicFile = musicFile;
|
||||
format = SupportedFormats.valueOf(musicFile.extension().toUpperCase());
|
||||
try {
|
||||
AudioFile file = AudioFileIO.read(musicFile.file());
|
||||
AudioHeader header = file.getAudioHeader();
|
||||
sampleRate = header.getSampleRateAsNumber();
|
||||
channelCount = (header.getChannels().equals("Mono") ? 1 : 2);
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public int getChannelCount() {
|
||||
return channelCount;
|
||||
}
|
||||
|
||||
|
||||
public long estimateSampleFrames() {
|
||||
switch (format) {
|
||||
case MP3:
|
||||
try {
|
||||
MP3File file = (MP3File) AudioFileIO.read(musicFile.file());
|
||||
MP3AudioHeader header = file.getMP3AudioHeader();
|
||||
return header.getNumberOfFrames();
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
262
old/core/src/zero1hd/rhythmbullet/audio/MusicController.java
Normal file
262
old/core/src/zero1hd/rhythmbullet/audio/MusicController.java
Normal file
@@ -0,0 +1,262 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Random;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
import com.badlogic.gdx.audio.Music.OnCompletionListener;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
/**
|
||||
* Manages current games music playback and does this in tandem with the {@link MusicList} by asking to retrieve files and then feeding it to LibGDX.
|
||||
* Notifies observers when a new song is loaded.
|
||||
* The loading model is like taking a disk and loading it into a player. It doesn't necessarily mean it'll play right away, but its ready and the only track that has a stream opened.
|
||||
* @author yunya
|
||||
*
|
||||
*/
|
||||
public class MusicController extends Observable implements OnCompletionListener, Observer {
|
||||
public final class States {
|
||||
public final Integer LOADED = new Integer(0), PLAYING = new Integer(1), PAUSED = new Integer(2);
|
||||
}
|
||||
|
||||
public final States states = new States();
|
||||
private MusicList musicList;
|
||||
private MinimalAudioHeader musicHeader;
|
||||
private volatile Music music;
|
||||
private int currentlyPlayingIndex;
|
||||
private boolean autoPlay;
|
||||
private boolean shuffle;
|
||||
private Random rand;
|
||||
private Preferences prefs;
|
||||
|
||||
public MusicController(MusicList musicList, Preferences prefs) {
|
||||
if (prefs == null) throw new NullPointerException("preferences can't be null...");
|
||||
if (musicList == null) throw new NullPointerException("music list can't be null...");
|
||||
musicList.addObserver(this);
|
||||
this.prefs = prefs;
|
||||
this.musicList = musicList;
|
||||
rand = new Random();
|
||||
}
|
||||
|
||||
/**
|
||||
* This play method automatically sets the volume.
|
||||
*/
|
||||
public void play() {
|
||||
if (music != null) {
|
||||
Gdx.app.debug("MusicController", "Playing from controller.");
|
||||
music.play();
|
||||
music.setVolume(prefs.getFloat("music vol", 100f)/100f);
|
||||
setChanged();
|
||||
notifyObservers(states.PLAYING);
|
||||
} else {
|
||||
Gdx.app.debug("MusicController", "Music isn't loaded!");
|
||||
Thread.dumpStack();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to pause current song. Does nothing if no song is playing or loaded.
|
||||
*/
|
||||
public void pause() {
|
||||
if (music != null) {
|
||||
music.pause();
|
||||
setChanged();
|
||||
notifyObservers(states.PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads music based on the index in the {@link MusicList}.
|
||||
* @param index of music to play
|
||||
*/
|
||||
public void setMusicByIndex(int index) {
|
||||
this.currentlyPlayingIndex = index;
|
||||
loadMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads music using the given file. The given file must be found in the {@link MusicList}.
|
||||
* This function gets the index of the given file within {@link MusicList} and passes that index to {@link #setMusicByIndex(index)}.
|
||||
* @param fileHandle to use.
|
||||
*/
|
||||
public void setMusicByFileHandle(FileHandle fileHandle) {
|
||||
setMusicByIndex(musicList.getIndexOfFileHandle(fileHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes to the next track
|
||||
*/
|
||||
public void skip() {
|
||||
currentlyPlayingIndex++;
|
||||
if (shuffle) {
|
||||
shuffle();
|
||||
}
|
||||
loadMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes to the previous track
|
||||
*/
|
||||
public void previous() {
|
||||
currentlyPlayingIndex--;
|
||||
if (shuffle) {
|
||||
shuffle();
|
||||
}
|
||||
loadMusic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletion(Music music) {
|
||||
if (autoPlay) {
|
||||
if (shuffle) {
|
||||
shuffle();
|
||||
} else {
|
||||
currentlyPlayingIndex++;
|
||||
}
|
||||
loadMusic();
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffles the controller whether the shuffle boolean is true or false.
|
||||
*/
|
||||
public void shuffle() {
|
||||
Gdx.app.debug("MusicListController", "shuffled.");
|
||||
if (musicList.getTotal() == 0) {
|
||||
currentlyPlayingIndex = 0;
|
||||
} else {
|
||||
currentlyPlayingIndex = rand.nextInt(musicList.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoPlay(boolean autoPlay) {
|
||||
this.autoPlay = autoPlay;
|
||||
}
|
||||
|
||||
public void setShuffle(boolean shuffle) {
|
||||
this.shuffle = shuffle;
|
||||
}
|
||||
|
||||
public void setLoop(boolean loop) {
|
||||
music.setLooping(loop);
|
||||
}
|
||||
|
||||
public boolean isShuffle() {
|
||||
return shuffle;
|
||||
}
|
||||
|
||||
public boolean isAutoPlay() {
|
||||
return autoPlay;
|
||||
}
|
||||
|
||||
public boolean isLoop() {
|
||||
return music.isLooping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the current selected song.
|
||||
*/
|
||||
public void loadMusic() {
|
||||
Gdx.app.debug("MusicListController", "music is being loaded from music list with " + musicList.getTotal() + " songs.");
|
||||
boolean playing = isPlaying();
|
||||
musicHeader = null;
|
||||
if (music != null) {
|
||||
music.dispose();
|
||||
}
|
||||
if (currentlyPlayingIndex < 0) {
|
||||
currentlyPlayingIndex = musicList.getTotal()-1;
|
||||
}
|
||||
if (currentlyPlayingIndex >= musicList.getTotal()) {
|
||||
currentlyPlayingIndex = 0;
|
||||
}
|
||||
if (musicList.getTotal() != 0) {
|
||||
this.music = Gdx.audio.newMusic(musicList.getAudioFileHandle(currentlyPlayingIndex));
|
||||
music.setOnCompletionListener(this);
|
||||
|
||||
setChanged();
|
||||
|
||||
notifyObservers(states.LOADED);
|
||||
if (playing || autoPlay) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MusicList getMusicList() {
|
||||
return musicList;
|
||||
}
|
||||
|
||||
public FileHandle getCurrentMusicFileHandle() {
|
||||
return musicList.getSongFileHandleFromIndex(currentlyPlayingIndex);
|
||||
}
|
||||
|
||||
public MinimalAudioHeader getCurrentMusicHeader() {
|
||||
if (musicHeader != null) {
|
||||
return musicHeader;
|
||||
} else {
|
||||
return musicHeader = musicList.newMinimalAudioHeader(getCurrentMusicFileHandle());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
if (o == musicList) {
|
||||
if (arg == musicList.states.LOADING) {
|
||||
pause();
|
||||
} else if (arg == musicList.states.COMPLETE) {
|
||||
if (shuffle) {
|
||||
shuffle();
|
||||
}
|
||||
loadMusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentSongName() {
|
||||
return getCurrentMusicFileHandle().nameWithoutExtension();
|
||||
}
|
||||
|
||||
public float getCurrentPosition() {
|
||||
if (music != null) {
|
||||
return music.getPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setMusicPosition(float position) {
|
||||
if (music != null) {
|
||||
music.setPosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
if (music != null) {
|
||||
return music.isPlaying();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current music. In no circumstances should this be used to begin playing or it would be playing independent of the controller.
|
||||
* Doing otherwise would mean you are playing the music separately of the controller.
|
||||
* @return the {@link Music} that is currently "loaded" and ready to play.
|
||||
*/
|
||||
public Music getCurrentMusic() {
|
||||
return music;
|
||||
}
|
||||
|
||||
public int getCurrentlyPlayingIndex() {
|
||||
return currentlyPlayingIndex;
|
||||
}
|
||||
|
||||
public boolean hasSongLoaded() {
|
||||
if (music != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
211
old/core/src/zero1hd/rhythmbullet/audio/MusicList.java
Normal file
211
old/core/src/zero1hd/rhythmbullet/audio/MusicList.java
Normal file
@@ -0,0 +1,211 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Observable;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Sort;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.processor.AudioProcessor;
|
||||
import zero1hd.rhythmbullet.audio.processor.WAVAudioProcessor;
|
||||
|
||||
/**
|
||||
* A music list made to store paths to all the songs within a given directory. Can activate the music calling {@link #newAudioProcessor(FileHandle)} and its derivatives.
|
||||
* Is observable, meaning, given there are observers, will notify when the list completes a refresh.
|
||||
* @author yunya
|
||||
*/
|
||||
public class MusicList extends Observable {
|
||||
public final class States {
|
||||
public final Integer LOADING = new Integer(0), COMPLETE = new Integer(1), EMPTY = new Integer(2);
|
||||
}
|
||||
public States states = new States();
|
||||
private Array<FileHandle> musicList;
|
||||
private RecursiveMusicSearchThread searchThread;
|
||||
private AudioProcessorFactory audioProcFactory;
|
||||
private volatile boolean searched;
|
||||
private String searchPath;
|
||||
private Comparator<FileHandle> compare;
|
||||
|
||||
public MusicList(AudioProcessorFactory audioProcessorFactory, String searchPath) {
|
||||
this.audioProcFactory = audioProcessorFactory;
|
||||
musicList = new Array<>();
|
||||
setSearchPath(searchPath);
|
||||
|
||||
compare = new Comparator<FileHandle>() {
|
||||
|
||||
@Override
|
||||
public int compare(FileHandle o1, FileHandle o2) {
|
||||
return o1.nameWithoutExtension().compareTo(o2.nameWithoutExtension());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous recursive search on music directory.
|
||||
* Also notifies listeners that are on the main thread.
|
||||
* @param refresh does a search whether or not path has changed and whether or not this list has searched before this.
|
||||
*/
|
||||
public void attemptAsyncSearch(boolean refresh) {
|
||||
if (refresh) {
|
||||
notifyObservers(states.LOADING);
|
||||
if (searchThread != null) {
|
||||
if (!searchThread.start()) {
|
||||
searchThread.stop();
|
||||
searchThread = new RecursiveMusicSearchThread("Music Search Thread", Gdx.files.absolute(searchPath));
|
||||
searchThread.start();
|
||||
}
|
||||
} else {
|
||||
searchThread = new RecursiveMusicSearchThread("Music Search Thread", Gdx.files.absolute(searchPath));
|
||||
searchThread.start();
|
||||
}
|
||||
} else {
|
||||
if (!searched || hasChanged()) {
|
||||
attemptAsyncSearch(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSearchPath(String searchPath) {
|
||||
if (this.searchPath != null && this.searchPath.equals(searchPath)) return;
|
||||
this.searchPath = searchPath;
|
||||
setChanged();
|
||||
}
|
||||
|
||||
public String getSearchPath() {
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file
|
||||
* @return a {@link AudioProcessor} of the given music file. Will return null if theres a format error.
|
||||
*/
|
||||
public AudioProcessor newAudioProcessor(FileHandle file) {
|
||||
switch (SupportedFormats.valueOf(file.extension().toUpperCase())) {
|
||||
case MP3:
|
||||
return audioProcFactory.newMP3AudioProcessor(file);
|
||||
case WAV:
|
||||
return new WAVAudioProcessor(file);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file the music file that you need the header for.
|
||||
* @return the header containing minimal info of the song.
|
||||
*/
|
||||
public MinimalAudioHeader newMinimalAudioHeader(FileHandle file) {
|
||||
return new MinimalAudioHeader(file);
|
||||
}
|
||||
|
||||
public AudioProcessor newAudioProcessorFromIndex(int index) {
|
||||
if (!searched) {
|
||||
Gdx.app.debug("MusicList", "Warning, this list has not completed it's search...");
|
||||
Thread.dumpStack();
|
||||
}
|
||||
if (musicList.size == 0) {
|
||||
return null;
|
||||
}
|
||||
return newAudioProcessor(musicList.get(index));
|
||||
}
|
||||
|
||||
|
||||
public FileHandle getSongFileHandleFromIndex(int index) {
|
||||
if (!searched) {
|
||||
Gdx.app.debug("MusicList", "Warning, this list has not completed it's search...");
|
||||
Thread.dumpStack();
|
||||
}
|
||||
if (musicList.size == 0) {
|
||||
return null;
|
||||
}
|
||||
return musicList.get(index);
|
||||
}
|
||||
|
||||
public FileHandle getAudioFileHandle(int index) {
|
||||
return musicList.get(index);
|
||||
}
|
||||
|
||||
public int getIndexOfFileHandle(FileHandle file) {
|
||||
return musicList.indexOf(file, true);
|
||||
}
|
||||
|
||||
public boolean isSearched() {
|
||||
return searched;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the amount of audio files discovered.
|
||||
*/
|
||||
public int getTotal() {
|
||||
return musicList.size;
|
||||
}
|
||||
|
||||
private class RecursiveMusicSearchThread implements Runnable {
|
||||
private Thread thread;
|
||||
private String threadName;
|
||||
private FileHandle directory;
|
||||
private volatile boolean work;
|
||||
|
||||
public RecursiveMusicSearchThread(String name, FileHandle searchDirectory) {
|
||||
this.threadName = name;
|
||||
this.directory = searchDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Gdx.app.debug("MusicList", "recursive async search beginning.");
|
||||
Array<FileHandle> obtainedAudioFiles = recursiveMusicSearch(directory);
|
||||
Sort.instance().sort(obtainedAudioFiles, compare);
|
||||
if (work) {
|
||||
musicList = obtainedAudioFiles;
|
||||
searched = true;
|
||||
Gdx.app.debug("MusicList", "recursive async search completed.");
|
||||
setChanged();
|
||||
if (musicList.size != 0) {
|
||||
notifyObservers(states.COMPLETE);
|
||||
} else {
|
||||
notifyObservers(states.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if (thread == null) {
|
||||
work = true;
|
||||
thread = new Thread(this, threadName);
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
work = false;
|
||||
}
|
||||
|
||||
private Array<FileHandle> recursiveMusicSearch(FileHandle fileHandle) {
|
||||
Array<FileHandle> musicFiles = new Array<>();
|
||||
FileHandle[] files = fileHandle.list();
|
||||
for (int i = 0; i < files.length && work; i++) {
|
||||
if (files[i].isDirectory()) {
|
||||
musicFiles.addAll(recursiveMusicSearch(files[i]));
|
||||
} else {
|
||||
try {
|
||||
SupportedFormats.valueOf(files[i].extension().toUpperCase());
|
||||
musicFiles.add(files[i]);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Gdx.app.log("MusicList", "Unsupported file format: " + files[i].name());
|
||||
}
|
||||
}
|
||||
}
|
||||
return musicFiles;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
public enum SupportedFormats {
|
||||
WAV, MP3;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package zero1hd.rhythmbullet.audio.analyzer;
|
||||
|
||||
import com.badlogic.gdx.utils.FloatArray;
|
||||
|
||||
public class AudioAnalyzerSection {
|
||||
private int lower, upper, thresholdRange;
|
||||
private float thresholdFactor;
|
||||
private FloatArray peaks;
|
||||
private int pUID;
|
||||
|
||||
public AudioAnalyzerSection(int lowerBin, int upperBin, float thresholdFactor, int thresholdRange) {
|
||||
this.upper = upperBin;
|
||||
this.lower = lowerBin;
|
||||
this.thresholdRange = thresholdRange;
|
||||
this.thresholdFactor = thresholdFactor;
|
||||
}
|
||||
|
||||
public void setPUID(int pUID) {
|
||||
this.pUID = pUID;
|
||||
}
|
||||
|
||||
public void setPeaks(FloatArray peaks) {
|
||||
this.peaks = peaks;
|
||||
}
|
||||
|
||||
public int getLower() {
|
||||
return lower;
|
||||
}
|
||||
|
||||
public int getUpper() {
|
||||
return upper;
|
||||
}
|
||||
|
||||
public float getThresholdFactor() {
|
||||
return thresholdFactor;
|
||||
}
|
||||
|
||||
public int getThresholdRange() {
|
||||
return thresholdRange;
|
||||
}
|
||||
|
||||
public FloatArray getPeaks() {
|
||||
return peaks;
|
||||
}
|
||||
|
||||
public int getPUID() {
|
||||
return pUID;
|
||||
}
|
||||
}
|
@@ -0,0 +1,148 @@
|
||||
package zero1hd.rhythmbullet.audio.analyzer;
|
||||
|
||||
import java.util.Observable;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.FloatArray;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
|
||||
import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D;
|
||||
import zero1hd.rhythmbullet.audio.processor.AudioProcessor;
|
||||
|
||||
public class DynamicAudioAnalyzer extends Observable implements Runnable {
|
||||
private volatile boolean work = true;
|
||||
private Thread thread;
|
||||
private String threadName = "analyzer";
|
||||
private final int WINDOWLENGTH = 1024;
|
||||
private AudioProcessor processor;
|
||||
private AudioAnalyzerSection[] sections;
|
||||
private FloatArray[] flux;
|
||||
private FloatArray[] threshold;
|
||||
private volatile int pUID = 0;
|
||||
private long timer;
|
||||
|
||||
public DynamicAudioAnalyzer(AudioProcessor processor, AudioAnalyzerSection... sections) {
|
||||
this.sections = sections;
|
||||
this.processor = processor;
|
||||
flux = new FloatArray[sections.length];
|
||||
threshold = new FloatArray[sections.length];
|
||||
|
||||
for (int section = 0; section < sections.length; section++) {
|
||||
flux[section] = new FloatArray();
|
||||
threshold[section] = new FloatArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
calculateSpectralFlux();
|
||||
calculateThreshold();
|
||||
calculatePeaks();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (thread == null) {
|
||||
thread = new Thread(this, threadName);
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot have two analyzer threads.");
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
work = false;
|
||||
}
|
||||
|
||||
private void calculateSpectralFlux() {
|
||||
Gdx.app.debug("Spectral Flux Calculation", "Beginning...");
|
||||
timer = TimeUtils.millis();
|
||||
float[] audioPCM = new float[WINDOWLENGTH];
|
||||
float[] spectrum = new float[(WINDOWLENGTH/2)+1];
|
||||
float[] lastSpectrum = new float[spectrum.length];
|
||||
FloatFFT_1D fft = new FloatFFT_1D(WINDOWLENGTH);
|
||||
int windowsComplete = 0;
|
||||
int seedCurrentDigit = 0;
|
||||
|
||||
int totalWindows = (int) processor.getSampleFrames()/WINDOWLENGTH;
|
||||
while (processor.readFrames(audioPCM) > 0 && work) {
|
||||
fft.realForward(audioPCM);
|
||||
|
||||
//Building a PUID (Pseudo unique ID)
|
||||
if (windowsComplete == (seedCurrentDigit*totalWindows/9)) {
|
||||
float avg = 0;
|
||||
for (int frame = 0; frame < spectrum.length; frame++) {
|
||||
avg += spectrum[frame];
|
||||
}
|
||||
avg /= spectrum.length;
|
||||
if (avg < 0) {
|
||||
avg *= -1f;
|
||||
}
|
||||
pUID +=(int) Math.pow(10, 9-seedCurrentDigit) * ((int)(avg*1000f)-(int)(avg*100f)*10);
|
||||
seedCurrentDigit ++;
|
||||
}
|
||||
|
||||
System.arraycopy(spectrum, 0, lastSpectrum, 0, spectrum.length);
|
||||
System.arraycopy(audioPCM, 0, spectrum, 0, spectrum.length);
|
||||
|
||||
for (int section = 0; section < sections.length; section++) {
|
||||
float currentFlux = 0;
|
||||
for (int bin = sections[section].getLower(); bin < sections[section].getUpper(); bin++) {
|
||||
currentFlux += Math.max(0f, spectrum[bin] - lastSpectrum[bin]);
|
||||
}
|
||||
flux[section].add(currentFlux);
|
||||
}
|
||||
|
||||
windowsComplete++;
|
||||
}
|
||||
|
||||
for (int section = 0; section < sections.length; section++) {
|
||||
sections[section].setPUID(pUID);
|
||||
}
|
||||
|
||||
Gdx.app.debug("Spectral Flux Calculation", "Finished. Took " + (TimeUtils.timeSinceMillis(timer)) + "ms");
|
||||
}
|
||||
|
||||
private void calculateThreshold() {
|
||||
long subTimer = TimeUtils.millis();
|
||||
Gdx.app.debug("Threshold Calculation", "Beginning...");
|
||||
for (int section = 0; section < sections.length && work; section++) {
|
||||
FloatArray fluxArray = flux[section];
|
||||
for (int bin = 0; bin < fluxArray.size; bin++) {
|
||||
int range = sections[section].getThresholdRange();
|
||||
int start = Math.max(0, bin - range);
|
||||
int end = Math.min(fluxArray.size, bin + range);
|
||||
|
||||
float average = 0;
|
||||
for (int pos = start; pos < end; pos++) {
|
||||
average += fluxArray.get(pos);
|
||||
}
|
||||
average /= (end - start);
|
||||
threshold[section].add(average);
|
||||
}
|
||||
}
|
||||
|
||||
Gdx.app.debug("Spectral Flux Calculation", "Finished. Took " + (TimeUtils.timeSinceMillis(subTimer)) + "ms");
|
||||
}
|
||||
|
||||
private void calculatePeaks() {
|
||||
long subTimer = TimeUtils.millis();
|
||||
Gdx.app.debug("Peak Calculation", "Beginning...");
|
||||
for (int section = 0; section < sections.length && work; section++) {
|
||||
FloatArray peaks = new FloatArray();
|
||||
|
||||
for (int bin = 0; bin < threshold[section].size -1; bin++) {
|
||||
float prunedFlux = flux[section].get(bin) - threshold[section].get(bin);
|
||||
float prunedNextFlux = flux[section].get(bin + 1) - threshold[section].get(bin + 1);
|
||||
|
||||
peaks.add((prunedFlux > prunedNextFlux) ? prunedFlux : 0);
|
||||
}
|
||||
|
||||
sections[section].setPeaks(peaks);
|
||||
}
|
||||
Gdx.app.debug("Spectral Flux Calculation", "Finished. Took " + (TimeUtils.timeSinceMillis(subTimer)) + "ms. Total time was " + (TimeUtils.timeSinceMillis(timer)));
|
||||
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Metadata for audio. Not thread-safe.
|
||||
* @author yunya
|
||||
*
|
||||
*/
|
||||
|
||||
package zero1hd.rhythmbullet.audio.metadata;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public interface AudioMetadata extends Disposable {
|
||||
/**
|
||||
* Load the album art data in to memory.
|
||||
* Will not load if already loaded.
|
||||
*/
|
||||
public void loadAlbumCover();
|
||||
|
||||
/**
|
||||
* Unloads album art from memory.
|
||||
* Requires OpenGL context.
|
||||
*/
|
||||
public void unloadAlbumCover();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the author for the song in the metadata.
|
||||
*/
|
||||
public String getAuthor();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the title of the song in the metadata, or if it doesn't exist, the filename without extension and _ is given.
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the length of the song with proper fomatting.
|
||||
*/
|
||||
public String getDuration();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the length of the song in seconds.
|
||||
*/
|
||||
public int getLength();
|
||||
|
||||
/**
|
||||
* Requires a OpenGL context.
|
||||
* @return the texture. Needs to be loaded before hand or else will return null.
|
||||
*/
|
||||
public Texture getAlbumCover();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return returns the genre of the song stored in metadata.
|
||||
*/
|
||||
public String getGenre();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the filehandle.
|
||||
*/
|
||||
public FileHandle getFileHandle();
|
||||
|
||||
@Override
|
||||
public void dispose();
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
package zero1hd.rhythmbullet.audio.metadata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jaudiotagger.audio.AudioFileIO;
|
||||
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
import org.jaudiotagger.audio.mp3.MP3File;
|
||||
import org.jaudiotagger.tag.TagException;
|
||||
import org.jaudiotagger.tag.id3.ID3v23FieldKey;
|
||||
import org.jaudiotagger.tag.id3.ID3v23Tag;
|
||||
import org.jaudiotagger.tag.images.Artwork;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
public class MP3Metadata implements AudioMetadata {
|
||||
private String title, author, duration, genre;
|
||||
private int length;
|
||||
private Texture albumCover;
|
||||
private FileHandle fileHandle;
|
||||
private Pixmap pixmap;
|
||||
|
||||
public MP3Metadata(FileHandle fileHandle) {
|
||||
this.fileHandle = fileHandle;
|
||||
|
||||
try {
|
||||
MP3File mp3file = (MP3File) AudioFileIO.read(fileHandle.file());
|
||||
ID3v23Tag tag;
|
||||
tag = (ID3v23Tag) mp3file.getTagAndConvertOrCreateAndSetDefault();
|
||||
|
||||
length = mp3file.getAudioHeader().getTrackLength();
|
||||
SimpleDateFormat f = new SimpleDateFormat("m:ss");
|
||||
duration = f.format(new Date(length*1000));
|
||||
|
||||
author = tag.getFirst(ID3v23FieldKey.ARTIST);
|
||||
genre = tag.getFirst(ID3v23FieldKey.GENRE);
|
||||
title = tag.getFirst(ID3v23FieldKey.TITLE);
|
||||
if (title.isEmpty()) {
|
||||
title = fileHandle.nameWithoutExtension().replace('_', ' ');
|
||||
}
|
||||
} catch (IOException | CannotReadException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
Gdx.app.error("MP3Metadata", "Failed to read metadata of file: " + fileHandle.name());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAlbumCover() {
|
||||
if (pixmap == null) {
|
||||
try {
|
||||
MP3File mp3file;
|
||||
mp3file = (MP3File) AudioFileIO.read(fileHandle.file());
|
||||
Artwork art = mp3file.getTag().getFirstArtwork();
|
||||
if (art != null) {
|
||||
byte[] imageData = art.getBinaryData();
|
||||
pixmap = new Pixmap(imageData, 0, imageData.length);
|
||||
}
|
||||
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGenre() {
|
||||
return genre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAlbumCover() {
|
||||
if (albumCover != null) {
|
||||
albumCover.dispose();
|
||||
albumCover = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getAlbumCover() {
|
||||
if (pixmap != null && albumCover == null) {
|
||||
albumCover = new Texture(pixmap);
|
||||
pixmap.dispose();
|
||||
pixmap = null;
|
||||
}
|
||||
return albumCover;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle getFileHandle() {
|
||||
return fileHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
unloadAlbumCover();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
package zero1hd.rhythmbullet.audio.metadata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jaudiotagger.audio.AudioFile;
|
||||
import org.jaudiotagger.audio.AudioFileIO;
|
||||
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
import org.jaudiotagger.tag.FieldKey;
|
||||
import org.jaudiotagger.tag.Tag;
|
||||
import org.jaudiotagger.tag.TagException;
|
||||
import org.jaudiotagger.tag.images.Artwork;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
public class WAVMetadata implements AudioMetadata {
|
||||
private String title, author, duration, genre;
|
||||
private int length;
|
||||
private Texture albumCover;
|
||||
private FileHandle fileHandle;
|
||||
private Pixmap pixmap;
|
||||
|
||||
public WAVMetadata(FileHandle fileHandle) {
|
||||
this.fileHandle = fileHandle;
|
||||
|
||||
try {
|
||||
AudioFile wav = AudioFileIO.read(fileHandle.file());
|
||||
length = wav.getAudioHeader().getTrackLength();
|
||||
SimpleDateFormat f = new SimpleDateFormat("m:ss");
|
||||
duration = f.format(new Date(length*1000));
|
||||
|
||||
Tag tag = wav.getTag();
|
||||
title = tag.getFirst(FieldKey.TITLE);
|
||||
author = tag.getFirst(FieldKey.ARTIST);
|
||||
genre = tag.getFirst(FieldKey.GENRE);
|
||||
if (title.isEmpty()) {
|
||||
title = fileHandle.nameWithoutExtension().replace('_', ' ');
|
||||
}
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
Gdx.app.error("WAVMetadata", "Failed to read metadata of file: " + fileHandle.name());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAlbumCover() {
|
||||
if (pixmap == null) {
|
||||
try {
|
||||
AudioFile wav = AudioFileIO.read(fileHandle.file());
|
||||
Artwork art = wav.getTag().getFirstArtwork();
|
||||
|
||||
if (art != null) {
|
||||
byte[] imageData = art.getBinaryData();
|
||||
pixmap = new Pixmap(imageData, 0, imageData.length);
|
||||
}
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void unloadAlbumCover() {
|
||||
if (albumCover != null) {
|
||||
albumCover.dispose();
|
||||
albumCover = null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
@Override
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getAlbumCover() {
|
||||
if (pixmap != null && albumCover == null) {
|
||||
albumCover = new Texture(pixmap);
|
||||
pixmap.dispose();
|
||||
pixmap = null;
|
||||
}
|
||||
return albumCover;
|
||||
}
|
||||
@Override
|
||||
public String getGenre() {
|
||||
return genre;
|
||||
}
|
||||
@Override
|
||||
public FileHandle getFileHandle() {
|
||||
return fileHandle;
|
||||
}
|
||||
@Override
|
||||
public void dispose() {
|
||||
unloadAlbumCover();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public interface AudioProcessor extends Disposable {
|
||||
/**
|
||||
* @return number of channels
|
||||
*/
|
||||
public boolean isStereo();
|
||||
|
||||
/**
|
||||
* @return sample rate
|
||||
*/
|
||||
public int getSampleRate();
|
||||
|
||||
/**
|
||||
* Reads samples with interwoven data for stereo.
|
||||
* stored in 16 bit format (first 8 are the first byte of data while the second 8 are the second byte of data that composes a short value)
|
||||
* @param pcm the array the samples should fill
|
||||
* @return the amount of samples read.
|
||||
*/
|
||||
public int readSamples(short[] pcm);
|
||||
|
||||
/**
|
||||
* Reads frames with interwoven data for stereo.
|
||||
* stored in 16 bit format (first 8 are the first byte of data while the second 8 are the second byte of data that composes a short value)
|
||||
* @param pcm the array the samples should fill
|
||||
* @return the amount of samples read.
|
||||
*/
|
||||
public int readFrames(float[] pcm);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The music file's {@link FileHandle}
|
||||
*/
|
||||
public FileHandle getMusicFileHandle();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the number of sample frames in the song.
|
||||
*/
|
||||
public long getSampleFrames();
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
public class WAVAudioProcessor implements AudioProcessor {
|
||||
private boolean stereo;
|
||||
private int sampleRate;
|
||||
private byte[] buffer;
|
||||
private FileHandle fileHandle;
|
||||
private AudioInputStream audioInputStream;
|
||||
private long sampleFrames;
|
||||
|
||||
public WAVAudioProcessor(FileHandle fileHandle) {
|
||||
this.fileHandle = fileHandle;
|
||||
AudioFormat format;
|
||||
try {
|
||||
audioInputStream = AudioSystem.getAudioInputStream(fileHandle.file());
|
||||
format = audioInputStream.getFormat();
|
||||
stereo = format.getChannels() > 1 ? true : false;
|
||||
sampleRate = (int) format.getSampleRate();
|
||||
sampleFrames = audioInputStream.getFrameLength();
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
Gdx.app.debug("WAVAudioProcessor", "Couldn't instantiate WAVAUdioProcessor due to error.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
buffer = new byte[audioInputStream.getFormat().getFrameSize()];
|
||||
|
||||
}
|
||||
|
||||
public boolean isStereo() {
|
||||
return stereo;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readSamples(short[] pcm) {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
|
||||
try {
|
||||
if (audioInputStream.read(buffer) > 0) {
|
||||
pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
|
||||
if (stereo) {
|
||||
short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
|
||||
sampleID++;
|
||||
pcm[sampleID] = secondChan;
|
||||
}
|
||||
framesRead++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readFrames(float[] pcm) {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
|
||||
try {
|
||||
if (audioInputStream.read(buffer) > 0) {
|
||||
pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
|
||||
if (stereo) {
|
||||
short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
|
||||
pcm[sampleID] = secondChan > pcm[sampleID] ? secondChan : pcm[sampleID];
|
||||
}
|
||||
framesRead++;
|
||||
pcm[sampleID] /= Short.MAX_VALUE+1;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle getMusicFileHandle() {
|
||||
return fileHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSampleFrames() {
|
||||
return sampleFrames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
audioInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,235 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Camera;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Mesh;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.VertexAttribute;
|
||||
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
|
||||
public class CircularVisualizer implements Disposable {
|
||||
private PCMSystem pcm;
|
||||
private int centerX, centerY;
|
||||
private int r;
|
||||
private int componentCount = 2 + 1;
|
||||
private Array<Vector2> circlePoints;
|
||||
private float[] vertComponents;
|
||||
private float color;
|
||||
private Mesh mesh;
|
||||
private ShaderProgram shader;
|
||||
private int barCount = 180;
|
||||
private float barHeightMultiplier = 1.5f;
|
||||
private float[] audioSpectrum;
|
||||
private Camera camera;
|
||||
|
||||
public CircularVisualizer(PCMSystem PCMSystem) {
|
||||
this.pcm = PCMSystem;
|
||||
shader = new ShaderProgram(Gdx.files.internal("shaders/mesh.vsh"), Gdx.files.internal("shaders/mesh.fsh"));
|
||||
if (!shader.isCompiled() || shader.getLog().length() != 0) {
|
||||
Gdx.app.debug("Circular visualizer shader", shader.getLog());
|
||||
Gdx.app.exit();
|
||||
}
|
||||
r = RhythmBullet.pixels_per_unit*RhythmBullet.SPAWN_CIRCLE_RADIUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only should be called when all changes have been done.
|
||||
*/
|
||||
public void applyPositionChanges() {
|
||||
circlePoints = new Array<>();
|
||||
createCircleVertices(r);
|
||||
vertComponents = new float[circlePoints.size * componentCount];
|
||||
|
||||
if (mesh != null) {
|
||||
mesh.dispose();
|
||||
}
|
||||
mesh = new Mesh(true, circlePoints.size, 0, new VertexAttribute(Usage.Position, 2, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color"));
|
||||
}
|
||||
|
||||
public void setCenter(int x, int y) {
|
||||
this.centerX = x;
|
||||
this.centerY = y;
|
||||
}
|
||||
|
||||
public void drawVisualizer() {
|
||||
for (int circlePointIndex = 0; circlePointIndex < circlePoints.size; circlePointIndex++) {
|
||||
for (int comp = 0; comp < componentCount; comp++) {
|
||||
if (comp != 2) {
|
||||
vertComponents[circlePointIndex*componentCount + comp] = circlePoints.get(circlePointIndex).x + centerX;
|
||||
comp++;
|
||||
vertComponents[circlePointIndex*componentCount + comp] = circlePoints.get(circlePointIndex).y + centerY;
|
||||
} else {
|
||||
vertComponents[circlePointIndex*componentCount + comp] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
private void flush() {
|
||||
mesh.setVertices(vertComponents);
|
||||
Gdx.gl.glDepthMask(false);
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
int vertexCount = circlePoints.size;
|
||||
((OrthographicCamera) camera).setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
|
||||
shader.begin();
|
||||
mesh.render(shader, GL20.GL_LINE_STRIP, 0, vertexCount);
|
||||
shader.end();
|
||||
|
||||
Gdx.gl.glDepthMask(true);
|
||||
}
|
||||
|
||||
private void createCircleVertices(int radius) {
|
||||
int x = radius - 1;
|
||||
int y = 0;
|
||||
int dx = 1;
|
||||
int dy = 1;
|
||||
int err = dx - (radius << 1);
|
||||
circlePoints.clear();
|
||||
|
||||
while (x >= y) {
|
||||
circlePoints.add(new Vector2(+ x, + y));
|
||||
circlePoints.add(new Vector2(+ y, + x));
|
||||
circlePoints.add(new Vector2(- y, + x));
|
||||
circlePoints.add(new Vector2(- x, + y));
|
||||
circlePoints.add(new Vector2(- x, - y));
|
||||
circlePoints.add(new Vector2(- y, - x));
|
||||
circlePoints.add(new Vector2(+ y, - x));
|
||||
circlePoints.add(new Vector2(+ x, - y));
|
||||
|
||||
if (err <= 0) {
|
||||
y++;
|
||||
err += dy;
|
||||
dy += 2;
|
||||
} else {
|
||||
x--;
|
||||
dx += 2;
|
||||
err += dx - (radius << 1);
|
||||
}
|
||||
}
|
||||
|
||||
circlePoints.sort(new Comparator<Vector2>() {
|
||||
@Override
|
||||
public int compare(Vector2 o1, Vector2 o2) {
|
||||
double deg1;
|
||||
if (o1.x != 0 || o1.y != 0) {
|
||||
deg1 = Math.atan(Math.abs(o1.y)/Math.abs(o1.x));
|
||||
if (o1.x < 0) {
|
||||
if (o1.y < 0) {
|
||||
deg1 += 180;
|
||||
} else {
|
||||
deg1 = 180 - deg1;
|
||||
}
|
||||
} else {
|
||||
if (o1.y < 0) {
|
||||
deg1 = 360 - deg1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (o1.x != 0) {
|
||||
if (o1.x > 0) {
|
||||
deg1 = 0;
|
||||
} else {
|
||||
deg1 = 180;
|
||||
}
|
||||
deg1 = 0;
|
||||
} else {
|
||||
if (o1.y > 0) {
|
||||
deg1 = 90;
|
||||
} else {
|
||||
deg1 = 270;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double deg2;
|
||||
if (o2.x != 0 || o2.y != 0) {
|
||||
deg2 = Math.atan(Math.abs(o2.y)/Math.abs(o2.x));
|
||||
if (o2.x < 0) {
|
||||
if (o2.y < 0) {
|
||||
deg2 += 180;
|
||||
} else {
|
||||
deg2 = 180 - deg2;
|
||||
}
|
||||
} else {
|
||||
if (o2.y < 0) {
|
||||
deg2 = 360 - deg2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (o2.x != 0) {
|
||||
if (o2.x > 0) {
|
||||
deg2 = 0;
|
||||
} else {
|
||||
deg2 = 180;
|
||||
}
|
||||
deg2 = 0;
|
||||
} else {
|
||||
if (o2.y > 0) {
|
||||
deg2 = 90;
|
||||
} else {
|
||||
deg2 = 270;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((deg1 - deg2) > 0) {
|
||||
return 1;
|
||||
} else if (deg1 - deg2 == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setColor(float color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
mesh.dispose();
|
||||
shader.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the maximum radius
|
||||
* @param r
|
||||
*/
|
||||
public void setR(int r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the maximum radius
|
||||
* @return
|
||||
*/
|
||||
public int getR() {
|
||||
return r;
|
||||
}
|
||||
|
||||
public void setCamera(Camera camera) {
|
||||
this.camera = camera;
|
||||
}
|
||||
|
||||
public Camera getCamera() {
|
||||
return camera;
|
||||
}
|
||||
}
|
@@ -0,0 +1,212 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.MusicController;
|
||||
|
||||
public class DoubleHorizontalVisualizer implements Disposable {
|
||||
private int width, height, barWidth, spaceBetweenBars;
|
||||
private int x, y;
|
||||
private ShapeRenderer shapeRenderer;
|
||||
private PCMSystem pcm;
|
||||
private float[] amplitudes;
|
||||
private int[] barHeights;
|
||||
private int binsPerBar;
|
||||
private float offset;
|
||||
private int boundaryThickness;
|
||||
private boolean debug = false;
|
||||
private boolean significantBeat;
|
||||
private float maxAverageAmplitude;
|
||||
private byte significantFrames;
|
||||
private byte requiredSignificantFrames;
|
||||
private float targetDelta;
|
||||
private float significantThreshold = 0.5f;
|
||||
private float spacePercentage = 0.7f;
|
||||
private float baseSensitivity = 0.009f;
|
||||
private int barCount = 120;
|
||||
private float barChangeRate = 6.5f;
|
||||
private int smoothRange = 2;
|
||||
private int binsToInclude = 120;
|
||||
private Color color = new Color(0.5f, 0.6f, 0.8f, 0.46f);
|
||||
private int averageAmplitude;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param barCount amount of bars this visualizer should have.
|
||||
* @param width the width of the visualizer.
|
||||
* @param spacePercentage the percentage of a bar that should be space.
|
||||
*/
|
||||
public DoubleHorizontalVisualizer(int width, int height, float heightSensitivity, int boundaryThickness, int targetFPS, MusicController musicController, PCMSystem PCMSystem) {
|
||||
this.barWidth = width/barCount;
|
||||
this.spaceBetweenBars = MathUtils.round(barWidth * spacePercentage);
|
||||
this.barWidth -= spaceBetweenBars;
|
||||
this.baseSensitivity *= heightSensitivity;
|
||||
pcm = PCMSystem;
|
||||
binsPerBar = (binsToInclude/barCount);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
amplitudes = new float[barCount];
|
||||
barHeights = new int[barCount];
|
||||
shapeRenderer = new ShapeRenderer();
|
||||
boundaryThickness = barWidth;
|
||||
offset = (width - (barCount*(barWidth+spaceBetweenBars)-spaceBetweenBars))/2f + x;
|
||||
this.targetDelta = 1f/targetFPS;
|
||||
}
|
||||
|
||||
public void act(float delta) {
|
||||
if (pcm.hasAudioChanged()) {
|
||||
maxAverageAmplitude = 0;
|
||||
averageAmplitude = 0;
|
||||
significantBeat = false;
|
||||
}
|
||||
float[] freqBins = pcm.getFrequencyBins();
|
||||
averageAmplitude = 0;
|
||||
for (int bar = 0; bar < amplitudes.length; bar++) {
|
||||
amplitudes[bar] = 0;
|
||||
for (int freq = bar*binsPerBar; freq < (bar*binsPerBar) + binsPerBar; freq++) {
|
||||
amplitudes[bar] += Math.abs(freqBins[freq]) * baseSensitivity;
|
||||
}
|
||||
amplitudes[bar] /= binsPerBar;
|
||||
|
||||
averageAmplitude += amplitudes[bar];
|
||||
}
|
||||
|
||||
averageAmplitude /= amplitudes.length;
|
||||
if (averageAmplitude > maxAverageAmplitude) {
|
||||
maxAverageAmplitude = averageAmplitude;
|
||||
}
|
||||
if (averageAmplitude > maxAverageAmplitude*significantThreshold && !significantBeat) {
|
||||
if (maxAverageAmplitude > 0) {
|
||||
significantFrames++;
|
||||
if (significantFrames >= requiredSignificantFrames) {
|
||||
significantFrames = 0;
|
||||
significantBeat = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (significantBeat) {
|
||||
significantBeat = false;
|
||||
requiredSignificantFrames = 16;
|
||||
} else {
|
||||
requiredSignificantFrames = 4;
|
||||
}
|
||||
significantFrames = 0;
|
||||
}
|
||||
|
||||
for (int bar = 0; bar < barHeights.length; bar++) {
|
||||
int smoothCount = 1;
|
||||
for (int range = 0; range < smoothRange; range++) {
|
||||
if (bar+range < amplitudes.length) {
|
||||
amplitudes[bar] += amplitudes[bar+range];
|
||||
smoothCount++;
|
||||
}
|
||||
if (bar-range > 0) {
|
||||
amplitudes[bar] += amplitudes[bar-range];
|
||||
smoothCount++;
|
||||
}
|
||||
}
|
||||
amplitudes[bar] /= smoothCount;
|
||||
|
||||
|
||||
int pixelsMoved = 0;
|
||||
int difference = MathUtils.round(amplitudes[bar] - barHeights[bar]);
|
||||
pixelsMoved = MathUtils.floor(difference*targetDelta*barChangeRate);
|
||||
if (pixelsMoved >= 0) {
|
||||
if (barHeights[bar] + pixelsMoved > amplitudes[bar]) {
|
||||
barHeights[bar] += MathUtils.round(difference*targetDelta);
|
||||
} else {
|
||||
barHeights[bar] += pixelsMoved;
|
||||
}
|
||||
} else {
|
||||
if (barHeights[bar] + pixelsMoved < amplitudes[bar]) {
|
||||
barHeights[bar] += MathUtils.round(difference*targetDelta);
|
||||
} else {
|
||||
barHeights[bar] += pixelsMoved;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Batch batch, float parentAlpha) {
|
||||
batch.end();
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||
shapeRenderer.begin(ShapeType.Filled);
|
||||
shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
|
||||
shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
|
||||
if (boundaryThickness > 0) {
|
||||
shapeRenderer.rect(x, y, width, boundaryThickness);
|
||||
shapeRenderer.rect(x, y+height, width, -boundaryThickness);
|
||||
}
|
||||
|
||||
for (int bar = 0; bar < barCount; bar++) {
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.rect(offset + (spaceBetweenBars+barWidth)*bar, y+height, barWidth, barHeights[bar]);
|
||||
shapeRenderer.rect(offset + (spaceBetweenBars+barWidth)*bar, y, barWidth, -barHeights[barHeights.length - 1 - bar]);
|
||||
}
|
||||
if (debug) {
|
||||
shapeRenderer.setColor(Color.RED);
|
||||
shapeRenderer.rect(0, maxAverageAmplitude+y, width, 1);
|
||||
if (significantBeat) {
|
||||
shapeRenderer.setColor(Color.GREEN);
|
||||
} else {
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
}
|
||||
shapeRenderer.rect(0, averageAmplitude+y, width, 1);
|
||||
shapeRenderer.setColor(Color.YELLOW);
|
||||
shapeRenderer.rect(0, maxAverageAmplitude*significantThreshold + y, width, 1);
|
||||
}
|
||||
shapeRenderer.end();
|
||||
Gdx.gl.glDisable(GL20.GL_BLEND);
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public boolean isSignificantBeat() {
|
||||
return significantBeat;
|
||||
}
|
||||
|
||||
public void updateMusic() {
|
||||
pcm.loadMusic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
pcm.dispose();
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public interface PCMSystem extends Disposable {
|
||||
|
||||
float[] getFrequencyBins();
|
||||
|
||||
int getWindowSize();
|
||||
|
||||
void loadMusic();
|
||||
|
||||
boolean hasAudioChanged();
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
package zero1hd.rhythmbullet.audio.wavedecoder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
|
||||
public class WAVSampleReader {
|
||||
private int channels;
|
||||
private double sampleRate;
|
||||
private byte[] buffer;
|
||||
private AudioInputStream audioInputStream;
|
||||
private boolean mergeChannels;
|
||||
|
||||
public WAVSampleReader(AudioInputStream ais) throws IOException {
|
||||
audioInputStream = ais;
|
||||
buffer = new byte[audioInputStream.getFormat().getFrameSize()];
|
||||
|
||||
channels = audioInputStream.getFormat().getChannels();
|
||||
sampleRate = audioInputStream.getFormat().getSampleRate();
|
||||
}
|
||||
|
||||
public int getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
public double getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public long getFrameLength() {
|
||||
return audioInputStream.getFrameLength();
|
||||
}
|
||||
|
||||
public int readSamplesAsFrames(float[] samples) throws IOException {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < samples.length; sampleID++) {
|
||||
if (audioInputStream.read(buffer) > 0) {
|
||||
samples[sampleID] += (buffer[1] << 8) + (buffer[0] & 0x00ff);
|
||||
if (audioInputStream.getFormat().getChannels() > 1) {
|
||||
short altChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
|
||||
if (mergeChannels) {
|
||||
samples[sampleID] = altChan > samples[sampleID] ? altChan : samples[sampleID];
|
||||
} else {
|
||||
sampleID++;
|
||||
samples[sampleID] = altChan;
|
||||
}
|
||||
}
|
||||
framesRead ++;
|
||||
samples[sampleID] /= Short.MAX_VALUE+1;
|
||||
}
|
||||
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
public AudioInputStream getAudioInputStream() {
|
||||
return audioInputStream;
|
||||
}
|
||||
|
||||
|
||||
public void setMergeChannels(boolean mergeChannels) {
|
||||
this.mergeChannels = mergeChannels;
|
||||
}
|
||||
public boolean isMergeChannels() {
|
||||
return mergeChannels;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package zero1hd.rhythmbullet.entity;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class CollisionDetector {
|
||||
Array<Entity> enemies;
|
||||
Array<Entity> allies;
|
||||
|
||||
AssetManager assets;
|
||||
Preferences prefs;
|
||||
|
||||
private int amassedPoints;
|
||||
Sound explosionSFX;
|
||||
public CollisionDetector(Array<Entity> enemies, Array<Entity> allies, AssetManager assetManager, Preferences prefs) {
|
||||
this.enemies = enemies;
|
||||
this.allies = allies;
|
||||
assets = assetManager;
|
||||
this.prefs = prefs;
|
||||
|
||||
}
|
||||
|
||||
public void collisionCheck() {
|
||||
if ((enemies.size != 0) && (allies.size != 0)) {
|
||||
for (int f = 0; f < enemies.size; f++) {
|
||||
Entity enemy = enemies.get(f);
|
||||
if (enemy.getHitZone() != null) {
|
||||
for (int s = 0; s < allies.size; s++) {
|
||||
Entity ally = allies.get(s);
|
||||
if (ally.getHitZone() != null) {
|
||||
if (enemy.getHitZone().overlaps(ally.getHitZone())) {
|
||||
Gdx.app.debug("Collision Detector", "Collision between entities: " + enemy.getClass().getSimpleName() + " and " + ally.getClass().getSimpleName());
|
||||
|
||||
enemy.collided(ally);
|
||||
ally.collided(enemy);
|
||||
|
||||
amassedPoints += enemy.getPoints();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getAmassedPoints() {
|
||||
int amassedPoints = this.amassedPoints;
|
||||
this.amassedPoints = 0;
|
||||
return amassedPoints;
|
||||
}
|
||||
}
|
201
old/core/src/zero1hd/rhythmbullet/entity/Entity.java
Normal file
201
old/core/src/zero1hd/rhythmbullet/entity/Entity.java
Normal file
@@ -0,0 +1,201 @@
|
||||
package zero1hd.rhythmbullet.entity;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
import zero1hd.rhythmbullet.entity.coordinator.Coordinator;
|
||||
|
||||
public class Entity implements Poolable {
|
||||
private Coordinator coordinator;
|
||||
private EntityFrame<?> ef;
|
||||
|
||||
protected AssetManager assets;
|
||||
protected Preferences prefs;
|
||||
protected EntityManager ec;
|
||||
|
||||
protected boolean enemy;
|
||||
protected boolean move = true;
|
||||
|
||||
protected boolean dead;
|
||||
protected Rectangle hitbox;
|
||||
protected Sprite sprite;
|
||||
protected Vector2 rotRatios;
|
||||
public float angle;
|
||||
public float speed;
|
||||
protected float hitBoxScale;
|
||||
|
||||
protected int points;
|
||||
|
||||
/**
|
||||
* called by the entity frame and only once (when this object is created).
|
||||
* Used by the frame to setup variables for simple calling later.
|
||||
* Anything that needs to be setup for the entity on first call should not override this.
|
||||
* (Unless you call the super of this and then the rest which is fine too).
|
||||
* This will then call preInit() which is the method you should override.
|
||||
*/
|
||||
protected void setup(EntityManager ec, EntityFrame<?> ef) {
|
||||
this.ec = ec;
|
||||
this.ef = ef;
|
||||
assets = ec.getAssets();
|
||||
prefs = ec.getPrefs();
|
||||
rotRatios = new Vector2();
|
||||
hitbox = new Rectangle();
|
||||
|
||||
preInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to override should any setup need to be done once (on entity first creation).
|
||||
*/
|
||||
public void preInit() {
|
||||
if (sprite.getTexture() == null) throw new NullPointerException("what, your not going to have a texture for your entity?");
|
||||
sprite.setOriginCenter();
|
||||
}
|
||||
|
||||
public void init(float deg, float speed, int hp) {
|
||||
rotRatios.set(MathUtils.cosDeg(angle), MathUtils.sinDeg(angle));
|
||||
sprite.setSize(sprite.getTexture().getWidth()/RhythmBullet.pixels_per_unit, sprite.getTexture().getHeight()/RhythmBullet.pixels_per_unit);
|
||||
float r = RhythmBullet.SPAWN_CIRCLE_RADIUS - sprite.getWidth();
|
||||
if (r < RhythmBullet.SPAWN_CIRCLE_RADIUS -1) {
|
||||
throw new InvalidParameterException("Entity is too big! Calculated final distance from center: " + r);
|
||||
}
|
||||
sprite.setPosition(r*rotRatios.x, r*rotRatios.y);
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever a collision is detected
|
||||
* @param entity is the entity that hit this one.
|
||||
*/
|
||||
public void collided(Entity entity) {
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the box that represents the hit box to calculate whether there is a collision or not
|
||||
* @return the object that represents the hit box
|
||||
*/
|
||||
public Rectangle getHitZone() {
|
||||
return hitbox;
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return dead;
|
||||
}
|
||||
|
||||
public void calculate(float delta) {
|
||||
if (coordinator != null) {
|
||||
coordinator.coordinate(delta);
|
||||
}
|
||||
|
||||
if (dead) {
|
||||
ef.recycleEntity(this);
|
||||
}
|
||||
|
||||
if (angle >= 360f) {
|
||||
angle -= 360f;
|
||||
}
|
||||
|
||||
if (sprite.getX() > RhythmBullet.WORLD_WIDTH || sprite.getY() > RhythmBullet.WORLD_HEIGHT || sprite.getX() < 0-sprite.getWidth() || sprite.getX() < 0-sprite.getWidth()) {
|
||||
dead = true;
|
||||
}
|
||||
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
public void draw(Batch batch) {
|
||||
sprite.draw(batch);
|
||||
batch.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
public void moveBy(float x, float y) {
|
||||
sprite.setCenter(sprite.getX() + x, sprite.getY() + y);
|
||||
}
|
||||
|
||||
public void updatePosition() {
|
||||
rotRatios.set(MathUtils.cosDeg(angle), MathUtils.sinDeg(angle));
|
||||
sprite.setOriginCenter();
|
||||
sprite.setRotation(angle);
|
||||
hitbox.setCenter(sprite.getOriginX(), sprite.getOriginY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
if (coordinator != null) {
|
||||
coordinator.clean();
|
||||
coordinator = null;
|
||||
}
|
||||
rotRatios.set(0, 0);
|
||||
sprite.setPosition(0, 0);
|
||||
hitbox.set(0, 0, 0, 0);
|
||||
sprite.setRotation(0);
|
||||
sprite.setColor(Color.WHITE);
|
||||
angle = 0;
|
||||
speed = 0;
|
||||
points = 0;
|
||||
dead = false;
|
||||
}
|
||||
|
||||
public float getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public void setSpeed(float speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public float getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setCoordinator(Coordinator coordinator) {
|
||||
this.coordinator = coordinator;
|
||||
coordinator.setEntity(this);
|
||||
}
|
||||
|
||||
public void kill() {
|
||||
dead = true;
|
||||
}
|
||||
|
||||
public int getPoints() {
|
||||
return points + (coordinator != null ? coordinator.getScoreBonus() : 0);
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return sprite.getX();
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return sprite.getY();
|
||||
}
|
||||
|
||||
public void setPosition(float x, float y) {
|
||||
sprite.setPosition(x, y);
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return sprite.getWidth();
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return sprite.getHeight();
|
||||
}
|
||||
|
||||
public void setSize(float width, float height) {
|
||||
sprite.setSize(width, height);
|
||||
}
|
||||
|
||||
public void setHitboxScale(float scale) {
|
||||
hitbox.setSize(sprite.getWidth()*scale, sprite.getHeight()*scale);
|
||||
}
|
||||
}
|
66
old/core/src/zero1hd/rhythmbullet/entity/EntityFrame.java
Normal file
66
old/core/src/zero1hd/rhythmbullet/entity/EntityFrame.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package zero1hd.rhythmbullet.entity;
|
||||
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
|
||||
public class EntityFrame<T extends Entity> {
|
||||
private Pool<T> pool;
|
||||
private EntityManager ec;
|
||||
Class<T> ct;
|
||||
EntityFrame<T> ef;
|
||||
|
||||
/**
|
||||
* Manages the entities pooling.
|
||||
* @param entityController
|
||||
* @param classType
|
||||
*/
|
||||
public EntityFrame(EntityManager entityController, Class<T> classType) {
|
||||
this.ct = classType;
|
||||
ef = this;
|
||||
ec = entityController;
|
||||
pool = new Pool<T>() {
|
||||
@Override
|
||||
protected T newObject() {
|
||||
try {
|
||||
T entity = ct.newInstance();
|
||||
entity.setup(ec, ef);
|
||||
|
||||
return entity;
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public T buildEntity() {
|
||||
T entity = pool.obtain();
|
||||
|
||||
if (entity.enemy) {
|
||||
ec.activeEnemies.add(entity);
|
||||
} else {
|
||||
ec.activeAllies.add(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the entity if no longer used.
|
||||
* @param entity to be freed.
|
||||
*/
|
||||
protected void recycleEntity(Entity entity) {
|
||||
if (entity.enemy) {
|
||||
ec.activeEnemies.removeValue(entity, true);
|
||||
} else {
|
||||
ec.activeAllies.removeValue(entity, true);
|
||||
}
|
||||
pool.free(ct.cast(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ct.getSimpleName();
|
||||
}
|
||||
}
|
46
old/core/src/zero1hd/rhythmbullet/entity/EntityManager.java
Normal file
46
old/core/src/zero1hd/rhythmbullet/entity/EntityManager.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package zero1hd.rhythmbullet.entity;
|
||||
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.ally.Laser;
|
||||
import zero1hd.rhythmbullet.entity.enemies.Pellet;
|
||||
import zero1hd.rhythmbullet.entity.enemies.Shard;
|
||||
|
||||
public class EntityManager {
|
||||
private AssetManager assets;
|
||||
private Preferences prefs;
|
||||
|
||||
public Array<Entity> activeAllies;
|
||||
public Array<Entity> activeEnemies;
|
||||
|
||||
public EntityFrame<Pellet> pellet;
|
||||
public EntityFrame<Shard> shard;
|
||||
|
||||
public EntityFrame<Laser> laser;
|
||||
|
||||
public EntityManager(AssetManager assetManager, Preferences preferences) {
|
||||
activeAllies = new Array<Entity>();
|
||||
activeEnemies = new Array<Entity>();
|
||||
this.assets = assetManager;
|
||||
this.prefs = preferences;
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
pellet = new EntityFrame<>(this, Pellet.class);
|
||||
shard = new EntityFrame<>(this, Shard.class);
|
||||
laser = new EntityFrame<>(this, Laser.class);
|
||||
|
||||
}
|
||||
|
||||
public AssetManager getAssets() {
|
||||
return assets;
|
||||
}
|
||||
|
||||
public Preferences getPrefs() {
|
||||
return prefs;
|
||||
}
|
||||
}
|
52
old/core/src/zero1hd/rhythmbullet/entity/ally/Laser.java
Normal file
52
old/core/src/zero1hd/rhythmbullet/entity/ally/Laser.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package zero1hd.rhythmbullet.entity.ally;
|
||||
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
|
||||
public class Laser extends Entity {
|
||||
Sound sfx;
|
||||
|
||||
@Override
|
||||
public void preInit() {
|
||||
sprite = new Sprite(assets.get("laser.png", Texture.class));
|
||||
sfx = assets.get("laser.ogg", Sound.class);
|
||||
setSize(0.25f, 2f);
|
||||
super.preInit();
|
||||
}
|
||||
|
||||
public void init(float x, float y, float rate) {
|
||||
setPosition(x-getWidth()/2f, y-getHeight()/2f);
|
||||
speed = rate;
|
||||
sfx.play(prefs.getFloat("fx vol")/100f);
|
||||
angle = 90f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(float delta) {
|
||||
if (getY() > RhythmBullet.WORLD_HEIGHT) {
|
||||
dead = true;
|
||||
}
|
||||
super.calculate(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch) {
|
||||
super.draw(batch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collided(Entity entity) {
|
||||
dead = true;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
package zero1hd.rhythmbullet.entity.ally;
|
||||
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
|
||||
public class PolyjetEntity extends Entity {
|
||||
public float health;
|
||||
private ParticleEffect thrust;
|
||||
private Texture polyjet;
|
||||
private ParticleEffect teleportCloak;
|
||||
public boolean moveLeft, moveRight, moveUp, moveDown, teleporting, accelerate;
|
||||
private float speed, accel;
|
||||
private float rate;
|
||||
private int maxH;
|
||||
public PolyjetEntity(AssetManager assets, float speed, float accel,int maxHealth, String jet) {
|
||||
health = 100;
|
||||
this.speed = speed;
|
||||
this.accel = accel;
|
||||
setSize(1.5f, 1.5f);
|
||||
setPosition(RhythmBullet.WORLD_WIDTH/2 - getWidth()/2, -4f);
|
||||
maxH = maxHealth;
|
||||
hitbox = new Rectangle(getX(), getY(), getWidth(), getHeight());
|
||||
polyjet = assets.get("polyjet-" + jet + ".png", Texture.class);
|
||||
thrust = assets.get("standard_thrust.p", ParticleEffect.class);
|
||||
thrust.start();
|
||||
|
||||
teleportCloak = assets.get("teleport-cloak.p", ParticleEffect.class);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(float delta) {
|
||||
hitbox.setPosition(getX(), getY());
|
||||
|
||||
thrust.setPosition(getX()+(getWidth())/2 - 1f/16f, getY()-0.2f);
|
||||
thrust.update(delta);
|
||||
teleportCloak.setPosition(getX() +(getWidth()-1)/2, getY() + (getHeight()-1)/2);
|
||||
|
||||
hitbox.setPosition(getX(), getY());
|
||||
|
||||
//Movement!
|
||||
if (accelerate) {
|
||||
rate = speed + accel;
|
||||
} else {
|
||||
rate = speed;
|
||||
}
|
||||
|
||||
if (moveLeft && !moveRight) {
|
||||
moveBy(-(rate*delta), 0);
|
||||
}
|
||||
if (moveRight && !moveLeft) {
|
||||
moveBy(rate*delta, 0);
|
||||
}
|
||||
if (moveUp && !moveDown) {
|
||||
moveBy(0, rate*delta);
|
||||
}
|
||||
|
||||
if (moveDown && !moveUp) {
|
||||
moveBy(0, -rate*delta);
|
||||
}
|
||||
|
||||
if (health <= 0) {
|
||||
dead = true;
|
||||
} else if (health > maxH) {
|
||||
health = maxH;
|
||||
}
|
||||
|
||||
super.calculate(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch) {
|
||||
thrust.draw(batch);
|
||||
batch.draw(polyjet, getX(), getY(), getWidth(), getHeight());
|
||||
super.draw(batch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collided(Entity entity) {
|
||||
}
|
||||
|
||||
public Rectangle getHitbox() {
|
||||
return hitbox;
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
this.health = health;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
package zero1hd.rhythmbullet.entity.coordinator;
|
||||
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
import zero1hd.rhythmbullet.entity.EntityManager;
|
||||
|
||||
/**
|
||||
* Coordinator coordinates movement of an entity. Movement can range from basic pre-determined to more advanced (with condition based behavior).
|
||||
* @author Yunyang
|
||||
*
|
||||
*/
|
||||
public class Coordinator implements Poolable {
|
||||
private CoordinatorFrame<? extends Coordinator> cf;
|
||||
protected EntityManager em;
|
||||
protected Entity entity;
|
||||
protected int scoreBonus;
|
||||
|
||||
public void setup(EntityManager em, CoordinatorFrame<? extends Coordinator> cf) {
|
||||
this.em = em;
|
||||
this.cf = cf;
|
||||
}
|
||||
|
||||
public void init(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public void coordinate(float delta) {
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
cf.recycleCoordinator(this);
|
||||
}
|
||||
|
||||
public void setEntity(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
entity = null;
|
||||
}
|
||||
|
||||
public int getScoreBonus() {
|
||||
return scoreBonus;
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
package zero1hd.rhythmbullet.entity.coordinator;
|
||||
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.EntityManager;
|
||||
|
||||
public class CoordinatorFrame<T extends Coordinator> {
|
||||
private Pool<T> pool;
|
||||
private EntityManager em;
|
||||
CoordinatorFrame<T> cf;
|
||||
Class<T> coordinatorType;
|
||||
|
||||
/**
|
||||
* Similar to an entityFrame, however this time, for a coordinator.
|
||||
* @param entityManager
|
||||
* @param classtype
|
||||
*/
|
||||
public CoordinatorFrame(EntityManager entityManager, Class<T> classtype) {
|
||||
this.em = entityManager;
|
||||
coordinatorType = classtype;
|
||||
cf = this;
|
||||
pool = new Pool<T>() {
|
||||
@Override
|
||||
protected T newObject() {
|
||||
try {
|
||||
T coordinator = coordinatorType.newInstance();
|
||||
coordinator.setup(em, cf);
|
||||
return coordinator;
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public T buildCoordinator() {
|
||||
T coordinator = pool.obtain();
|
||||
return coordinator;
|
||||
}
|
||||
|
||||
protected void recycleCoordinator(Coordinator coordinator) {
|
||||
pool.free(coordinatorType.cast(coordinator));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return coordinatorType.getSimpleName();
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package zero1hd.rhythmbullet.entity.coordinator;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.EntityManager;
|
||||
|
||||
public class CoordinatorManager {
|
||||
private EntityManager em;
|
||||
|
||||
public CoordinatorFrame<SlowLeftCoordinator> slowLeft;
|
||||
public CoordinatorFrame<SlowRightCoordinator> slowRight;
|
||||
|
||||
public CoordinatorManager(EntityManager em) {
|
||||
this.em = em;
|
||||
setup();
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
slowLeft = new CoordinatorFrame<>(em, SlowLeftCoordinator.class);
|
||||
slowRight = new CoordinatorFrame<>(em, SlowRightCoordinator.class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package zero1hd.rhythmbullet.entity.coordinator;
|
||||
|
||||
public class SlowLeftCoordinator extends Coordinator {
|
||||
@Override
|
||||
public void coordinate(float delta) {
|
||||
entity.angle -= 32*delta;
|
||||
super.coordinate(delta);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package zero1hd.rhythmbullet.entity.coordinator;
|
||||
|
||||
public class SlowRightCoordinator extends Coordinator {
|
||||
@Override
|
||||
public void coordinate(float delta) {
|
||||
entity.angle += 32*delta;
|
||||
super.coordinate(delta);
|
||||
}
|
||||
}
|
40
old/core/src/zero1hd/rhythmbullet/entity/enemies/Pellet.java
Normal file
40
old/core/src/zero1hd/rhythmbullet/entity/enemies/Pellet.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package zero1hd.rhythmbullet.entity.enemies;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
|
||||
public class Pellet extends Entity implements Poolable {
|
||||
|
||||
@Override
|
||||
public void preInit() {
|
||||
sprite = new Sprite(assets.get("pellet.png", Texture.class));
|
||||
enemy = true;
|
||||
setSize(0.5f, 0.5f);
|
||||
sprite.setColor(0.5f, 1f, 1f, 0.5f);
|
||||
super.preInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(float deg, float speed, int hp) {
|
||||
this.speed = speed;
|
||||
this.angle = deg;
|
||||
super.init(deg, speed, hp);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void collided(Entity entity) {
|
||||
dead = true;
|
||||
super.collided(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
dead = false;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
}
|
68
old/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java
Normal file
68
old/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package zero1hd.rhythmbullet.entity.enemies;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
import zero1hd.rhythmbullet.entity.ally.Laser;
|
||||
|
||||
public class Shard extends Entity {
|
||||
private int hp;
|
||||
private int maxHp;
|
||||
|
||||
@Override
|
||||
public void preInit() {
|
||||
sprite = new Sprite(assets.get("shard.png", Texture.class));
|
||||
setSize(2f, 2f);
|
||||
sprite.setSize(3f, 2f);
|
||||
enemy = true;
|
||||
super.preInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(float deg, float speed, int hp) {
|
||||
this.speed = speed;
|
||||
this.hp = hp;
|
||||
maxHp = hp;
|
||||
this.angle = deg;
|
||||
super.init(deg, speed, hp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
hp = 0;
|
||||
maxHp = 0;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(float delta) {
|
||||
if (hp <= 0) {
|
||||
dead = true;
|
||||
}
|
||||
super.calculate(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch) {
|
||||
sprite.setColor(((float)hp/(float)maxHp), ((float)hp/(float)maxHp), ((float)hp/(float)maxHp), 0.5f);
|
||||
super.draw(batch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collided(Entity entity) {
|
||||
if (entity.getClass() == Laser.class) {
|
||||
hp --;
|
||||
} else {
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getHitZone() {
|
||||
return hitbox;
|
||||
}
|
||||
|
||||
}
|
28
old/core/src/zero1hd/rhythmbullet/game/EntitySpawnInfo.java
Normal file
28
old/core/src/zero1hd/rhythmbullet/game/EntitySpawnInfo.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package zero1hd.rhythmbullet.game;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
import zero1hd.rhythmbullet.entity.EntityFrame;
|
||||
import zero1hd.rhythmbullet.entity.coordinator.Coordinator;
|
||||
import zero1hd.rhythmbullet.entity.coordinator.CoordinatorFrame;
|
||||
|
||||
public class EntitySpawnInfo {
|
||||
private EntityFrame<? extends Entity> entityToSpawn;
|
||||
private CoordinatorFrame<? extends Coordinator> entityCoordinator;
|
||||
public HashMap<String, Float> parameters;
|
||||
|
||||
|
||||
public EntitySpawnInfo(EntityFrame<? extends Entity> entityToSpawn, CoordinatorFrame<? extends Coordinator> coordinator) {
|
||||
this.entityToSpawn = entityToSpawn;
|
||||
parameters = new HashMap<>();
|
||||
}
|
||||
|
||||
public EntityFrame<? extends Entity> getEntityToSpawn() {
|
||||
return entityToSpawn;
|
||||
}
|
||||
|
||||
public CoordinatorFrame<? extends Coordinator> getEntityCoordinator() {
|
||||
return entityCoordinator;
|
||||
}
|
||||
}
|
18
old/core/src/zero1hd/rhythmbullet/game/MapWindowData.java
Normal file
18
old/core/src/zero1hd/rhythmbullet/game/MapWindowData.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package zero1hd.rhythmbullet.game;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class MapWindowData {
|
||||
Array<EntitySpawnInfo> entityDatas;
|
||||
public MapWindowData() {
|
||||
entityDatas = new Array<>(EntitySpawnInfo.class);
|
||||
}
|
||||
|
||||
public void addEntity(EntitySpawnInfo entity) {
|
||||
entityDatas.add(entity);
|
||||
}
|
||||
|
||||
public EntitySpawnInfo[] getArray() {
|
||||
return entityDatas.toArray();
|
||||
}
|
||||
}
|
26
old/core/src/zero1hd/rhythmbullet/game/ScoreManager.java
Normal file
26
old/core/src/zero1hd/rhythmbullet/game/ScoreManager.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package zero1hd.rhythmbullet.game;
|
||||
|
||||
public class ScoreManager {
|
||||
private int score;
|
||||
private boolean different;
|
||||
|
||||
public void setScore(int score) {
|
||||
this.score = score;
|
||||
different = true;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void addScore(int addedScore) {
|
||||
score += addedScore;
|
||||
different = true;
|
||||
}
|
||||
|
||||
public boolean checkDifferent() {
|
||||
boolean current = different;
|
||||
different = false;
|
||||
return current;
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
package zero1hd.rhythmbullet.graphics.shaders;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
|
||||
public class BloomShader implements Disposable {
|
||||
private ShaderProgram gaussianBlurShader;
|
||||
private ShaderProgram brightFilterShader;
|
||||
private ShaderProgram combineShader;
|
||||
private FrameBuffer lightFilterBuffer;
|
||||
private FrameBuffer normalBuffer;
|
||||
private FrameBuffer hBlur, vBlur;
|
||||
private TextureRegion fboRegion;
|
||||
private Batch screenBatch;
|
||||
private ScreenViewport screenViewport;
|
||||
|
||||
public BloomShader(Batch batch) {
|
||||
this.screenBatch = batch;
|
||||
|
||||
Gdx.app.debug("Shader", "Loading glow shaders.");
|
||||
screenViewport = new ScreenViewport();
|
||||
screenViewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
((OrthographicCamera) screenViewport.getCamera()).setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
|
||||
Gdx.app.debug("Shader", "using glow shader");
|
||||
brightFilterShader = new ShaderProgram(Gdx.files.internal("shaders/basic.vsh"), Gdx.files.internal("shaders/bright_filter.fsh"));
|
||||
if (!brightFilterShader.isCompiled()) {
|
||||
Gdx.app.error("Shader failed to compile bright filter shader", brightFilterShader.getLog());
|
||||
System.exit(1);
|
||||
}
|
||||
if (brightFilterShader.getLog().length() != 0) {
|
||||
Gdx.app.error("Shader", brightFilterShader.getLog());
|
||||
}
|
||||
|
||||
gaussianBlurShader = new ShaderProgram(Gdx.files.internal("shaders/basic.vsh"), Gdx.files.internal("shaders/gaussian_blur.fsh"));
|
||||
if (!gaussianBlurShader.isCompiled()) {
|
||||
Gdx.app.error("Shader failed to compile gaussian blur shader", gaussianBlurShader.getLog());
|
||||
System.exit(1);
|
||||
}
|
||||
if (gaussianBlurShader.getLog().length() != 0) {
|
||||
Gdx.app.error("Shader", gaussianBlurShader.getLog());
|
||||
}
|
||||
|
||||
combineShader = new ShaderProgram(Gdx.files.internal("shaders/basic.vsh"), Gdx.files.internal("shaders/combine.fsh"));
|
||||
if (!combineShader.isCompiled()) {
|
||||
Gdx.app.error("Shader failed to compile combination shader", combineShader.getLog());
|
||||
System.exit(1);
|
||||
}
|
||||
if (combineShader.getLog().length() != 0) {
|
||||
Gdx.app.error("Shader", combineShader.getLog());
|
||||
}
|
||||
|
||||
lightFilterBuffer = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
|
||||
normalBuffer = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
|
||||
hBlur = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
|
||||
vBlur = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
|
||||
|
||||
fboRegion = new TextureRegion(normalBuffer.getColorBufferTexture());
|
||||
fboRegion.flip(false, true);
|
||||
|
||||
combineShader.begin();
|
||||
combineShader.setUniformi("u_texture1", 1);
|
||||
combineShader.end();
|
||||
|
||||
gaussianBlurShader.begin();
|
||||
gaussianBlurShader.setUniformf("radius", 1.5f);
|
||||
gaussianBlurShader.setUniformf("resolution", hBlur.getWidth(), vBlur.getHeight());
|
||||
gaussianBlurShader.end();
|
||||
|
||||
vBlur.getColorBufferTexture().bind(1);
|
||||
lightFilterBuffer.getColorBufferTexture().bind(2);
|
||||
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
|
||||
}
|
||||
|
||||
public void begin() {
|
||||
// Begin drawing a normal version of screen
|
||||
normalBuffer.begin();
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public void end(float width, float height) {
|
||||
normalBuffer.end();
|
||||
|
||||
// BEGINNING NORMAL SCREEN RENDER
|
||||
screenViewport.apply();
|
||||
|
||||
// Begin light filtering
|
||||
lightFilterBuffer.begin();
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
fboRegion.setTexture(normalBuffer.getColorBufferTexture());
|
||||
screenBatch.setShader(brightFilterShader);
|
||||
screenBatch.setProjectionMatrix(screenViewport.getCamera().combined);
|
||||
screenBatch.begin(); //SCREEN BATCH STARTS HERE
|
||||
screenBatch.draw(fboRegion, 0, 0, width, height);
|
||||
screenBatch.flush();
|
||||
lightFilterBuffer.end();
|
||||
|
||||
// Horizontal gaussian blur
|
||||
fboRegion.setTexture(lightFilterBuffer.getColorBufferTexture());
|
||||
hBlur.begin();
|
||||
screenBatch.setShader(gaussianBlurShader);
|
||||
gaussianBlurShader.setUniformi("pass", 0);
|
||||
screenBatch.draw(fboRegion, 0f, 0f, width, height);
|
||||
screenBatch.flush();
|
||||
hBlur.end();
|
||||
|
||||
|
||||
// //Vertical gaussian blur
|
||||
fboRegion.setTexture(hBlur.getColorBufferTexture());
|
||||
vBlur.begin();
|
||||
gaussianBlurShader.setUniformi("pass", 1);
|
||||
screenBatch.draw(fboRegion, 0f, 0f, width, height);
|
||||
screenBatch.flush();
|
||||
vBlur.end();
|
||||
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
screenBatch.setShader(combineShader);
|
||||
fboRegion.setTexture(normalBuffer.getColorBufferTexture());
|
||||
screenBatch.draw(fboRegion, 0f, 0f, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
screenBatch.setShader(null);
|
||||
screenBatch.end(); //STAGE BATCH ENDS HERE
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
brightFilterShader.dispose();
|
||||
combineShader.dispose();
|
||||
gaussianBlurShader.dispose();
|
||||
normalBuffer.dispose();
|
||||
lightFilterBuffer.dispose();
|
||||
vBlur.dispose();
|
||||
hBlur.dispose();
|
||||
|
||||
brightFilterShader = null;
|
||||
combineShader = null;
|
||||
gaussianBlurShader = null;
|
||||
normalBuffer = null;
|
||||
lightFilterBuffer = null;
|
||||
vBlur = null;
|
||||
hBlur = null;
|
||||
}
|
||||
}
|
74
old/core/src/zero1hd/rhythmbullet/graphics/ui/Page.java
Normal file
74
old/core/src/zero1hd/rhythmbullet/graphics/ui/Page.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package zero1hd.rhythmbullet.graphics.ui;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.scenes.scene2d.Group;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
|
||||
public class Page extends Group implements Disposable {
|
||||
private Label pageTitle;
|
||||
private int baseXPos, baseYPos;
|
||||
|
||||
public Page(int baseXPos, int baseYPos) {
|
||||
this.baseXPos = baseXPos;
|
||||
this.baseYPos = baseYPos;
|
||||
setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
setTouchable(Touchable.childrenOnly);
|
||||
setToBasePosition();
|
||||
setName(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
public Page(int baseXPos, int baseYPos, String titleText, Skin skin) {
|
||||
this(baseXPos, baseYPos);
|
||||
pageTitle = new Label(titleText, skin, "large-font", skin.getColor("default"));
|
||||
pageTitle.setPosition(18f, getHeight()-pageTitle.getHeight()-15f);
|
||||
addActor(pageTitle);
|
||||
}
|
||||
|
||||
public float getHeightBelowTitle() {
|
||||
return pageTitle.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStage(Stage stage) {
|
||||
if (stage == null) {
|
||||
if (!hasParent()) {
|
||||
dispose();
|
||||
}
|
||||
} else if (!(stage.getViewport() instanceof ScreenViewport)) {
|
||||
throw new IllegalArgumentException("Pages are explicitly for GUIs, and thus should have a 1:1 ratio between pixel and texture size for maximum clarity. This means that the stage should be using a ScreenViewport.");
|
||||
}
|
||||
super.setStage(stage);
|
||||
}
|
||||
|
||||
public void setCameraPositionToPage(Vector3 cameraPosition) {
|
||||
cameraPosition.x = (baseXPos+0.5f) * getWidth();
|
||||
cameraPosition.y = (baseYPos+0.5f) * getHeight();
|
||||
}
|
||||
|
||||
public void setToBasePosition() {
|
||||
setPosition(baseXPos*getWidth(), baseYPos*getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(Group parent) {
|
||||
if (parent == null && getStage() == null) {
|
||||
dispose();
|
||||
}
|
||||
super.setParent(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Gdx.app.debug(getClass().getSimpleName(), "Disposing...");
|
||||
}
|
||||
|
||||
public void simpleDebug(String message) {
|
||||
Gdx.app.debug(getClass().getSimpleName(), message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package zero1hd.rhythmbullet.graphics.ui.components;
|
||||
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
|
||||
|
||||
import zero1hd.rhythmbullet.entity.ally.PolyjetEntity;
|
||||
|
||||
public class HealthBar extends WidgetGroup {
|
||||
Image empty;
|
||||
Image filler;
|
||||
float health;
|
||||
float maxHealth;
|
||||
|
||||
PolyjetEntity pje;
|
||||
public HealthBar(Skin skin, float maxHealth) {
|
||||
super();
|
||||
filler = new Image(skin.getPatch("bar-fill"));
|
||||
addActor(filler);
|
||||
|
||||
empty = new Image(skin.getPatch("bar-empty"));
|
||||
addActor(empty);
|
||||
|
||||
this.maxHealth = maxHealth;
|
||||
|
||||
}
|
||||
|
||||
public void setPolyjetEntity(PolyjetEntity pje) {
|
||||
this.pje = pje;
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
this.health = health;
|
||||
|
||||
filler.addAction(Actions.sizeTo(getWidth(), MathUtils.round((health/maxHealth)*getHeight()), 0.1f));;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta) {
|
||||
if (pje != null) {
|
||||
health = pje.health;
|
||||
}
|
||||
super.act(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(float width, float height) {
|
||||
empty.setSize(width, height);
|
||||
filler.setSize(width, height);
|
||||
super.setSize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidth(float width) {
|
||||
empty.setWidth(width);
|
||||
filler.setWidth(width);
|
||||
super.setWidth(width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeight(float height) {
|
||||
empty.setHeight(height);
|
||||
super.setHeight(height);
|
||||
}
|
||||
|
||||
public float getMaxHealth() {
|
||||
return maxHealth;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
package zero1hd.rhythmbullet.graphics.ui.components;
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.MusicController;
|
||||
|
||||
public class MusicControls extends HorizontalGroup {
|
||||
private ImageButton reverse, forward;
|
||||
private CheckBox shuffle, play;
|
||||
public MusicControls(Skin skin, final MusicController sc) {
|
||||
reverse = new ImageButton(skin, "rewind-button");
|
||||
reverse.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
sc.previous();
|
||||
}
|
||||
});
|
||||
addActor(reverse);
|
||||
|
||||
play = new CheckBox(null, skin, "play-button") {
|
||||
@Override
|
||||
public void act(float delta) {
|
||||
if (sc.hasSongLoaded()) {
|
||||
play.setChecked(sc.isPlaying());
|
||||
} else {
|
||||
play.setChecked(false);
|
||||
}
|
||||
super.act(delta);
|
||||
}
|
||||
};
|
||||
play.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
if (play.isChecked()) {
|
||||
sc.play();
|
||||
} else {
|
||||
sc.pause();
|
||||
}
|
||||
super.clicked(event, x, y);
|
||||
}
|
||||
});
|
||||
addActor(play);
|
||||
|
||||
forward = new ImageButton(skin, "fast-forward-button");
|
||||
forward.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
sc.skip();
|
||||
}
|
||||
});
|
||||
addActor(forward);
|
||||
shuffle = new CheckBox(null, skin, "shuffle-button") {
|
||||
@Override
|
||||
public void act(float delta) {
|
||||
shuffle.setChecked(sc.isShuffle());
|
||||
super.act(delta);
|
||||
}
|
||||
};
|
||||
shuffle.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
if (shuffle.isChecked()) {
|
||||
sc.setShuffle(true);
|
||||
} else {
|
||||
sc.setShuffle(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
addActor(shuffle);
|
||||
space(15);
|
||||
|
||||
setSize(getMinWidth(), getMinHeight());
|
||||
}
|
||||
}
|
@@ -0,0 +1,205 @@
|
||||
package zero1hd.rhythmbullet.graphics.ui.components;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Widget;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
||||
|
||||
public class ScrollingText extends Widget {
|
||||
Rectangle scissors = new Rectangle();
|
||||
Rectangle clipBounds = new Rectangle();
|
||||
|
||||
GlyphLayout gLayout;
|
||||
String text1;
|
||||
String text2;
|
||||
BitmapFont font;
|
||||
private float textHeight;
|
||||
private float text1Width;
|
||||
private float text2Width;
|
||||
|
||||
private boolean dupFirstText;
|
||||
private boolean scrollOnHover;
|
||||
private boolean scroll;
|
||||
|
||||
private float text1Offset, text2Offset;
|
||||
|
||||
private NinePatch background;
|
||||
|
||||
private Vector2 coords;
|
||||
|
||||
private float targetDelta;
|
||||
|
||||
public ScrollingText(String text, String text2, Skin skin, boolean scrollOnHover, boolean useBackground, float targetDelta) {
|
||||
super();
|
||||
font = skin.getFont("default-font");
|
||||
init(text, text2, skin, scrollOnHover, useBackground);
|
||||
this.targetDelta = targetDelta;
|
||||
}
|
||||
|
||||
public ScrollingText(String text, String text2, Skin skin, String fontName, Color color, boolean scrollOnHover, boolean useBackground) {
|
||||
super();
|
||||
font = skin.getFont(fontName);
|
||||
font.setColor(color);
|
||||
init(text, text2, skin, scrollOnHover, useBackground);
|
||||
}
|
||||
|
||||
private void init(String text1, String text2, Skin skin, boolean scrollOnHover, boolean useBackground) {
|
||||
setName(text1);
|
||||
if (useBackground) {
|
||||
this.background = skin.getPatch("side-bars");
|
||||
}
|
||||
|
||||
this.scrollOnHover = scrollOnHover;
|
||||
|
||||
coords = new Vector2();
|
||||
addListener(new ClickListener() {
|
||||
@Override
|
||||
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
||||
scroll = true;
|
||||
super.enter(event, x, y, pointer, fromActor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
|
||||
scroll = false;
|
||||
super.exit(event, x, y, pointer, toActor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
}
|
||||
});
|
||||
|
||||
setText(text1, text2);
|
||||
layout();
|
||||
}
|
||||
|
||||
public float getFontHeight() {
|
||||
return textHeight;
|
||||
}
|
||||
|
||||
public float getFontWidth() {
|
||||
return text1Width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layout() {
|
||||
super.layout();
|
||||
|
||||
if (getHeight() < (textHeight+4)) {
|
||||
setHeight(textHeight + 4);
|
||||
}
|
||||
clipBounds.setSize(getWidth()-2, getHeight()*1.5f);
|
||||
|
||||
text2Offset = clipBounds.getWidth();
|
||||
if (text1Width < clipBounds.getWidth()) {
|
||||
text1Offset = (clipBounds.getWidth()-text1Width)/2f;
|
||||
}
|
||||
}
|
||||
|
||||
public void scroll(float delta) {
|
||||
if (text1Offset >= -text1Width) {
|
||||
text1Offset -= 60*targetDelta;
|
||||
if ((text1Offset < - Math.abs((text1Width - clipBounds.getWidth())) - 50) || text2Offset != clipBounds.getWidth()) {
|
||||
text2Offset -= 60*targetDelta;
|
||||
if (text2Offset <= -text2Width) {
|
||||
text2Offset = clipBounds.getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
text2Offset -= 60*targetDelta;
|
||||
if (text2Offset < - Math.abs((text2Width - clipBounds.getWidth())) - 50) {
|
||||
text1Offset = clipBounds.getWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta) {
|
||||
clipBounds.setSize(getWidth()-2, getHeight()*1.5f);
|
||||
if (dupFirstText) {
|
||||
if (text1Width > clipBounds.getWidth()) {
|
||||
if (scrollOnHover) {
|
||||
if (scroll || text1Offset < 0 || text1Offset > 2) {
|
||||
scroll(delta);
|
||||
}
|
||||
} else {
|
||||
scroll(delta);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (text1Width + text2Width > clipBounds.getWidth()) {
|
||||
if (scrollOnHover) {
|
||||
if (scroll || text1Offset < 0 || text1Offset > 2) {
|
||||
scroll(delta);
|
||||
}
|
||||
} else {
|
||||
scroll(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.act(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float parentAlpha) {
|
||||
if (background != null) {
|
||||
background.draw(batch, getX(), getY(), getWidth(), getHeight());
|
||||
}
|
||||
coords.x = getX();
|
||||
coords.y = getY();
|
||||
|
||||
clipBounds.setX(coords.x+1);
|
||||
clipBounds.setY(coords.y - 0.5f*getHeight());
|
||||
|
||||
getStage().calculateScissors(clipBounds, scissors);
|
||||
batch.flush();
|
||||
if (ScissorStack.pushScissors(scissors)) {
|
||||
font.draw(batch, text1, coords.x + text1Offset, coords.y + getFontHeight() + 4);
|
||||
font.draw(batch, text2, coords.x + text2Offset, coords.y + getFontHeight() + 4);
|
||||
batch.flush();
|
||||
ScissorStack.popScissors();
|
||||
}
|
||||
|
||||
super.draw(batch, parentAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinHeight() {
|
||||
return textHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the two strings that will be scrolling.
|
||||
* @param text1 cannot be null.
|
||||
* @param text2 can be null.
|
||||
*/
|
||||
public void setText(String text1, String text2) {
|
||||
this.text1 = text1;
|
||||
gLayout = new GlyphLayout(font, text1);
|
||||
text1Width = gLayout.width;
|
||||
textHeight = gLayout.height;
|
||||
|
||||
if (text2 != null) {
|
||||
this.text2 = text2;
|
||||
gLayout = new GlyphLayout(font, text2);
|
||||
text2Width = gLayout.width;
|
||||
} else {
|
||||
dupFirstText = true;
|
||||
this.text2 = text1;
|
||||
this.text2Width = text1Width;
|
||||
}
|
||||
|
||||
layout();
|
||||
}
|
||||
}
|
45
old/core/src/zero1hd/rhythmbullet/util/AssetPack.java
Normal file
45
old/core/src/zero1hd/rhythmbullet/util/AssetPack.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public interface AssetPack extends Disposable {
|
||||
|
||||
/**
|
||||
* Called right after the game instance is created and passed to LWJGL. This method is called once for you to instantiate things for later use but require Libgdx functions.
|
||||
*/
|
||||
public void initiate();
|
||||
|
||||
/**
|
||||
* Game manager calls this when it needs to load textures.
|
||||
*/
|
||||
public void queueTextures(AssetManager assetManager);
|
||||
|
||||
/**
|
||||
* Game manager calls this when it needs to load sound effects.
|
||||
*/
|
||||
public void queueSFX(AssetManager assetManager);
|
||||
|
||||
/**
|
||||
* Game manager calls this when it needs to load particles.
|
||||
*/
|
||||
public void queueParticles(AssetManager assetManager);
|
||||
|
||||
/**
|
||||
* Game manager calls when it needs to load particles. Usually called after textures are loaded since the skin requires the other assets.
|
||||
* @param skin the skin object to set up.
|
||||
*/
|
||||
public void setupSkin(Skin skin);
|
||||
|
||||
/**
|
||||
* Game manager calls when it needs the fonts to be generated. Usually called right before setting up the skin itself since items in the skin need fonts.
|
||||
*/
|
||||
public void generateFonts(Skin skin);
|
||||
|
||||
/**
|
||||
* Game manager calls this once all assets are loaded. This function should be used to make some in-code adjustments to assets that will be consistent throughout the game for that run.
|
||||
* @param assetManager gives you access to the assets to modify.
|
||||
*/
|
||||
public void complete(AssetManager assetManager);
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
public class GenericFileTypeHandler implements FileHandleResolver {
|
||||
private final FileHandleResolver resolver;
|
||||
|
||||
public GenericFileTypeHandler(FileHandleResolver fileResolver) {
|
||||
resolver = fileResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle resolve(String fileName) {
|
||||
|
||||
if (fileName.endsWith(".p")) {
|
||||
return resolver.resolve("particles/" +fileName);
|
||||
} else if (fileName.endsWith(".ogg")) {
|
||||
return resolver.resolve("sounds/" + fileName);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
20
old/core/src/zero1hd/rhythmbullet/util/InitialScreen.java
Normal file
20
old/core/src/zero1hd/rhythmbullet/util/InitialScreen.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
import com.badlogic.gdx.Screen;
|
||||
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
|
||||
public interface InitialScreen extends ResizeReadyScreen {
|
||||
/**
|
||||
* Called when everythings loaded and ready to advance.
|
||||
* Screen should be created on platform.
|
||||
* @param gameManager the game manager.
|
||||
* @return the screen that is created.
|
||||
*/
|
||||
public Screen advance(RhythmBullet gameManager);
|
||||
|
||||
/**
|
||||
* Immediately called after the LibGDX instance has been instantiated.
|
||||
*/
|
||||
public void init();
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
import com.badlogic.gdx.Screen;
|
||||
|
||||
public interface ResizeReadyScreen extends Screen {
|
||||
/**
|
||||
* called before assets are cleared from memory.
|
||||
*/
|
||||
public void preAssetLoad();
|
||||
|
||||
/**
|
||||
* called after transition completes and assets reloaded.
|
||||
*/
|
||||
public void postAssetLoad();
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
|
||||
import com.badlogic.gdx.assets.loaders.resolvers.ResolutionFileResolver.Resolution;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
|
||||
public class RoundingResolutionHandler implements FileHandleResolver {
|
||||
private final Resolution[] descriptors;
|
||||
private final FileHandleResolver resolver;
|
||||
private boolean silent = true;
|
||||
private int width, height;
|
||||
public RoundingResolutionHandler(FileHandleResolver fileResolver, Resolution... descriptors) {
|
||||
if (descriptors.length == 0) throw new IllegalArgumentException("At least one Resolution needs to be supplied.");
|
||||
this.descriptors = descriptors;
|
||||
this.resolver = fileResolver;
|
||||
}
|
||||
|
||||
public void setResolution(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public void resetResolution() {
|
||||
width = Gdx.graphics.getWidth();
|
||||
height = Gdx.graphics.getHeight();
|
||||
}
|
||||
|
||||
public Resolution chooseRounded(Resolution... descriptors) {
|
||||
Resolution best = descriptors[0];
|
||||
|
||||
int leastDifference = -1;
|
||||
|
||||
int w = width, h = height;
|
||||
|
||||
if (w > h) {
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
int currentDiff = h - descriptors[i].portraitHeight;
|
||||
|
||||
if (currentDiff < 0) {
|
||||
currentDiff = currentDiff*-1;
|
||||
}
|
||||
|
||||
if ((currentDiff < leastDifference) || leastDifference == -1) {
|
||||
best = descriptors[i];
|
||||
leastDifference = currentDiff;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
int currentDiff = w - descriptors[i].portraitWidth;
|
||||
|
||||
if (currentDiff < 0) {
|
||||
currentDiff = currentDiff*-1;
|
||||
}
|
||||
|
||||
if (currentDiff < leastDifference || leastDifference == -1) {
|
||||
best = descriptors[i];
|
||||
leastDifference = currentDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle resolve(String fileName) {
|
||||
Resolution bestRes = chooseRounded(descriptors);
|
||||
if (!silent) {
|
||||
Gdx.app.debug("RResolution Handler", "Finding best match for resolution: " + width + "x" + height + " for file: " + fileName);
|
||||
Gdx.app.debug("RResolution Handler", "Selected folder: " + bestRes.folder);
|
||||
}
|
||||
FileHandle resSpecificFile = resolver.resolve(bestRes.folder + "/" + fileName);
|
||||
if (!resSpecificFile.exists()) resSpecificFile = resolver.resolve(fileName);
|
||||
return resSpecificFile;
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package zero1hd.rhythmbullet.util;
|
||||
|
||||
public interface ScreenConfiguration {
|
||||
public void setFramesPerSecond(int fps);
|
||||
|
||||
public int getTargetFramesPerSecond();
|
||||
|
||||
/**
|
||||
* @param useVsync whether or not to use vSync.
|
||||
*/
|
||||
public void setVsync(boolean useVsync);
|
||||
|
||||
public boolean getVsync();
|
||||
|
||||
public int getScreenWidth();
|
||||
|
||||
public int getScreenHeight();
|
||||
|
||||
public int getWindowPosX();
|
||||
|
||||
public int getWindowPosY();
|
||||
|
||||
public void setWindowLocationX(int x);
|
||||
|
||||
public void setWindowLocationY(int y);
|
||||
|
||||
public void setWindowLocation(int x, int y);
|
||||
|
||||
public void queueBorderless(boolean borderless);
|
||||
}
|
Reference in New Issue
Block a user