add gradle
This commit is contained in:
parent
bb6ebb0be8
commit
4e51e18bdc
3033 changed files with 470 additions and 0 deletions
3406
client/src/main/java/client/Client.java
Executable file
3406
client/src/main/java/client/Client.java
Executable file
File diff suppressed because it is too large
Load diff
258
client/src/main/java/client/audio/AudioInterface.java
Normal file
258
client/src/main/java/client/audio/AudioInterface.java
Normal file
|
@ -0,0 +1,258 @@
|
|||
package client.audio;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioFormat.Encoding;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine.Info;
|
||||
|
||||
import common.collect.Lists;
|
||||
import common.log.Log;
|
||||
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
public class AudioInterface implements Runnable {
|
||||
private static class Channel {
|
||||
short[] buffer;
|
||||
int pos;
|
||||
int level;
|
||||
int type;
|
||||
boolean loop;
|
||||
boolean run;
|
||||
boolean load;
|
||||
}
|
||||
|
||||
private static class Command {
|
||||
Object buffer;
|
||||
Cmd command;
|
||||
short address;
|
||||
int param;
|
||||
}
|
||||
|
||||
private static enum Cmd {
|
||||
STOP,
|
||||
QUERY,
|
||||
VOLUME,
|
||||
PLAY,
|
||||
BREAK,
|
||||
LEVEL
|
||||
};
|
||||
|
||||
private final int blocksize;
|
||||
private final int devbufsize;
|
||||
private final byte[] buffer;
|
||||
|
||||
private final Thread thread;
|
||||
private final List<Command> cmds = Lists.newArrayList();
|
||||
private final short[] volumes = new short[Volume.values().length];
|
||||
private final Channel[] channels = new Channel[32];
|
||||
|
||||
private SourceDataLine line;
|
||||
private int smppos;
|
||||
private long peak = 32767L;
|
||||
private boolean opened;
|
||||
private boolean waiting;
|
||||
|
||||
private void push(short data) {
|
||||
for(int z = 0; z < 2 * 2; z++) {
|
||||
this.buffer[this.smppos * 2 * 2 + z] = (byte)((data >> ((z & 1) * 8)) & 0xff);
|
||||
}
|
||||
this.smppos++;
|
||||
if(this.smppos == this.blocksize) {
|
||||
this.write(this.buffer, this.blocksize);
|
||||
this.smppos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void write(byte[] data, int samples) {
|
||||
if(this.line == null)
|
||||
return;
|
||||
int rc;
|
||||
int avail;
|
||||
int channels = 2;
|
||||
int offset = 0;
|
||||
samples *= 2 * 2;
|
||||
int block = this.blocksize * 2 * 2;
|
||||
while(samples > 0) {
|
||||
block = samples < block ? samples : block;
|
||||
avail = this.line.available();
|
||||
rc = this.line.write(data, offset, avail < block ? avail : block);
|
||||
// this.line.drain();
|
||||
if(rc > 0) {
|
||||
offset += rc;
|
||||
samples -= rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private short generate() {
|
||||
long mix = 0;
|
||||
for(int z = 0; z < this.channels.length; z++) {
|
||||
Channel ch = this.channels[z];
|
||||
if(ch.run) {
|
||||
mix += (long)ch.buffer[ch.pos] * (long)ch.level * (((long)this.volumes[ch.type] * (long)this.volumes[0]) / 32767);
|
||||
if(++ch.pos >= ch.buffer.length) {
|
||||
ch.pos = 0;
|
||||
if(!ch.loop)
|
||||
ch.run = ch.load = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mix /= 32767L * 32767L;
|
||||
long amp = Math.abs(mix);
|
||||
if(amp > 32767L)
|
||||
this.peak = Math.max(this.peak, amp);
|
||||
else if(this.peak > 32767L)
|
||||
this.peak = Math.max(this.peak - 3L, 32767L);
|
||||
return (short)((mix * 32767L) / this.peak);
|
||||
}
|
||||
|
||||
private void dispatch(Object buf, Cmd op, short addr, int param) {
|
||||
switch(op) {
|
||||
case VOLUME:
|
||||
this.volumes[addr] = (short)param;
|
||||
break;
|
||||
case PLAY:
|
||||
if(buf != null) {
|
||||
this.channels[addr].buffer = (short[])buf;
|
||||
this.channels[addr].pos = 0;
|
||||
this.channels[addr].type = param & 0xff;
|
||||
this.channels[addr].run = this.channels[addr].load = true;
|
||||
this.channels[addr].loop = (param & 0x100) != 0;
|
||||
}
|
||||
break;
|
||||
case BREAK:
|
||||
this.channels[addr].run = this.channels[addr].load = false;
|
||||
break;
|
||||
case LEVEL:
|
||||
this.channels[addr].level = param;
|
||||
break;
|
||||
case QUERY:
|
||||
this.waiting = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
AudioFormat format = new AudioFormat(Encoding.PCM_SIGNED, 48000, 16, 2, 2 * 2, 48000, false);
|
||||
Info info = new Info(SourceDataLine.class, format, this.devbufsize == 0 ? AudioSystem.NOT_SPECIFIED : this.devbufsize);
|
||||
try {
|
||||
this.line = (SourceDataLine)AudioSystem.getLine(info);
|
||||
this.line.open(format, this.devbufsize == 0 ? AudioSystem.NOT_SPECIFIED : this.devbufsize);
|
||||
}
|
||||
catch(Exception e) {
|
||||
this.line = null;
|
||||
Log.SOUND.error(e, "Konnte Audiogerät nicht öffnen");
|
||||
}
|
||||
if(this.line != null)
|
||||
this.line.start();
|
||||
this.opened = this.line != null;
|
||||
long sampletime = 1000000000L / 48000L; // * (long)this.blocksize;
|
||||
boolean running = true;
|
||||
long elapsed = 0;
|
||||
while(running) {
|
||||
synchronized(this.cmds) {
|
||||
while(!this.cmds.isEmpty()) {
|
||||
Command cmd = this.cmds.remove(0);
|
||||
if(cmd.command == Cmd.STOP)
|
||||
running = false;
|
||||
else
|
||||
this.dispatch(cmd.buffer, cmd.command, cmd.address, cmd.param);
|
||||
}
|
||||
}
|
||||
elapsed += 1000L;
|
||||
while((elapsed >= sampletime)) {
|
||||
this.push(this.generate());
|
||||
elapsed -= sampletime;
|
||||
}
|
||||
}
|
||||
if(this.smppos != 0)
|
||||
this.write(this.buffer, this.smppos);
|
||||
if(this.line != null) {
|
||||
this.line.drain();
|
||||
this.line.stop();
|
||||
this.line.close();
|
||||
}
|
||||
this.line = null;
|
||||
this.waiting = false;
|
||||
}
|
||||
|
||||
private void instruct(Object buf, Cmd op, int addr, int param) {
|
||||
if(this.thread == null)
|
||||
return;
|
||||
Command cmd = new Command();
|
||||
cmd.command = op;
|
||||
cmd.address = (short)addr;
|
||||
cmd.param = param;
|
||||
cmd.buffer = buf;
|
||||
synchronized(this.cmds) {
|
||||
this.cmds.add(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public AudioInterface(int frames, int bufsize, boolean disabled) {
|
||||
this.blocksize = frames;
|
||||
this.devbufsize = bufsize;
|
||||
this.buffer = new byte[this.blocksize * 2 * 2];
|
||||
this.thread = disabled ? null : new Thread(this, "Audio Thread");
|
||||
for(int z = 0; z < this.channels.length; z++) {
|
||||
this.channels[z] = new Channel();
|
||||
}
|
||||
Arrays.fill(this.volumes, (short)32767);
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if(this.thread == null)
|
||||
return false;
|
||||
this.thread.start();
|
||||
this.waiting = true;
|
||||
this.instruct(null, Cmd.QUERY, 0, 0);
|
||||
while(this.waiting) {
|
||||
try {
|
||||
Thread.sleep(1L);
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
return this.opened;
|
||||
}
|
||||
|
||||
public boolean end() {
|
||||
if(this.thread == null)
|
||||
return false;
|
||||
this.waiting = true;
|
||||
this.instruct(null, Cmd.STOP, 0, 0);
|
||||
while(this.waiting) {
|
||||
try {
|
||||
Thread.sleep(1L);
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
}
|
||||
}
|
||||
return this.opened;
|
||||
}
|
||||
|
||||
public void alSetVolume(Volume channel, short volume) {
|
||||
this.instruct(null, Cmd.VOLUME, channel.ordinal(), volume);
|
||||
}
|
||||
|
||||
public void alSourcePlay(int source, short[] buffer, Volume channel, boolean loop) {
|
||||
this.channels[source].load = true;
|
||||
this.instruct(buffer, Cmd.PLAY, source, channel.ordinal() | (loop ? 0x100 : 0));
|
||||
}
|
||||
|
||||
public void alSourceStop(int source) {
|
||||
this.channels[source].load = false;
|
||||
this.instruct(null, Cmd.BREAK, source, 0);
|
||||
}
|
||||
|
||||
public boolean alPlaying(int source) {
|
||||
return this.channels[source].load;
|
||||
}
|
||||
|
||||
public void alGain(int source, float value) {
|
||||
this.instruct(null, Cmd.LEVEL, source, (int)(value * 32767.0f));
|
||||
}
|
||||
}
|
478
client/src/main/java/client/audio/CodecJOrbis.java
Normal file
478
client/src/main/java/client/audio/CodecJOrbis.java
Normal file
|
@ -0,0 +1,478 @@
|
|||
package client.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import client.audio.jogg.Packet;
|
||||
import client.audio.jogg.Page;
|
||||
import client.audio.jogg.StreamState;
|
||||
import client.audio.jogg.SyncState;
|
||||
import client.audio.jorbis.Block;
|
||||
import client.audio.jorbis.Comment;
|
||||
import client.audio.jorbis.DspState;
|
||||
import client.audio.jorbis.Info;
|
||||
|
||||
public class CodecJOrbis
|
||||
{
|
||||
private boolean endOfStream = false;
|
||||
private byte[] buffer = null;
|
||||
private int bufferSize;
|
||||
private int count = 0;
|
||||
private int index = 0;
|
||||
private short[] convertedBuffer = null;
|
||||
private float[][][] pcmInfo;
|
||||
private int[] pcmIndex;
|
||||
private Packet joggPacket = new Packet();
|
||||
private Page joggPage = new Page();
|
||||
private StreamState joggStreamState = new StreamState();
|
||||
private SyncState joggSyncState = new SyncState();
|
||||
private DspState jorbisDspState = new DspState();
|
||||
private Block jorbisBlock = new Block(jorbisDspState);
|
||||
private Comment jorbisComment = new Comment();
|
||||
private Info jorbisInfo = new Info();
|
||||
|
||||
private CodecJOrbis() {
|
||||
}
|
||||
|
||||
private boolean initialize( InputStream in ) throws IOException
|
||||
{
|
||||
// initialized( SET, false );
|
||||
|
||||
if( joggStreamState != null )
|
||||
joggStreamState.clear();
|
||||
if( jorbisBlock != null )
|
||||
jorbisBlock.clear();
|
||||
if( jorbisDspState != null )
|
||||
jorbisDspState.clear();
|
||||
if( jorbisInfo != null )
|
||||
jorbisInfo.clear();
|
||||
if( joggSyncState != null )
|
||||
joggSyncState.clear();
|
||||
|
||||
// this.url = url;
|
||||
//this.bufferSize = SoundSystemConfig.getStreamingBufferSize() / 2;
|
||||
this.bufferSize = 4096*2;
|
||||
|
||||
buffer = null;
|
||||
count = 0;
|
||||
index = 0;
|
||||
|
||||
joggStreamState = new StreamState();
|
||||
jorbisBlock = new Block(jorbisDspState);
|
||||
jorbisDspState = new DspState();
|
||||
jorbisInfo = new Info();
|
||||
joggSyncState = new SyncState();
|
||||
|
||||
// URLConnection urlConnection = null;
|
||||
// try
|
||||
// {
|
||||
// urlConnection = url.openConnection();
|
||||
// }
|
||||
// catch( UnknownServiceException use )
|
||||
// {
|
||||
// errorMessage( "Unable to create a UrlConnection in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( use );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// catch( IOException ioe )
|
||||
// {
|
||||
// errorMessage( "Unable to create a UrlConnection in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( ioe );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// if( urlConnection != null )
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// inputStream = in; // urlConnection.getInputStream();
|
||||
// }
|
||||
// catch( IOException ioe )
|
||||
// {
|
||||
// errorMessage( "Unable to acquire inputstream in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( ioe );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// endOfStream( SET, false );
|
||||
|
||||
joggSyncState.init();
|
||||
joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
|
||||
try
|
||||
{
|
||||
if( !readHeader(in) )
|
||||
{
|
||||
errorMessage( "Error reading the header" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch( IOException ioe )
|
||||
{
|
||||
errorMessage( "Error reading the header" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// convertedBufferSize = bufferSize * 2;
|
||||
|
||||
jorbisDspState.synthesis_init( jorbisInfo );
|
||||
jorbisBlock.init( jorbisDspState );
|
||||
|
||||
if(jorbisInfo.channels != 1) {
|
||||
errorMessage("Stream muss genau einen Kanal besitzen");
|
||||
return false;
|
||||
}
|
||||
if(jorbisInfo.rate != 48000) {
|
||||
errorMessage("Stream muss eine Samplerate von 48000 Hz besitzen");
|
||||
return false;
|
||||
}
|
||||
|
||||
// audioFormat = ;
|
||||
pcmInfo = new float[1][][];
|
||||
pcmIndex = new int[ 1 ];
|
||||
|
||||
// initialized( SET, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static short[] readAll(InputStream in) throws IOException
|
||||
{
|
||||
CodecJOrbis codec = new CodecJOrbis();
|
||||
if(!codec.initialize(in))
|
||||
return null;
|
||||
short[] returnBuffer = null;
|
||||
|
||||
while( !codec.endOfStream )
|
||||
{
|
||||
if( returnBuffer == null )
|
||||
returnBuffer = codec.readBytes(in);
|
||||
else
|
||||
returnBuffer = appendByteArrays( returnBuffer, codec.readBytes(in) );
|
||||
}
|
||||
|
||||
// if( returnBuffer == null )
|
||||
// return null;
|
||||
// this.cleanup();
|
||||
return returnBuffer; // new SoundBuffer( returnBuffer, audioFormat );
|
||||
}
|
||||
|
||||
private boolean readHeader(InputStream inputStream) throws IOException
|
||||
{
|
||||
// Update up JOrbis internal buffer:
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
// Read in a buffer of data:
|
||||
int bytes = inputStream.read( joggSyncState.data, index, bufferSize );
|
||||
if( bytes < 0 )
|
||||
bytes = 0;
|
||||
// Let JOrbis know how many bytes we got:
|
||||
joggSyncState.wrote( bytes );
|
||||
|
||||
if( joggSyncState.pageout( joggPage ) != 1 )
|
||||
{
|
||||
// Finished reading the entire file:
|
||||
if( bytes < bufferSize )
|
||||
return true;
|
||||
|
||||
errorMessage( "Ogg header not recognized in method 'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize JOrbis:
|
||||
joggStreamState.init( joggPage.serialno() );
|
||||
|
||||
jorbisInfo.init();
|
||||
jorbisComment.init();
|
||||
if( joggStreamState.pagein( joggPage ) < 0 )
|
||||
{
|
||||
errorMessage( "Problem with first Ogg header page in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( joggStreamState.packetout( joggPacket ) != 1 )
|
||||
{
|
||||
errorMessage( "Problem with first Ogg header packet in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( jorbisInfo.synthesis_headerin( jorbisComment, joggPacket ) < 0 )
|
||||
{
|
||||
errorMessage( "File does not contain Vorbis header in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while( i < 2 )
|
||||
{
|
||||
while( i < 2 )
|
||||
{
|
||||
int result = joggSyncState.pageout( joggPage );
|
||||
if( result == 0 )
|
||||
break;
|
||||
if( result == 1 )
|
||||
{
|
||||
joggStreamState.pagein( joggPage );
|
||||
while( i < 2 )
|
||||
{
|
||||
result = joggStreamState.packetout( joggPacket );
|
||||
if( result == 0 )
|
||||
break;
|
||||
|
||||
if( result == -1 )
|
||||
{
|
||||
errorMessage( "Secondary Ogg header corrupt in " +
|
||||
"method 'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
jorbisInfo.synthesis_headerin( jorbisComment,
|
||||
joggPacket );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
bytes = inputStream.read( joggSyncState.data, index, bufferSize );
|
||||
if( bytes < 0 )
|
||||
bytes = 0;
|
||||
if( bytes == 0 && i < 2 )
|
||||
{
|
||||
errorMessage( "End of file reached before finished reading" +
|
||||
"Ogg header in method 'readHeader'" );
|
||||
return false;
|
||||
}
|
||||
|
||||
joggSyncState.wrote( bytes );
|
||||
}
|
||||
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private short[] readBytes(InputStream inputStream) throws IOException
|
||||
{
|
||||
// if( !initialized( GET, XXX ) )
|
||||
// return null;
|
||||
|
||||
if( endOfStream )
|
||||
return null;
|
||||
|
||||
if( convertedBuffer == null )
|
||||
convertedBuffer = new short[ bufferSize ];
|
||||
short[] returnBuffer = null;
|
||||
|
||||
float[][] pcmf;
|
||||
int samples, bout, /* ptr, */ mono, val, i, j;
|
||||
|
||||
switch( joggSyncState.pageout( joggPage ) )
|
||||
{
|
||||
case( 0 ):
|
||||
case( -1 ):
|
||||
break;
|
||||
default:
|
||||
{
|
||||
joggStreamState.pagein( joggPage );
|
||||
if( joggPage.granulepos() == 0 )
|
||||
{
|
||||
endOfStream = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
processPackets: while( true )
|
||||
{
|
||||
switch( joggStreamState.packetout( joggPacket ) )
|
||||
{
|
||||
case( 0 ):
|
||||
break processPackets;
|
||||
case( -1 ):
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if( jorbisBlock.synthesis( joggPacket ) == 0 )
|
||||
jorbisDspState.synthesis_blockin( jorbisBlock );
|
||||
|
||||
while( ( samples=jorbisDspState.synthesis_pcmout(
|
||||
pcmInfo, pcmIndex ) ) > 0 )
|
||||
{
|
||||
pcmf = pcmInfo[0];
|
||||
bout = ( samples < bufferSize ?
|
||||
samples : bufferSize );
|
||||
// for( i = 0; i < jorbisInfo.channels; i++ )
|
||||
// {
|
||||
// ptr = 0; // i * 2;
|
||||
mono = pcmIndex[0];
|
||||
for( j = 0; j < bout; j++ )
|
||||
{
|
||||
val = (int) ( pcmf[0][mono + j] *
|
||||
32767. );
|
||||
if( val > 32767 )
|
||||
val = 32767;
|
||||
if( val < -32768 )
|
||||
val = -32768;
|
||||
if( val < 0 )
|
||||
val = val | 0x8000;
|
||||
convertedBuffer[j] = (short)val;
|
||||
// convertedBuffer[ptr] = (byte) (val);
|
||||
// convertedBuffer[ptr+1] =
|
||||
// (byte) (val>>>8);
|
||||
// ptr += 2 * (jorbisInfo.channels);
|
||||
}
|
||||
// }
|
||||
jorbisDspState.synthesis_read( bout );
|
||||
|
||||
returnBuffer = appendByteArrays( returnBuffer,
|
||||
convertedBuffer,
|
||||
bout );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( joggPage.eos() != 0 )
|
||||
endOfStream = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !endOfStream )
|
||||
{
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
// try
|
||||
// {
|
||||
count = inputStream.read( buffer, index, bufferSize );
|
||||
// }
|
||||
// catch( Exception e )
|
||||
// {
|
||||
// printStackTrace( e );
|
||||
// return null;
|
||||
// }
|
||||
if( count == -1 )
|
||||
return returnBuffer;
|
||||
|
||||
joggSyncState.wrote( count );
|
||||
if( count==0 )
|
||||
endOfStream = true;
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with the second array appended to the end of the first
|
||||
* array.
|
||||
* @param arrayOne The first array.
|
||||
* @param arrayTwo The second array.
|
||||
* @param arrayTwoBytes The number of bytes to append from the second array.
|
||||
* @return Byte array containing information from both arrays.
|
||||
*/
|
||||
private static short[] appendByteArrays( short[] arrayOne, short[] arrayTwo,
|
||||
int arrayTwoBytes )
|
||||
{
|
||||
short[] newArray;
|
||||
int bytes = arrayTwoBytes;
|
||||
|
||||
// Make sure we aren't trying to append more than is there:
|
||||
if( arrayTwo == null || arrayTwo.length == 0 )
|
||||
bytes = 0;
|
||||
else if( arrayTwo.length < arrayTwoBytes )
|
||||
bytes = arrayTwo.length;
|
||||
|
||||
if( arrayOne == null && (arrayTwo == null || bytes <= 0) )
|
||||
{
|
||||
// no data, just return
|
||||
return null;
|
||||
}
|
||||
else if( arrayOne == null )
|
||||
{
|
||||
// create the new array, same length as arrayTwo:
|
||||
newArray = new short[ bytes ];
|
||||
// fill the new array with the contents of arrayTwo:
|
||||
System.arraycopy( arrayTwo, 0, newArray, 0, bytes );
|
||||
arrayTwo = null;
|
||||
}
|
||||
else if( arrayTwo == null || bytes <= 0 )
|
||||
{
|
||||
// create the new array, same length as arrayOne:
|
||||
newArray = new short[ arrayOne.length ];
|
||||
// fill the new array with the contents of arrayOne:
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
arrayOne = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the new array large enough to hold both arrays:
|
||||
newArray = new short[ arrayOne.length + bytes ];
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
// fill the new array with the contents of both arrays:
|
||||
System.arraycopy( arrayTwo, 0, newArray, arrayOne.length,
|
||||
bytes );
|
||||
arrayOne = null;
|
||||
arrayTwo = null;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with the second array appended to the end of the first
|
||||
* array.
|
||||
* @param arrayOne The first array.
|
||||
* @param arrayTwo The second array.
|
||||
* @return Byte array containing information from both arrays.
|
||||
*/
|
||||
private static short[] appendByteArrays( short[] arrayOne, short[] arrayTwo )
|
||||
{
|
||||
short[] newArray;
|
||||
if( arrayOne == null && arrayTwo == null )
|
||||
{
|
||||
// no data, just return
|
||||
return null;
|
||||
}
|
||||
else if( arrayOne == null )
|
||||
{
|
||||
// create the new array, same length as arrayTwo:
|
||||
newArray = new short[ arrayTwo.length ];
|
||||
// fill the new array with the contents of arrayTwo:
|
||||
System.arraycopy( arrayTwo, 0, newArray, 0, arrayTwo.length );
|
||||
arrayTwo = null;
|
||||
}
|
||||
else if( arrayTwo == null )
|
||||
{
|
||||
// create the new array, same length as arrayOne:
|
||||
newArray = new short[ arrayOne.length ];
|
||||
// fill the new array with the contents of arrayOne:
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
arrayOne = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the new array large enough to hold both arrays:
|
||||
newArray = new short[ arrayOne.length + arrayTwo.length ];
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
// fill the new array with the contents of both arrays:
|
||||
System.arraycopy( arrayTwo, 0, newArray, arrayOne.length,
|
||||
arrayTwo.length );
|
||||
arrayOne = null;
|
||||
arrayTwo = null;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private void errorMessage( String message ) throws IOException
|
||||
{
|
||||
throw new IOException(message);
|
||||
}
|
||||
}
|
297
client/src/main/java/client/audio/SoundManager.java
Executable file
297
client/src/main/java/client/audio/SoundManager.java
Executable file
|
@ -0,0 +1,297 @@
|
|||
package client.audio;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import client.Client;
|
||||
import client.util.FileUtils;
|
||||
import common.collect.BiMap;
|
||||
import common.collect.HashBiMap;
|
||||
import common.collect.Lists;
|
||||
import common.collect.Maps;
|
||||
import common.entity.npc.EntityNPC;
|
||||
import common.init.SoundEvent;
|
||||
import common.log.Log;
|
||||
import common.rng.Random;
|
||||
import common.sound.MovingSound;
|
||||
import common.sound.Sound;
|
||||
import common.util.ExtMath;
|
||||
|
||||
public class SoundManager {
|
||||
private class Source {
|
||||
private final boolean attModel;
|
||||
private final float distOrRoll;
|
||||
private final int source;
|
||||
|
||||
private float positionX;
|
||||
private float positionY;
|
||||
private float positionZ;
|
||||
private float volume;
|
||||
|
||||
public Source(short[] buffer, Volume type, boolean toLoop, String sourcename, float x, float y, float z, boolean attModel,
|
||||
float distOrRoll, float volume) {
|
||||
this.positionX = x;
|
||||
this.positionY = y;
|
||||
this.positionZ = z;
|
||||
this.attModel = attModel;
|
||||
this.distOrRoll = distOrRoll;
|
||||
this.volume = volume;
|
||||
this.source = SoundManager.this.getNextChannel(sourcename);
|
||||
updateGain();
|
||||
SoundManager.this.gm.getAudioInterface().alSourcePlay(this.source, buffer, type, toLoop);
|
||||
}
|
||||
|
||||
public void updateGain() {
|
||||
float gain;
|
||||
if(attModel) {
|
||||
double dX = positionX - SoundManager.this.listenerX;
|
||||
double dY = positionY - SoundManager.this.listenerY;
|
||||
double dZ = positionZ - SoundManager.this.listenerZ;
|
||||
float dist = (float)Math.sqrt(dX * dX + dY * dY + dZ * dZ);
|
||||
if(dist <= 0) {
|
||||
gain = 1.0f;
|
||||
}
|
||||
else if(dist >= distOrRoll) {
|
||||
gain = 0.0f;
|
||||
}
|
||||
else {
|
||||
gain = 1.0f - (dist / distOrRoll);
|
||||
}
|
||||
if(gain > 1.0f)
|
||||
gain = 1.0f;
|
||||
if(gain < 0.0f)
|
||||
gain = 0.0f;
|
||||
}
|
||||
else {
|
||||
gain = 1.0f;
|
||||
}
|
||||
SoundManager.this.gm.getAudioInterface().alGain(source, (gain * volume));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final Map<SoundEvent, short[][]> BUFFERS = Maps.newEnumMap(SoundEvent.class);
|
||||
|
||||
private final Map<String, Sound> playingSounds = HashBiMap.<String, Sound>create();
|
||||
private final Map<Sound, String> invPlayingSounds = ((BiMap)this.playingSounds).inverse();
|
||||
private final List<MovingSound> tickableSounds = Lists.<MovingSound>newArrayList();
|
||||
private final Map<String, Integer> playingSoundsStopTime = Maps.<String, Integer>newHashMap();
|
||||
private final Map<String, Source> sources = new HashMap<String, Source>();
|
||||
private final String[] channels = new String[28];
|
||||
private final Client gm;
|
||||
|
||||
private float listenerX;
|
||||
private float listenerY;
|
||||
private float listenerZ;
|
||||
private int nextChannel = 0;
|
||||
private int playTime = 0;
|
||||
private int eventId = 0;
|
||||
|
||||
public SoundManager(Client gm) {
|
||||
this.gm = gm;
|
||||
}
|
||||
|
||||
public static void loadSounds() {
|
||||
for(SoundEvent entry : SoundEvent.values()) {
|
||||
short[][] buffers = new short[entry.getSounds().length][];
|
||||
for(int z = 0; z < entry.getSounds().length; z++) {
|
||||
String sound = entry.getSounds()[z];
|
||||
Log.SOUND.trace("Lade Sound %s", sound);
|
||||
buffers[z] = readOgg("sounds/" + sound + ".ogg");
|
||||
}
|
||||
BUFFERS.put(entry, buffers);
|
||||
}
|
||||
}
|
||||
|
||||
private static short[] readOgg(String filename) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new BufferedInputStream(FileUtils.getResource(filename));
|
||||
return CodecJOrbis.readAll(in);
|
||||
}
|
||||
catch(FileNotFoundException e) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Datei nicht gefunden", filename);
|
||||
return null;
|
||||
}
|
||||
catch(Exception e) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': %s", filename, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if(in != null)
|
||||
in.close();
|
||||
}
|
||||
catch(IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static short[] getBuffer(SoundEvent event) {
|
||||
return RANDOM.pick(BUFFERS.get(event));
|
||||
}
|
||||
|
||||
public void unload()
|
||||
{
|
||||
this.stopSounds();
|
||||
for(int x = 0; x < this.channels.length; x++) {
|
||||
channels[x] = null;
|
||||
}
|
||||
this.sources.clear();
|
||||
this.nextChannel = 0;
|
||||
this.eventId = 0;
|
||||
}
|
||||
|
||||
public void stopSounds()
|
||||
{
|
||||
for (String s : this.playingSounds.keySet())
|
||||
{
|
||||
Source src = sources.get(s);
|
||||
if(src != null)
|
||||
this.gm.getAudioInterface().alSourceStop(src.source);
|
||||
sources.remove(s);
|
||||
}
|
||||
this.playingSounds.clear();
|
||||
this.tickableSounds.clear();
|
||||
this.playingSoundsStopTime.clear();
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
++this.playTime;
|
||||
|
||||
for (MovingSound itickablesound : this.tickableSounds)
|
||||
{
|
||||
itickablesound.update();
|
||||
|
||||
if (itickablesound.isDonePlaying())
|
||||
{
|
||||
String s = (String)this.invPlayingSounds.get(itickablesound);
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
Source src = sources.get(s);
|
||||
if(src != null)
|
||||
this.gm.getAudioInterface().alSourceStop(src.source);
|
||||
sources.remove(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String s = (String)this.invPlayingSounds.get(itickablesound);
|
||||
Source source = sources.get(s);
|
||||
if(source != null) {
|
||||
source.volume = ExtMath.clampf(itickablesound.getVolume(), 0.0f, 1.0f);
|
||||
source.positionX = itickablesound.getXPosF();
|
||||
source.positionY = itickablesound.getYPosF();
|
||||
source.positionZ = itickablesound.getZPosF();
|
||||
source.updateGain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<Entry<String, Sound>> iterator = this.playingSounds.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Entry<String, Sound> entry = (Entry)iterator.next();
|
||||
String s1 = (String)entry.getKey();
|
||||
Sound isound = (Sound)entry.getValue();
|
||||
|
||||
Source source = this.sources.get(s1);
|
||||
if (source == null || !this.gm.getAudioInterface().alPlaying(source.source))
|
||||
{
|
||||
int i = ((Integer)this.playingSoundsStopTime.get(s1)).intValue();
|
||||
|
||||
if (i <= this.playTime)
|
||||
{
|
||||
iterator.remove();
|
||||
this.sources.remove(s1);
|
||||
this.playingSoundsStopTime.remove(s1);
|
||||
|
||||
if (isound instanceof MovingSound)
|
||||
{
|
||||
this.tickableSounds.remove(isound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void playSound(Sound sound)
|
||||
{
|
||||
float volume = sound.getVolume();
|
||||
float attn = 16.0F;
|
||||
if (volume > 1.0F)
|
||||
attn *= volume;
|
||||
volume = ExtMath.clampf(volume, 0.0f, 1.0f);
|
||||
if (volume > 0.0F)
|
||||
{
|
||||
String s = String.format("snd-%016x", this.eventId++);
|
||||
this.sources.put(s, new Source(getBuffer(sound.getSoundLocation()), Volume.getByType(sound.getChannelType()), sound.canRepeat(), s, sound.getXPosF(), sound.getYPosF(), sound.getZPosF(), sound.getAttenuationType(), attn, volume));
|
||||
this.playingSoundsStopTime.put(s, this.playTime + 20);
|
||||
this.playingSounds.put(s, sound);
|
||||
if (sound instanceof MovingSound)
|
||||
this.tickableSounds.add((MovingSound)sound);
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener(EntityNPC player, float partial)
|
||||
{
|
||||
double x = player.prevX + (player.posX - player.prevX) * (double)partial;
|
||||
double y = player.prevY + (player.posY - player.prevY) * (double)partial + (double)player.getEyeHeight();
|
||||
double z = player.prevZ + (player.posZ - player.prevZ) * (double)partial;
|
||||
this.listenerX = (float)x;
|
||||
this.listenerY = (float)y;
|
||||
this.listenerZ = (float)z;
|
||||
for(Source source : this.sources.values()) {
|
||||
source.updateGain();
|
||||
}
|
||||
}
|
||||
|
||||
private int getNextChannel(String sourcename) {
|
||||
int x;
|
||||
int next;
|
||||
String name;
|
||||
next = nextChannel;
|
||||
|
||||
int n = next;
|
||||
Source src;
|
||||
for(x = 0; x < channels.length; x++) {
|
||||
name = this.channels[n];
|
||||
src = name == null ? null : sources.get(name);
|
||||
|
||||
if(src == null || !this.gm.getAudioInterface().alPlaying(src.source)) {
|
||||
nextChannel = n + 1;
|
||||
if(nextChannel >= channels.length)
|
||||
nextChannel = 0;
|
||||
this.channels[n] = sourcename;
|
||||
if(src != null)
|
||||
this.sources.remove(name);
|
||||
return n;
|
||||
}
|
||||
n++;
|
||||
if(n >= channels.length)
|
||||
n = 0;
|
||||
}
|
||||
|
||||
n = next;
|
||||
name = this.channels[n];
|
||||
src = name == null ? null : sources.get(name);
|
||||
|
||||
nextChannel = n + 1;
|
||||
if(nextChannel >= channels.length)
|
||||
nextChannel = 0;
|
||||
this.channels[n] = sourcename;
|
||||
if(src != null)
|
||||
this.sources.remove(name);
|
||||
return n;
|
||||
}
|
||||
}
|
107
client/src/main/java/client/audio/Volume.java
Normal file
107
client/src/main/java/client/audio/Volume.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package client.audio;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.element.Slider;
|
||||
import client.gui.element.SliderCallback;
|
||||
import client.vars.CVar;
|
||||
import client.vars.CVarCategory;
|
||||
import common.color.TextColor;
|
||||
import common.sound.EventType;
|
||||
|
||||
public enum Volume implements CVar {
|
||||
MASTER("master", "Gesamt"),
|
||||
MUSIC("music", "Musik"),
|
||||
SFX("sfx", "Geräusche", EventType.SOUND_EFFECT),
|
||||
GUI("gui", "Oberfläche", EventType.UI_INTERFACE);
|
||||
|
||||
private static final Volume[] LOOKUP = new Volume[EventType.values().length];
|
||||
|
||||
public final String id;
|
||||
public final String name;
|
||||
public final EventType type;
|
||||
|
||||
private int value = 100;
|
||||
|
||||
private Volume(String id, String name, EventType type) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private Volume(String id, String name) {
|
||||
this(id, name, null);
|
||||
}
|
||||
|
||||
static {
|
||||
for(Volume volume : values()) {
|
||||
if(volume.type != null)
|
||||
LOOKUP[volume.type.ordinal()] = volume;
|
||||
}
|
||||
}
|
||||
|
||||
public static Volume getByType(EventType type) {
|
||||
return LOOKUP[type.ordinal()];
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getCVarName() {
|
||||
return "snd_volume_" + this.id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return TextColor.DGREEN + "volume";
|
||||
}
|
||||
|
||||
public CVarCategory getCategory() {
|
||||
return CVarCategory.SOUND;
|
||||
}
|
||||
|
||||
public boolean parse(String str) {
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(str);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
if(value < 0 || value > 100)
|
||||
return false;
|
||||
this.value = value;
|
||||
this.apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
public String format() {
|
||||
return "" + this.value;
|
||||
}
|
||||
|
||||
public String getDefault() {
|
||||
return "100";
|
||||
}
|
||||
|
||||
public void setDefault() {
|
||||
this.value = 100;
|
||||
this.apply();
|
||||
}
|
||||
|
||||
public String getValues() {
|
||||
return "0..100";
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
if(Client.CLIENT.getAudioInterface() != null)
|
||||
Client.CLIENT.getAudioInterface().alSetVolume(this, (short)(((float)this.value) / 100.0f * 32767.0f));
|
||||
}
|
||||
|
||||
public Slider selector(int x, int y, int w, int h) {
|
||||
return new Slider(x, y, w, h, 0, 0, 100, 100, this.value, new SliderCallback() {
|
||||
public void use(Slider elem, int value) {
|
||||
Volume.this.value = value;
|
||||
Volume.this.apply();
|
||||
}
|
||||
}, this.name, "%");
|
||||
}
|
||||
}
|
294
client/src/main/java/client/audio/jogg/Buffer.java
Normal file
294
client/src/main/java/client/audio/jogg/Buffer.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jogg;
|
||||
|
||||
public class Buffer{
|
||||
private static final int BUFFER_INCREMENT=256;
|
||||
|
||||
private static final int[] mask= {0x00000000, 0x00000001, 0x00000003,
|
||||
0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
|
||||
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
|
||||
0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
|
||||
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
|
||||
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
|
||||
|
||||
int ptr=0;
|
||||
byte[] buffer=null;
|
||||
int endbit=0;
|
||||
int endbyte=0;
|
||||
int storage=0;
|
||||
|
||||
public void writeinit(){
|
||||
buffer=new byte[BUFFER_INCREMENT];
|
||||
ptr=0;
|
||||
buffer[0]=(byte)'\0';
|
||||
storage=BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
public void write(byte[] s){
|
||||
for(int i=0; i<s.length; i++){
|
||||
if(s[i]==0)
|
||||
break;
|
||||
write(s[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(byte[] s, int bytes){
|
||||
int i=0;
|
||||
while(bytes--!=0){
|
||||
s[i++]=(byte)(read(8));
|
||||
}
|
||||
}
|
||||
|
||||
void reset(){
|
||||
ptr=0;
|
||||
buffer[0]=(byte)'\0';
|
||||
endbit=endbyte=0;
|
||||
}
|
||||
|
||||
public void writeclear(){
|
||||
buffer=null;
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int bytes){
|
||||
readinit(buf, 0, bytes);
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int start, int bytes){
|
||||
ptr=start;
|
||||
buffer=buf;
|
||||
endbit=endbyte=0;
|
||||
storage=bytes;
|
||||
}
|
||||
|
||||
public void write(int value, int bits){
|
||||
if(endbyte+4>=storage){
|
||||
byte[] foo=new byte[storage+BUFFER_INCREMENT];
|
||||
System.arraycopy(buffer, 0, foo, 0, storage);
|
||||
buffer=foo;
|
||||
storage+=BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
value&=mask[bits];
|
||||
bits+=endbit;
|
||||
buffer[ptr]|=(byte)(value<<endbit);
|
||||
|
||||
if(bits>=8){
|
||||
buffer[ptr+1]=(byte)(value>>>(8-endbit));
|
||||
if(bits>=16){
|
||||
buffer[ptr+2]=(byte)(value>>>(16-endbit));
|
||||
if(bits>=24){
|
||||
buffer[ptr+3]=(byte)(value>>>(24-endbit));
|
||||
if(bits>=32){
|
||||
if(endbit>0)
|
||||
buffer[ptr+4]=(byte)(value>>>(32-endbit));
|
||||
else
|
||||
buffer[ptr+4]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endbyte+=bits/8;
|
||||
ptr+=bits/8;
|
||||
endbit=bits&7;
|
||||
}
|
||||
|
||||
public int look(int bits){
|
||||
int ret;
|
||||
int m=mask[bits];
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
if(endbyte+(bits-1)/8>=storage)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
if(bits>32&&endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (m&ret);
|
||||
}
|
||||
|
||||
public int look1(){
|
||||
if(endbyte>=storage)
|
||||
return (-1);
|
||||
return ((buffer[ptr]>>endbit)&1);
|
||||
}
|
||||
|
||||
public void adv(int bits){
|
||||
bits+=endbit;
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
}
|
||||
|
||||
public void adv1(){
|
||||
++endbit;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(int bits){
|
||||
int ret;
|
||||
int m=mask[bits];
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
ret=-1;
|
||||
if(endbyte+(bits-1)/8>=storage){
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
if(bits>32&&endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret&=m;
|
||||
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int readB(int bits){
|
||||
int ret;
|
||||
int m=32-bits;
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
/* not the main path */
|
||||
ret=-1;
|
||||
if(endbyte*8+bits>storage*8){
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret=(buffer[ptr]&0xff)<<(24+endbit);
|
||||
if(bits>8){
|
||||
ret|=(buffer[ptr+1]&0xff)<<(16+endbit);
|
||||
if(bits>16){
|
||||
ret|=(buffer[ptr+2]&0xff)<<(8+endbit);
|
||||
if(bits>24){
|
||||
ret|=(buffer[ptr+3]&0xff)<<(endbit);
|
||||
if(bits>32&&(endbit!=0))
|
||||
ret|=(buffer[ptr+4]&0xff)>>(8-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret=(ret>>>(m>>1))>>>((m+1)>>1);
|
||||
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int read1(){
|
||||
int ret;
|
||||
if(endbyte>=storage){
|
||||
ret=-1;
|
||||
endbit++;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret=(buffer[ptr]>>endbit)&1;
|
||||
|
||||
endbit++;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int bytes(){
|
||||
return (endbyte+(endbit+7)/8);
|
||||
}
|
||||
|
||||
public int bits(){
|
||||
return (endbyte*8+endbit);
|
||||
}
|
||||
|
||||
public byte[] buffer(){
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
public static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v>0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public static void report(String in){
|
||||
System.err.println(in);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
47
client/src/main/java/client/audio/jogg/Packet.java
Normal file
47
client/src/main/java/client/audio/jogg/Packet.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jogg;
|
||||
|
||||
public class Packet{
|
||||
public byte[] packet_base;
|
||||
public int packet;
|
||||
public int bytes;
|
||||
public int b_o_s;
|
||||
public int e_o_s;
|
||||
|
||||
public long granulepos;
|
||||
|
||||
/**
|
||||
* sequence number for decode; the framing
|
||||
* knows where there's a hole in the data,
|
||||
* but we need coupling so that the codec
|
||||
* (which is in a seperate abstraction
|
||||
* layer) also knows about the gap
|
||||
*/
|
||||
public long packetno;
|
||||
|
||||
}
|
135
client/src/main/java/client/audio/jogg/Page.java
Normal file
135
client/src/main/java/client/audio/jogg/Page.java
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jogg;
|
||||
|
||||
public class Page{
|
||||
private static int[] crc_lookup=new int[256];
|
||||
static{
|
||||
for(int i=0; i<crc_lookup.length; i++){
|
||||
crc_lookup[i]=crc_entry(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static int crc_entry(int index){
|
||||
int r=index<<24;
|
||||
for(int i=0; i<8; i++){
|
||||
if((r&0x80000000)!=0){
|
||||
r=(r<<1)^0x04c11db7; /* The same as the ethernet generator
|
||||
polynomial, although we use an
|
||||
unreflected alg and an init/final
|
||||
of 0, not 0xffffffff */
|
||||
}
|
||||
else{
|
||||
r<<=1;
|
||||
}
|
||||
}
|
||||
return (r&0xffffffff);
|
||||
}
|
||||
|
||||
public byte[] header_base;
|
||||
public int header;
|
||||
public int header_len;
|
||||
public byte[] body_base;
|
||||
public int body;
|
||||
public int body_len;
|
||||
|
||||
int version(){
|
||||
return header_base[header+4]&0xff;
|
||||
}
|
||||
|
||||
int continued(){
|
||||
return (header_base[header+5]&0x01);
|
||||
}
|
||||
|
||||
public int bos(){
|
||||
return (header_base[header+5]&0x02);
|
||||
}
|
||||
|
||||
public int eos(){
|
||||
return (header_base[header+5]&0x04);
|
||||
}
|
||||
|
||||
public long granulepos(){
|
||||
long foo=header_base[header+13]&0xff;
|
||||
foo=(foo<<8)|(header_base[header+12]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+11]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+10]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+9]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+8]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+7]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+6]&0xff);
|
||||
return (foo);
|
||||
}
|
||||
|
||||
public int serialno(){
|
||||
return (header_base[header+14]&0xff)|((header_base[header+15]&0xff)<<8)
|
||||
|((header_base[header+16]&0xff)<<16)
|
||||
|((header_base[header+17]&0xff)<<24);
|
||||
}
|
||||
|
||||
int pageno(){
|
||||
return (header_base[header+18]&0xff)|((header_base[header+19]&0xff)<<8)
|
||||
|((header_base[header+20]&0xff)<<16)
|
||||
|((header_base[header+21]&0xff)<<24);
|
||||
}
|
||||
|
||||
void checksum(){
|
||||
int crc_reg=0;
|
||||
|
||||
for(int i=0; i<header_len; i++){
|
||||
crc_reg=(crc_reg<<8)
|
||||
^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
|
||||
}
|
||||
for(int i=0; i<body_len; i++){
|
||||
crc_reg=(crc_reg<<8)
|
||||
^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
|
||||
}
|
||||
header_base[header+22]=(byte)crc_reg;
|
||||
header_base[header+23]=(byte)(crc_reg>>>8);
|
||||
header_base[header+24]=(byte)(crc_reg>>>16);
|
||||
header_base[header+25]=(byte)(crc_reg>>>24);
|
||||
}
|
||||
|
||||
public Page copy(){
|
||||
return copy(new Page());
|
||||
}
|
||||
|
||||
public Page copy(Page p){
|
||||
byte[] tmp=new byte[header_len];
|
||||
System.arraycopy(header_base, header, tmp, 0, header_len);
|
||||
p.header_len=header_len;
|
||||
p.header_base=tmp;
|
||||
p.header=0;
|
||||
tmp=new byte[body_len];
|
||||
System.arraycopy(body_base, body, tmp, 0, body_len);
|
||||
p.body_len=body_len;
|
||||
p.body_base=tmp;
|
||||
p.body=0;
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
526
client/src/main/java/client/audio/jogg/StreamState.java
Normal file
526
client/src/main/java/client/audio/jogg/StreamState.java
Normal file
|
@ -0,0 +1,526 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jogg;
|
||||
|
||||
public class StreamState{
|
||||
byte[] body_data; /* bytes from packet bodies */
|
||||
int body_storage; /* storage elements allocated */
|
||||
int body_fill; /* elements stored; fill mark */
|
||||
private int body_returned; /* elements of fill returned */
|
||||
|
||||
int[] lacing_vals; /* The values that will go to the segment table */
|
||||
long[] granule_vals; /* pcm_pos values for headers. Not compact
|
||||
this way, but it is simple coupled to the
|
||||
lacing fifo */
|
||||
int lacing_storage;
|
||||
int lacing_fill;
|
||||
int lacing_packet;
|
||||
int lacing_returned;
|
||||
|
||||
byte[] header=new byte[282]; /* working space for header encode */
|
||||
int header_fill;
|
||||
|
||||
public int e_o_s; /* set when we have buffered the last packet in the
|
||||
logical bitstream */
|
||||
int b_o_s; /* set after we've written the initial page
|
||||
of a logical bitstream */
|
||||
int serialno;
|
||||
int pageno;
|
||||
long packetno; /* sequence number for decode; the framing
|
||||
knows where there's a hole in the data,
|
||||
but we need coupling so that the codec
|
||||
(which is in a seperate abstraction
|
||||
layer) also knows about the gap */
|
||||
long granulepos;
|
||||
|
||||
public StreamState(){
|
||||
init();
|
||||
}
|
||||
|
||||
StreamState(int serialno){
|
||||
this();
|
||||
init(serialno);
|
||||
}
|
||||
|
||||
void init(){
|
||||
body_storage=16*1024;
|
||||
body_data=new byte[body_storage];
|
||||
lacing_storage=1024;
|
||||
lacing_vals=new int[lacing_storage];
|
||||
granule_vals=new long[lacing_storage];
|
||||
}
|
||||
|
||||
public void init(int serialno){
|
||||
if(body_data==null){
|
||||
init();
|
||||
}
|
||||
else{
|
||||
for(int i=0; i<body_data.length; i++)
|
||||
body_data[i]=0;
|
||||
for(int i=0; i<lacing_vals.length; i++)
|
||||
lacing_vals[i]=0;
|
||||
for(int i=0; i<granule_vals.length; i++)
|
||||
granule_vals[i]=0;
|
||||
}
|
||||
this.serialno=serialno;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
body_data=null;
|
||||
lacing_vals=null;
|
||||
granule_vals=null;
|
||||
}
|
||||
|
||||
void destroy(){
|
||||
clear();
|
||||
}
|
||||
|
||||
void body_expand(int needed){
|
||||
if(body_storage<=body_fill+needed){
|
||||
body_storage+=(needed+1024);
|
||||
byte[] foo=new byte[body_storage];
|
||||
System.arraycopy(body_data, 0, foo, 0, body_data.length);
|
||||
body_data=foo;
|
||||
}
|
||||
}
|
||||
|
||||
void lacing_expand(int needed){
|
||||
if(lacing_storage<=lacing_fill+needed){
|
||||
lacing_storage+=(needed+32);
|
||||
int[] foo=new int[lacing_storage];
|
||||
System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
|
||||
lacing_vals=foo;
|
||||
|
||||
long[] bar=new long[lacing_storage];
|
||||
System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
|
||||
granule_vals=bar;
|
||||
}
|
||||
}
|
||||
|
||||
/* submit data to the internal buffer of the framing engine */
|
||||
public int packetin(Packet op){
|
||||
int lacing_val=op.bytes/255+1;
|
||||
|
||||
if(body_returned!=0){
|
||||
/* advance packet data according to the body_returned pointer. We
|
||||
had to keep it around to return a pointer into the buffer last
|
||||
call */
|
||||
|
||||
body_fill-=body_returned;
|
||||
if(body_fill!=0){
|
||||
System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned=0;
|
||||
}
|
||||
|
||||
/* make sure we have the buffer storage */
|
||||
body_expand(op.bytes);
|
||||
lacing_expand(lacing_val);
|
||||
|
||||
/* Copy in the submitted packet. Yes, the copy is a waste; this is
|
||||
the liability of overly clean abstraction for the time being. It
|
||||
will actually be fairly easy to eliminate the extra copy in the
|
||||
future */
|
||||
|
||||
System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
|
||||
body_fill+=op.bytes;
|
||||
|
||||
/* Store lacing vals for this packet */
|
||||
int j;
|
||||
for(j=0; j<lacing_val-1; j++){
|
||||
lacing_vals[lacing_fill+j]=255;
|
||||
granule_vals[lacing_fill+j]=granulepos;
|
||||
}
|
||||
lacing_vals[lacing_fill+j]=(op.bytes)%255;
|
||||
granulepos=granule_vals[lacing_fill+j]=op.granulepos;
|
||||
|
||||
/* flag the first segment as the beginning of the packet */
|
||||
lacing_vals[lacing_fill]|=0x100;
|
||||
|
||||
lacing_fill+=lacing_val;
|
||||
|
||||
/* for the sake of completeness */
|
||||
packetno++;
|
||||
|
||||
if(op.e_o_s!=0)
|
||||
e_o_s=1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int packetout(Packet op){
|
||||
|
||||
/* The last part of decode. We have the stream broken into packet
|
||||
segments. Now we need to group them into packets (or return the
|
||||
out of sync markers) */
|
||||
|
||||
int ptr=lacing_returned;
|
||||
|
||||
if(lacing_packet<=ptr){
|
||||
return (0);
|
||||
}
|
||||
|
||||
if((lacing_vals[ptr]&0x400)!=0){
|
||||
/* We lost sync here; let the app know */
|
||||
lacing_returned++;
|
||||
|
||||
/* we need to tell the codec there's a gap; it might need to
|
||||
handle previous packet dependencies. */
|
||||
packetno++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Gather the whole packet. We'll have no holes or a partial packet */
|
||||
{
|
||||
int size=lacing_vals[ptr]&0xff;
|
||||
int bytes=0;
|
||||
|
||||
op.packet_base=body_data;
|
||||
op.packet=body_returned;
|
||||
op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
|
||||
op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
|
||||
bytes+=size;
|
||||
|
||||
while(size==255){
|
||||
int val=lacing_vals[++ptr];
|
||||
size=val&0xff;
|
||||
if((val&0x200)!=0)
|
||||
op.e_o_s=0x200;
|
||||
bytes+=size;
|
||||
}
|
||||
|
||||
op.packetno=packetno;
|
||||
op.granulepos=granule_vals[ptr];
|
||||
op.bytes=bytes;
|
||||
|
||||
body_returned+=bytes;
|
||||
|
||||
lacing_returned=ptr+1;
|
||||
}
|
||||
packetno++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
// add the incoming page to the stream state; we decompose the page
|
||||
// into packet segments here as well.
|
||||
|
||||
public int pagein(Page og){
|
||||
byte[] header_base=og.header_base;
|
||||
int header=og.header;
|
||||
byte[] body_base=og.body_base;
|
||||
int body=og.body;
|
||||
int bodysize=og.body_len;
|
||||
int segptr=0;
|
||||
|
||||
int version=og.version();
|
||||
int continued=og.continued();
|
||||
int bos=og.bos();
|
||||
int eos=og.eos();
|
||||
long granulepos=og.granulepos();
|
||||
int _serialno=og.serialno();
|
||||
int _pageno=og.pageno();
|
||||
int segments=header_base[header+26]&0xff;
|
||||
|
||||
// clean up 'returned data'
|
||||
{
|
||||
int lr=lacing_returned;
|
||||
int br=body_returned;
|
||||
|
||||
// body data
|
||||
if(br!=0){
|
||||
body_fill-=br;
|
||||
if(body_fill!=0){
|
||||
System.arraycopy(body_data, br, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned=0;
|
||||
}
|
||||
|
||||
if(lr!=0){
|
||||
// segment table
|
||||
if((lacing_fill-lr)!=0){
|
||||
System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
|
||||
System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
|
||||
}
|
||||
lacing_fill-=lr;
|
||||
lacing_packet-=lr;
|
||||
lacing_returned=0;
|
||||
}
|
||||
}
|
||||
|
||||
// check the serial number
|
||||
if(_serialno!=serialno)
|
||||
return (-1);
|
||||
if(version>0)
|
||||
return (-1);
|
||||
|
||||
lacing_expand(segments+1);
|
||||
|
||||
// are we in sequence?
|
||||
if(_pageno!=pageno){
|
||||
int i;
|
||||
|
||||
// unroll previous partial packet (if any)
|
||||
for(i=lacing_packet; i<lacing_fill; i++){
|
||||
body_fill-=lacing_vals[i]&0xff;
|
||||
//System.out.println("??");
|
||||
}
|
||||
lacing_fill=lacing_packet;
|
||||
|
||||
// make a note of dropped data in segment table
|
||||
if(pageno!=-1){
|
||||
lacing_vals[lacing_fill++]=0x400;
|
||||
lacing_packet++;
|
||||
}
|
||||
|
||||
// are we a 'continued packet' page? If so, we'll need to skip
|
||||
// some segments
|
||||
if(continued!=0){
|
||||
bos=0;
|
||||
for(; segptr<segments; segptr++){
|
||||
int val=(header_base[header+27+segptr]&0xff);
|
||||
body+=val;
|
||||
bodysize-=val;
|
||||
if(val<255){
|
||||
segptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bodysize!=0){
|
||||
body_expand(bodysize);
|
||||
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
|
||||
body_fill+=bodysize;
|
||||
}
|
||||
|
||||
{
|
||||
int saved=-1;
|
||||
while(segptr<segments){
|
||||
int val=(header_base[header+27+segptr]&0xff);
|
||||
lacing_vals[lacing_fill]=val;
|
||||
granule_vals[lacing_fill]=-1;
|
||||
|
||||
if(bos!=0){
|
||||
lacing_vals[lacing_fill]|=0x100;
|
||||
bos=0;
|
||||
}
|
||||
|
||||
if(val<255)
|
||||
saved=lacing_fill;
|
||||
|
||||
lacing_fill++;
|
||||
segptr++;
|
||||
|
||||
if(val<255)
|
||||
lacing_packet=lacing_fill;
|
||||
}
|
||||
|
||||
/* set the granulepos on the last pcmval of the last full packet */
|
||||
if(saved!=-1){
|
||||
granule_vals[saved]=granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
if(eos!=0){
|
||||
e_o_s=1;
|
||||
if(lacing_fill>0)
|
||||
lacing_vals[lacing_fill-1]|=0x200;
|
||||
}
|
||||
|
||||
pageno=_pageno+1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* This will flush remaining packets into a page (returning nonzero),
|
||||
even if there is not enough data to trigger a flush normally
|
||||
(undersized page). If there are no packets or partial packets to
|
||||
flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
|
||||
try to flush a normal sized page like ogg_stream_pageout; a call to
|
||||
ogg_stream_flush does not gurantee that all packets have flushed.
|
||||
Only a return value of 0 from ogg_stream_flush indicates all packet
|
||||
data is flushed into pages.
|
||||
|
||||
ogg_stream_page will flush the last page in a stream even if it's
|
||||
undersized; you almost certainly want to use ogg_stream_pageout
|
||||
(and *not* ogg_stream_flush) unless you need to flush an undersized
|
||||
page in the middle of a stream for some reason. */
|
||||
|
||||
public int flush(Page og){
|
||||
|
||||
int i;
|
||||
int vals=0;
|
||||
int maxvals=(lacing_fill>255 ? 255 : lacing_fill);
|
||||
int bytes=0;
|
||||
int acc=0;
|
||||
long granule_pos=granule_vals[0];
|
||||
|
||||
if(maxvals==0)
|
||||
return (0);
|
||||
|
||||
/* construct a page */
|
||||
/* decide how many segments to include */
|
||||
|
||||
/* If this is the initial header case, the first page must only include
|
||||
the initial header packet */
|
||||
if(b_o_s==0){ /* 'initial header page' case */
|
||||
granule_pos=0;
|
||||
for(vals=0; vals<maxvals; vals++){
|
||||
if((lacing_vals[vals]&0x0ff)<255){
|
||||
vals++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(vals=0; vals<maxvals; vals++){
|
||||
if(acc>4096)
|
||||
break;
|
||||
acc+=(lacing_vals[vals]&0x0ff);
|
||||
granule_pos=granule_vals[vals];
|
||||
}
|
||||
}
|
||||
|
||||
/* construct the header in temp storage */
|
||||
System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
|
||||
|
||||
/* stream structure version */
|
||||
header[4]=0x00;
|
||||
|
||||
/* continued packet flag? */
|
||||
header[5]=0x00;
|
||||
if((lacing_vals[0]&0x100)==0)
|
||||
header[5]|=0x01;
|
||||
/* first page flag? */
|
||||
if(b_o_s==0)
|
||||
header[5]|=0x02;
|
||||
/* last page flag? */
|
||||
if(e_o_s!=0&&lacing_fill==vals)
|
||||
header[5]|=0x04;
|
||||
b_o_s=1;
|
||||
|
||||
/* 64 bits of PCM position */
|
||||
for(i=6; i<14; i++){
|
||||
header[i]=(byte)granule_pos;
|
||||
granule_pos>>>=8;
|
||||
}
|
||||
|
||||
/* 32 bits of stream serial number */
|
||||
{
|
||||
int _serialno=serialno;
|
||||
for(i=14; i<18; i++){
|
||||
header[i]=(byte)_serialno;
|
||||
_serialno>>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
/* 32 bits of page counter (we have both counter and page header
|
||||
because this val can roll over) */
|
||||
if(pageno==-1)
|
||||
pageno=0; /* because someone called
|
||||
stream_reset; this would be a
|
||||
strange thing to do in an
|
||||
encode stream, but it has
|
||||
plausible uses */
|
||||
{
|
||||
int _pageno=pageno++;
|
||||
for(i=18; i<22; i++){
|
||||
header[i]=(byte)_pageno;
|
||||
_pageno>>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
/* zero for computation; filled in later */
|
||||
header[22]=0;
|
||||
header[23]=0;
|
||||
header[24]=0;
|
||||
header[25]=0;
|
||||
|
||||
/* segment table */
|
||||
header[26]=(byte)vals;
|
||||
for(i=0; i<vals; i++){
|
||||
header[i+27]=(byte)lacing_vals[i];
|
||||
bytes+=(header[i+27]&0xff);
|
||||
}
|
||||
|
||||
/* set pointers in the ogg_page struct */
|
||||
og.header_base=header;
|
||||
og.header=0;
|
||||
og.header_len=header_fill=vals+27;
|
||||
og.body_base=body_data;
|
||||
og.body=body_returned;
|
||||
og.body_len=bytes;
|
||||
|
||||
/* advance the lacing data and set the body_returned pointer */
|
||||
|
||||
lacing_fill-=vals;
|
||||
System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
|
||||
System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
|
||||
body_returned+=bytes;
|
||||
|
||||
/* calculate the checksum */
|
||||
|
||||
og.checksum();
|
||||
|
||||
/* done */
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* This constructs pages from buffered packet segments. The pointers
|
||||
returned are to static buffers; do not free. The returned buffers are
|
||||
good only until the next call (using the same ogg_stream_state) */
|
||||
public int pageout(Page og){
|
||||
if((e_o_s!=0&&lacing_fill!=0)|| /* 'were done, now flush' case */
|
||||
body_fill-body_returned>4096|| /* 'page nominal size' case */
|
||||
lacing_fill>=255|| /* 'segment table full' case */
|
||||
(lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
|
||||
return flush(og);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int eof(){
|
||||
return e_o_s;
|
||||
}
|
||||
|
||||
public int reset(){
|
||||
body_fill=0;
|
||||
body_returned=0;
|
||||
|
||||
lacing_fill=0;
|
||||
lacing_packet=0;
|
||||
lacing_returned=0;
|
||||
|
||||
header_fill=0;
|
||||
|
||||
e_o_s=0;
|
||||
b_o_s=0;
|
||||
pageno=-1;
|
||||
packetno=0;
|
||||
granulepos=0;
|
||||
return (0);
|
||||
}
|
||||
}
|
275
client/src/main/java/client/audio/jogg/SyncState.java
Normal file
275
client/src/main/java/client/audio/jogg/SyncState.java
Normal file
|
@ -0,0 +1,275 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jogg;
|
||||
|
||||
// DECODING PRIMITIVES: packet streaming layer
|
||||
|
||||
// This has two layers to place more of the multi-serialno and paging
|
||||
// control in the application's hands. First, we expose a data buffer
|
||||
// using ogg_decode_buffer(). The app either copies into the
|
||||
// buffer, or passes it directly to read(), etc. We then call
|
||||
// ogg_decode_wrote() to tell how many bytes we just added.
|
||||
//
|
||||
// Pages are returned (pointers into the buffer in ogg_sync_state)
|
||||
// by ogg_decode_stream(). The page is then submitted to
|
||||
// ogg_decode_page() along with the appropriate
|
||||
// ogg_stream_state* (ie, matching serialno). We then get raw
|
||||
// packets out calling ogg_stream_packet() with a
|
||||
// ogg_stream_state. See the 'frame-prog.txt' docs for details and
|
||||
// example code.
|
||||
|
||||
public class SyncState{
|
||||
|
||||
public byte[] data;
|
||||
int storage;
|
||||
int fill;
|
||||
int returned;
|
||||
|
||||
int unsynced;
|
||||
int headerbytes;
|
||||
int bodybytes;
|
||||
|
||||
public int clear(){
|
||||
data=null;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int buffer(int size){
|
||||
// first, clear out any space that has been previously returned
|
||||
if(returned!=0){
|
||||
fill-=returned;
|
||||
if(fill>0){
|
||||
System.arraycopy(data, returned, data, 0, fill);
|
||||
}
|
||||
returned=0;
|
||||
}
|
||||
|
||||
if(size>storage-fill){
|
||||
// We need to extend the internal buffer
|
||||
int newsize=size+fill+4096; // an extra page to be nice
|
||||
if(data!=null){
|
||||
byte[] foo=new byte[newsize];
|
||||
System.arraycopy(data, 0, foo, 0, data.length);
|
||||
data=foo;
|
||||
}
|
||||
else{
|
||||
data=new byte[newsize];
|
||||
}
|
||||
storage=newsize;
|
||||
}
|
||||
|
||||
return (fill);
|
||||
}
|
||||
|
||||
public int wrote(int bytes){
|
||||
if(fill+bytes>storage)
|
||||
return (-1);
|
||||
fill+=bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
// sync the stream. This is meant to be useful for finding page
|
||||
// boundaries.
|
||||
//
|
||||
// return values for this:
|
||||
// -n) skipped n bytes
|
||||
// 0) page not ready; more data (no bytes skipped)
|
||||
// n) page synced at current location; page length n bytes
|
||||
private Page pageseek=new Page();
|
||||
private byte[] chksum=new byte[4];
|
||||
|
||||
public int pageseek(Page og){
|
||||
int page=returned;
|
||||
int next;
|
||||
int bytes=fill-returned;
|
||||
|
||||
if(headerbytes==0){
|
||||
int _headerbytes, i;
|
||||
if(bytes<27)
|
||||
return (0); // not enough for a header
|
||||
|
||||
/* verify capture pattern */
|
||||
if(data[page]!='O'||data[page+1]!='g'||data[page+2]!='g'
|
||||
||data[page+3]!='S'){
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
|
||||
// search for possible capture
|
||||
next=0;
|
||||
for(int ii=0; ii<bytes-1; ii++){
|
||||
if(data[page+1+ii]=='O'){
|
||||
next=page+1+ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//next=memchr(page+1,'O',bytes-1);
|
||||
if(next==0)
|
||||
next=fill;
|
||||
|
||||
returned=next;
|
||||
return (-(next-page));
|
||||
}
|
||||
_headerbytes=(data[page+26]&0xff)+27;
|
||||
if(bytes<_headerbytes)
|
||||
return (0); // not enough for header + seg table
|
||||
|
||||
// count up body length in the segment table
|
||||
|
||||
for(i=0; i<(data[page+26]&0xff); i++){
|
||||
bodybytes+=(data[page+27+i]&0xff);
|
||||
}
|
||||
headerbytes=_headerbytes;
|
||||
}
|
||||
|
||||
if(bodybytes+headerbytes>bytes)
|
||||
return (0);
|
||||
|
||||
// The whole test page is buffered. Verify the checksum
|
||||
synchronized(chksum){
|
||||
// Grab the checksum bytes, set the header field to zero
|
||||
|
||||
System.arraycopy(data, page+22, chksum, 0, 4);
|
||||
data[page+22]=0;
|
||||
data[page+23]=0;
|
||||
data[page+24]=0;
|
||||
data[page+25]=0;
|
||||
|
||||
// set up a temp page struct and recompute the checksum
|
||||
Page log=pageseek;
|
||||
log.header_base=data;
|
||||
log.header=page;
|
||||
log.header_len=headerbytes;
|
||||
|
||||
log.body_base=data;
|
||||
log.body=page+headerbytes;
|
||||
log.body_len=bodybytes;
|
||||
log.checksum();
|
||||
|
||||
// Compare
|
||||
if(chksum[0]!=data[page+22]||chksum[1]!=data[page+23]
|
||||
||chksum[2]!=data[page+24]||chksum[3]!=data[page+25]){
|
||||
// D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
|
||||
// replace the computed checksum with the one actually read in
|
||||
System.arraycopy(chksum, 0, data, page+22, 4);
|
||||
// Bad checksum. Lose sync */
|
||||
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
// search for possible capture
|
||||
next=0;
|
||||
for(int ii=0; ii<bytes-1; ii++){
|
||||
if(data[page+1+ii]=='O'){
|
||||
next=page+1+ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//next=memchr(page+1,'O',bytes-1);
|
||||
if(next==0)
|
||||
next=fill;
|
||||
returned=next;
|
||||
return (-(next-page));
|
||||
}
|
||||
}
|
||||
|
||||
// yes, have a whole page all ready to go
|
||||
{
|
||||
page=returned;
|
||||
|
||||
if(og!=null){
|
||||
og.header_base=data;
|
||||
og.header=page;
|
||||
og.header_len=headerbytes;
|
||||
og.body_base=data;
|
||||
og.body=page+headerbytes;
|
||||
og.body_len=bodybytes;
|
||||
}
|
||||
|
||||
unsynced=0;
|
||||
returned+=(bytes=headerbytes+bodybytes);
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
return (bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// sync the stream and get a page. Keep trying until we find a page.
|
||||
// Supress 'sync errors' after reporting the first.
|
||||
//
|
||||
// return values:
|
||||
// -1) recapture (hole in data)
|
||||
// 0) need more data
|
||||
// 1) page returned
|
||||
//
|
||||
// Returns pointers into buffered data; invalidated by next call to
|
||||
// _stream, _clear, _init, or _buffer
|
||||
|
||||
public int pageout(Page og){
|
||||
// all we need to do is verify a page at the head of the stream
|
||||
// buffer. If it doesn't verify, we look for the next potential
|
||||
// frame
|
||||
|
||||
while(true){
|
||||
int ret=pageseek(og);
|
||||
if(ret>0){
|
||||
// have a page
|
||||
return (1);
|
||||
}
|
||||
if(ret==0){
|
||||
// need more data
|
||||
return (0);
|
||||
}
|
||||
|
||||
// head did not start a synced page... skipped some bytes
|
||||
if(unsynced==0){
|
||||
unsynced=1;
|
||||
return (-1);
|
||||
}
|
||||
// loop. keep looking
|
||||
}
|
||||
}
|
||||
|
||||
// clear things to an initial state. Good to call, eg, before seeking
|
||||
public int reset(){
|
||||
fill=0;
|
||||
returned=0;
|
||||
unsynced=0;
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void init(){
|
||||
}
|
||||
|
||||
public int getDataOffset(){
|
||||
return returned;
|
||||
}
|
||||
|
||||
public int getBufferOffset(){
|
||||
return fill;
|
||||
}
|
||||
}
|
129
client/src/main/java/client/audio/jorbis/Block.java
Normal file
129
client/src/main/java/client/audio/jorbis/Block.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
import client.audio.jogg.Packet;
|
||||
|
||||
public class Block{
|
||||
///necessary stream state for linking to the framing abstraction
|
||||
float[][] pcm=new float[0][]; // this is a pointer into local storage
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int pcmend;
|
||||
int mode;
|
||||
|
||||
int eofflag;
|
||||
long granulepos;
|
||||
long sequence;
|
||||
DspState vd; // For read-only access of configuration
|
||||
|
||||
// bitmetrics for the frame
|
||||
int glue_bits;
|
||||
int time_bits;
|
||||
int floor_bits;
|
||||
int res_bits;
|
||||
|
||||
public Block(DspState vd){
|
||||
this.vd=vd;
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeinit();
|
||||
}
|
||||
}
|
||||
|
||||
public void init(DspState vd){
|
||||
this.vd=vd;
|
||||
}
|
||||
|
||||
public int clear(){
|
||||
if(vd!=null){
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeclear();
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis(Packet op){
|
||||
Info vi=vd.vi;
|
||||
|
||||
// first things first. Make sure decode is ready
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
// Check the packet type
|
||||
if(opb.read(1)!=0){
|
||||
// Oops. This is not an audio data packet
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// read our mode and pre/post windowsize
|
||||
int _mode=opb.read(vd.modebits);
|
||||
if(_mode==-1)
|
||||
return (-1);
|
||||
|
||||
mode=_mode;
|
||||
W=vi.mode_param[mode].blockflag;
|
||||
if(W!=0){
|
||||
lW=opb.read(1);
|
||||
nW=opb.read(1);
|
||||
if(nW==-1)
|
||||
return (-1);
|
||||
}
|
||||
else{
|
||||
lW=0;
|
||||
nW=0;
|
||||
}
|
||||
|
||||
// more setup
|
||||
granulepos=op.granulepos;
|
||||
sequence=op.packetno-3; // first block is third packet
|
||||
eofflag=op.e_o_s;
|
||||
|
||||
// alloc pcm passback storage
|
||||
pcmend=vi.blocksizes[W];
|
||||
if(pcm.length<vi.channels){
|
||||
pcm=new float[vi.channels][];
|
||||
}
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
if(pcm[i]==null||pcm[i].length<pcmend){
|
||||
pcm[i]=new float[pcmend];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<pcmend; j++){
|
||||
pcm[i][j]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unpack_header enforces range checking
|
||||
int type=vi.map_type[vi.mode_param[mode].mapping];
|
||||
return (FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class ChainingExample{
|
||||
public static void main(String[] arg){
|
||||
VorbisFile ov=null;
|
||||
|
||||
try{
|
||||
if(arg.length>0){
|
||||
ov=new VorbisFile(arg[0]);
|
||||
}
|
||||
else{
|
||||
ov=new VorbisFile(System.in, null, -1);
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ov.seekable()){
|
||||
System.out.println("Input bitstream contained "+ov.streams()
|
||||
+" logical bitstream section(s).");
|
||||
System.out.println("Total bitstream playing time: "+ov.time_total(-1)
|
||||
+" seconds\n");
|
||||
}
|
||||
else{
|
||||
System.out.println("Standard input was not seekable.");
|
||||
System.out.println("First logical bitstream information:\n");
|
||||
}
|
||||
|
||||
for(int i=0; i<ov.streams(); i++){
|
||||
Info vi=ov.getInfo(i);
|
||||
System.out.println("\tlogical bitstream section "+(i+1)+" information:");
|
||||
System.out.println("\t\t"+vi.rate+"Hz "+vi.channels+" channels bitrate "
|
||||
+(ov.bitrate(i)/1000)+"kbps serial number="+ov.serialnumber(i));
|
||||
System.out.print("\t\tcompressed length: "+ov.raw_total(i)+" bytes ");
|
||||
System.out.println(" play time: "+ov.time_total(i)+"s");
|
||||
Comment vc=ov.getComment(i);
|
||||
System.out.println(vc);
|
||||
}
|
||||
//ov.clear();
|
||||
}
|
||||
}
|
478
client/src/main/java/client/audio/jorbis/CodeBook.java
Normal file
478
client/src/main/java/client/audio/jorbis/CodeBook.java
Normal file
|
@ -0,0 +1,478 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class CodeBook{
|
||||
int dim; // codebook dimensions (elements per vector)
|
||||
int entries; // codebook entries
|
||||
StaticCodeBook c=new StaticCodeBook();
|
||||
|
||||
float[] valuelist; // list of dim*entries actual entry values
|
||||
int[] codelist; // list of bitstream codewords for each entry
|
||||
DecodeAux decode_tree;
|
||||
|
||||
// returns the number of bits
|
||||
int encode(int a, Buffer b){
|
||||
b.write(codelist[a], c.lengthlist[a]);
|
||||
return (c.lengthlist[a]);
|
||||
}
|
||||
|
||||
// One the encode side, our vector writers are each designed for a
|
||||
// specific purpose, and the encoder is not flexible without modification:
|
||||
//
|
||||
// The LSP vector coder uses a single stage nearest-match with no
|
||||
// interleave, so no step and no error return. This is specced by floor0
|
||||
// and doesn't change.
|
||||
//
|
||||
// Residue0 encoding interleaves, uses multiple stages, and each stage
|
||||
// peels of a specific amount of resolution from a lattice (thus we want
|
||||
// to match by threshhold, not nearest match). Residue doesn't *have* to
|
||||
// be encoded that way, but to change it, one will need to add more
|
||||
// infrastructure on the encode side (decode side is specced and simpler)
|
||||
|
||||
// floor0 LSP (single stage, non interleaved, nearest match)
|
||||
// returns entry number and *modifies a* to the quantization value
|
||||
int errorv(float[] a){
|
||||
int best=best(a, 1);
|
||||
for(int k=0; k<dim; k++){
|
||||
a[k]=valuelist[best*dim+k];
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
// returns the number of bits and *modifies a* to the quantization value
|
||||
int encodev(int best, float[] a, Buffer b){
|
||||
for(int k=0; k<dim; k++){
|
||||
a[k]=valuelist[best*dim+k];
|
||||
}
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
// res0 (multistage, interleave, lattice)
|
||||
// returns the number of bits and *modifies a* to the remainder value
|
||||
int encodevs(float[] a, Buffer b, int step, int addmul){
|
||||
int best=besterror(a, step, addmul);
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
|
||||
|
||||
synchronized int decodevs_add(float[] a, int offset, Buffer b, int n){
|
||||
int step=n/dim;
|
||||
int entry;
|
||||
int i, j, o;
|
||||
|
||||
if(t.length<step){
|
||||
t=new int[step];
|
||||
}
|
||||
|
||||
for(i=0; i<step; i++){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t[i]=entry*dim;
|
||||
}
|
||||
for(i=0, o=0; i<dim; i++, o+=step){
|
||||
for(j=0; j<step; j++){
|
||||
a[offset+o+j]+=valuelist[t[j]+i];
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_add(float[] a, int offset, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
if(dim>8){
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
for(j=0; j<dim;){
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
j=0;
|
||||
switch(dim){
|
||||
case 8:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 7:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 6:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 5:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 4:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 3:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 2:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 1:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_set(float[] a, int offset, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
for(j=0; j<dim;){
|
||||
a[offset+i++]=valuelist[t+(j++)];
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodevv_add(float[][] a, int offset, int ch, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int chptr=0;
|
||||
|
||||
for(i=offset/ch; i<(offset+n)/ch;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
|
||||
int t=entry*dim;
|
||||
for(j=0; j<dim; j++){
|
||||
a[chptr++][i]+=valuelist[t+j];
|
||||
if(chptr==ch){
|
||||
chptr=0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Decode side is specced and easier, because we don't need to find
|
||||
// matches using different criteria; we simply read and map. There are
|
||||
// two things we need to do 'depending':
|
||||
//
|
||||
// We may need to support interleave. We don't really, but it's
|
||||
// convenient to do it here rather than rebuild the vector later.
|
||||
//
|
||||
// Cascades may be additive or multiplicitive; this is not inherent in
|
||||
// the codebook, but set in the code using the codebook. Like
|
||||
// interleaving, it's easiest to do it here.
|
||||
// stage==0 -> declarative (set the value)
|
||||
// stage==1 -> additive
|
||||
// stage==2 -> multiplicitive
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decode(Buffer b){
|
||||
int ptr=0;
|
||||
DecodeAux t=decode_tree;
|
||||
int lok=b.look(t.tabn);
|
||||
|
||||
if(lok>=0){
|
||||
ptr=t.tab[lok];
|
||||
b.adv(t.tabl[lok]);
|
||||
if(ptr<=0){
|
||||
return -ptr;
|
||||
}
|
||||
}
|
||||
do{
|
||||
switch(b.read1()){
|
||||
case 0:
|
||||
ptr=t.ptr0[ptr];
|
||||
break;
|
||||
case 1:
|
||||
ptr=t.ptr1[ptr];
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
while(ptr>0);
|
||||
return (-ptr);
|
||||
}
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decodevs(float[] a, int index, Buffer b, int step, int addmul){
|
||||
int entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
switch(addmul){
|
||||
case -1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]=valuelist[entry*dim+i];
|
||||
break;
|
||||
case 0:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]+=valuelist[entry*dim+i];
|
||||
break;
|
||||
case 1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]*=valuelist[entry*dim+i];
|
||||
break;
|
||||
default:
|
||||
//System.err.println("CodeBook.decodeves: addmul="+addmul);
|
||||
}
|
||||
return (entry);
|
||||
}
|
||||
|
||||
int best(float[] a, int step){
|
||||
// brute force it!
|
||||
{
|
||||
int besti=-1;
|
||||
float best=0.f;
|
||||
int e=0;
|
||||
for(int i=0; i<entries; i++){
|
||||
if(c.lengthlist[i]>0){
|
||||
float _this=dist(dim, valuelist, e, a, step);
|
||||
if(besti==-1||_this<best){
|
||||
best=_this;
|
||||
besti=i;
|
||||
}
|
||||
}
|
||||
e+=dim;
|
||||
}
|
||||
return (besti);
|
||||
}
|
||||
}
|
||||
|
||||
// returns the entry number and *modifies a* to the remainder value
|
||||
int besterror(float[] a, int step, int addmul){
|
||||
int best=best(a, step);
|
||||
switch(addmul){
|
||||
case 0:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[o]-=valuelist[best*dim+i];
|
||||
break;
|
||||
case 1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step){
|
||||
float val=valuelist[best*dim+i];
|
||||
if(val==0){
|
||||
a[o]=0;
|
||||
}
|
||||
else{
|
||||
a[o]/=val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
private static float dist(int el, float[] ref, int index, float[] b, int step){
|
||||
float acc=(float)0.;
|
||||
for(int i=0; i<el; i++){
|
||||
float val=(ref[index+i]-b[i*step]);
|
||||
acc+=val*val;
|
||||
}
|
||||
return (acc);
|
||||
}
|
||||
|
||||
int init_decode(StaticCodeBook s){
|
||||
c=s;
|
||||
entries=s.entries;
|
||||
dim=s.dim;
|
||||
valuelist=s.unquantize();
|
||||
|
||||
decode_tree=make_decode_tree();
|
||||
if(decode_tree==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// given a list of word lengths, generate a list of codewords. Works
|
||||
// for length ordered or unordered, always assigns the lowest valued
|
||||
// codewords first. Extended to handle unused entries (length 0)
|
||||
static int[] make_words(int[] l, int n){
|
||||
int[] marker=new int[33];
|
||||
int[] r=new int[n];
|
||||
|
||||
for(int i=0; i<n; i++){
|
||||
int length=l[i];
|
||||
if(length>0){
|
||||
int entry=marker[length];
|
||||
|
||||
// when we claim a node for an entry, we also claim the nodes
|
||||
// below it (pruning off the imagined tree that may have dangled
|
||||
// from it) as well as blocking the use of any nodes directly
|
||||
// above for leaves
|
||||
|
||||
// update ourself
|
||||
if(length<32&&(entry>>>length)!=0){
|
||||
// error condition; the lengths must specify an overpopulated tree
|
||||
//free(r);
|
||||
return (null);
|
||||
}
|
||||
r[i]=entry;
|
||||
|
||||
// Look to see if the next shorter marker points to the node
|
||||
// above. if so, update it and repeat.
|
||||
{
|
||||
for(int j=length; j>0; j--){
|
||||
if((marker[j]&1)!=0){
|
||||
// have to jump branches
|
||||
if(j==1)
|
||||
marker[1]++;
|
||||
else
|
||||
marker[j]=marker[j-1]<<1;
|
||||
break; // invariant says next upper marker would already
|
||||
// have been moved if it was on the same path
|
||||
}
|
||||
marker[j]++;
|
||||
}
|
||||
}
|
||||
|
||||
// prune the tree; the implicit invariant says all the longer
|
||||
// markers were dangling from our just-taken node. Dangle them
|
||||
// from our *new* node.
|
||||
for(int j=length+1; j<33; j++){
|
||||
if((marker[j]>>>1)==entry){
|
||||
entry=marker[j];
|
||||
marker[j]=marker[j-1]<<1;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bitreverse the words because our bitwise packer/unpacker is LSb
|
||||
// endian
|
||||
for(int i=0; i<n; i++){
|
||||
int temp=0;
|
||||
for(int j=0; j<l[i]; j++){
|
||||
temp<<=1;
|
||||
temp|=(r[i]>>>j)&1;
|
||||
}
|
||||
r[i]=temp;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
// build the decode helper tree from the codewords
|
||||
DecodeAux make_decode_tree(){
|
||||
int top=0;
|
||||
DecodeAux t=new DecodeAux();
|
||||
int[] ptr0=t.ptr0=new int[entries*2];
|
||||
int[] ptr1=t.ptr1=new int[entries*2];
|
||||
int[] codelist=make_words(c.lengthlist, c.entries);
|
||||
|
||||
if(codelist==null)
|
||||
return (null);
|
||||
t.aux=entries*2;
|
||||
|
||||
for(int i=0; i<entries; i++){
|
||||
if(c.lengthlist[i]>0){
|
||||
int ptr=0;
|
||||
int j;
|
||||
for(j=0; j<c.lengthlist[i]-1; j++){
|
||||
int bit=(codelist[i]>>>j)&1;
|
||||
if(bit==0){
|
||||
if(ptr0[ptr]==0){
|
||||
ptr0[ptr]=++top;
|
||||
}
|
||||
ptr=ptr0[ptr];
|
||||
}
|
||||
else{
|
||||
if(ptr1[ptr]==0){
|
||||
ptr1[ptr]=++top;
|
||||
}
|
||||
ptr=ptr1[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
if(((codelist[i]>>>j)&1)==0){
|
||||
ptr0[ptr]=-i;
|
||||
}
|
||||
else{
|
||||
ptr1[ptr]=-i;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
t.tabn=Util.ilog(entries)-4;
|
||||
|
||||
if(t.tabn<5)
|
||||
t.tabn=5;
|
||||
int n=1<<t.tabn;
|
||||
t.tab=new int[n];
|
||||
t.tabl=new int[n];
|
||||
for(int i=0; i<n; i++){
|
||||
int p=0;
|
||||
int j=0;
|
||||
for(j=0; j<t.tabn&&(p>0||j==0); j++){
|
||||
if((i&(1<<j))!=0){
|
||||
p=ptr1[p];
|
||||
}
|
||||
else{
|
||||
p=ptr0[p];
|
||||
}
|
||||
}
|
||||
t.tab[i]=p; // -code
|
||||
t.tabl[i]=j; // length
|
||||
}
|
||||
|
||||
return (t);
|
||||
}
|
||||
|
||||
class DecodeAux{
|
||||
int[] tab;
|
||||
int[] tabl;
|
||||
int tabn;
|
||||
|
||||
int[] ptr0;
|
||||
int[] ptr1;
|
||||
int aux; // number of tree entries
|
||||
}
|
||||
}
|
244
client/src/main/java/client/audio/jorbis/Comment.java
Normal file
244
client/src/main/java/client/audio/jorbis/Comment.java
Normal file
|
@ -0,0 +1,244 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
import client.audio.jogg.Packet;
|
||||
|
||||
// the comments are not part of vorbis_info so that vorbis_info can be
|
||||
// static storage
|
||||
public class Comment{
|
||||
private static byte[] _vorbis="vorbis".getBytes();
|
||||
private static byte[] _vendor="Xiphophorus libVorbis I 20000508".getBytes();
|
||||
|
||||
private static final int OV_EIMPL=-130;
|
||||
|
||||
// unlimited user comment fields.
|
||||
public byte[][] user_comments;
|
||||
public int[] comment_lengths;
|
||||
public int comments;
|
||||
public byte[] vendor;
|
||||
|
||||
public void init(){
|
||||
user_comments=null;
|
||||
comments=0;
|
||||
vendor=null;
|
||||
}
|
||||
|
||||
public void add(String comment){
|
||||
add(comment.getBytes());
|
||||
}
|
||||
|
||||
private void add(byte[] comment){
|
||||
byte[][] foo=new byte[comments+2][];
|
||||
if(user_comments!=null){
|
||||
System.arraycopy(user_comments, 0, foo, 0, comments);
|
||||
}
|
||||
user_comments=foo;
|
||||
|
||||
int[] goo=new int[comments+2];
|
||||
if(comment_lengths!=null){
|
||||
System.arraycopy(comment_lengths, 0, goo, 0, comments);
|
||||
}
|
||||
comment_lengths=goo;
|
||||
|
||||
byte[] bar=new byte[comment.length+1];
|
||||
System.arraycopy(comment, 0, bar, 0, comment.length);
|
||||
user_comments[comments]=bar;
|
||||
comment_lengths[comments]=comment.length;
|
||||
comments++;
|
||||
user_comments[comments]=null;
|
||||
}
|
||||
|
||||
public void add_tag(String tag, String contents){
|
||||
if(contents==null)
|
||||
contents="";
|
||||
add(tag+"="+contents);
|
||||
}
|
||||
|
||||
static boolean tagcompare(byte[] s1, byte[] s2, int n){
|
||||
int c=0;
|
||||
byte u1, u2;
|
||||
while(c<n){
|
||||
u1=s1[c];
|
||||
u2=s2[c];
|
||||
if('Z'>=u1&&u1>='A')
|
||||
u1=(byte)(u1-'A'+'a');
|
||||
if('Z'>=u2&&u2>='A')
|
||||
u2=(byte)(u2-'A'+'a');
|
||||
if(u1!=u2){
|
||||
return false;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String query(String tag){
|
||||
return query(tag, 0);
|
||||
}
|
||||
|
||||
public String query(String tag, int count){
|
||||
int foo=query(tag.getBytes(), count);
|
||||
if(foo==-1)
|
||||
return null;
|
||||
byte[] comment=user_comments[foo];
|
||||
for(int i=0; i<comment_lengths[foo]; i++){
|
||||
if(comment[i]=='='){
|
||||
return new String(comment, i+1, comment_lengths[foo]-(i+1));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int query(byte[] tag, int count){
|
||||
int i=0;
|
||||
int found=0;
|
||||
int fulltaglen=tag.length+1;
|
||||
byte[] fulltag=new byte[fulltaglen];
|
||||
System.arraycopy(tag, 0, fulltag, 0, tag.length);
|
||||
fulltag[tag.length]=(byte)'=';
|
||||
|
||||
for(i=0; i<comments; i++){
|
||||
if(tagcompare(user_comments[i], fulltag, fulltaglen)){
|
||||
if(count==found){
|
||||
// We return a pointer to the data, not a copy
|
||||
//return user_comments[i] + taglen + 1;
|
||||
return i;
|
||||
}
|
||||
else{
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unpack(Buffer opb){
|
||||
int vendorlen=opb.read(32);
|
||||
if(vendorlen<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
vendor=new byte[vendorlen+1];
|
||||
opb.read(vendor, vendorlen);
|
||||
comments=opb.read(32);
|
||||
if(comments<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
user_comments=new byte[comments+1][];
|
||||
comment_lengths=new int[comments+1];
|
||||
|
||||
for(int i=0; i<comments; i++){
|
||||
int len=opb.read(32);
|
||||
if(len<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
comment_lengths[i]=len;
|
||||
user_comments[i]=new byte[len+1];
|
||||
opb.read(user_comments[i], len);
|
||||
}
|
||||
if(opb.read(1)!=1){
|
||||
clear();
|
||||
return (-1);
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pack(Buffer opb){
|
||||
// preamble
|
||||
opb.write(0x03, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// vendor
|
||||
opb.write(_vendor.length, 32);
|
||||
opb.write(_vendor);
|
||||
|
||||
// comments
|
||||
opb.write(comments, 32);
|
||||
if(comments!=0){
|
||||
for(int i=0; i<comments; i++){
|
||||
if(user_comments[i]!=null){
|
||||
opb.write(comment_lengths[i], 32);
|
||||
opb.write(user_comments[i]);
|
||||
}
|
||||
else{
|
||||
opb.write(0, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int header_out(Packet op){
|
||||
Buffer opb=new Buffer();
|
||||
opb.writeinit();
|
||||
|
||||
if(pack(opb)!=0)
|
||||
return OV_EIMPL;
|
||||
|
||||
op.packet_base=new byte[opb.bytes()];
|
||||
op.packet=0;
|
||||
op.bytes=opb.bytes();
|
||||
System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
|
||||
op.b_o_s=0;
|
||||
op.e_o_s=0;
|
||||
op.granulepos=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
for(int i=0; i<comments; i++)
|
||||
user_comments[i]=null;
|
||||
user_comments=null;
|
||||
vendor=null;
|
||||
}
|
||||
|
||||
public String getVendor(){
|
||||
return new String(vendor, 0, vendor.length-1);
|
||||
}
|
||||
|
||||
public String getComment(int i){
|
||||
if(comments<=i)
|
||||
return null;
|
||||
return new String(user_comments[i], 0, user_comments[i].length-1);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
String foo="Vendor: "+new String(vendor, 0, vendor.length-1);
|
||||
for(int i=0; i<comments; i++){
|
||||
foo=foo+"\nComment: "
|
||||
+new String(user_comments[i], 0, user_comments[i].length-1);
|
||||
}
|
||||
foo=foo+"\n";
|
||||
return foo;
|
||||
}
|
||||
}
|
327
client/src/main/java/client/audio/jorbis/DecodeExample.java
Normal file
327
client/src/main/java/client/audio/jorbis/DecodeExample.java
Normal file
|
@ -0,0 +1,327 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Packet;
|
||||
import client.audio.jogg.Page;
|
||||
import client.audio.jogg.StreamState;
|
||||
import client.audio.jogg.SyncState;
|
||||
|
||||
// Takes a vorbis bitstream from stdin and writes raw stereo PCM to
|
||||
// stdout. Decodes simple and chained OggVorbis files from beginning
|
||||
// to end. Vorbisfile.a is somewhat more complex than the code below.
|
||||
|
||||
class DecodeExample{
|
||||
static int convsize=4096*2;
|
||||
static byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack
|
||||
|
||||
public static void main(String[] arg){
|
||||
java.io.InputStream input=System.in;
|
||||
if(arg.length>0){
|
||||
try{
|
||||
input=new java.io.FileInputStream(arg[0]);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
SyncState oy=new SyncState(); // sync and verify incoming physical bitstream
|
||||
StreamState os=new StreamState(); // take physical pages, weld into a logical stream of packets
|
||||
Page og=new Page(); // one Ogg bitstream page. Vorbis packets are inside
|
||||
Packet op=new Packet(); // one raw packet of data for decode
|
||||
|
||||
Info vi=new Info(); // struct that stores all the static vorbis bitstream settings
|
||||
Comment vc=new Comment(); // struct that stores all the bitstream user comments
|
||||
DspState vd=new DspState(); // central working state for the packet->PCM decoder
|
||||
Block vb=new Block(vd); // local working space for packet->PCM decode
|
||||
|
||||
byte[] buffer;
|
||||
int bytes=0;
|
||||
|
||||
// Decode setup
|
||||
|
||||
oy.init(); // Now we can read pages
|
||||
|
||||
while(true){ // we repeat if the bitstream is chained
|
||||
int eos=0;
|
||||
|
||||
// grab some data at the head of the stream. We want the first page
|
||||
// (which is guaranteed to be small and only contain the Vorbis
|
||||
// stream initial header) We need the first page to get the stream
|
||||
// serialno.
|
||||
|
||||
// submit a 4k block to libvorbis' Ogg layer
|
||||
int index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(-1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
|
||||
// Get the first page.
|
||||
if(oy.pageout(og)!=1){
|
||||
// have we simply run out of data? If so, we're done.
|
||||
if(bytes<4096)
|
||||
break;
|
||||
|
||||
// error case. Must not be Vorbis data
|
||||
System.err.println("Input does not appear to be an Ogg bitstream.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Get the serial number and set up the rest of decode.
|
||||
// serialno first; use it to set up a logical stream
|
||||
os.init(og.serialno());
|
||||
|
||||
// extract the initial header from the first page and verify that the
|
||||
// Ogg bitstream is in fact Vorbis data
|
||||
|
||||
// I handle the initial header first instead of just having the code
|
||||
// read all three Vorbis headers at once because reading the initial
|
||||
// header is an easy way to identify a Vorbis bitstream and it's
|
||||
// useful to see that functionality seperated out.
|
||||
|
||||
vi.init();
|
||||
vc.init();
|
||||
if(os.pagein(og)<0){
|
||||
// error; stream version mismatch perhaps
|
||||
System.err.println("Error reading first page of Ogg bitstream data.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(os.packetout(op)!=1){
|
||||
// no page? must not be vorbis
|
||||
System.err.println("Error reading initial header packet.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(vi.synthesis_headerin(vc, op)<0){
|
||||
// error case; not a vorbis header
|
||||
System.err
|
||||
.println("This Ogg bitstream does not contain Vorbis audio data.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// At this point, we're sure we're Vorbis. We've set up the logical
|
||||
// (Ogg) bitstream decoder. Get the comment and codebook headers and
|
||||
// set up the Vorbis decoder
|
||||
|
||||
// The next two packets in order are the comment and codebook headers.
|
||||
// They're likely large and may span multiple pages. Thus we reead
|
||||
// and submit data until we get our two pacakets, watching that no
|
||||
// pages are missing. If a page is missing, error out; losing a
|
||||
// header page is the only place where missing data is fatal. */
|
||||
|
||||
int i=0;
|
||||
while(i<2){
|
||||
while(i<2){
|
||||
|
||||
int result=oy.pageout(og);
|
||||
if(result==0)
|
||||
break; // Need more data
|
||||
// Don't complain about missing or corrupt data yet. We'll
|
||||
// catch it at the packet output phase
|
||||
|
||||
if(result==1){
|
||||
os.pagein(og); // we can ignore any errors here
|
||||
// as they'll also become apparent
|
||||
// at packetout
|
||||
while(i<2){
|
||||
result=os.packetout(op);
|
||||
if(result==0)
|
||||
break;
|
||||
if(result==-1){
|
||||
// Uh oh; data at some point was corrupted or missing!
|
||||
// We can't tolerate that in a header. Die.
|
||||
System.err.println("Corrupt secondary header. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
vi.synthesis_headerin(vc, op);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no harm in not checking before adding more
|
||||
index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
}
|
||||
if(bytes==0&&i<2){
|
||||
System.err.println("End of file before finding all Vorbis headers!");
|
||||
System.exit(1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
}
|
||||
|
||||
// Throw the comments plus a few lines about the bitstream we're
|
||||
// decoding
|
||||
{
|
||||
byte[][] ptr=vc.user_comments;
|
||||
for(int j=0; j<ptr.length; j++){
|
||||
if(ptr[j]==null)
|
||||
break;
|
||||
System.err.println(new String(ptr[j], 0, ptr[j].length-1));
|
||||
}
|
||||
System.err.println("\nBitstream is "+vi.channels+" channel, "+vi.rate
|
||||
+"Hz");
|
||||
System.err.println("Encoded by: "
|
||||
+new String(vc.vendor, 0, vc.vendor.length-1)+"\n");
|
||||
}
|
||||
|
||||
convsize=4096/vi.channels;
|
||||
|
||||
// OK, got and parsed all three headers. Initialize the Vorbis
|
||||
// packet->PCM decoder.
|
||||
vd.synthesis_init(vi); // central decode state
|
||||
vb.init(vd); // local state for most of the decode
|
||||
// so multiple block decodes can
|
||||
// proceed in parallel. We could init
|
||||
// multiple vorbis_block structures
|
||||
// for vd here
|
||||
|
||||
float[][][] _pcm=new float[1][][];
|
||||
int[] _index=new int[vi.channels];
|
||||
// The rest is just a straight decode loop until end of stream
|
||||
while(eos==0){
|
||||
while(eos==0){
|
||||
|
||||
int result=oy.pageout(og);
|
||||
if(result==0)
|
||||
break; // need more data
|
||||
if(result==-1){ // missing or corrupt data at this page position
|
||||
System.err
|
||||
.println("Corrupt or missing data in bitstream; continuing...");
|
||||
}
|
||||
else{
|
||||
os.pagein(og); // can safely ignore errors at
|
||||
// this point
|
||||
while(true){
|
||||
result=os.packetout(op);
|
||||
|
||||
if(result==0)
|
||||
break; // need more data
|
||||
if(result==-1){ // missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
}
|
||||
else{
|
||||
// we have a packet. Decode it
|
||||
int samples;
|
||||
if(vb.synthesis(op)==0){ // test for success!
|
||||
vd.synthesis_blockin(vb);
|
||||
}
|
||||
|
||||
// **pcm is a multichannel float vector. In stereo, for
|
||||
// example, pcm[0] is left, and pcm[1] is right. samples is
|
||||
// the size of each channel. Convert the float values
|
||||
// (-1.<=range<=1.) to whatever PCM format and write it out
|
||||
|
||||
while((samples=vd.synthesis_pcmout(_pcm, _index))>0){
|
||||
float[][] pcm=_pcm[0];
|
||||
int bout=(samples<convsize ? samples : convsize);
|
||||
|
||||
// convert floats to 16 bit signed ints (host order) and
|
||||
// interleave
|
||||
for(i=0; i<vi.channels; i++){
|
||||
int ptr=i*2;
|
||||
//int ptr=i;
|
||||
int mono=_index[i];
|
||||
for(int j=0; j<bout; j++){
|
||||
int val=(int)(pcm[i][mono+j]*32767.);
|
||||
// short val=(short)(pcm[i][mono+j]*32767.);
|
||||
// int val=(int)Math.round(pcm[i][mono+j]*32767.);
|
||||
// might as well guard against clipping
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
}
|
||||
if(val<0)
|
||||
val=val|0x8000;
|
||||
convbuffer[ptr]=(byte)(val);
|
||||
convbuffer[ptr+1]=(byte)(val>>>8);
|
||||
ptr+=2*(vi.channels);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.write(convbuffer, 0, 2*vi.channels*bout);
|
||||
|
||||
// tell libvorbis how
|
||||
// many samples we
|
||||
// actually consumed
|
||||
vd.synthesis_read(bout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(og.eos()!=0)
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
if(eos==0){
|
||||
index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
if(bytes==0)
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up this logical bitstream; before exit we see if we're
|
||||
// followed by another [chained]
|
||||
|
||||
os.clear();
|
||||
|
||||
// ogg_page and ogg_packet structs always point to storage in
|
||||
// libvorbis. They're never freed or manipulated directly
|
||||
|
||||
vb.clear();
|
||||
vd.clear();
|
||||
vi.clear(); // must be called last
|
||||
}
|
||||
|
||||
// OK, clean up the framer
|
||||
oy.clear();
|
||||
System.err.println("Done.");
|
||||
}
|
||||
}
|
1327
client/src/main/java/client/audio/jorbis/Drft.java
Normal file
1327
client/src/main/java/client/audio/jorbis/Drft.java
Normal file
File diff suppressed because it is too large
Load diff
376
client/src/main/java/client/audio/jorbis/DspState.java
Normal file
376
client/src/main/java/client/audio/jorbis/DspState.java
Normal file
|
@ -0,0 +1,376 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
public class DspState{
|
||||
static final float M_PI=3.1415926539f;
|
||||
static final int VI_TRANSFORMB=1;
|
||||
static final int VI_WINDOWB=1;
|
||||
|
||||
int analysisp;
|
||||
Info vi;
|
||||
int modebits;
|
||||
|
||||
float[][] pcm;
|
||||
int pcm_storage;
|
||||
int pcm_current;
|
||||
int pcm_returned;
|
||||
|
||||
float[] multipliers;
|
||||
int envelope_storage;
|
||||
int envelope_current;
|
||||
|
||||
int eofflag;
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int centerW;
|
||||
|
||||
long granulepos;
|
||||
long sequence;
|
||||
|
||||
long glue_bits;
|
||||
long time_bits;
|
||||
long floor_bits;
|
||||
long res_bits;
|
||||
|
||||
// local lookup storage
|
||||
float[][][][][] window; // block, leadin, leadout, type
|
||||
Object[][] transform;
|
||||
CodeBook[] fullbooks;
|
||||
// backend lookups are tied to the mode, not the backend or naked mapping
|
||||
Object[] mode;
|
||||
|
||||
// local storage, only used on the encoding side. This way the
|
||||
// application does not need to worry about freeing some packets'
|
||||
// memory and not others'; packet storage is always tracked.
|
||||
// Cleared next call to a _dsp_ function
|
||||
byte[] header;
|
||||
byte[] header1;
|
||||
byte[] header2;
|
||||
|
||||
public DspState(){
|
||||
transform=new Object[2][];
|
||||
window=new float[2][][][][];
|
||||
window[0]=new float[2][][][];
|
||||
window[0][0]=new float[2][][];
|
||||
window[0][1]=new float[2][][];
|
||||
window[0][0][0]=new float[2][];
|
||||
window[0][0][1]=new float[2][];
|
||||
window[0][1][0]=new float[2][];
|
||||
window[0][1][1]=new float[2][];
|
||||
window[1]=new float[2][][][];
|
||||
window[1][0]=new float[2][][];
|
||||
window[1][1]=new float[2][][];
|
||||
window[1][0][0]=new float[2][];
|
||||
window[1][0][1]=new float[2][];
|
||||
window[1][1][0]=new float[2][];
|
||||
window[1][1][1]=new float[2][];
|
||||
}
|
||||
|
||||
static float[] window(int type, int window, int left, int right){
|
||||
float[] ret=new float[window];
|
||||
switch(type){
|
||||
case 0:
|
||||
// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
|
||||
{
|
||||
int leftbegin=window/4-left/2;
|
||||
int rightbegin=window-window/4-right/2;
|
||||
|
||||
for(int i=0; i<left; i++){
|
||||
float x=(float)((i+.5)/left*M_PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=M_PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
ret[i+leftbegin]=x;
|
||||
}
|
||||
|
||||
for(int i=leftbegin+left; i<rightbegin; i++){
|
||||
ret[i]=1.f;
|
||||
}
|
||||
|
||||
for(int i=0; i<right; i++){
|
||||
float x=(float)((right-i-.5)/right*M_PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=M_PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
ret[i+rightbegin]=x;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//free(ret);
|
||||
return (null);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
// Analysis side code, but directly related to blocking. Thus it's
|
||||
// here and not in analysis.c (which is for analysis transforms only).
|
||||
// The init is here because some of it is shared
|
||||
|
||||
int init(Info vi, boolean encp){
|
||||
this.vi=vi;
|
||||
modebits=Util.ilog2(vi.modes);
|
||||
|
||||
transform[0]=new Object[VI_TRANSFORMB];
|
||||
transform[1]=new Object[VI_TRANSFORMB];
|
||||
|
||||
// MDCT is tranform 0
|
||||
|
||||
transform[0][0]=new Mdct();
|
||||
transform[1][0]=new Mdct();
|
||||
((Mdct)transform[0][0]).init(vi.blocksizes[0]);
|
||||
((Mdct)transform[1][0]).init(vi.blocksizes[1]);
|
||||
|
||||
window[0][0][0]=new float[VI_WINDOWB][];
|
||||
window[0][0][1]=window[0][0][0];
|
||||
window[0][1][0]=window[0][0][0];
|
||||
window[0][1][1]=window[0][0][0];
|
||||
window[1][0][0]=new float[VI_WINDOWB][];
|
||||
window[1][0][1]=new float[VI_WINDOWB][];
|
||||
window[1][1][0]=new float[VI_WINDOWB][];
|
||||
window[1][1][1]=new float[VI_WINDOWB][];
|
||||
|
||||
for(int i=0; i<VI_WINDOWB; i++){
|
||||
window[0][0][0][i]=window(i, vi.blocksizes[0], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][0][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][0][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[1]/2);
|
||||
window[1][1][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][1][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
|
||||
vi.blocksizes[1]/2);
|
||||
}
|
||||
|
||||
fullbooks=new CodeBook[vi.books];
|
||||
for(int i=0; i<vi.books; i++){
|
||||
fullbooks[i]=new CodeBook();
|
||||
fullbooks[i].init_decode(vi.book_param[i]);
|
||||
}
|
||||
|
||||
// initialize the storage vectors to a decent size greater than the
|
||||
// minimum
|
||||
|
||||
pcm_storage=8192; // we'll assume later that we have
|
||||
// a minimum of twice the blocksize of
|
||||
// accumulated samples in analysis
|
||||
pcm=new float[vi.channels][];
|
||||
{
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
pcm[i]=new float[pcm_storage];
|
||||
}
|
||||
}
|
||||
|
||||
// all 1 (large block) or 0 (small block)
|
||||
// explicitly set for the sake of clarity
|
||||
lW=0; // previous window size
|
||||
W=0; // current window size
|
||||
|
||||
// all vector indexes; multiples of samples_per_envelope_step
|
||||
centerW=vi.blocksizes[1]/2;
|
||||
|
||||
pcm_current=centerW;
|
||||
|
||||
// initialize all the mapping/backend lookups
|
||||
mode=new Object[vi.modes];
|
||||
for(int i=0; i<vi.modes; i++){
|
||||
int mapnum=vi.mode_param[i].mapping;
|
||||
int maptype=vi.map_type[mapnum];
|
||||
mode[i]=FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i],
|
||||
vi.map_param[mapnum]);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_init(Info vi){
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned=centerW;
|
||||
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
|
||||
granulepos=-1;
|
||||
sequence=-1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DspState(Info vi){
|
||||
this();
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned=centerW;
|
||||
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
|
||||
granulepos=-1;
|
||||
sequence=-1;
|
||||
}
|
||||
|
||||
// Unike in analysis, the window is only partially applied for each
|
||||
// block. The time domain envelope is not yet handled at the point of
|
||||
// calling (as it relies on the previous block).
|
||||
|
||||
public int synthesis_blockin(Block vb){
|
||||
// Shift out any PCM/multipliers that we returned previously
|
||||
// centerW is currently the center of the last block added
|
||||
if(centerW>vi.blocksizes[1]/2&&pcm_returned>8192){
|
||||
// don't shift too much; we need to have a minimum PCM buffer of
|
||||
// 1/2 long block
|
||||
|
||||
int shiftPCM=centerW-vi.blocksizes[1]/2;
|
||||
shiftPCM=(pcm_returned<shiftPCM ? pcm_returned : shiftPCM);
|
||||
|
||||
pcm_current-=shiftPCM;
|
||||
centerW-=shiftPCM;
|
||||
pcm_returned-=shiftPCM;
|
||||
if(shiftPCM!=0){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lW=W;
|
||||
W=vb.W;
|
||||
nW=-1;
|
||||
|
||||
glue_bits+=vb.glue_bits;
|
||||
time_bits+=vb.time_bits;
|
||||
floor_bits+=vb.floor_bits;
|
||||
res_bits+=vb.res_bits;
|
||||
|
||||
if(sequence+1!=vb.sequence)
|
||||
granulepos=-1; // out of sequence; lose count
|
||||
|
||||
sequence=vb.sequence;
|
||||
|
||||
{
|
||||
int sizeW=vi.blocksizes[W];
|
||||
int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4;
|
||||
int beginW=_centerW-sizeW/2;
|
||||
int endW=beginW+sizeW;
|
||||
int beginSl=0;
|
||||
int endSl=0;
|
||||
|
||||
// Do we have enough PCM/mult storage for the block?
|
||||
if(endW>pcm_storage){
|
||||
// expand the storage
|
||||
pcm_storage=endW+vi.blocksizes[1];
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] foo=new float[pcm_storage];
|
||||
System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
|
||||
pcm[i]=foo;
|
||||
}
|
||||
}
|
||||
|
||||
// overlap/add PCM
|
||||
switch(W){
|
||||
case 0:
|
||||
beginSl=0;
|
||||
endSl=vi.blocksizes[0]/2;
|
||||
break;
|
||||
case 1:
|
||||
beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4;
|
||||
endSl=beginSl+vi.blocksizes[lW]/2;
|
||||
break;
|
||||
}
|
||||
|
||||
for(int j=0; j<vi.channels; j++){
|
||||
int _pcm=beginW;
|
||||
// the overlap/add section
|
||||
int i=0;
|
||||
for(i=beginSl; i<endSl; i++){
|
||||
pcm[j][_pcm+i]+=vb.pcm[j][i];
|
||||
}
|
||||
// the remaining section
|
||||
for(; i<sizeW; i++){
|
||||
pcm[j][_pcm+i]=vb.pcm[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
// track the frame number... This is for convenience, but also
|
||||
// making sure our last packet doesn't end with added padding. If
|
||||
// the last packet is partial, the number of samples we'll have to
|
||||
// return will be past the vb->granulepos.
|
||||
//
|
||||
// This is not foolproof! It will be confused if we begin
|
||||
// decoding at the last page after a seek or hole. In that case,
|
||||
// we don't have a starting point to judge where the last frame
|
||||
// is. For this reason, vorbisfile will always try to make sure
|
||||
// it reads the last two marked pages in proper sequence
|
||||
|
||||
if(granulepos==-1){
|
||||
granulepos=vb.granulepos;
|
||||
}
|
||||
else{
|
||||
granulepos+=(_centerW-centerW);
|
||||
if(vb.granulepos!=-1&&granulepos!=vb.granulepos){
|
||||
if(granulepos>vb.granulepos&&vb.eofflag!=0){
|
||||
// partial last frame. Strip the padding off
|
||||
_centerW-=(granulepos-vb.granulepos);
|
||||
}// else{ Shouldn't happen *unless* the bitstream is out of
|
||||
// spec. Either way, believe the bitstream }
|
||||
granulepos=vb.granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
// Update, cleanup
|
||||
|
||||
centerW=_centerW;
|
||||
pcm_current=endW;
|
||||
if(vb.eofflag!=0)
|
||||
eofflag=1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// pcm==NULL indicates we just want the pending samples, no more
|
||||
public int synthesis_pcmout(float[][][] _pcm, int[] index){
|
||||
if(pcm_returned<centerW){
|
||||
if(_pcm!=null){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
index[i]=pcm_returned;
|
||||
}
|
||||
_pcm[0]=pcm;
|
||||
}
|
||||
return (centerW-pcm_returned);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_read(int bytes){
|
||||
if(bytes!=0&&pcm_returned+bytes>centerW)
|
||||
return (-1);
|
||||
pcm_returned+=bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
}
|
||||
}
|
335
client/src/main/java/client/audio/jorbis/Floor0.java
Normal file
335
client/src/main/java/client/audio/jorbis/Floor0.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class Floor0 extends FuncFloor{
|
||||
|
||||
void pack(Object i, Buffer opb){
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
opb.write(info.order, 8);
|
||||
opb.write(info.rate, 16);
|
||||
opb.write(info.barkmap, 16);
|
||||
opb.write(info.ampbits, 6);
|
||||
opb.write(info.ampdB, 8);
|
||||
opb.write(info.numbooks-1, 4);
|
||||
for(int j=0; j<info.numbooks; j++)
|
||||
opb.write(info.books[j], 8);
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
InfoFloor0 info=new InfoFloor0();
|
||||
info.order=opb.read(8);
|
||||
info.rate=opb.read(16);
|
||||
info.barkmap=opb.read(16);
|
||||
info.ampbits=opb.read(6);
|
||||
info.ampdB=opb.read(8);
|
||||
info.numbooks=opb.read(4)+1;
|
||||
|
||||
if((info.order<1)||(info.rate<1)||(info.barkmap<1)||(info.numbooks<1)){
|
||||
return (null);
|
||||
}
|
||||
|
||||
for(int j=0; j<info.numbooks; j++){
|
||||
info.books[j]=opb.read(8);
|
||||
if(info.books[j]<0||info.books[j]>=vi.books){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
float scale;
|
||||
Info vi=vd.vi;
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
LookFloor0 look=new LookFloor0();
|
||||
look.m=info.order;
|
||||
look.n=vi.blocksizes[mi.blockflag]/2;
|
||||
look.ln=info.barkmap;
|
||||
look.vi=info;
|
||||
look.lpclook.init(look.ln, look.m);
|
||||
|
||||
// we choose a scaling constant so that:
|
||||
scale=look.ln/toBARK((float)(info.rate/2.));
|
||||
|
||||
// the mapping from a linear scale to a smaller bark scale is
|
||||
// straightforward. We do *not* make sure that the linear mapping
|
||||
// does not skip bark-scale bins; the decoder simply skips them and
|
||||
// the encoder may do what it wishes in filling them. They're
|
||||
// necessary in some mapping combinations to keep the scale spacing
|
||||
// accurate
|
||||
look.linearmap=new int[look.n];
|
||||
for(int j=0; j<look.n; j++){
|
||||
int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))*scale); // bark numbers represent band edges
|
||||
if(val>=look.ln)
|
||||
val=look.ln; // guard against the approximation
|
||||
look.linearmap[j]=val;
|
||||
}
|
||||
return look;
|
||||
}
|
||||
|
||||
static float toBARK(float f){
|
||||
return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f));
|
||||
}
|
||||
|
||||
Object state(Object i){
|
||||
EchstateFloor0 state=new EchstateFloor0();
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
|
||||
// a safe size if usually too big (dim==1)
|
||||
state.codewords=new int[info.order];
|
||||
state.curve=new float[info.barkmap];
|
||||
state.frameno=-1;
|
||||
return (state);
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
void free_state(Object vs){
|
||||
}
|
||||
|
||||
int forward(Block vb, Object i, float[] in, float[] out, Object vs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
float[] lsp=null;
|
||||
|
||||
int inverse(Block vb, Object i, float[] out){
|
||||
//System.err.println("Floor0.inverse "+i.getClass()+"]");
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
int ampraw=vb.opb.read(info.ampbits);
|
||||
if(ampraw>0){ // also handles the -1 out of data case
|
||||
int maxval=(1<<info.ampbits)-1;
|
||||
float amp=(float)ampraw/maxval*info.ampdB;
|
||||
int booknum=vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if(booknum!=-1&&booknum<info.numbooks){
|
||||
|
||||
synchronized(this){
|
||||
if(lsp==null||lsp.length<look.m){
|
||||
lsp=new float[look.m];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<look.m; j++)
|
||||
lsp[j]=0.f;
|
||||
}
|
||||
|
||||
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
|
||||
float last=0.f;
|
||||
|
||||
for(int j=0; j<look.m; j++)
|
||||
out[j]=0.0f;
|
||||
|
||||
for(int j=0; j<look.m; j+=b.dim){
|
||||
if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){
|
||||
for(int k=0; k<look.n; k++)
|
||||
out[k]=0.0f;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
for(int j=0; j<look.m;){
|
||||
for(int k=0; k<b.dim; k++, j++)
|
||||
lsp[j]+=last;
|
||||
last=lsp[j-1];
|
||||
}
|
||||
// take the coefficients back to a spectral envelope curve
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m,
|
||||
amp, info.ampdB);
|
||||
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object i, Object memo){
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
float[] lsp=null;
|
||||
if(memo instanceof float[]){
|
||||
lsp=(float[])memo;
|
||||
}
|
||||
|
||||
int ampraw=vb.opb.read(info.ampbits);
|
||||
if(ampraw>0){ // also handles the -1 out of data case
|
||||
int maxval=(1<<info.ampbits)-1;
|
||||
float amp=(float)ampraw/maxval*info.ampdB;
|
||||
int booknum=vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if(booknum!=-1&&booknum<info.numbooks){
|
||||
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
|
||||
float last=0.f;
|
||||
|
||||
if(lsp==null||lsp.length<look.m+1){
|
||||
lsp=new float[look.m+1];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<lsp.length; j++)
|
||||
lsp[j]=0.f;
|
||||
}
|
||||
|
||||
for(int j=0; j<look.m; j+=b.dim){
|
||||
if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
for(int j=0; j<look.m;){
|
||||
for(int k=0; k<b.dim; k++, j++)
|
||||
lsp[j]+=last;
|
||||
last=lsp[j-1];
|
||||
}
|
||||
lsp[look.m]=amp;
|
||||
return (lsp);
|
||||
}
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out){
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
|
||||
if(memo!=null){
|
||||
float[] lsp=(float[])memo;
|
||||
float amp=lsp[look.m];
|
||||
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp,
|
||||
info.ampdB);
|
||||
return (1);
|
||||
}
|
||||
for(int j=0; j<look.n; j++){
|
||||
out[j]=0.f;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static float fromdB(float x){
|
||||
return (float)(Math.exp((x)*.11512925));
|
||||
}
|
||||
|
||||
static void lsp_to_lpc(float[] lsp, float[] lpc, int m){
|
||||
int i, j, m2=m/2;
|
||||
float[] O=new float[m2];
|
||||
float[] E=new float[m2];
|
||||
float A;
|
||||
float[] Ae=new float[m2+1];
|
||||
float[] Ao=new float[m2+1];
|
||||
float B;
|
||||
float[] Be=new float[m2];
|
||||
float[] Bo=new float[m2];
|
||||
float temp;
|
||||
|
||||
// even/odd roots setup
|
||||
for(i=0; i<m2; i++){
|
||||
O[i]=(float)(-2.*Math.cos(lsp[i*2]));
|
||||
E[i]=(float)(-2.*Math.cos(lsp[i*2+1]));
|
||||
}
|
||||
|
||||
// set up impulse response
|
||||
for(j=0; j<m2; j++){
|
||||
Ae[j]=0.f;
|
||||
Ao[j]=1.f;
|
||||
Be[j]=0.f;
|
||||
Bo[j]=1.f;
|
||||
}
|
||||
Ao[j]=1.f;
|
||||
Ae[j]=1.f;
|
||||
|
||||
// run impulse response
|
||||
for(i=1; i<m+1; i++){
|
||||
A=B=0.f;
|
||||
for(j=0; j<m2; j++){
|
||||
temp=O[j]*Ao[j]+Ae[j];
|
||||
Ae[j]=Ao[j];
|
||||
Ao[j]=A;
|
||||
A+=temp;
|
||||
|
||||
temp=E[j]*Bo[j]+Be[j];
|
||||
Be[j]=Bo[j];
|
||||
Bo[j]=B;
|
||||
B+=temp;
|
||||
}
|
||||
lpc[i-1]=(A+Ao[j]+B-Ae[j])/2;
|
||||
Ao[j]=A;
|
||||
Ae[j]=B;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l,
|
||||
String name, int frameno){
|
||||
// l->m+1 must be less than l->ln, but guard in case we get a bad stream
|
||||
float[] lcurve=new float[Math.max(l.ln*2, l.m*2+2)];
|
||||
|
||||
if(amp==0){
|
||||
for(int j=0; j<l.n; j++)
|
||||
curve[j]=0.0f;
|
||||
return;
|
||||
}
|
||||
l.lpclook.lpc_to_curve(lcurve, lpc, amp);
|
||||
|
||||
for(int i=0; i<l.n; i++)
|
||||
curve[i]=lcurve[l.linearmap[i]];
|
||||
}
|
||||
|
||||
class InfoFloor0{
|
||||
int order;
|
||||
int rate;
|
||||
int barkmap;
|
||||
|
||||
int ampbits;
|
||||
int ampdB;
|
||||
|
||||
int numbooks; // <= 16
|
||||
int[] books=new int[16];
|
||||
}
|
||||
|
||||
class LookFloor0{
|
||||
int n;
|
||||
int ln;
|
||||
int m;
|
||||
int[] linearmap;
|
||||
|
||||
InfoFloor0 vi;
|
||||
Lpc lpclook=new Lpc();
|
||||
}
|
||||
|
||||
class EchstateFloor0{
|
||||
int[] codewords;
|
||||
float[] curve;
|
||||
long frameno;
|
||||
long codes;
|
||||
}
|
||||
}
|
611
client/src/main/java/client/audio/jorbis/Floor1.java
Normal file
611
client/src/main/java/client/audio/jorbis/Floor1.java
Normal file
|
@ -0,0 +1,611 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class Floor1 extends FuncFloor{
|
||||
static final int floor1_rangedb=140;
|
||||
static final int VIF_POSIT=63;
|
||||
|
||||
void pack(Object i, Buffer opb){
|
||||
InfoFloor1 info=(InfoFloor1)i;
|
||||
|
||||
int count=0;
|
||||
int rangebits;
|
||||
int maxposit=info.postlist[1];
|
||||
int maxclass=-1;
|
||||
|
||||
/* save out partitions */
|
||||
opb.write(info.partitions, 5); /* only 0 to 31 legal */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
opb.write(info.partitionclass[j], 4); /* only 0 to 15 legal */
|
||||
if(maxclass<info.partitionclass[j])
|
||||
maxclass=info.partitionclass[j];
|
||||
}
|
||||
|
||||
/* save out partition classes */
|
||||
for(int j=0; j<maxclass+1; j++){
|
||||
opb.write(info.class_dim[j]-1, 3); /* 1 to 8 */
|
||||
opb.write(info.class_subs[j], 2); /* 0 to 3 */
|
||||
if(info.class_subs[j]!=0){
|
||||
opb.write(info.class_book[j], 8);
|
||||
}
|
||||
for(int k=0; k<(1<<info.class_subs[j]); k++){
|
||||
opb.write(info.class_subbook[j][k]+1, 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* save out the post list */
|
||||
opb.write(info.mult-1, 2); /* only 1,2,3,4 legal now */
|
||||
opb.write(Util.ilog2(maxposit), 4);
|
||||
rangebits=Util.ilog2(maxposit);
|
||||
|
||||
for(int j=0, k=0; j<info.partitions; j++){
|
||||
count+=info.class_dim[info.partitionclass[j]];
|
||||
for(; k<count; k++){
|
||||
opb.write(info.postlist[k+2], rangebits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
int count=0, maxclass=-1, rangebits;
|
||||
InfoFloor1 info=new InfoFloor1();
|
||||
|
||||
/* read partitions */
|
||||
info.partitions=opb.read(5); /* only 0 to 31 legal */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
info.partitionclass[j]=opb.read(4); /* only 0 to 15 legal */
|
||||
if(maxclass<info.partitionclass[j])
|
||||
maxclass=info.partitionclass[j];
|
||||
}
|
||||
|
||||
/* read partition classes */
|
||||
for(int j=0; j<maxclass+1; j++){
|
||||
info.class_dim[j]=opb.read(3)+1; /* 1 to 8 */
|
||||
info.class_subs[j]=opb.read(2); /* 0,1,2,3 bits */
|
||||
if(info.class_subs[j]<0){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
if(info.class_subs[j]!=0){
|
||||
info.class_book[j]=opb.read(8);
|
||||
}
|
||||
if(info.class_book[j]<0||info.class_book[j]>=vi.books){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
for(int k=0; k<(1<<info.class_subs[j]); k++){
|
||||
info.class_subbook[j][k]=opb.read(8)-1;
|
||||
if(info.class_subbook[j][k]<-1||info.class_subbook[j][k]>=vi.books){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* read the post list */
|
||||
info.mult=opb.read(2)+1; /* only 1,2,3,4 legal now */
|
||||
rangebits=opb.read(4);
|
||||
|
||||
for(int j=0, k=0; j<info.partitions; j++){
|
||||
count+=info.class_dim[info.partitionclass[j]];
|
||||
for(; k<count; k++){
|
||||
int t=info.postlist[k+2]=opb.read(rangebits);
|
||||
if(t<0||t>=(1<<rangebits)){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
info.postlist[0]=0;
|
||||
info.postlist[1]=1<<rangebits;
|
||||
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
int _n=0;
|
||||
|
||||
int[] sortpointer=new int[VIF_POSIT+2];
|
||||
|
||||
// Info vi=vd.vi;
|
||||
|
||||
InfoFloor1 info=(InfoFloor1)i;
|
||||
LookFloor1 look=new LookFloor1();
|
||||
look.vi=info;
|
||||
look.n=info.postlist[1];
|
||||
|
||||
/* we drop each position value in-between already decoded values,
|
||||
and use linear interpolation to predict each new value past the
|
||||
edges. The positions are read in the order of the position
|
||||
list... we precompute the bounding positions in the lookup. Of
|
||||
course, the neighbors can change (if a position is declined), but
|
||||
this is an initial mapping */
|
||||
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
_n+=info.class_dim[info.partitionclass[j]];
|
||||
}
|
||||
_n+=2;
|
||||
look.posts=_n;
|
||||
|
||||
/* also store a sorted position index */
|
||||
for(int j=0; j<_n; j++){
|
||||
sortpointer[j]=j;
|
||||
}
|
||||
// qsort(sortpointer,n,sizeof(int),icomp); // !!
|
||||
|
||||
int foo;
|
||||
for(int j=0; j<_n-1; j++){
|
||||
for(int k=j; k<_n; k++){
|
||||
if(info.postlist[sortpointer[j]]>info.postlist[sortpointer[k]]){
|
||||
foo=sortpointer[k];
|
||||
sortpointer[k]=sortpointer[j];
|
||||
sortpointer[j]=foo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* points from sort order back to range number */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.forward_index[j]=sortpointer[j];
|
||||
}
|
||||
/* points from range order to sorted position */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.reverse_index[look.forward_index[j]]=j;
|
||||
}
|
||||
/* we actually need the post values too */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.sorted_index[j]=info.postlist[look.forward_index[j]];
|
||||
}
|
||||
|
||||
/* quantize values to multiplier spec */
|
||||
switch(info.mult){
|
||||
case 1: /* 1024 -> 256 */
|
||||
look.quant_q=256;
|
||||
break;
|
||||
case 2: /* 1024 -> 128 */
|
||||
look.quant_q=128;
|
||||
break;
|
||||
case 3: /* 1024 -> 86 */
|
||||
look.quant_q=86;
|
||||
break;
|
||||
case 4: /* 1024 -> 64 */
|
||||
look.quant_q=64;
|
||||
break;
|
||||
default:
|
||||
look.quant_q=-1;
|
||||
}
|
||||
|
||||
/* discover our neighbors for decode where we don't use fit flags
|
||||
(that would push the neighbors outward) */
|
||||
for(int j=0; j<_n-2; j++){
|
||||
int lo=0;
|
||||
int hi=1;
|
||||
int lx=0;
|
||||
int hx=look.n;
|
||||
int currentx=info.postlist[j+2];
|
||||
for(int k=0; k<j+2; k++){
|
||||
int x=info.postlist[k];
|
||||
if(x>lx&&x<currentx){
|
||||
lo=k;
|
||||
lx=x;
|
||||
}
|
||||
if(x<hx&&x>currentx){
|
||||
hi=k;
|
||||
hx=x;
|
||||
}
|
||||
}
|
||||
look.loneighbor[j]=lo;
|
||||
look.hineighbor[j]=hi;
|
||||
}
|
||||
|
||||
return look;
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
void free_state(Object vs){
|
||||
}
|
||||
|
||||
int forward(Block vb, Object i, float[] in, float[] out, Object vs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object ii, Object memo){
|
||||
LookFloor1 look=(LookFloor1)ii;
|
||||
InfoFloor1 info=look.vi;
|
||||
CodeBook[] books=vb.vd.fullbooks;
|
||||
|
||||
/* unpack wrapped/predicted values from stream */
|
||||
if(vb.opb.read(1)==1){
|
||||
int[] fit_value=null;
|
||||
if(memo instanceof int[]){
|
||||
fit_value=(int[])memo;
|
||||
}
|
||||
if(fit_value==null||fit_value.length<look.posts){
|
||||
fit_value=new int[look.posts];
|
||||
}
|
||||
else{
|
||||
for(int i=0; i<fit_value.length; i++)
|
||||
fit_value[i]=0;
|
||||
}
|
||||
|
||||
fit_value[0]=vb.opb.read(Util.ilog(look.quant_q-1));
|
||||
fit_value[1]=vb.opb.read(Util.ilog(look.quant_q-1));
|
||||
|
||||
/* partition by partition */
|
||||
for(int i=0, j=2; i<info.partitions; i++){
|
||||
int clss=info.partitionclass[i];
|
||||
int cdim=info.class_dim[clss];
|
||||
int csubbits=info.class_subs[clss];
|
||||
int csub=1<<csubbits;
|
||||
int cval=0;
|
||||
|
||||
/* decode the partition's first stage cascade value */
|
||||
if(csubbits!=0){
|
||||
cval=books[info.class_book[clss]].decode(vb.opb);
|
||||
|
||||
if(cval==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
for(int k=0; k<cdim; k++){
|
||||
int book=info.class_subbook[clss][cval&(csub-1)];
|
||||
cval>>>=csubbits;
|
||||
if(book>=0){
|
||||
if((fit_value[j+k]=books[book].decode(vb.opb))==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
else{
|
||||
fit_value[j+k]=0;
|
||||
}
|
||||
}
|
||||
j+=cdim;
|
||||
}
|
||||
|
||||
/* unwrap positive values and reconsitute via linear interpolation */
|
||||
for(int i=2; i<look.posts; i++){
|
||||
int predicted=render_point(info.postlist[look.loneighbor[i-2]],
|
||||
info.postlist[look.hineighbor[i-2]],
|
||||
fit_value[look.loneighbor[i-2]], fit_value[look.hineighbor[i-2]],
|
||||
info.postlist[i]);
|
||||
int hiroom=look.quant_q-predicted;
|
||||
int loroom=predicted;
|
||||
int room=(hiroom<loroom ? hiroom : loroom)<<1;
|
||||
int val=fit_value[i];
|
||||
|
||||
if(val!=0){
|
||||
if(val>=room){
|
||||
if(hiroom>loroom){
|
||||
val=val-loroom;
|
||||
}
|
||||
else{
|
||||
val=-1-(val-hiroom);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if((val&1)!=0){
|
||||
val=-((val+1)>>>1);
|
||||
}
|
||||
else{
|
||||
val>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
fit_value[i]=val+predicted;
|
||||
fit_value[look.loneighbor[i-2]]&=0x7fff;
|
||||
fit_value[look.hineighbor[i-2]]&=0x7fff;
|
||||
}
|
||||
else{
|
||||
fit_value[i]=predicted|0x8000;
|
||||
}
|
||||
}
|
||||
return (fit_value);
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
private static int render_point(int x0, int x1, int y0, int y1, int x){
|
||||
y0&=0x7fff; /* mask off flag */
|
||||
y1&=0x7fff;
|
||||
|
||||
{
|
||||
int dy=y1-y0;
|
||||
int adx=x1-x0;
|
||||
int ady=Math.abs(dy);
|
||||
int err=ady*(x-x0);
|
||||
|
||||
int off=(int)(err/adx);
|
||||
if(dy<0)
|
||||
return (y0-off);
|
||||
return (y0+off);
|
||||
}
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out){
|
||||
LookFloor1 look=(LookFloor1)i;
|
||||
InfoFloor1 info=look.vi;
|
||||
int n=vb.vd.vi.blocksizes[vb.mode]/2;
|
||||
|
||||
if(memo!=null){
|
||||
/* render the lines */
|
||||
int[] fit_value=(int[])memo;
|
||||
int hx=0;
|
||||
int lx=0;
|
||||
int ly=fit_value[0]*info.mult;
|
||||
for(int j=1; j<look.posts; j++){
|
||||
int current=look.forward_index[j];
|
||||
int hy=fit_value[current]&0x7fff;
|
||||
if(hy==fit_value[current]){
|
||||
hy*=info.mult;
|
||||
hx=info.postlist[current];
|
||||
|
||||
render_line(lx, hx, ly, hy, out);
|
||||
|
||||
lx=hx;
|
||||
ly=hy;
|
||||
}
|
||||
}
|
||||
for(int j=hx; j<n; j++){
|
||||
out[j]*=out[j-1]; /* be certain */
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
for(int j=0; j<n; j++){
|
||||
out[j]=0.f;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
private static float[] FLOOR_fromdB_LOOKUP= {1.0649863e-07F, 1.1341951e-07F,
|
||||
1.2079015e-07F, 1.2863978e-07F, 1.3699951e-07F, 1.4590251e-07F,
|
||||
1.5538408e-07F, 1.6548181e-07F, 1.7623575e-07F, 1.8768855e-07F,
|
||||
1.9988561e-07F, 2.128753e-07F, 2.2670913e-07F, 2.4144197e-07F,
|
||||
2.5713223e-07F, 2.7384213e-07F, 2.9163793e-07F, 3.1059021e-07F,
|
||||
3.3077411e-07F, 3.5226968e-07F, 3.7516214e-07F, 3.9954229e-07F,
|
||||
4.2550680e-07F, 4.5315863e-07F, 4.8260743e-07F, 5.1396998e-07F,
|
||||
5.4737065e-07F, 5.8294187e-07F, 6.2082472e-07F, 6.6116941e-07F,
|
||||
7.0413592e-07F, 7.4989464e-07F, 7.9862701e-07F, 8.5052630e-07F,
|
||||
9.0579828e-07F, 9.6466216e-07F, 1.0273513e-06F, 1.0941144e-06F,
|
||||
1.1652161e-06F, 1.2409384e-06F, 1.3215816e-06F, 1.4074654e-06F,
|
||||
1.4989305e-06F, 1.5963394e-06F, 1.7000785e-06F, 1.8105592e-06F,
|
||||
1.9282195e-06F, 2.0535261e-06F, 2.1869758e-06F, 2.3290978e-06F,
|
||||
2.4804557e-06F, 2.6416497e-06F, 2.8133190e-06F, 2.9961443e-06F,
|
||||
3.1908506e-06F, 3.3982101e-06F, 3.6190449e-06F, 3.8542308e-06F,
|
||||
4.1047004e-06F, 4.3714470e-06F, 4.6555282e-06F, 4.9580707e-06F,
|
||||
5.2802740e-06F, 5.6234160e-06F, 5.9888572e-06F, 6.3780469e-06F,
|
||||
6.7925283e-06F, 7.2339451e-06F, 7.7040476e-06F, 8.2047000e-06F,
|
||||
8.7378876e-06F, 9.3057248e-06F, 9.9104632e-06F, 1.0554501e-05F,
|
||||
1.1240392e-05F, 1.1970856e-05F, 1.2748789e-05F, 1.3577278e-05F,
|
||||
1.4459606e-05F, 1.5399272e-05F, 1.6400004e-05F, 1.7465768e-05F,
|
||||
1.8600792e-05F, 1.9809576e-05F, 2.1096914e-05F, 2.2467911e-05F,
|
||||
2.3928002e-05F, 2.5482978e-05F, 2.7139006e-05F, 2.8902651e-05F,
|
||||
3.0780908e-05F, 3.2781225e-05F, 3.4911534e-05F, 3.7180282e-05F,
|
||||
3.9596466e-05F, 4.2169667e-05F, 4.4910090e-05F, 4.7828601e-05F,
|
||||
5.0936773e-05F, 5.4246931e-05F, 5.7772202e-05F, 6.1526565e-05F,
|
||||
6.5524908e-05F, 6.9783085e-05F, 7.4317983e-05F, 7.9147585e-05F,
|
||||
8.4291040e-05F, 8.9768747e-05F, 9.5602426e-05F, 0.00010181521F,
|
||||
0.00010843174F, 0.00011547824F, 0.00012298267F, 0.00013097477F,
|
||||
0.00013948625F, 0.00014855085F, 0.00015820453F, 0.00016848555F,
|
||||
0.00017943469F, 0.00019109536F, 0.00020351382F, 0.00021673929F,
|
||||
0.00023082423F, 0.00024582449F, 0.00026179955F, 0.00027881276F,
|
||||
0.00029693158F, 0.00031622787F, 0.00033677814F, 0.00035866388F,
|
||||
0.00038197188F, 0.00040679456F, 0.00043323036F, 0.00046138411F,
|
||||
0.00049136745F, 0.00052329927F, 0.00055730621F, 0.00059352311F,
|
||||
0.00063209358F, 0.00067317058F, 0.00071691700F, 0.00076350630F,
|
||||
0.00081312324F, 0.00086596457F, 0.00092223983F, 0.00098217216F,
|
||||
0.0010459992F, 0.0011139742F, 0.0011863665F, 0.0012634633F,
|
||||
0.0013455702F, 0.0014330129F, 0.0015261382F, 0.0016253153F,
|
||||
0.0017309374F, 0.0018434235F, 0.0019632195F, 0.0020908006F,
|
||||
0.0022266726F, 0.0023713743F, 0.0025254795F, 0.0026895994F,
|
||||
0.0028643847F, 0.0030505286F, 0.0032487691F, 0.0034598925F,
|
||||
0.0036847358F, 0.0039241906F, 0.0041792066F, 0.0044507950F,
|
||||
0.0047400328F, 0.0050480668F, 0.0053761186F, 0.0057254891F,
|
||||
0.0060975636F, 0.0064938176F, 0.0069158225F, 0.0073652516F,
|
||||
0.0078438871F, 0.0083536271F, 0.0088964928F, 0.009474637F, 0.010090352F,
|
||||
0.010746080F, 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
|
||||
0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, 0.018938423F,
|
||||
0.020169149F, 0.021479854F, 0.022875735F, 0.024362330F, 0.025945531F,
|
||||
0.027631618F, 0.029427276F, 0.031339626F, 0.033376252F, 0.035545228F,
|
||||
0.037855157F, 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
|
||||
0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, 0.066714279F,
|
||||
0.071049749F, 0.075666962F, 0.080584227F, 0.085821044F, 0.091398179F,
|
||||
0.097337747F, 0.10366330F, 0.11039993F, 0.11757434F, 0.12521498F,
|
||||
0.13335215F, 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
|
||||
0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, 0.23501402F,
|
||||
0.25028656F, 0.26655159F, 0.28387361F, 0.30232132F, 0.32196786F,
|
||||
0.34289114F, 0.36517414F, 0.38890521F, 0.41417847F, 0.44109412F,
|
||||
0.46975890F, 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
|
||||
0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, 0.82788260F,
|
||||
0.88168307F, 0.9389798F, 1.F};
|
||||
|
||||
private static void render_line(int x0, int x1, int y0, int y1, float[] d){
|
||||
int dy=y1-y0;
|
||||
int adx=x1-x0;
|
||||
int ady=Math.abs(dy);
|
||||
int base=dy/adx;
|
||||
int sy=(dy<0 ? base-1 : base+1);
|
||||
int x=x0;
|
||||
int y=y0;
|
||||
int err=0;
|
||||
|
||||
ady-=Math.abs(base*adx);
|
||||
|
||||
d[x]*=FLOOR_fromdB_LOOKUP[y];
|
||||
while(++x<x1){
|
||||
err=err+ady;
|
||||
if(err>=adx){
|
||||
err-=adx;
|
||||
y+=sy;
|
||||
}
|
||||
else{
|
||||
y+=base;
|
||||
}
|
||||
d[x]*=FLOOR_fromdB_LOOKUP[y];
|
||||
}
|
||||
}
|
||||
|
||||
class InfoFloor1{
|
||||
static final int VIF_POSIT=63;
|
||||
static final int VIF_CLASS=16;
|
||||
static final int VIF_PARTS=31;
|
||||
|
||||
int partitions; /* 0 to 31 */
|
||||
int[] partitionclass=new int[VIF_PARTS]; /* 0 to 15 */
|
||||
|
||||
int[] class_dim=new int[VIF_CLASS]; /* 1 to 8 */
|
||||
int[] class_subs=new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
|
||||
int[] class_book=new int[VIF_CLASS]; /* subs ^ dim entries */
|
||||
int[][] class_subbook=new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
|
||||
|
||||
int mult; /* 1 2 3 or 4 */
|
||||
int[] postlist=new int[VIF_POSIT+2]; /* first two implicit */
|
||||
|
||||
/* encode side analysis parameters */
|
||||
float maxover;
|
||||
float maxunder;
|
||||
float maxerr;
|
||||
|
||||
int twofitminsize;
|
||||
int twofitminused;
|
||||
int twofitweight;
|
||||
float twofitatten;
|
||||
int unusedminsize;
|
||||
int unusedmin_n;
|
||||
|
||||
int n;
|
||||
|
||||
InfoFloor1(){
|
||||
for(int i=0; i<class_subbook.length; i++){
|
||||
class_subbook[i]=new int[8];
|
||||
}
|
||||
}
|
||||
|
||||
void free(){
|
||||
partitionclass=null;
|
||||
class_dim=null;
|
||||
class_subs=null;
|
||||
class_book=null;
|
||||
class_subbook=null;
|
||||
postlist=null;
|
||||
}
|
||||
|
||||
Object copy_info(){
|
||||
InfoFloor1 info=this;
|
||||
InfoFloor1 ret=new InfoFloor1();
|
||||
|
||||
ret.partitions=info.partitions;
|
||||
System
|
||||
.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
|
||||
System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
|
||||
System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
|
||||
System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
|
||||
|
||||
for(int j=0; j<VIF_CLASS; j++){
|
||||
System.arraycopy(info.class_subbook[j], 0, ret.class_subbook[j], 0, 8);
|
||||
}
|
||||
|
||||
ret.mult=info.mult;
|
||||
System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT+2);
|
||||
|
||||
ret.maxover=info.maxover;
|
||||
ret.maxunder=info.maxunder;
|
||||
ret.maxerr=info.maxerr;
|
||||
|
||||
ret.twofitminsize=info.twofitminsize;
|
||||
ret.twofitminused=info.twofitminused;
|
||||
ret.twofitweight=info.twofitweight;
|
||||
ret.twofitatten=info.twofitatten;
|
||||
ret.unusedminsize=info.unusedminsize;
|
||||
ret.unusedmin_n=info.unusedmin_n;
|
||||
|
||||
ret.n=info.n;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LookFloor1{
|
||||
static final int VIF_POSIT=63;
|
||||
|
||||
int[] sorted_index=new int[VIF_POSIT+2];
|
||||
int[] forward_index=new int[VIF_POSIT+2];
|
||||
int[] reverse_index=new int[VIF_POSIT+2];
|
||||
int[] hineighbor=new int[VIF_POSIT];
|
||||
int[] loneighbor=new int[VIF_POSIT];
|
||||
int posts;
|
||||
|
||||
int n;
|
||||
int quant_q;
|
||||
InfoFloor1 vi;
|
||||
|
||||
int phrasebits;
|
||||
int postbits;
|
||||
int frames;
|
||||
|
||||
void free(){
|
||||
sorted_index=null;
|
||||
forward_index=null;
|
||||
reverse_index=null;
|
||||
hineighbor=null;
|
||||
loneighbor=null;
|
||||
}
|
||||
}
|
||||
|
||||
class Lsfit_acc{
|
||||
long x0;
|
||||
long x1;
|
||||
|
||||
long xa;
|
||||
long ya;
|
||||
long x2a;
|
||||
long y2a;
|
||||
long xya;
|
||||
long n;
|
||||
long an;
|
||||
long un;
|
||||
long edgey0;
|
||||
long edgey1;
|
||||
}
|
||||
|
||||
class EchstateFloor1{
|
||||
int[] codewords;
|
||||
float[] curve;
|
||||
long frameno;
|
||||
long codes;
|
||||
}
|
||||
}
|
52
client/src/main/java/client/audio/jorbis/FuncFloor.java
Normal file
52
client/src/main/java/client/audio/jorbis/FuncFloor.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
abstract class FuncFloor{
|
||||
|
||||
public static FuncFloor[] floor_P= {new Floor0(), new Floor1()};
|
||||
|
||||
abstract void pack(Object i, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode mi, Object i);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract void free_state(Object vs);
|
||||
|
||||
abstract int forward(Block vb, Object i, float[] in, float[] out, Object vs);
|
||||
|
||||
abstract Object inverse1(Block vb, Object i, Object memo);
|
||||
|
||||
abstract int inverse2(Block vb, Object i, Object memo, float[] out);
|
||||
}
|
45
client/src/main/java/client/audio/jorbis/FuncMapping.java
Normal file
45
client/src/main/java/client/audio/jorbis/FuncMapping.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
abstract class FuncMapping{
|
||||
public static FuncMapping[] mapping_P= {new Mapping0()};
|
||||
|
||||
abstract void pack(Info info, Object imap, Buffer buffer);
|
||||
|
||||
abstract Object unpack(Info info, Buffer buffer);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object m);
|
||||
|
||||
abstract void free_info(Object imap);
|
||||
|
||||
abstract void free_look(Object imap);
|
||||
|
||||
abstract int inverse(Block vd, Object lm);
|
||||
}
|
46
client/src/main/java/client/audio/jorbis/FuncResidue.java
Normal file
46
client/src/main/java/client/audio/jorbis/FuncResidue.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
abstract class FuncResidue{
|
||||
public static FuncResidue[] residue_P= {new Residue0(), new Residue1(),
|
||||
new Residue2()};
|
||||
|
||||
abstract void pack(Object vr, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object vr);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch);
|
||||
}
|
45
client/src/main/java/client/audio/jorbis/FuncTime.java
Normal file
45
client/src/main/java/client/audio/jorbis/FuncTime.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
abstract class FuncTime{
|
||||
public static FuncTime[] time_P= {new Time0()};
|
||||
|
||||
abstract void pack(Object i, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object i);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract int inverse(Block vb, Object i, float[] in, float[] out);
|
||||
}
|
470
client/src/main/java/client/audio/jorbis/Info.java
Normal file
470
client/src/main/java/client/audio/jorbis/Info.java
Normal file
|
@ -0,0 +1,470 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
import client.audio.jogg.Packet;
|
||||
|
||||
public class Info{
|
||||
private static final int OV_EBADPACKET=-136;
|
||||
private static final int OV_ENOTAUDIO=-135;
|
||||
|
||||
private static byte[] _vorbis="vorbis".getBytes();
|
||||
private static final int VI_TIMEB=1;
|
||||
// private static final int VI_FLOORB=1;
|
||||
private static final int VI_FLOORB=2;
|
||||
// private static final int VI_RESB=1;
|
||||
private static final int VI_RESB=3;
|
||||
private static final int VI_MAPB=1;
|
||||
private static final int VI_WINDOWB=1;
|
||||
|
||||
public int version;
|
||||
public int channels;
|
||||
public int rate;
|
||||
|
||||
// The below bitrate declarations are *hints*.
|
||||
// Combinations of the three values carry the following implications:
|
||||
//
|
||||
// all three set to the same value:
|
||||
// implies a fixed rate bitstream
|
||||
// only nominal set:
|
||||
// implies a VBR stream that averages the nominal bitrate. No hard
|
||||
// upper/lower limit
|
||||
// upper and or lower set:
|
||||
// implies a VBR bitstream that obeys the bitrate limits. nominal
|
||||
// may also be set to give a nominal rate.
|
||||
// none set:
|
||||
// the coder does not care to speculate.
|
||||
|
||||
int bitrate_upper;
|
||||
int bitrate_nominal;
|
||||
int bitrate_lower;
|
||||
|
||||
// Vorbis supports only short and long blocks, but allows the
|
||||
// encoder to choose the sizes
|
||||
|
||||
int[] blocksizes=new int[2];
|
||||
|
||||
// modes are the primary means of supporting on-the-fly different
|
||||
// blocksizes, different channel mappings (LR or mid-side),
|
||||
// different residue backends, etc. Each mode consists of a
|
||||
// blocksize flag and a mapping (along with the mapping setup
|
||||
|
||||
int modes;
|
||||
int maps;
|
||||
int times;
|
||||
int floors;
|
||||
int residues;
|
||||
int books;
|
||||
int psys; // encode only
|
||||
|
||||
InfoMode[] mode_param=null;
|
||||
|
||||
int[] map_type=null;
|
||||
Object[] map_param=null;
|
||||
|
||||
int[] time_type=null;
|
||||
Object[] time_param=null;
|
||||
|
||||
int[] floor_type=null;
|
||||
Object[] floor_param=null;
|
||||
|
||||
int[] residue_type=null;
|
||||
Object[] residue_param=null;
|
||||
|
||||
StaticCodeBook[] book_param=null;
|
||||
|
||||
PsyInfo[] psy_param=new PsyInfo[64]; // encode only
|
||||
|
||||
// for block long/sort tuning; encode only
|
||||
int envelopesa;
|
||||
float preecho_thresh;
|
||||
float preecho_clamp;
|
||||
|
||||
// used by synthesis, which has a full, alloced vi
|
||||
public void init(){
|
||||
rate=0;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
for(int i=0; i<modes; i++){
|
||||
mode_param[i]=null;
|
||||
}
|
||||
mode_param=null;
|
||||
|
||||
for(int i=0; i<maps; i++){ // unpack does the range checking
|
||||
FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
|
||||
}
|
||||
map_param=null;
|
||||
|
||||
for(int i=0; i<times; i++){ // unpack does the range checking
|
||||
FuncTime.time_P[time_type[i]].free_info(time_param[i]);
|
||||
}
|
||||
time_param=null;
|
||||
|
||||
for(int i=0; i<floors; i++){ // unpack does the range checking
|
||||
FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
|
||||
}
|
||||
floor_param=null;
|
||||
|
||||
for(int i=0; i<residues; i++){ // unpack does the range checking
|
||||
FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
|
||||
}
|
||||
residue_param=null;
|
||||
|
||||
// the static codebooks *are* freed if you call info_clear, because
|
||||
// decode side does alloc a 'static' codebook. Calling clear on the
|
||||
// full codebook does not clear the static codebook (that's our
|
||||
// responsibility)
|
||||
for(int i=0; i<books; i++){
|
||||
// just in case the decoder pre-cleared to save space
|
||||
if(book_param[i]!=null){
|
||||
book_param[i].clear();
|
||||
book_param[i]=null;
|
||||
}
|
||||
}
|
||||
//if(vi->book_param)free(vi->book_param);
|
||||
book_param=null;
|
||||
|
||||
for(int i=0; i<psys; i++){
|
||||
psy_param[i].free();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Header packing/unpacking
|
||||
int unpack_info(Buffer opb){
|
||||
version=opb.read(32);
|
||||
if(version!=0)
|
||||
return (-1);
|
||||
|
||||
channels=opb.read(8);
|
||||
rate=opb.read(32);
|
||||
|
||||
bitrate_upper=opb.read(32);
|
||||
bitrate_nominal=opb.read(32);
|
||||
bitrate_lower=opb.read(32);
|
||||
|
||||
blocksizes[0]=1<<opb.read(4);
|
||||
blocksizes[1]=1<<opb.read(4);
|
||||
|
||||
if((rate<1)||(channels<1)||(blocksizes[0]<8)||(blocksizes[1]<blocksizes[0])
|
||||
||(opb.read(1)!=1)){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// all of the real encoding details are here. The modes, books,
|
||||
// everything
|
||||
int unpack_books(Buffer opb){
|
||||
|
||||
books=opb.read(8)+1;
|
||||
|
||||
if(book_param==null||book_param.length!=books)
|
||||
book_param=new StaticCodeBook[books];
|
||||
for(int i=0; i<books; i++){
|
||||
book_param[i]=new StaticCodeBook();
|
||||
if(book_param[i].unpack(opb)!=0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// time backend settings
|
||||
times=opb.read(6)+1;
|
||||
if(time_type==null||time_type.length!=times)
|
||||
time_type=new int[times];
|
||||
if(time_param==null||time_param.length!=times)
|
||||
time_param=new Object[times];
|
||||
for(int i=0; i<times; i++){
|
||||
time_type[i]=opb.read(16);
|
||||
if(time_type[i]<0||time_type[i]>=VI_TIMEB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
|
||||
if(time_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// floor backend settings
|
||||
floors=opb.read(6)+1;
|
||||
if(floor_type==null||floor_type.length!=floors)
|
||||
floor_type=new int[floors];
|
||||
if(floor_param==null||floor_param.length!=floors)
|
||||
floor_param=new Object[floors];
|
||||
|
||||
for(int i=0; i<floors; i++){
|
||||
floor_type[i]=opb.read(16);
|
||||
if(floor_type[i]<0||floor_type[i]>=VI_FLOORB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this, opb);
|
||||
if(floor_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// residue backend settings
|
||||
residues=opb.read(6)+1;
|
||||
|
||||
if(residue_type==null||residue_type.length!=residues)
|
||||
residue_type=new int[residues];
|
||||
|
||||
if(residue_param==null||residue_param.length!=residues)
|
||||
residue_param=new Object[residues];
|
||||
|
||||
for(int i=0; i<residues; i++){
|
||||
residue_type[i]=opb.read(16);
|
||||
if(residue_type[i]<0||residue_type[i]>=VI_RESB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this, opb);
|
||||
if(residue_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// map backend settings
|
||||
maps=opb.read(6)+1;
|
||||
if(map_type==null||map_type.length!=maps)
|
||||
map_type=new int[maps];
|
||||
if(map_param==null||map_param.length!=maps)
|
||||
map_param=new Object[maps];
|
||||
for(int i=0; i<maps; i++){
|
||||
map_type[i]=opb.read(16);
|
||||
if(map_type[i]<0||map_type[i]>=VI_MAPB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this, opb);
|
||||
if(map_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// mode settings
|
||||
modes=opb.read(6)+1;
|
||||
if(mode_param==null||mode_param.length!=modes)
|
||||
mode_param=new InfoMode[modes];
|
||||
for(int i=0; i<modes; i++){
|
||||
mode_param[i]=new InfoMode();
|
||||
mode_param[i].blockflag=opb.read(1);
|
||||
mode_param[i].windowtype=opb.read(16);
|
||||
mode_param[i].transformtype=opb.read(16);
|
||||
mode_param[i].mapping=opb.read(8);
|
||||
|
||||
if((mode_param[i].windowtype>=VI_WINDOWB)
|
||||
||(mode_param[i].transformtype>=VI_WINDOWB)
|
||||
||(mode_param[i].mapping>=maps)){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(opb.read(1)!=1){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// The Vorbis header is in three packets; the initial small packet in
|
||||
// the first page that identifies basic parameters, a second packet
|
||||
// with bitstream comments and a third packet that holds the
|
||||
// codebook.
|
||||
|
||||
public int synthesis_headerin(Comment vc, Packet op){
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
if(op!=null){
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
// Which of the three types of header is this?
|
||||
// Also verify header-ness, vorbis
|
||||
{
|
||||
byte[] buffer=new byte[6];
|
||||
int packtype=opb.read(8);
|
||||
opb.read(buffer, 6);
|
||||
if(buffer[0]!='v'||buffer[1]!='o'||buffer[2]!='r'||buffer[3]!='b'
|
||||
||buffer[4]!='i'||buffer[5]!='s'){
|
||||
// not a vorbis header
|
||||
return (-1);
|
||||
}
|
||||
switch(packtype){
|
||||
case 0x01: // least significant *bit* is read first
|
||||
if(op.b_o_s==0){
|
||||
// Not the initial packet
|
||||
return (-1);
|
||||
}
|
||||
if(rate!=0){
|
||||
// previously initialized info header
|
||||
return (-1);
|
||||
}
|
||||
return (unpack_info(opb));
|
||||
case 0x03: // least significant *bit* is read first
|
||||
if(rate==0){
|
||||
// um... we didn't get the initial header
|
||||
return (-1);
|
||||
}
|
||||
return (vc.unpack(opb));
|
||||
case 0x05: // least significant *bit* is read first
|
||||
if(rate==0||vc.vendor==null){
|
||||
// um... we didn;t get the initial header or comments yet
|
||||
return (-1);
|
||||
}
|
||||
return (unpack_books(opb));
|
||||
default:
|
||||
// Not a valid vorbis header type
|
||||
//return(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// pack side
|
||||
int pack_info(Buffer opb){
|
||||
// preamble
|
||||
opb.write(0x01, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// basic information about the stream
|
||||
opb.write(0x00, 32);
|
||||
opb.write(channels, 8);
|
||||
opb.write(rate, 32);
|
||||
|
||||
opb.write(bitrate_upper, 32);
|
||||
opb.write(bitrate_nominal, 32);
|
||||
opb.write(bitrate_lower, 32);
|
||||
|
||||
opb.write(Util.ilog2(blocksizes[0]), 4);
|
||||
opb.write(Util.ilog2(blocksizes[1]), 4);
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pack_books(Buffer opb){
|
||||
opb.write(0x05, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// books
|
||||
opb.write(books-1, 8);
|
||||
for(int i=0; i<books; i++){
|
||||
if(book_param[i].pack(opb)!=0){
|
||||
//goto err_out;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// times
|
||||
opb.write(times-1, 6);
|
||||
for(int i=0; i<times; i++){
|
||||
opb.write(time_type[i], 16);
|
||||
FuncTime.time_P[time_type[i]].pack(this.time_param[i], opb);
|
||||
}
|
||||
|
||||
// floors
|
||||
opb.write(floors-1, 6);
|
||||
for(int i=0; i<floors; i++){
|
||||
opb.write(floor_type[i], 16);
|
||||
FuncFloor.floor_P[floor_type[i]].pack(floor_param[i], opb);
|
||||
}
|
||||
|
||||
// residues
|
||||
opb.write(residues-1, 6);
|
||||
for(int i=0; i<residues; i++){
|
||||
opb.write(residue_type[i], 16);
|
||||
FuncResidue.residue_P[residue_type[i]].pack(residue_param[i], opb);
|
||||
}
|
||||
|
||||
// maps
|
||||
opb.write(maps-1, 6);
|
||||
for(int i=0; i<maps; i++){
|
||||
opb.write(map_type[i], 16);
|
||||
FuncMapping.mapping_P[map_type[i]].pack(this, map_param[i], opb);
|
||||
}
|
||||
|
||||
// modes
|
||||
opb.write(modes-1, 6);
|
||||
for(int i=0; i<modes; i++){
|
||||
opb.write(mode_param[i].blockflag, 1);
|
||||
opb.write(mode_param[i].windowtype, 16);
|
||||
opb.write(mode_param[i].transformtype, 16);
|
||||
opb.write(mode_param[i].mapping, 8);
|
||||
}
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int blocksize(Packet op){
|
||||
//codec_setup_info
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
int mode;
|
||||
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
/* Check the packet type */
|
||||
if(opb.read(1)!=0){
|
||||
/* Oops. This is not an audio data packet */
|
||||
return (OV_ENOTAUDIO);
|
||||
}
|
||||
{
|
||||
int modebits=0;
|
||||
int v=modes;
|
||||
while(v>1){
|
||||
modebits++;
|
||||
v>>>=1;
|
||||
}
|
||||
|
||||
/* read our mode and pre/post windowsize */
|
||||
mode=opb.read(modebits);
|
||||
}
|
||||
if(mode==-1)
|
||||
return (OV_EBADPACKET);
|
||||
return (blocksizes[mode_param[mode].blockflag]);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return "version:"+version+", channels:"+channels
|
||||
+", rate:"+rate+", bitrate:"+bitrate_upper
|
||||
+","+bitrate_nominal+","+bitrate_lower;
|
||||
}
|
||||
}
|
34
client/src/main/java/client/audio/jorbis/InfoMode.java
Normal file
34
client/src/main/java/client/audio/jorbis/InfoMode.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class InfoMode{
|
||||
int blockflag;
|
||||
int windowtype;
|
||||
int transformtype;
|
||||
int mapping;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
public class JOrbisException extends Exception{
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
public JOrbisException(){
|
||||
super();
|
||||
}
|
||||
|
||||
public JOrbisException(String s){
|
||||
super("JOrbis: "+s);
|
||||
}
|
||||
}
|
152
client/src/main/java/client/audio/jorbis/Lookup.java
Normal file
152
client/src/main/java/client/audio/jorbis/Lookup.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class Lookup{
|
||||
static final int COS_LOOKUP_SZ=128;
|
||||
static final float[] COS_LOOKUP= {+1.0000000000000f, +0.9996988186962f,
|
||||
+0.9987954562052f, +0.9972904566787f, +0.9951847266722f,
|
||||
+0.9924795345987f, +0.9891765099648f, +0.9852776423889f,
|
||||
+0.9807852804032f, +0.9757021300385f, +0.9700312531945f,
|
||||
+0.9637760657954f, +0.9569403357322f, +0.9495281805930f,
|
||||
+0.9415440651830f, +0.9329927988347f, +0.9238795325113f,
|
||||
+0.9142097557035f, +0.9039892931234f, +0.8932243011955f,
|
||||
+0.8819212643484f, +0.8700869911087f, +0.8577286100003f,
|
||||
+0.8448535652497f, +0.8314696123025f, +0.8175848131516f,
|
||||
+0.8032075314806f, +0.7883464276266f, +0.7730104533627f,
|
||||
+0.7572088465065f, +0.7409511253550f, +0.7242470829515f,
|
||||
+0.7071067811865f, +0.6895405447371f, +0.6715589548470f,
|
||||
+0.6531728429538f, +0.6343932841636f, +0.6152315905806f,
|
||||
+0.5956993044924f, +0.5758081914178f, +0.5555702330196f,
|
||||
+0.5349976198871f, +0.5141027441932f, +0.4928981922298f,
|
||||
+0.4713967368260f, +0.4496113296546f, +0.4275550934303f,
|
||||
+0.4052413140050f, +0.3826834323651f, +0.3598950365350f,
|
||||
+0.3368898533922f, +0.3136817403989f, +0.2902846772545f,
|
||||
+0.2667127574749f, +0.2429801799033f, +0.2191012401569f,
|
||||
+0.1950903220161f, +0.1709618887603f, +0.1467304744554f,
|
||||
+0.1224106751992f, +0.0980171403296f, +0.0735645635997f,
|
||||
+0.0490676743274f, +0.0245412285229f, +0.0000000000000f,
|
||||
-0.0245412285229f, -0.0490676743274f, -0.0735645635997f,
|
||||
-0.0980171403296f, -0.1224106751992f, -0.1467304744554f,
|
||||
-0.1709618887603f, -0.1950903220161f, -0.2191012401569f,
|
||||
-0.2429801799033f, -0.2667127574749f, -0.2902846772545f,
|
||||
-0.3136817403989f, -0.3368898533922f, -0.3598950365350f,
|
||||
-0.3826834323651f, -0.4052413140050f, -0.4275550934303f,
|
||||
-0.4496113296546f, -0.4713967368260f, -0.4928981922298f,
|
||||
-0.5141027441932f, -0.5349976198871f, -0.5555702330196f,
|
||||
-0.5758081914178f, -0.5956993044924f, -0.6152315905806f,
|
||||
-0.6343932841636f, -0.6531728429538f, -0.6715589548470f,
|
||||
-0.6895405447371f, -0.7071067811865f, -0.7242470829515f,
|
||||
-0.7409511253550f, -0.7572088465065f, -0.7730104533627f,
|
||||
-0.7883464276266f, -0.8032075314806f, -0.8175848131516f,
|
||||
-0.8314696123025f, -0.8448535652497f, -0.8577286100003f,
|
||||
-0.8700869911087f, -0.8819212643484f, -0.8932243011955f,
|
||||
-0.9039892931234f, -0.9142097557035f, -0.9238795325113f,
|
||||
-0.9329927988347f, -0.9415440651830f, -0.9495281805930f,
|
||||
-0.9569403357322f, -0.9637760657954f, -0.9700312531945f,
|
||||
-0.9757021300385f, -0.9807852804032f, -0.9852776423889f,
|
||||
-0.9891765099648f, -0.9924795345987f, -0.9951847266722f,
|
||||
-0.9972904566787f, -0.9987954562052f, -0.9996988186962f,
|
||||
-1.0000000000000f,};
|
||||
|
||||
/* interpolated lookup based cos function, domain 0 to PI only */
|
||||
static float coslook(float a){
|
||||
double d=a*(.31830989*(float)COS_LOOKUP_SZ);
|
||||
int i=(int)d;
|
||||
return COS_LOOKUP[i]+((float)(d-i))*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
|
||||
}
|
||||
|
||||
static final int INVSQ_LOOKUP_SZ=32;
|
||||
static final float[] INVSQ_LOOKUP= {1.414213562373f, 1.392621247646f,
|
||||
1.371988681140f, 1.352246807566f, 1.333333333333f, 1.315191898443f,
|
||||
1.297771369046f, 1.281025230441f, 1.264911064067f, 1.249390095109f,
|
||||
1.234426799697f, 1.219988562661f, 1.206045378311f, 1.192569588000f,
|
||||
1.179535649239f, 1.166919931983f, 1.154700538379f, 1.142857142857f,
|
||||
1.131370849898f, 1.120224067222f, 1.109400392450f, 1.098884511590f,
|
||||
1.088662107904f, 1.078719779941f, 1.069044967650f, 1.059625885652f,
|
||||
1.050451462878f, 1.041511287847f, 1.032795558989f, 1.024295039463f,
|
||||
1.016001016002f, 1.007905261358f, 1.000000000000f,};
|
||||
|
||||
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
|
||||
static float invsqlook(float a){
|
||||
double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
|
||||
int i=(int)d;
|
||||
return INVSQ_LOOKUP[i]+((float)(d-i))*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
|
||||
}
|
||||
|
||||
static final int INVSQ2EXP_LOOKUP_MIN=-32;
|
||||
static final int INVSQ2EXP_LOOKUP_MAX=32;
|
||||
static final float[] INVSQ2EXP_LOOKUP= {65536.f, 46340.95001f, 32768.f,
|
||||
23170.47501f, 16384.f, 11585.2375f, 8192.f, 5792.618751f, 4096.f,
|
||||
2896.309376f, 2048.f, 1448.154688f, 1024.f, 724.0773439f, 512.f,
|
||||
362.038672f, 256.f, 181.019336f, 128.f, 90.50966799f, 64.f, 45.254834f,
|
||||
32.f, 22.627417f, 16.f, 11.3137085f, 8.f, 5.656854249f, 4.f,
|
||||
2.828427125f, 2.f, 1.414213562f, 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
|
||||
0.25f, 0.1767766953f, 0.125f, 0.08838834765f, 0.0625f, 0.04419417382f,
|
||||
0.03125f, 0.02209708691f, 0.015625f, 0.01104854346f, 0.0078125f,
|
||||
0.005524271728f, 0.00390625f, 0.002762135864f, 0.001953125f,
|
||||
0.001381067932f, 0.0009765625f, 0.000690533966f, 0.00048828125f,
|
||||
0.000345266983f, 0.000244140625f, 0.0001726334915f, 0.0001220703125f,
|
||||
8.631674575e-05f, 6.103515625e-05f, 4.315837288e-05f, 3.051757812e-05f,
|
||||
2.157918644e-05f, 1.525878906e-05f,};
|
||||
|
||||
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
|
||||
static float invsq2explook(int a){
|
||||
return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
|
||||
}
|
||||
|
||||
static final int FROMdB_LOOKUP_SZ=35;
|
||||
static final int FROMdB2_LOOKUP_SZ=32;
|
||||
static final int FROMdB_SHIFT=5;
|
||||
static final int FROMdB2_SHIFT=3;
|
||||
static final int FROMdB2_MASK=31;
|
||||
static final float[] FROMdB_LOOKUP= {1.f, 0.6309573445f, 0.3981071706f,
|
||||
0.2511886432f, 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
|
||||
0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, 0.003981071706f,
|
||||
0.002511886432f, 0.001584893192f, 0.001f, 0.0006309573445f,
|
||||
0.0003981071706f, 0.0002511886432f, 0.0001584893192f, 0.0001f,
|
||||
6.309573445e-05f, 3.981071706e-05f, 2.511886432e-05f, 1.584893192e-05f,
|
||||
1e-05f, 6.309573445e-06f, 3.981071706e-06f, 2.511886432e-06f,
|
||||
1.584893192e-06f, 1e-06f, 6.309573445e-07f, 3.981071706e-07f,
|
||||
2.511886432e-07f, 1.584893192e-07f,};
|
||||
static final float[] FROMdB2_LOOKUP= {0.9928302478f, 0.9786445908f,
|
||||
0.9646616199f, 0.9508784391f, 0.9372921937f, 0.92390007f, 0.9106992942f,
|
||||
0.8976871324f, 0.8848608897f, 0.8722179097f, 0.8597555737f,
|
||||
0.8474713009f, 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
|
||||
0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, 0.7445176537f,
|
||||
0.7338799116f, 0.7233941627f, 0.7130582353f, 0.7028699885f,
|
||||
0.6928273125f, 0.6829281272f, 0.6731703824f, 0.6635520573f,
|
||||
0.6540711597f, 0.6447257262f, 0.6355138211f,};
|
||||
|
||||
/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
|
||||
static float fromdBlook(float a){
|
||||
int i=(int)(a*((float)(-(1<<FROMdB2_SHIFT))));
|
||||
return (i<0) ? 1.f : ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT)) ? 0.f
|
||||
: FROMdB_LOOKUP[i>>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
|
||||
}
|
||||
|
||||
}
|
188
client/src/main/java/client/audio/jorbis/Lpc.java
Normal file
188
client/src/main/java/client/audio/jorbis/Lpc.java
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class Lpc{
|
||||
// en/decode lookups
|
||||
Drft fft=new Drft();;
|
||||
|
||||
int ln;
|
||||
int m;
|
||||
|
||||
// Autocorrelation LPC coeff generation algorithm invented by
|
||||
// N. Levinson in 1947, modified by J. Durbin in 1959.
|
||||
|
||||
// Input : n elements of time doamin data
|
||||
// Output: m lpc coefficients, excitation energy
|
||||
|
||||
static float lpc_from_data(float[] data, float[] lpc, int n, int m){
|
||||
float[] aut=new float[m+1];
|
||||
float error;
|
||||
int i, j;
|
||||
|
||||
// autocorrelation, p+1 lag coefficients
|
||||
|
||||
j=m+1;
|
||||
while(j--!=0){
|
||||
float d=0;
|
||||
for(i=j; i<n; i++)
|
||||
d+=data[i]*data[i-j];
|
||||
aut[j]=d;
|
||||
}
|
||||
|
||||
// Generate lpc coefficients from autocorr values
|
||||
|
||||
error=aut[0];
|
||||
/*
|
||||
if(error==0){
|
||||
for(int k=0; k<m; k++) lpc[k]=0.0f;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
for(i=0; i<m; i++){
|
||||
float r=-aut[i+1];
|
||||
|
||||
if(error==0){
|
||||
for(int k=0; k<m; k++)
|
||||
lpc[k]=0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sum up this iteration's reflection coefficient; note that in
|
||||
// Vorbis we don't save it. If anyone wants to recycle this code
|
||||
// and needs reflection coefficients, save the results of 'r' from
|
||||
// each iteration.
|
||||
|
||||
for(j=0; j<i; j++)
|
||||
r-=lpc[j]*aut[i-j];
|
||||
r/=error;
|
||||
|
||||
// Update LPC coefficients and total error
|
||||
|
||||
lpc[i]=r;
|
||||
for(j=0; j<i/2; j++){
|
||||
float tmp=lpc[j];
|
||||
lpc[j]+=r*lpc[i-1-j];
|
||||
lpc[i-1-j]+=r*tmp;
|
||||
}
|
||||
if(i%2!=0)
|
||||
lpc[j]+=lpc[j]*r;
|
||||
|
||||
error*=1.0-r*r;
|
||||
}
|
||||
|
||||
// we need the error value to know how big an impulse to hit the
|
||||
// filter with later
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// Input : n element envelope spectral curve
|
||||
// Output: m lpc coefficients, excitation energy
|
||||
|
||||
float lpc_from_curve(float[] curve, float[] lpc){
|
||||
int n=ln;
|
||||
float[] work=new float[n+n];
|
||||
float fscale=(float)(.5/n);
|
||||
int i, j;
|
||||
|
||||
// input is a real curve. make it complex-real
|
||||
// This mixes phase, but the LPC generation doesn't care.
|
||||
for(i=0; i<n; i++){
|
||||
work[i*2]=curve[i]*fscale;
|
||||
work[i*2+1]=0;
|
||||
}
|
||||
work[n*2-1]=curve[n-1]*fscale;
|
||||
|
||||
n*=2;
|
||||
fft.backward(work);
|
||||
|
||||
// The autocorrelation will not be circular. Shift, else we lose
|
||||
// most of the power in the edges.
|
||||
|
||||
for(i=0, j=n/2; i<n/2;){
|
||||
float temp=work[i];
|
||||
work[i++]=work[j];
|
||||
work[j++]=temp;
|
||||
}
|
||||
|
||||
return (lpc_from_data(work, lpc, n, m));
|
||||
}
|
||||
|
||||
void init(int mapped, int m){
|
||||
ln=mapped;
|
||||
this.m=m;
|
||||
|
||||
// we cheat decoding the LPC spectrum via FFTs
|
||||
fft.init(mapped*2);
|
||||
}
|
||||
|
||||
void clear(){
|
||||
fft.clear();
|
||||
}
|
||||
|
||||
static float FAST_HYPOT(float a, float b){
|
||||
return (float)Math.sqrt((a)*(a)+(b)*(b));
|
||||
}
|
||||
|
||||
// One can do this the long way by generating the transfer function in
|
||||
// the time domain and taking the forward FFT of the result. The
|
||||
// results from direct calculation are cleaner and faster.
|
||||
//
|
||||
// This version does a linear curve generation and then later
|
||||
// interpolates the log curve from the linear curve.
|
||||
|
||||
void lpc_to_curve(float[] curve, float[] lpc, float amp){
|
||||
|
||||
for(int i=0; i<ln*2; i++)
|
||||
curve[i]=0.0f;
|
||||
|
||||
if(amp==0)
|
||||
return;
|
||||
|
||||
for(int i=0; i<m; i++){
|
||||
curve[i*2+1]=lpc[i]/(4*amp);
|
||||
curve[i*2+2]=-lpc[i]/(4*amp);
|
||||
}
|
||||
|
||||
fft.backward(curve);
|
||||
|
||||
{
|
||||
int l2=ln*2;
|
||||
float unit=(float)(1./amp);
|
||||
curve[0]=(float)(1./(curve[0]*2+unit));
|
||||
for(int i=1; i<ln; i++){
|
||||
float real=(curve[i]+curve[l2-i]);
|
||||
float imag=(curve[i]-curve[l2-i]);
|
||||
|
||||
float a=real+unit;
|
||||
curve[i]=(float)(1.0/FAST_HYPOT(a, imag));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
107
client/src/main/java/client/audio/jorbis/Lsp.java
Normal file
107
client/src/main/java/client/audio/jorbis/Lsp.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
/*
|
||||
function: LSP (also called LSF) conversion routines
|
||||
|
||||
The LSP generation code is taken (with minimal modification) from
|
||||
"On the Computation of the LSP Frequencies" by Joseph Rothweiler
|
||||
<rothwlr@altavista.net>, available at:
|
||||
|
||||
http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html
|
||||
********************************************************************/
|
||||
|
||||
class Lsp{
|
||||
|
||||
static final float M_PI=(float)(3.1415926539);
|
||||
|
||||
static void lsp_to_curve(float[] curve, int[] map, int n, int ln,
|
||||
float[] lsp, int m, float amp, float ampoffset){
|
||||
int i;
|
||||
float wdel=M_PI/ln;
|
||||
for(i=0; i<m; i++)
|
||||
lsp[i]=Lookup.coslook(lsp[i]);
|
||||
int m2=(m/2)*2;
|
||||
|
||||
i=0;
|
||||
while(i<n){
|
||||
int k=map[i];
|
||||
float p=.7071067812f;
|
||||
float q=.7071067812f;
|
||||
float w=Lookup.coslook(wdel*k);
|
||||
|
||||
for(int j=0; j<m2; j+=2){
|
||||
q*=lsp[j]-w;
|
||||
p*=lsp[j+1]-w;
|
||||
}
|
||||
|
||||
if((m&1)!=0){
|
||||
/* odd order filter; slightly assymetric */
|
||||
/* the last coefficient */
|
||||
q*=lsp[m-1]-w;
|
||||
q*=q;
|
||||
p*=p*(1.f-w*w);
|
||||
}
|
||||
else{
|
||||
/* even order filter; still symmetric */
|
||||
q*=q*(1.f+w);
|
||||
p*=p*(1.f-w);
|
||||
}
|
||||
|
||||
// q=frexp(p+q,&qexp);
|
||||
q=p+q;
|
||||
int hx=Float.floatToIntBits(q);
|
||||
int ix=0x7fffffff&hx;
|
||||
int qexp=0;
|
||||
|
||||
if(ix>=0x7f800000||(ix==0)){
|
||||
// 0,inf,nan
|
||||
}
|
||||
else{
|
||||
if(ix<0x00800000){ // subnormal
|
||||
q*=3.3554432000e+07; // 0x4c000000
|
||||
hx=Float.floatToIntBits(q);
|
||||
ix=0x7fffffff&hx;
|
||||
qexp=-25;
|
||||
}
|
||||
qexp+=((ix>>>23)-126);
|
||||
hx=(hx&0x807fffff)|0x3f000000;
|
||||
q=Float.intBitsToFloat(hx);
|
||||
}
|
||||
|
||||
q=Lookup.fromdBlook(amp*Lookup.invsqlook(q)*Lookup.invsq2explook(qexp+m)
|
||||
-ampoffset);
|
||||
|
||||
do{
|
||||
curve[i++]*=q;
|
||||
}
|
||||
while(i<n&&map[i]==k);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
375
client/src/main/java/client/audio/jorbis/Mapping0.java
Normal file
375
client/src/main/java/client/audio/jorbis/Mapping0.java
Normal file
|
@ -0,0 +1,375 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class Mapping0 extends FuncMapping{
|
||||
static int seq=0;
|
||||
|
||||
void free_info(Object imap){
|
||||
};
|
||||
|
||||
void free_look(Object imap){
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode vm, Object m){
|
||||
//System.err.println("Mapping0.look");
|
||||
Info vi=vd.vi;
|
||||
LookMapping0 look=new LookMapping0();
|
||||
InfoMapping0 info=look.map=(InfoMapping0)m;
|
||||
look.mode=vm;
|
||||
|
||||
look.time_look=new Object[info.submaps];
|
||||
look.floor_look=new Object[info.submaps];
|
||||
look.residue_look=new Object[info.submaps];
|
||||
|
||||
look.time_func=new FuncTime[info.submaps];
|
||||
look.floor_func=new FuncFloor[info.submaps];
|
||||
look.residue_func=new FuncResidue[info.submaps];
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
int timenum=info.timesubmap[i];
|
||||
int floornum=info.floorsubmap[i];
|
||||
int resnum=info.residuesubmap[i];
|
||||
|
||||
look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]];
|
||||
look.time_look[i]=look.time_func[i].look(vd, vm, vi.time_param[timenum]);
|
||||
look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]];
|
||||
look.floor_look[i]=look.floor_func[i].look(vd, vm,
|
||||
vi.floor_param[floornum]);
|
||||
look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]];
|
||||
look.residue_look[i]=look.residue_func[i].look(vd, vm,
|
||||
vi.residue_param[resnum]);
|
||||
|
||||
}
|
||||
|
||||
if(vi.psys!=0&&vd.analysisp!=0){
|
||||
// ??
|
||||
}
|
||||
|
||||
look.ch=vi.channels;
|
||||
|
||||
return (look);
|
||||
}
|
||||
|
||||
void pack(Info vi, Object imap, Buffer opb){
|
||||
InfoMapping0 info=(InfoMapping0)imap;
|
||||
|
||||
/* another 'we meant to do it this way' hack... up to beta 4, we
|
||||
packed 4 binary zeros here to signify one submapping in use. We
|
||||
now redefine that to mean four bitflags that indicate use of
|
||||
deeper features; bit0:submappings, bit1:coupling,
|
||||
bit2,3:reserved. This is backward compatable with all actual uses
|
||||
of the beta code. */
|
||||
|
||||
if(info.submaps>1){
|
||||
opb.write(1, 1);
|
||||
opb.write(info.submaps-1, 4);
|
||||
}
|
||||
else{
|
||||
opb.write(0, 1);
|
||||
}
|
||||
|
||||
if(info.coupling_steps>0){
|
||||
opb.write(1, 1);
|
||||
opb.write(info.coupling_steps-1, 8);
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
opb.write(info.coupling_mag[i], Util.ilog2(vi.channels));
|
||||
opb.write(info.coupling_ang[i], Util.ilog2(vi.channels));
|
||||
}
|
||||
}
|
||||
else{
|
||||
opb.write(0, 1);
|
||||
}
|
||||
|
||||
opb.write(0, 2); /* 2,3:reserved */
|
||||
|
||||
/* we don't write the channel submappings if we only have one... */
|
||||
if(info.submaps>1){
|
||||
for(int i=0; i<vi.channels; i++)
|
||||
opb.write(info.chmuxlist[i], 4);
|
||||
}
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
opb.write(info.timesubmap[i], 8);
|
||||
opb.write(info.floorsubmap[i], 8);
|
||||
opb.write(info.residuesubmap[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
// also responsible for range checking
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
InfoMapping0 info=new InfoMapping0();
|
||||
|
||||
if(opb.read(1)!=0){
|
||||
info.submaps=opb.read(4)+1;
|
||||
}
|
||||
else{
|
||||
info.submaps=1;
|
||||
}
|
||||
|
||||
if(opb.read(1)!=0){
|
||||
info.coupling_steps=opb.read(8)+1;
|
||||
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
int testM=info.coupling_mag[i]=opb.read(Util.ilog2(vi.channels));
|
||||
int testA=info.coupling_ang[i]=opb.read(Util.ilog2(vi.channels));
|
||||
|
||||
if(testM<0||testA<0||testM==testA||testM>=vi.channels
|
||||
||testA>=vi.channels){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(opb.read(2)>0){ /* 2,3:reserved */
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(info.submaps>1){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
info.chmuxlist[i]=opb.read(4);
|
||||
if(info.chmuxlist[i]>=info.submaps){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
info.timesubmap[i]=opb.read(8);
|
||||
if(info.timesubmap[i]>=vi.times){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
info.floorsubmap[i]=opb.read(8);
|
||||
if(info.floorsubmap[i]>=vi.floors){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
info.residuesubmap[i]=opb.read(8);
|
||||
if(info.residuesubmap[i]>=vi.residues){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
float[][] pcmbundle=null;
|
||||
int[] zerobundle=null;
|
||||
int[] nonzero=null;
|
||||
Object[] floormemo=null;
|
||||
|
||||
synchronized int inverse(Block vb, Object l){
|
||||
DspState vd=vb.vd;
|
||||
Info vi=vd.vi;
|
||||
LookMapping0 look=(LookMapping0)l;
|
||||
InfoMapping0 info=look.map;
|
||||
InfoMode mode=look.mode;
|
||||
int n=vb.pcmend=vi.blocksizes[vb.W];
|
||||
|
||||
float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
|
||||
if(pcmbundle==null||pcmbundle.length<vi.channels){
|
||||
pcmbundle=new float[vi.channels][];
|
||||
nonzero=new int[vi.channels];
|
||||
zerobundle=new int[vi.channels];
|
||||
floormemo=new Object[vi.channels];
|
||||
}
|
||||
|
||||
// time domain information decode (note that applying the
|
||||
// information would have to happen later; we'll probably add a
|
||||
// function entry to the harness for that later
|
||||
// NOT IMPLEMENTED
|
||||
|
||||
// recover the spectral envelope; store it in the PCM vector for now
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
int submap=info.chmuxlist[i];
|
||||
|
||||
floormemo[i]=look.floor_func[submap].inverse1(vb,
|
||||
look.floor_look[submap], floormemo[i]);
|
||||
if(floormemo[i]!=null){
|
||||
nonzero[i]=1;
|
||||
}
|
||||
else{
|
||||
nonzero[i]=0;
|
||||
}
|
||||
for(int j=0; j<n/2; j++){
|
||||
pcm[j]=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
if(nonzero[info.coupling_mag[i]]!=0||nonzero[info.coupling_ang[i]]!=0){
|
||||
nonzero[info.coupling_mag[i]]=1;
|
||||
nonzero[info.coupling_ang[i]]=1;
|
||||
}
|
||||
}
|
||||
|
||||
// recover the residue, apply directly to the spectral envelope
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
int ch_in_bundle=0;
|
||||
for(int j=0; j<vi.channels; j++){
|
||||
if(info.chmuxlist[j]==i){
|
||||
if(nonzero[j]!=0){
|
||||
zerobundle[ch_in_bundle]=1;
|
||||
}
|
||||
else{
|
||||
zerobundle[ch_in_bundle]=0;
|
||||
}
|
||||
pcmbundle[ch_in_bundle++]=vb.pcm[j];
|
||||
}
|
||||
}
|
||||
|
||||
look.residue_func[i].inverse(vb, look.residue_look[i], pcmbundle,
|
||||
zerobundle, ch_in_bundle);
|
||||
}
|
||||
|
||||
for(int i=info.coupling_steps-1; i>=0; i--){
|
||||
float[] pcmM=vb.pcm[info.coupling_mag[i]];
|
||||
float[] pcmA=vb.pcm[info.coupling_ang[i]];
|
||||
|
||||
for(int j=0; j<n/2; j++){
|
||||
float mag=pcmM[j];
|
||||
float ang=pcmA[j];
|
||||
|
||||
if(mag>0){
|
||||
if(ang>0){
|
||||
pcmM[j]=mag;
|
||||
pcmA[j]=mag-ang;
|
||||
}
|
||||
else{
|
||||
pcmA[j]=mag;
|
||||
pcmM[j]=mag+ang;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(ang>0){
|
||||
pcmM[j]=mag;
|
||||
pcmA[j]=mag+ang;
|
||||
}
|
||||
else{
|
||||
pcmA[j]=mag;
|
||||
pcmM[j]=mag-ang;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// /* compute and apply spectral envelope */
|
||||
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
int submap=info.chmuxlist[i];
|
||||
look.floor_func[submap].inverse2(vb, look.floor_look[submap],
|
||||
floormemo[i], pcm);
|
||||
}
|
||||
|
||||
// transform the PCM data; takes PCM vector, vb; modifies PCM vector
|
||||
// only MDCT right now....
|
||||
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
//_analysis_output("out",seq+i,pcm,n/2,0,0);
|
||||
((Mdct)vd.transform[vb.W][0]).backward(pcm, pcm);
|
||||
}
|
||||
|
||||
// now apply the decoded pre-window time information
|
||||
// NOT IMPLEMENTED
|
||||
|
||||
// window the data
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
if(nonzero[i]!=0){
|
||||
for(int j=0; j<n; j++){
|
||||
pcm[j]*=window[j];
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<n; j++){
|
||||
pcm[j]=0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now apply the decoded post-window time information
|
||||
// NOT IMPLEMENTED
|
||||
// all done!
|
||||
return (0);
|
||||
}
|
||||
|
||||
class InfoMapping0{
|
||||
int submaps; // <= 16
|
||||
int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream
|
||||
|
||||
int[] timesubmap=new int[16]; // [mux]
|
||||
int[] floorsubmap=new int[16]; // [mux] submap to floors
|
||||
int[] residuesubmap=new int[16];// [mux] submap to residue
|
||||
int[] psysubmap=new int[16]; // [mux]; encode only
|
||||
|
||||
int coupling_steps;
|
||||
int[] coupling_mag=new int[256];
|
||||
int[] coupling_ang=new int[256];
|
||||
|
||||
void free(){
|
||||
chmuxlist=null;
|
||||
timesubmap=null;
|
||||
floorsubmap=null;
|
||||
residuesubmap=null;
|
||||
psysubmap=null;
|
||||
|
||||
coupling_mag=null;
|
||||
coupling_ang=null;
|
||||
}
|
||||
}
|
||||
|
||||
class LookMapping0{
|
||||
InfoMode mode;
|
||||
InfoMapping0 map;
|
||||
Object[] time_look;
|
||||
Object[] floor_look;
|
||||
Object[] floor_state;
|
||||
Object[] residue_look;
|
||||
PsyLook[] psy_look;
|
||||
|
||||
FuncTime[] time_func;
|
||||
FuncFloor[] floor_func;
|
||||
FuncResidue[] residue_func;
|
||||
|
||||
int ch;
|
||||
float[][] decay;
|
||||
int lastframe; // if a different mode is called, we need to
|
||||
// invalidate decay and floor state
|
||||
}
|
||||
|
||||
}
|
250
client/src/main/java/client/audio/jorbis/Mdct.java
Normal file
250
client/src/main/java/client/audio/jorbis/Mdct.java
Normal file
|
@ -0,0 +1,250 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class Mdct{
|
||||
|
||||
int n;
|
||||
int log2n;
|
||||
|
||||
float[] trig;
|
||||
int[] bitrev;
|
||||
|
||||
float scale;
|
||||
|
||||
void init(int n){
|
||||
bitrev=new int[n/4];
|
||||
trig=new float[n+n/4];
|
||||
|
||||
log2n=(int)Math.rint(Math.log(n)/Math.log(2));
|
||||
this.n=n;
|
||||
|
||||
int AE=0;
|
||||
int AO=1;
|
||||
int BE=AE+n/2;
|
||||
int BO=BE+1;
|
||||
int CE=BE+n/2;
|
||||
int CO=CE+1;
|
||||
// trig lookups...
|
||||
for(int i=0; i<n/4; i++){
|
||||
trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
|
||||
trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
|
||||
trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
|
||||
trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
|
||||
}
|
||||
for(int i=0; i<n/8; i++){
|
||||
trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
|
||||
trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
|
||||
}
|
||||
|
||||
{
|
||||
int mask=(1<<(log2n-1))-1;
|
||||
int msb=1<<(log2n-2);
|
||||
for(int i=0; i<n/8; i++){
|
||||
int acc=0;
|
||||
for(int j=0; msb>>>j!=0; j++)
|
||||
if(((msb>>>j)&i)!=0)
|
||||
acc|=1<<j;
|
||||
bitrev[i*2]=((~acc)&mask);
|
||||
// bitrev[i*2]=((~acc)&mask)-1;
|
||||
bitrev[i*2+1]=acc;
|
||||
}
|
||||
}
|
||||
scale=4.f/n;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
void forward(float[] in, float[] out){
|
||||
}
|
||||
|
||||
float[] _x=new float[1024];
|
||||
float[] _w=new float[1024];
|
||||
|
||||
synchronized void backward(float[] in, float[] out){
|
||||
if(_x.length<n/2){
|
||||
_x=new float[n/2];
|
||||
}
|
||||
if(_w.length<n/2){
|
||||
_w=new float[n/2];
|
||||
}
|
||||
float[] x=_x;
|
||||
float[] w=_w;
|
||||
int n2=n>>>1;
|
||||
int n4=n>>>2;
|
||||
int n8=n>>>3;
|
||||
|
||||
// rotate + step 1
|
||||
{
|
||||
int inO=1;
|
||||
int xO=0;
|
||||
int A=n2;
|
||||
|
||||
int i;
|
||||
for(i=0; i<n8; i++){
|
||||
A-=2;
|
||||
x[xO++]=-in[inO+2]*trig[A+1]-in[inO]*trig[A];
|
||||
x[xO++]=in[inO]*trig[A+1]-in[inO+2]*trig[A];
|
||||
inO+=4;
|
||||
}
|
||||
|
||||
inO=n2-4;
|
||||
|
||||
for(i=0; i<n8; i++){
|
||||
A-=2;
|
||||
x[xO++]=in[inO]*trig[A+1]+in[inO+2]*trig[A];
|
||||
x[xO++]=in[inO]*trig[A]-in[inO+2]*trig[A+1];
|
||||
inO-=4;
|
||||
}
|
||||
}
|
||||
|
||||
float[] xxx=mdct_kernel(x, w, n, n2, n4, n8);
|
||||
int xx=0;
|
||||
|
||||
// step 8
|
||||
|
||||
{
|
||||
int B=n2;
|
||||
int o1=n4, o2=o1-1;
|
||||
int o3=n4+n2, o4=o3-1;
|
||||
|
||||
for(int i=0; i<n4; i++){
|
||||
float temp1=(xxx[xx]*trig[B+1]-xxx[xx+1]*trig[B]);
|
||||
float temp2=-(xxx[xx]*trig[B]+xxx[xx+1]*trig[B+1]);
|
||||
|
||||
out[o1]=-temp1;
|
||||
out[o2]=temp1;
|
||||
out[o3]=temp2;
|
||||
out[o4]=temp2;
|
||||
|
||||
o1++;
|
||||
o2--;
|
||||
o3++;
|
||||
o4--;
|
||||
xx+=2;
|
||||
B+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float[] mdct_kernel(float[] x, float[] w, int n, int n2, int n4,
|
||||
int n8){
|
||||
// step 2
|
||||
|
||||
int xA=n4;
|
||||
int xB=0;
|
||||
int w2=n4;
|
||||
int A=n2;
|
||||
|
||||
for(int i=0; i<n4;){
|
||||
float x0=x[xA]-x[xB];
|
||||
float x1;
|
||||
w[w2+i]=x[xA++]+x[xB++];
|
||||
|
||||
x1=x[xA]-x[xB];
|
||||
A-=4;
|
||||
|
||||
w[i++]=x0*trig[A]+x1*trig[A+1];
|
||||
w[i]=x1*trig[A]-x0*trig[A+1];
|
||||
|
||||
w[w2+i]=x[xA++]+x[xB++];
|
||||
i++;
|
||||
}
|
||||
|
||||
// step 3
|
||||
|
||||
{
|
||||
for(int i=0; i<log2n-3; i++){
|
||||
int k0=n>>>(i+2);
|
||||
int k1=1<<(i+3);
|
||||
int wbase=n2-2;
|
||||
|
||||
A=0;
|
||||
float[] temp;
|
||||
|
||||
for(int r=0; r<(k0>>>2); r++){
|
||||
int w1=wbase;
|
||||
w2=w1-(k0>>1);
|
||||
float AEv=trig[A], wA;
|
||||
float AOv=trig[A+1], wB;
|
||||
wbase-=2;
|
||||
|
||||
k0++;
|
||||
for(int s=0; s<(2<<i); s++){
|
||||
wB=w[w1]-w[w2];
|
||||
x[w1]=w[w1]+w[w2];
|
||||
|
||||
wA=w[++w1]-w[++w2];
|
||||
x[w1]=w[w1]+w[w2];
|
||||
|
||||
x[w2]=wA*AEv-wB*AOv;
|
||||
x[w2-1]=wB*AEv+wA*AOv;
|
||||
|
||||
w1-=k0;
|
||||
w2-=k0;
|
||||
}
|
||||
k0--;
|
||||
A+=k1;
|
||||
}
|
||||
|
||||
temp=w;
|
||||
w=x;
|
||||
x=temp;
|
||||
}
|
||||
}
|
||||
|
||||
// step 4, 5, 6, 7
|
||||
{
|
||||
int C=n;
|
||||
int bit=0;
|
||||
int x1=0;
|
||||
int x2=n2-1;
|
||||
|
||||
for(int i=0; i<n8; i++){
|
||||
int t1=bitrev[bit++];
|
||||
int t2=bitrev[bit++];
|
||||
|
||||
float wA=w[t1]-w[t2+1];
|
||||
float wB=w[t1-1]+w[t2];
|
||||
float wC=w[t1]+w[t2+1];
|
||||
float wD=w[t1-1]-w[t2];
|
||||
|
||||
float wACE=wA*trig[C];
|
||||
float wBCE=wB*trig[C++];
|
||||
float wACO=wA*trig[C];
|
||||
float wBCO=wB*trig[C++];
|
||||
|
||||
x[x1++]=(wC+wACO+wBCE)*.5f;
|
||||
x[x2--]=(-wD+wBCO-wACE)*.5f;
|
||||
x[x1++]=(wD+wBCO-wACE)*.5f;
|
||||
x[x2--]=(wC-wACO-wBCE)*.5f;
|
||||
}
|
||||
}
|
||||
return (x);
|
||||
}
|
||||
}
|
74
client/src/main/java/client/audio/jorbis/PsyInfo.java
Normal file
74
client/src/main/java/client/audio/jorbis/PsyInfo.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
// psychoacoustic setup
|
||||
class PsyInfo{
|
||||
int athp;
|
||||
int decayp;
|
||||
int smoothp;
|
||||
int noisefitp;
|
||||
int noisefit_subblock;
|
||||
float noisefit_threshdB;
|
||||
|
||||
float ath_att;
|
||||
|
||||
int tonemaskp;
|
||||
float[] toneatt_125Hz=new float[5];
|
||||
float[] toneatt_250Hz=new float[5];
|
||||
float[] toneatt_500Hz=new float[5];
|
||||
float[] toneatt_1000Hz=new float[5];
|
||||
float[] toneatt_2000Hz=new float[5];
|
||||
float[] toneatt_4000Hz=new float[5];
|
||||
float[] toneatt_8000Hz=new float[5];
|
||||
|
||||
int peakattp;
|
||||
float[] peakatt_125Hz=new float[5];
|
||||
float[] peakatt_250Hz=new float[5];
|
||||
float[] peakatt_500Hz=new float[5];
|
||||
float[] peakatt_1000Hz=new float[5];
|
||||
float[] peakatt_2000Hz=new float[5];
|
||||
float[] peakatt_4000Hz=new float[5];
|
||||
float[] peakatt_8000Hz=new float[5];
|
||||
|
||||
int noisemaskp;
|
||||
float[] noiseatt_125Hz=new float[5];
|
||||
float[] noiseatt_250Hz=new float[5];
|
||||
float[] noiseatt_500Hz=new float[5];
|
||||
float[] noiseatt_1000Hz=new float[5];
|
||||
float[] noiseatt_2000Hz=new float[5];
|
||||
float[] noiseatt_4000Hz=new float[5];
|
||||
float[] noiseatt_8000Hz=new float[5];
|
||||
|
||||
float max_curve_dB;
|
||||
|
||||
float attack_coeff;
|
||||
float decay_coeff;
|
||||
|
||||
void free(){
|
||||
}
|
||||
}
|
42
client/src/main/java/client/audio/jorbis/PsyLook.java
Normal file
42
client/src/main/java/client/audio/jorbis/PsyLook.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class PsyLook{
|
||||
int n;
|
||||
PsyInfo vi;
|
||||
|
||||
float[][][] tonecurves;
|
||||
float[][] peakatt;
|
||||
float[][][] noisecurves;
|
||||
|
||||
float[] ath;
|
||||
int[] octave;
|
||||
|
||||
void init(PsyInfo vi, int n, int rate){
|
||||
}
|
||||
}
|
330
client/src/main/java/client/audio/jorbis/Residue0.java
Normal file
330
client/src/main/java/client/audio/jorbis/Residue0.java
Normal file
|
@ -0,0 +1,330 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class Residue0 extends FuncResidue{
|
||||
void pack(Object vr, Buffer opb){
|
||||
InfoResidue0 info=(InfoResidue0)vr;
|
||||
int acc=0;
|
||||
opb.write(info.begin, 24);
|
||||
opb.write(info.end, 24);
|
||||
|
||||
opb.write(info.grouping-1, 24); /* residue vectors to group and
|
||||
code with a partitioned book */
|
||||
opb.write(info.partitions-1, 6); /* possible partition choices */
|
||||
opb.write(info.groupbook, 8); /* group huffman book */
|
||||
|
||||
/* secondstages is a bitmask; as encoding progresses pass by pass, a
|
||||
bitmask of one indicates this partition class has bits to write
|
||||
this pass */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
int i=info.secondstages[j];
|
||||
if(Util.ilog(i)>3){
|
||||
/* yes, this is a minor hack due to not thinking ahead */
|
||||
opb.write(i, 3);
|
||||
opb.write(1, 1);
|
||||
opb.write(i>>>3, 5);
|
||||
}
|
||||
else{
|
||||
opb.write(i, 4); /* trailing zero */
|
||||
}
|
||||
acc+=Util.icount(i);
|
||||
}
|
||||
for(int j=0; j<acc; j++){
|
||||
opb.write(info.booklist[j], 8);
|
||||
}
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
int acc=0;
|
||||
InfoResidue0 info=new InfoResidue0();
|
||||
info.begin=opb.read(24);
|
||||
info.end=opb.read(24);
|
||||
info.grouping=opb.read(24)+1;
|
||||
info.partitions=opb.read(6)+1;
|
||||
info.groupbook=opb.read(8);
|
||||
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
int cascade=opb.read(3);
|
||||
if(opb.read(1)!=0){
|
||||
cascade|=(opb.read(5)<<3);
|
||||
}
|
||||
info.secondstages[j]=cascade;
|
||||
acc+=Util.icount(cascade);
|
||||
}
|
||||
|
||||
for(int j=0; j<acc; j++){
|
||||
info.booklist[j]=opb.read(8);
|
||||
}
|
||||
|
||||
if(info.groupbook>=vi.books){
|
||||
free_info(info);
|
||||
return (null);
|
||||
}
|
||||
|
||||
for(int j=0; j<acc; j++){
|
||||
if(info.booklist[j]>=vi.books){
|
||||
free_info(info);
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode vm, Object vr){
|
||||
InfoResidue0 info=(InfoResidue0)vr;
|
||||
LookResidue0 look=new LookResidue0();
|
||||
int acc=0;
|
||||
int dim;
|
||||
int maxstage=0;
|
||||
look.info=info;
|
||||
look.map=vm.mapping;
|
||||
|
||||
look.parts=info.partitions;
|
||||
look.fullbooks=vd.fullbooks;
|
||||
look.phrasebook=vd.fullbooks[info.groupbook];
|
||||
|
||||
dim=look.phrasebook.dim;
|
||||
|
||||
look.partbooks=new int[look.parts][];
|
||||
|
||||
for(int j=0; j<look.parts; j++){
|
||||
int i=info.secondstages[j];
|
||||
int stages=Util.ilog(i);
|
||||
if(stages!=0){
|
||||
if(stages>maxstage)
|
||||
maxstage=stages;
|
||||
look.partbooks[j]=new int[stages];
|
||||
for(int k=0; k<stages; k++){
|
||||
if((i&(1<<k))!=0){
|
||||
look.partbooks[j][k]=info.booklist[acc++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
look.partvals=(int)Math.rint(Math.pow(look.parts, dim));
|
||||
look.stages=maxstage;
|
||||
look.decodemap=new int[look.partvals][];
|
||||
for(int j=0; j<look.partvals; j++){
|
||||
int val=j;
|
||||
int mult=look.partvals/look.parts;
|
||||
look.decodemap[j]=new int[dim];
|
||||
|
||||
for(int k=0; k<dim; k++){
|
||||
int deco=val/mult;
|
||||
val-=deco*mult;
|
||||
mult/=look.parts;
|
||||
look.decodemap[j][k]=deco;
|
||||
}
|
||||
}
|
||||
return (look);
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
private static int[][][] _01inverse_partword=new int[2][][]; // _01inverse is synchronized for
|
||||
|
||||
// re-using partword
|
||||
synchronized static int _01inverse(Block vb, Object vl, float[][] in, int ch,
|
||||
int decodepart){
|
||||
int i, j, k, l, s;
|
||||
LookResidue0 look=(LookResidue0)vl;
|
||||
InfoResidue0 info=look.info;
|
||||
|
||||
// move all this setup out later
|
||||
int samples_per_partition=info.grouping;
|
||||
int partitions_per_word=look.phrasebook.dim;
|
||||
int n=info.end-info.begin;
|
||||
|
||||
int partvals=n/samples_per_partition;
|
||||
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
|
||||
|
||||
if(_01inverse_partword.length<ch){
|
||||
_01inverse_partword=new int[ch][][];
|
||||
}
|
||||
|
||||
for(j=0; j<ch; j++){
|
||||
if(_01inverse_partword[j]==null||_01inverse_partword[j].length<partwords){
|
||||
_01inverse_partword[j]=new int[partwords][];
|
||||
}
|
||||
}
|
||||
|
||||
for(s=0; s<look.stages; s++){
|
||||
// each loop decodes on partition codeword containing
|
||||
// partitions_pre_word partitions
|
||||
for(i=0, l=0; i<partvals; l++){
|
||||
if(s==0){
|
||||
// fetch the partition word for each channel
|
||||
for(j=0; j<ch; j++){
|
||||
int temp=look.phrasebook.decode(vb.opb);
|
||||
if(temp==-1){
|
||||
return (0);
|
||||
}
|
||||
_01inverse_partword[j][l]=look.decodemap[temp];
|
||||
if(_01inverse_partword[j][l]==null){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we decode residual values for the partitions
|
||||
for(k=0; k<partitions_per_word&&i<partvals; k++, i++)
|
||||
for(j=0; j<ch; j++){
|
||||
int offset=info.begin+i*samples_per_partition;
|
||||
int index=_01inverse_partword[j][l][k];
|
||||
if((info.secondstages[index]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
|
||||
if(stagebook!=null){
|
||||
if(decodepart==0){
|
||||
if(stagebook.decodevs_add(in[j], offset, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if(decodepart==1){
|
||||
if(stagebook.decodev_add(in[j], offset, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int[][] _2inverse_partword=null;
|
||||
|
||||
synchronized static int _2inverse(Block vb, Object vl, float[][] in, int ch){
|
||||
int i, k, l, s;
|
||||
LookResidue0 look=(LookResidue0)vl;
|
||||
InfoResidue0 info=look.info;
|
||||
|
||||
// move all this setup out later
|
||||
int samples_per_partition=info.grouping;
|
||||
int partitions_per_word=look.phrasebook.dim;
|
||||
int n=info.end-info.begin;
|
||||
|
||||
int partvals=n/samples_per_partition;
|
||||
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
|
||||
|
||||
if(_2inverse_partword==null||_2inverse_partword.length<partwords){
|
||||
_2inverse_partword=new int[partwords][];
|
||||
}
|
||||
for(s=0; s<look.stages; s++){
|
||||
for(i=0, l=0; i<partvals; l++){
|
||||
if(s==0){
|
||||
// fetch the partition word for each channel
|
||||
int temp=look.phrasebook.decode(vb.opb);
|
||||
if(temp==-1){
|
||||
return (0);
|
||||
}
|
||||
_2inverse_partword[l]=look.decodemap[temp];
|
||||
if(_2inverse_partword[l]==null){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
// now we decode residual values for the partitions
|
||||
for(k=0; k<partitions_per_word&&i<partvals; k++, i++){
|
||||
int offset=info.begin+i*samples_per_partition;
|
||||
int index=_2inverse_partword[l][k];
|
||||
if((info.secondstages[index]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
|
||||
if(stagebook!=null){
|
||||
if(stagebook.decodevv_add(in, offset, ch, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int used=0;
|
||||
for(int i=0; i<ch; i++){
|
||||
if(nonzero[i]!=0){
|
||||
in[used++]=in[i];
|
||||
}
|
||||
}
|
||||
if(used!=0)
|
||||
return (_01inverse(vb, vl, in, used, 0));
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
class LookResidue0{
|
||||
InfoResidue0 info;
|
||||
int map;
|
||||
|
||||
int parts;
|
||||
int stages;
|
||||
CodeBook[] fullbooks;
|
||||
CodeBook phrasebook;
|
||||
int[][] partbooks;
|
||||
|
||||
int partvals;
|
||||
int[][] decodemap;
|
||||
|
||||
int postbits;
|
||||
int phrasebits;
|
||||
int frames;
|
||||
}
|
||||
|
||||
class InfoResidue0{
|
||||
// block-partitioned VQ coded straight residue
|
||||
int begin;
|
||||
int end;
|
||||
|
||||
// first stage (lossless partitioning)
|
||||
int grouping; // group n vectors per partition
|
||||
int partitions; // possible codebooks for a partition
|
||||
int groupbook; // huffbook for partitioning
|
||||
int[] secondstages=new int[64]; // expanded out to pointers in lookup
|
||||
int[] booklist=new int[256]; // list of second stage books
|
||||
|
||||
// encode-only heuristic settings
|
||||
float[] entmax=new float[64]; // book entropy threshholds
|
||||
float[] ampmax=new float[64]; // book amp threshholds
|
||||
int[] subgrp=new int[64]; // book heuristic subgroup size
|
||||
int[] blimit=new int[64]; // subgroup position limits
|
||||
}
|
||||
|
||||
}
|
45
client/src/main/java/client/audio/jorbis/Residue1.java
Normal file
45
client/src/main/java/client/audio/jorbis/Residue1.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class Residue1 extends Residue0{
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int used=0;
|
||||
for(int i=0; i<ch; i++){
|
||||
if(nonzero[i]!=0){
|
||||
in[used++]=in[i];
|
||||
}
|
||||
}
|
||||
if(used!=0){
|
||||
return (_01inverse(vb, vl, in, used, 1));
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
41
client/src/main/java/client/audio/jorbis/Residue2.java
Normal file
41
client/src/main/java/client/audio/jorbis/Residue2.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
class Residue2 extends Residue0{
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int i=0;
|
||||
for(i=0; i<ch; i++)
|
||||
if(nonzero[i]!=0)
|
||||
break;
|
||||
if(i==ch)
|
||||
return (0); /* no nonzero vectors */
|
||||
|
||||
return (_2inverse(vb, vl, in, ch));
|
||||
}
|
||||
}
|
443
client/src/main/java/client/audio/jorbis/StaticCodeBook.java
Normal file
443
client/src/main/java/client/audio/jorbis/StaticCodeBook.java
Normal file
|
@ -0,0 +1,443 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class StaticCodeBook{
|
||||
int dim; // codebook dimensions (elements per vector)
|
||||
int entries; // codebook entries
|
||||
int[] lengthlist; // codeword lengths in bits
|
||||
|
||||
// mapping
|
||||
int maptype; // 0=none
|
||||
// 1=implicitly populated values from map column
|
||||
// 2=listed arbitrary values
|
||||
|
||||
// The below does a linear, single monotonic sequence mapping.
|
||||
int q_min; // packed 32 bit float; quant value 0 maps to minval
|
||||
int q_delta; // packed 32 bit float; val 1 - val 0 == delta
|
||||
int q_quant; // bits: 0 < quant <= 16
|
||||
int q_sequencep; // bitflag
|
||||
|
||||
// additional information for log (dB) mapping; the linear mapping
|
||||
// is assumed to actually be values in dB. encodebias is used to
|
||||
// assign an error weight to 0 dB. We have two additional flags:
|
||||
// zeroflag indicates if entry zero is to represent -Inf dB; negflag
|
||||
// indicates if we're to represent negative linear values in a
|
||||
// mirror of the positive mapping.
|
||||
|
||||
int[] quantlist; // map == 1: (int)(entries/dim) element column map
|
||||
// map == 2: list of dim*entries quantized entry vals
|
||||
|
||||
StaticCodeBook(){
|
||||
}
|
||||
|
||||
int pack(Buffer opb){
|
||||
int i;
|
||||
boolean ordered=false;
|
||||
|
||||
opb.write(0x564342, 24);
|
||||
opb.write(dim, 16);
|
||||
opb.write(entries, 24);
|
||||
|
||||
// pack the codewords. There are two packings; length ordered and
|
||||
// length random. Decide between the two now.
|
||||
|
||||
for(i=1; i<entries; i++){
|
||||
if(lengthlist[i]<lengthlist[i-1])
|
||||
break;
|
||||
}
|
||||
if(i==entries)
|
||||
ordered=true;
|
||||
|
||||
if(ordered){
|
||||
// length ordered. We only need to say how many codewords of
|
||||
// each length. The actual codewords are generated
|
||||
// deterministically
|
||||
|
||||
int count=0;
|
||||
opb.write(1, 1); // ordered
|
||||
opb.write(lengthlist[0]-1, 5); // 1 to 32
|
||||
|
||||
for(i=1; i<entries; i++){
|
||||
int _this=lengthlist[i];
|
||||
int _last=lengthlist[i-1];
|
||||
if(_this>_last){
|
||||
for(int j=_last; j<_this; j++){
|
||||
opb.write(i-count, Util.ilog(entries-count));
|
||||
count=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(i-count, Util.ilog(entries-count));
|
||||
}
|
||||
else{
|
||||
// length random. Again, we don't code the codeword itself, just
|
||||
// the length. This time, though, we have to encode each length
|
||||
opb.write(0, 1); // unordered
|
||||
|
||||
// algortihmic mapping has use for 'unused entries', which we tag
|
||||
// here. The algorithmic mapping happens as usual, but the unused
|
||||
// entry has no codeword.
|
||||
for(i=0; i<entries; i++){
|
||||
if(lengthlist[i]==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i==entries){
|
||||
opb.write(0, 1); // no unused entries
|
||||
for(i=0; i<entries; i++){
|
||||
opb.write(lengthlist[i]-1, 5);
|
||||
}
|
||||
}
|
||||
else{
|
||||
opb.write(1, 1); // we have unused entries; thus we tag
|
||||
for(i=0; i<entries; i++){
|
||||
if(lengthlist[i]==0){
|
||||
opb.write(0, 1);
|
||||
}
|
||||
else{
|
||||
opb.write(1, 1);
|
||||
opb.write(lengthlist[i]-1, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// is the entry number the desired return value, or do we have a
|
||||
// mapping? If we have a mapping, what type?
|
||||
opb.write(maptype, 4);
|
||||
switch(maptype){
|
||||
case 0:
|
||||
// no mapping
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// implicitly populated value mapping
|
||||
// explicitly populated value mapping
|
||||
if(quantlist==null){
|
||||
// no quantlist? error
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// values that define the dequantization
|
||||
opb.write(q_min, 32);
|
||||
opb.write(q_delta, 32);
|
||||
opb.write(q_quant-1, 4);
|
||||
opb.write(q_sequencep, 1);
|
||||
|
||||
{
|
||||
int quantvals=0;
|
||||
switch(maptype){
|
||||
case 1:
|
||||
// a single column of (c->entries/c->dim) quantized values for
|
||||
// building a full value list algorithmically (square lattice)
|
||||
quantvals=maptype1_quantvals();
|
||||
break;
|
||||
case 2:
|
||||
// every value (c->entries*c->dim total) specified explicitly
|
||||
quantvals=entries*dim;
|
||||
break;
|
||||
}
|
||||
|
||||
// quantized values
|
||||
for(i=0; i<quantvals; i++){
|
||||
opb.write(Math.abs(quantlist[i]), q_quant);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// error case; we don't have any other map types now
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// unpacks a codebook from the packet buffer into the codebook struct,
|
||||
// readies the codebook auxiliary structures for decode
|
||||
int unpack(Buffer opb){
|
||||
int i;
|
||||
//memset(s,0,sizeof(static_codebook));
|
||||
|
||||
// make sure alignment is correct
|
||||
if(opb.read(24)!=0x564342){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// first the basic parameters
|
||||
dim=opb.read(16);
|
||||
entries=opb.read(24);
|
||||
if(entries==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// codeword ordering.... length ordered or unordered?
|
||||
switch(opb.read(1)){
|
||||
case 0:
|
||||
// unordered
|
||||
lengthlist=new int[entries];
|
||||
|
||||
// allocated but unused entries?
|
||||
if(opb.read(1)!=0){
|
||||
// yes, unused entries
|
||||
|
||||
for(i=0; i<entries; i++){
|
||||
if(opb.read(1)!=0){
|
||||
int num=opb.read(5);
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
lengthlist[i]=num+1;
|
||||
}
|
||||
else{
|
||||
lengthlist[i]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
// all entries used; no tagging
|
||||
for(i=0; i<entries; i++){
|
||||
int num=opb.read(5);
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
lengthlist[i]=num+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// ordered
|
||||
{
|
||||
int length=opb.read(5)+1;
|
||||
lengthlist=new int[entries];
|
||||
|
||||
for(i=0; i<entries;){
|
||||
int num=opb.read(Util.ilog(entries-i));
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
for(int j=0; j<num; j++, i++){
|
||||
lengthlist[i]=length;
|
||||
}
|
||||
length++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// EOF
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// Do we have a mapping to unpack?
|
||||
switch((maptype=opb.read(4))){
|
||||
case 0:
|
||||
// no mapping
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// implicitly populated value mapping
|
||||
// explicitly populated value mapping
|
||||
q_min=opb.read(32);
|
||||
q_delta=opb.read(32);
|
||||
q_quant=opb.read(4)+1;
|
||||
q_sequencep=opb.read(1);
|
||||
|
||||
{
|
||||
int quantvals=0;
|
||||
switch(maptype){
|
||||
case 1:
|
||||
quantvals=maptype1_quantvals();
|
||||
break;
|
||||
case 2:
|
||||
quantvals=entries*dim;
|
||||
break;
|
||||
}
|
||||
|
||||
// quantized values
|
||||
quantlist=new int[quantvals];
|
||||
for(i=0; i<quantvals; i++){
|
||||
quantlist[i]=opb.read(q_quant);
|
||||
}
|
||||
if(quantlist[quantvals-1]==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
// all set
|
||||
return (0);
|
||||
// _errout:
|
||||
// _eofout:
|
||||
// vorbis_staticbook_clear(s);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
// there might be a straightforward one-line way to do the below
|
||||
// that's portable and totally safe against roundoff, but I haven't
|
||||
// thought of it. Therefore, we opt on the side of caution
|
||||
private int maptype1_quantvals(){
|
||||
int vals=(int)(Math.floor(Math.pow(entries, 1./dim)));
|
||||
|
||||
// the above *should* be reliable, but we'll not assume that FP is
|
||||
// ever reliable when bitstream sync is at stake; verify via integer
|
||||
// means that vals really is the greatest value of dim for which
|
||||
// vals^b->bim <= b->entries
|
||||
// treat the above as an initial guess
|
||||
while(true){
|
||||
int acc=1;
|
||||
int acc1=1;
|
||||
for(int i=0; i<dim; i++){
|
||||
acc*=vals;
|
||||
acc1*=vals+1;
|
||||
}
|
||||
if(acc<=entries&&acc1>entries){
|
||||
return (vals);
|
||||
}
|
||||
else{
|
||||
if(acc>entries){
|
||||
vals--;
|
||||
}
|
||||
else{
|
||||
vals++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
// unpack the quantized list of values for encode/decode
|
||||
// we need to deal with two map types: in map type 1, the values are
|
||||
// generated algorithmically (each column of the vector counts through
|
||||
// the values in the quant vector). in map type 2, all the values came
|
||||
// in in an explicit list. Both value lists must be unpacked
|
||||
float[] unquantize(){
|
||||
|
||||
if(maptype==1||maptype==2){
|
||||
int quantvals;
|
||||
float mindel=float32_unpack(q_min);
|
||||
float delta=float32_unpack(q_delta);
|
||||
float[] r=new float[entries*dim];
|
||||
|
||||
// maptype 1 and 2 both use a quantized value vector, but
|
||||
// different sizes
|
||||
switch(maptype){
|
||||
case 1:
|
||||
// most of the time, entries%dimensions == 0, but we need to be
|
||||
// well defined. We define that the possible vales at each
|
||||
// scalar is values == entries/dim. If entries%dim != 0, we'll
|
||||
// have 'too few' values (values*dim<entries), which means that
|
||||
// we'll have 'left over' entries; left over entries use zeroed
|
||||
// values (and are wasted). So don't generate codebooks like that
|
||||
quantvals=maptype1_quantvals();
|
||||
for(int j=0; j<entries; j++){
|
||||
float last=0.f;
|
||||
int indexdiv=1;
|
||||
for(int k=0; k<dim; k++){
|
||||
int index=(j/indexdiv)%quantvals;
|
||||
float val=quantlist[index];
|
||||
val=Math.abs(val)*delta+mindel+last;
|
||||
if(q_sequencep!=0)
|
||||
last=val;
|
||||
r[j*dim+k]=val;
|
||||
indexdiv*=quantvals;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for(int j=0; j<entries; j++){
|
||||
float last=0.f;
|
||||
for(int k=0; k<dim; k++){
|
||||
float val=quantlist[j*dim+k];
|
||||
//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
|
||||
val=Math.abs(val)*delta+mindel+last;
|
||||
if(q_sequencep!=0)
|
||||
last=val;
|
||||
r[j*dim+k]=val;
|
||||
//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
|
||||
}
|
||||
}
|
||||
//System.err.println("\nr[0]="+r[0]);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
// 32 bit float (not IEEE; nonnormalized mantissa +
|
||||
// biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
|
||||
// Why not IEEE? It's just not that important here.
|
||||
|
||||
static final int VQ_FEXP=10;
|
||||
static final int VQ_FMAN=21;
|
||||
static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1.
|
||||
|
||||
// doesn't currently guard under/overflow
|
||||
static long float32_pack(float val){
|
||||
int sign=0;
|
||||
int exp;
|
||||
int mant;
|
||||
if(val<0){
|
||||
sign=0x80000000;
|
||||
val=-val;
|
||||
}
|
||||
exp=(int)Math.floor(Math.log(val)/Math.log(2));
|
||||
mant=(int)Math.rint(Math.pow(val, (VQ_FMAN-1)-exp));
|
||||
exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
|
||||
return (sign|exp|mant);
|
||||
}
|
||||
|
||||
static float float32_unpack(int val){
|
||||
float mant=val&0x1fffff;
|
||||
float exp=(val&0x7fe00000)>>>VQ_FMAN;
|
||||
if((val&0x80000000)!=0)
|
||||
mant=-mant;
|
||||
return (ldexp(mant, ((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS));
|
||||
}
|
||||
|
||||
static float ldexp(float foo, int e){
|
||||
return (float)(foo*Math.pow(2, e));
|
||||
}
|
||||
}
|
52
client/src/main/java/client/audio/jorbis/Time0.java
Normal file
52
client/src/main/java/client/audio/jorbis/Time0.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package client.audio.jorbis;
|
||||
|
||||
import client.audio.jogg.Buffer;
|
||||
|
||||
class Time0 extends FuncTime{
|
||||
void pack(Object i, Buffer opb){
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
return "";
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
return "";
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object i, float[] in, float[] out){
|
||||
return 0;
|
||||
}
|
||||
}
|
30
client/src/main/java/client/audio/jorbis/Util.java
Normal file
30
client/src/main/java/client/audio/jorbis/Util.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package client.audio.jorbis;
|
||||
|
||||
class Util{
|
||||
static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int icount(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret+=(v&1);
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
}
|
1400
client/src/main/java/client/audio/jorbis/VorbisFile.java
Normal file
1400
client/src/main/java/client/audio/jorbis/VorbisFile.java
Normal file
File diff suppressed because it is too large
Load diff
7
client/src/main/java/client/gui/FileCallback.java
Normal file
7
client/src/main/java/client/gui/FileCallback.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package client.gui;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface FileCallback {
|
||||
void selected(File file);
|
||||
}
|
107
client/src/main/java/client/gui/Font.java
Normal file
107
client/src/main/java/client/gui/Font.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package client.gui;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import client.renderer.GlState;
|
||||
import client.renderer.texture.TextureUtil;
|
||||
import client.util.FileUtils;
|
||||
import common.log.Log;
|
||||
|
||||
public class Font {
|
||||
public static final FontChar[] SIZES = new FontChar[256];
|
||||
public static final int XGLYPH = 12;
|
||||
public static final int YGLYPH = 18;
|
||||
|
||||
private static int texture;
|
||||
|
||||
public static void bindTexture() {
|
||||
GlState.bindTexture(texture);
|
||||
}
|
||||
|
||||
private static int stride(int width, int height, int x, int y, int c) {
|
||||
return ((c & 15) * width + x) + (((c >> 4) & 15) * height + y) * (width << 4); // << 2;
|
||||
}
|
||||
|
||||
private static byte specialChar(int width, int ch) {
|
||||
return (byte)((ch == Log.CHR_UNK) ? width : ((ch == Log.CHR_SPC) ? (width / 6) : 127));
|
||||
}
|
||||
|
||||
private static void calculate(int[] data, FontChar[] glyphs, int width, int height, int page) {
|
||||
int off;
|
||||
for(int z = 0; z < 256; z++) {
|
||||
byte s, t, u, v;
|
||||
if((u = specialChar(width, (page << 8) + z)) != 127) {
|
||||
s = t = 0;
|
||||
v = (byte)(((int)u) * height / width);
|
||||
if(((page << 8) + z) != Log.CHR_UNK) {
|
||||
for(int x = 0; x < width; x++) {
|
||||
for(int y = 0; y < height; y++) {
|
||||
off = stride(width, height, x, y, z);
|
||||
data[off/*+3*/] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
glyphs[z] = new FontChar(s, t, u, v);
|
||||
continue;
|
||||
}
|
||||
s = t = 127;
|
||||
u = v = 0;
|
||||
for(int x = 0; x < width; x++) {
|
||||
for(int y = 0; y < height; y++) {
|
||||
off = stride(width, height, x, y, z);
|
||||
if((data[off/*+3*/] & 0xff000000) != 0) {
|
||||
s = x < s ? (byte)x : s;
|
||||
t = y < t ? (byte)y : t;
|
||||
u = x > u ? (byte)x : u;
|
||||
v = y > v ? (byte)y : v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(s == 127 && t == 127 && u == 0 && v == 0) {
|
||||
s = t = 0;
|
||||
}
|
||||
else {
|
||||
u += 1;
|
||||
v += 1;
|
||||
}
|
||||
glyphs[z] = new FontChar(s, t, u, v);
|
||||
}
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
BufferedImage img = null;
|
||||
try {
|
||||
img = TextureUtil.readImage(FileUtils.getResource("textures/font.png"));
|
||||
}
|
||||
catch(FileNotFoundException e) {
|
||||
Log.IO.error("Konnte Font-Textur nicht laden: Datei nicht vorhanden");
|
||||
}
|
||||
catch(IOException e) {
|
||||
Log.IO.error(e, "Konnte Font-Textur nicht laden");
|
||||
}
|
||||
if(img != null && (img.getWidth() != XGLYPH * 16 || img.getHeight() != YGLYPH * 16)) {
|
||||
Log.IO.error("Konnte Font-Textur nicht laden: Größe ist nicht %dx%d", XGLYPH * 16, YGLYPH * 16);
|
||||
img = null;
|
||||
}
|
||||
if(img == null)
|
||||
throw new IllegalStateException("Konnte erforderliche Schriftart nicht laden");
|
||||
int[] data = new int[XGLYPH * 16 * YGLYPH * 16];
|
||||
img.getRGB(0, 0, XGLYPH * 16, YGLYPH * 16, data, 0, XGLYPH * 16);
|
||||
calculate(data, SIZES, XGLYPH, YGLYPH, 0);
|
||||
texture = GL11.glGenTextures();
|
||||
TextureUtil.uploadImage(texture, img);
|
||||
Log.RENDER.debug("Font-Textur wurde mit ID #%d geladen", texture);
|
||||
}
|
||||
|
||||
public static void unload() {
|
||||
if(texture != 0) {
|
||||
GL11.glDeleteTextures(texture);
|
||||
Log.RENDER.debug("Font-Textur mit ID #%d wurde gelöscht", texture);
|
||||
texture = 0;
|
||||
}
|
||||
}
|
||||
}
|
15
client/src/main/java/client/gui/FontChar.java
Normal file
15
client/src/main/java/client/gui/FontChar.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package client.gui;
|
||||
|
||||
public class FontChar {
|
||||
public final byte s;
|
||||
public final byte t;
|
||||
public final byte u;
|
||||
public final byte v;
|
||||
|
||||
public FontChar(byte s, byte t, byte u, byte v) {
|
||||
this.s = s;
|
||||
this.t = t;
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
}
|
||||
}
|
7
client/src/main/java/client/gui/Formatter.java
Normal file
7
client/src/main/java/client/gui/Formatter.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package client.gui;
|
||||
|
||||
import client.gui.element.Element;
|
||||
|
||||
public interface Formatter<T extends Element> {
|
||||
String use(T elem);
|
||||
}
|
329
client/src/main/java/client/gui/Gui.java
Normal file
329
client/src/main/java/client/gui/Gui.java
Normal file
|
@ -0,0 +1,329 @@
|
|||
package client.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.element.Dropdown;
|
||||
import client.gui.element.Dropdown.Handle;
|
||||
import client.gui.element.Element;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.GlState;
|
||||
import client.window.Bind;
|
||||
import client.window.Button;
|
||||
import client.window.Keysym;
|
||||
import common.collect.Lists;
|
||||
|
||||
public abstract class Gui {
|
||||
public static final String DIRT_BACKGROUND = "textures/background.png";
|
||||
public static final int HOVER_COLOR = 0x288080ff;
|
||||
public static final int PRESS_COLOR = 0x30afafff;
|
||||
|
||||
protected final Client gm = Client.CLIENT;
|
||||
|
||||
public Element selected;
|
||||
private int min_x;
|
||||
private int min_y;
|
||||
private int max_x;
|
||||
private int max_y;
|
||||
public final List<Element> elems = Lists.newArrayList();
|
||||
|
||||
public abstract void init(int width, int height);
|
||||
public abstract String getTitle();
|
||||
|
||||
public void updateScreen() {
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
}
|
||||
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
}
|
||||
|
||||
public void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
}
|
||||
|
||||
public void mouseDragged(int mouseX, int mouseY) {
|
||||
}
|
||||
|
||||
public void drawPost() {
|
||||
}
|
||||
|
||||
// public void drawGuiContainerForegroundLayer() {
|
||||
// }
|
||||
//
|
||||
// public void drawGuiContainerBackgroundLayer() {
|
||||
// }
|
||||
|
||||
public void drawOverlays() {
|
||||
}
|
||||
|
||||
public void useHotbar(int slot) {
|
||||
}
|
||||
|
||||
public void dropItem() {
|
||||
}
|
||||
|
||||
public void drawBackground() {
|
||||
|
||||
}
|
||||
|
||||
public Element clicked(int x, int y) {
|
||||
if(this.selected != null && this.selected.visible && (this.selected instanceof Handle) && this.selected.inside(x, y))
|
||||
return this.selected; // fix (?)
|
||||
for(Element elem : this.elems) {
|
||||
if(elem.visible && elem.enabled && elem.inside(x, y))
|
||||
return elem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reformat() {
|
||||
for(Element elem : this.elems) {
|
||||
elem.reformat();
|
||||
}
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
if(this.selected != null && !(this.selected instanceof Handle)) {
|
||||
this.selected.deselect();
|
||||
this.selected = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void select(Element elem) {
|
||||
if(this.selected != elem && !(this.selected instanceof Handle) && !(elem instanceof Handle)) {
|
||||
if(this.selected != null)
|
||||
this.selected.deselect();
|
||||
if(elem != null)
|
||||
elem.select();
|
||||
this.selected = elem;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
int prev;
|
||||
Element elem = this.clicked(x, y);
|
||||
if(this.selected != null && this.selected != elem && this.selected instanceof Handle) {
|
||||
this.selected.deselect();
|
||||
return;
|
||||
}
|
||||
else if(this.selected != elem) {
|
||||
if(this.selected != null)
|
||||
this.selected.deselect();
|
||||
if(elem != null)
|
||||
elem.select();
|
||||
this.selected = elem;
|
||||
}
|
||||
if(elem != null)
|
||||
elem.mouse(btn, x, y, ctrl, shift);
|
||||
}
|
||||
|
||||
public void mouserel(Button btn, int x, int y) {
|
||||
if(this.selected != null)
|
||||
this.selected.mouserel();
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
if(this.selected != null && (Button.MOUSE_LEFT.isDown() || Button.MOUSE_RIGHT.isDown()))
|
||||
this.selected.drag(x, y);
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
Element elem = this.clicked(x, y);
|
||||
if(elem != null)
|
||||
elem.scroll(scr_x, scr_y, x, y, ctrl, shift);
|
||||
}
|
||||
|
||||
public void key(Keysym key, boolean ctrl, boolean shift) {
|
||||
if(this.selected != null)
|
||||
this.selected.key(key, ctrl, shift);
|
||||
}
|
||||
|
||||
public void character(char code) {
|
||||
if(this.selected != null)
|
||||
this.selected.character(code);
|
||||
}
|
||||
|
||||
protected void shift() {
|
||||
if(this.gm.fb_x != 0 && this.gm.fb_y != 0) {
|
||||
int shift_x = (this.gm.fb_x - (this.max_x - this.min_x)) / 2 - this.min_x;
|
||||
int shift_y = (this.gm.fb_y - (this.max_y - this.min_y)) / 2 - this.min_y;
|
||||
for(Element elem : this.elems) {
|
||||
elem.shift(shift_x, shift_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
this.selected = null;
|
||||
this.min_x = this.min_y = Integer.MAX_VALUE;
|
||||
this.max_x = this.max_y = Integer.MIN_VALUE;
|
||||
this.elems.clear();
|
||||
this.init(this.gm.fb_x, this.gm.fb_y);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(this.selected != null)
|
||||
this.selected.update();
|
||||
}
|
||||
|
||||
protected <T extends Element> T add(T elem) {
|
||||
this.elems.add(elem);
|
||||
elem.setGui(this);
|
||||
this.min_x = Math.min(this.min_x, elem.getX());
|
||||
this.min_y = Math.min(this.min_y, elem.getY());
|
||||
this.max_x = Math.max(this.max_x, elem.getX() + elem.getWidth());
|
||||
this.max_y = Math.max(this.max_y, elem.getY() + elem.getHeight());
|
||||
if(elem instanceof Dropdown)
|
||||
this.add(((Dropdown)elem).getHandle());
|
||||
return elem;
|
||||
}
|
||||
|
||||
protected Element addSelector(String cvar, int x, int y, int w, int h) {
|
||||
return this.add(this.gm.getVar(cvar).selector(x, y, w, h));
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
if(this.selected != null && /* this.selected.r_dirty && */ this.selected instanceof Handle && !this.selected.visible) {
|
||||
this.selected = null;
|
||||
}
|
||||
for(Element elem : this.elems) {
|
||||
if(/* this.selected != e || */ !(elem instanceof Handle)) // || !e.visible)
|
||||
elem.draw();
|
||||
}
|
||||
if(this.selected != null && /* elem.r_dirty && */ this.selected instanceof Handle && this.selected.visible) {
|
||||
this.selected.draw();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawOverlay() {
|
||||
Element elem = this.selected;
|
||||
if(Button.isMouseDown() && elem != null && elem.enabled && elem.visible && elem.canClick()) {
|
||||
elem.drawPress();
|
||||
return;
|
||||
}
|
||||
if(elem != null && elem.enabled && elem.visible)
|
||||
elem.drawOverlay();
|
||||
elem = this.clicked(this.gm.mouse_x, this.gm.mouse_y);
|
||||
if(elem != null && elem.enabled && elem.visible && elem.canHover())
|
||||
elem.drawHover();
|
||||
}
|
||||
|
||||
// public static void drawRect(int left, int top, int right, int bottom, int color)
|
||||
// {
|
||||
// if (left < right)
|
||||
// {
|
||||
// int i = left;
|
||||
// left = right;
|
||||
// right = i;
|
||||
// }
|
||||
//
|
||||
// if (top < bottom)
|
||||
// {
|
||||
// int j = top;
|
||||
// top = bottom;
|
||||
// bottom = j;
|
||||
// }
|
||||
//
|
||||
// float f3 = (float)(color >> 24 & 255) / 255.0F;
|
||||
// float f = (float)(color >> 16 & 255) / 255.0F;
|
||||
// float f1 = (float)(color >> 8 & 255) / 255.0F;
|
||||
// float f2 = (float)(color & 255) / 255.0F;
|
||||
// RenderBuffer worldrenderer = Tessellator.getBuffer();
|
||||
// GlState.enableBlend();
|
||||
// GlState.disableTexture2D();
|
||||
// GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
// GlState.color(f, f1, f2, f3);
|
||||
// worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
|
||||
// worldrenderer.pos((double)left, (double)bottom, 0.0D).endVertex();
|
||||
// worldrenderer.pos((double)right, (double)bottom, 0.0D).endVertex();
|
||||
// worldrenderer.pos((double)right, (double)top, 0.0D).endVertex();
|
||||
// worldrenderer.pos((double)left, (double)top, 0.0D).endVertex();
|
||||
// Tessellator.draw();
|
||||
// GlState.enableTexture2D();
|
||||
// GlState.disableBlend();
|
||||
// }
|
||||
|
||||
// public static void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height)
|
||||
// {
|
||||
// float f = 0.00390625F;
|
||||
// float f1 = 0.00390625F;
|
||||
// RenderBuffer worldrenderer = Tessellator.getBuffer();
|
||||
// worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
// worldrenderer.pos((double)(x + 0), (double)(y + height), 0.0D).tex((double)((float)(textureX + 0) * f), (double)((float)(textureY + height) * f1)).endVertex();
|
||||
// worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D).tex((double)((float)(textureX + width) * f), (double)((float)(textureY + height) * f1)).endVertex();
|
||||
// worldrenderer.pos((double)(x + width), (double)(y + 0), 0.0D).tex((double)((float)(textureX + width) * f), (double)((float)(textureY + 0) * f1)).endVertex();
|
||||
// worldrenderer.pos((double)(x + 0), (double)(y + 0), 0.0D).tex((double)((float)(textureX + 0) * f), (double)((float)(textureY + 0) * f1)).endVertex();
|
||||
// Tessellator.draw();
|
||||
// }
|
||||
//
|
||||
// public static void drawScaledCustomSizeModalRect(int x, int y, float u, float v, int uWidth, int vHeight, int width, int height, float tileWidth, float tileHeight)
|
||||
// {
|
||||
// float f = 1.0F / tileWidth;
|
||||
// float f1 = 1.0F / tileHeight;
|
||||
// RenderBuffer worldrenderer = Tessellator.getBuffer();
|
||||
// worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
// worldrenderer.pos((double)x, (double)(y + height), 0.0D).tex((double)(u * f), (double)((v + (float)vHeight) * f1)).endVertex();
|
||||
// worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D).tex((double)((u + (float)uWidth) * f), (double)((v + (float)vHeight) * f1)).endVertex();
|
||||
// worldrenderer.pos((double)(x + width), (double)y, 0.0D).tex((double)((u + (float)uWidth) * f), (double)(v * f1)).endVertex();
|
||||
// worldrenderer.pos((double)x, (double)y, 0.0D).tex((double)(u * f), (double)(v * f1)).endVertex();
|
||||
// Tessellator.draw();
|
||||
// }
|
||||
//
|
||||
// public static void drawGradientRect(int left, int top, int right, int bottom, int startColor, int endColor)
|
||||
// {
|
||||
// float f = (float)(startColor >> 24 & 255) / 255.0F;
|
||||
// float f1 = (float)(startColor >> 16 & 255) / 255.0F;
|
||||
// float f2 = (float)(startColor >> 8 & 255) / 255.0F;
|
||||
// float f3 = (float)(startColor & 255) / 255.0F;
|
||||
// float f4 = (float)(endColor >> 24 & 255) / 255.0F;
|
||||
// float f5 = (float)(endColor >> 16 & 255) / 255.0F;
|
||||
// float f6 = (float)(endColor >> 8 & 255) / 255.0F;
|
||||
// float f7 = (float)(endColor & 255) / 255.0F;
|
||||
// GlState.disableTexture2D();
|
||||
// GlState.enableBlend();
|
||||
// GlState.disableAlpha();
|
||||
// GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
// GlState.shadeModel(GL11.GL_SMOOTH);
|
||||
// RenderBuffer worldrenderer = Tessellator.getBuffer();
|
||||
// worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||
// worldrenderer.pos((double)right, (double)top, 0.0).color(f1, f2, f3, f).endVertex();
|
||||
// worldrenderer.pos((double)left, (double)top, 0.0).color(f1, f2, f3, f).endVertex();
|
||||
// worldrenderer.pos((double)left, (double)bottom, 0.0).color(f5, f6, f7, f4).endVertex();
|
||||
// worldrenderer.pos((double)right, (double)bottom, 0.0).color(f5, f6, f7, f4).endVertex();
|
||||
// Tessellator.draw();
|
||||
// GlState.shadeModel(GL11.GL_FLAT);
|
||||
// GlState.disableBlend();
|
||||
// GlState.enableAlpha();
|
||||
// GlState.enableTexture2D();
|
||||
// }
|
||||
|
||||
public void drawMainBackground() {
|
||||
if(this.gm.world != null && !this.gm.charEditor) {
|
||||
// Drawing.drawGradient(0, 0, this.fb_x, this.fb_y, this.theWorld == null ? this.style.bg_top : 0x3f202020,
|
||||
// this.theWorld == null ? this.style.bg_btm : 0x3f000000);
|
||||
Drawing.drawGradient(0, 0, this.gm.fb_x, this.gm.fb_y, 0xc0101010, 0xd0101010);
|
||||
}
|
||||
else {
|
||||
Drawing.drawScaled(this.gm, DIRT_BACKGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
this.drawMainBackground();
|
||||
this.drawBackground();
|
||||
if(this.gm.fb_x != 0 && this.gm.fb_y != 0)
|
||||
this.draw();
|
||||
GlState.bindTexture(0);
|
||||
GlState.setActiveTexture(GL13.GL_TEXTURE0);
|
||||
GlState.enableTexture2D();
|
||||
GlState.disableDepth();
|
||||
this.drawPost();
|
||||
GlState.disableDepth();
|
||||
this.drawOverlays();
|
||||
if(Bind.isWindowActive())
|
||||
this.drawOverlay();
|
||||
}
|
||||
}
|
45
client/src/main/java/client/gui/GuiConfirm.java
Executable file
45
client/src/main/java/client/gui/GuiConfirm.java
Executable file
|
@ -0,0 +1,45 @@
|
|||
package client.gui;
|
||||
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Label;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.TransparentArea;
|
||||
|
||||
public class GuiConfirm extends Gui implements ButtonCallback {
|
||||
public static interface Callback {
|
||||
void confirm(boolean confirmed);
|
||||
}
|
||||
|
||||
protected Callback callback;
|
||||
protected String messageLine1;
|
||||
private String messageLine2;
|
||||
protected String confirmButtonText;
|
||||
protected String cancelButtonText;
|
||||
private ActButton confirmBtn;
|
||||
private ActButton cancelBtn;
|
||||
|
||||
public GuiConfirm(Callback callback, String msg1, String msg2, String msgConfirm, String msgCancel) {
|
||||
this.callback = callback;
|
||||
this.messageLine1 = msg1;
|
||||
this.messageLine2 = msg2;
|
||||
this.confirmButtonText = msgConfirm;
|
||||
this.cancelButtonText = msgCancel;
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
this.add(new Label(0, 0, 500, 24, this.messageLine1, true));
|
||||
this.add(new TransparentArea(0, 80, 500, 300, this.messageLine2, this.gm.world != null && !this.gm.charEditor));
|
||||
this.confirmBtn = this.add(new ActButton(48, 500, 200, 24, this, this.confirmButtonText));
|
||||
this.cancelBtn = this.add(new ActButton(252, 500, 200, 24, this, this.cancelButtonText));
|
||||
this.shift();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Aktion bestätigen";
|
||||
}
|
||||
|
||||
public void use(ActButton btn, PressType mode) {
|
||||
this.callback.confirm(btn == this.confirmBtn);
|
||||
}
|
||||
}
|
267
client/src/main/java/client/gui/GuiConnect.java
Normal file
267
client/src/main/java/client/gui/GuiConnect.java
Normal file
|
@ -0,0 +1,267 @@
|
|||
package client.gui;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.GuiList;
|
||||
import client.gui.element.ListEntry;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.renderer.Drawing;
|
||||
import client.util.FileUtils;
|
||||
import common.color.TextColor;
|
||||
import common.log.Log;
|
||||
import common.network.IPlayer;
|
||||
import common.util.Tuple;
|
||||
import common.util.Util;
|
||||
|
||||
public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements ButtonCallback {
|
||||
public class ServerInfo implements Comparable<ServerInfo>, ListEntry {
|
||||
private String name;
|
||||
private String address;
|
||||
private int port;
|
||||
private String user;
|
||||
private String password;
|
||||
private String access;
|
||||
private long lastConnected;
|
||||
|
||||
public ServerInfo(String name, String address, int port, String user, String password, String access, long lastConnected) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.access = access;
|
||||
this.lastConnected = lastConnected;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public String getAccess() {
|
||||
return this.access;
|
||||
}
|
||||
|
||||
public long getLastConnected() {
|
||||
return this.lastConnected;
|
||||
}
|
||||
|
||||
public void setData(String name, String address, int port, String user, String password, String access) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.access = access;
|
||||
}
|
||||
|
||||
public void setLastConnected() {
|
||||
this.lastConnected = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public int compareTo(ServerInfo comp) {
|
||||
return this.lastConnected < comp.lastConnected ? 1 : (this.lastConnected > comp.lastConnected ? -1 : this.name.compareTo(comp.name));
|
||||
}
|
||||
|
||||
public void select(boolean isDoubleClick, int mouseX, int mouseY) {
|
||||
GuiConnect.this.selectButton.enabled = true;
|
||||
GuiConnect.this.deleteButton.enabled = true;
|
||||
GuiConnect.this.editButton.enabled = true;
|
||||
GuiConnect.this.copyButton.enabled = true;
|
||||
|
||||
if(isDoubleClick) {
|
||||
GuiConnect.this.use(GuiConnect.this.selectButton, PressType.PRIMARY);
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int mouseXIn, int mouseYIn, boolean hover) {
|
||||
Drawing.drawText(this.name + TextColor.GRAY + " - " + TextColor.RESET + this.user, x + 2, y, 0xffffffff);
|
||||
Drawing.drawText(this.address + TextColor.GRAY + " Port " + TextColor.RESET + this.port, x + 2, y + 18, 0xff808080);
|
||||
Drawing.drawText("Zuletzt verbunden: " + (this.lastConnected == -1L ? "nie" : DATE_FORMAT.format(new Date(this.lastConnected))), x + 2, y + 18 + 16, 0xff808080);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiConnect INSTANCE = new GuiConnect();
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
|
||||
private static final File SERVERS_FILE = new File("servers.cfg");
|
||||
|
||||
private ActButton deleteButton;
|
||||
private ActButton selectButton;
|
||||
private ActButton copyButton;
|
||||
private ActButton editButton;
|
||||
private ActButton createButton;
|
||||
|
||||
private GuiConnect() {
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
super.init(width, height);
|
||||
this.setDimensions(width, height, 32, height - 32);
|
||||
this.elements.clear();
|
||||
if(SERVERS_FILE.exists()) {
|
||||
try {
|
||||
String[] lines = FileUtils.read(SERVERS_FILE).split("\n");
|
||||
String name = "";
|
||||
String address = "";
|
||||
int port = -1;
|
||||
String user = "";
|
||||
String password = "";
|
||||
String access = "";
|
||||
long time = -1L;
|
||||
for(int z = 0; z <= lines.length; z++) {
|
||||
String line = z == lines.length ? null : lines[z];
|
||||
if(line == null || (line.startsWith("[") && line.endsWith("]"))) {
|
||||
if(!name.isEmpty() && !address.isEmpty() && !user.isEmpty() && user.length() < IPlayer.MAX_USER_LENGTH && IPlayer.isValidUser(user) && password.length() < IPlayer.MAX_PASS_LENGTH && access.length() < IPlayer.MAX_PASS_LENGTH && address.length() < 128 && name.length() < 128 && port >= 1024 && port <= 32767)
|
||||
this.elements.add(new ServerInfo(name, address, port, user, password, access, time));
|
||||
if(line != null) {
|
||||
address = "";
|
||||
port = -1;
|
||||
user = "";
|
||||
password = "";
|
||||
access = "";
|
||||
time = -1L;
|
||||
name = line.substring(1, line.length() - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Tuple<String, String> value = Util.getKeyValue(line);
|
||||
if(value.first.equals("address"))
|
||||
address = value.second;
|
||||
else if(value.first.equals("port"))
|
||||
try {
|
||||
port = Integer.parseInt(value.second);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
else if(value.first.equals("user"))
|
||||
user = value.second;
|
||||
else if(value.first.equals("password"))
|
||||
password = value.second;
|
||||
else if(value.first.equals("access"))
|
||||
access = value.second;
|
||||
else if(value.first.equals("connected"))
|
||||
try {
|
||||
time = Long.parseLong(value.second);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(this.elements);
|
||||
}
|
||||
catch(Exception e) {
|
||||
Log.IO.error("Konnte Serverliste nicht laden", e);
|
||||
this.elements.clear();
|
||||
}
|
||||
}
|
||||
|
||||
this.add(this.selectButton = new ActButton(width / 2 - 383, height - 28, 150, 24, this, "Verbinden"));
|
||||
this.add(this.createButton = new ActButton(width - 204, 4, 200, 24, this, "Server hinzufügen ..."));
|
||||
this.add(this.deleteButton = new ActButton(width / 2 - 75, height - 28, 150, 24, this, "Löschen"));
|
||||
this.add(this.editButton = new ActButton(width / 2 + 79, height - 28, 150, 24, this, "Bearbeiten"));
|
||||
this.add(this.copyButton = new ActButton(width / 2 - 229, height - 28, 150, 24, this, "Kopieren"));
|
||||
this.add(new NavButton(width / 2 + 233, height - 28, 150, 24, GuiMenu.INSTANCE, "Abbrechen"));
|
||||
|
||||
this.selectButton.enabled = false;
|
||||
this.deleteButton.enabled = false;
|
||||
this.editButton.enabled = false;
|
||||
this.copyButton.enabled = false;
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void applyServer(ServerInfo server) {
|
||||
if(this.selectedElement < 0)
|
||||
this.elements.add(server);
|
||||
this.save();
|
||||
this.gm.displayGuiScreen(this);
|
||||
}
|
||||
|
||||
private void save() {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(ServerInfo server : this.elements) {
|
||||
if(sb.length() > 0)
|
||||
sb.append("\n");
|
||||
sb.append("[" + server.getName() + "]\n");
|
||||
sb.append("address " + server.getAddress() + "\n");
|
||||
sb.append("port " + server.getPort() + "\n");
|
||||
sb.append("user " + server.getUser() + "\n");
|
||||
sb.append("password " + server.getPassword() + "\n");
|
||||
sb.append("access " + server.getAccess() + "\n");
|
||||
sb.append("connected " + server.getLastConnected());
|
||||
}
|
||||
FileUtils.write(SERVERS_FILE, sb.toString());
|
||||
}
|
||||
catch(Exception e) {
|
||||
Log.IO.error("Konnte Serverliste nicht speichern", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Server auswählen";
|
||||
}
|
||||
|
||||
public int getListWidth() {
|
||||
return 660;
|
||||
}
|
||||
|
||||
public int getSlotHeight() {
|
||||
return 56;
|
||||
}
|
||||
|
||||
public void use(ActButton button, PressType mode) {
|
||||
if(button == this.deleteButton) {
|
||||
if(this.selectedElement >= 0) {
|
||||
this.elements.remove(this.selectedElement);
|
||||
this.gm.displayGuiScreen(this);
|
||||
}
|
||||
}
|
||||
else if(button == this.selectButton) {
|
||||
ServerInfo server = this.getSelected();
|
||||
if(server != null) {
|
||||
server.setLastConnected();
|
||||
this.gm.connect(server.address, server.port, server.user, server.password, server.access);
|
||||
}
|
||||
}
|
||||
else if(button == this.createButton) {
|
||||
this.setSelected(-1);
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo("", "", -1, "", "", "", -1L)));
|
||||
}
|
||||
else if(button == this.editButton) {
|
||||
ServerInfo server = this.getSelected();
|
||||
if(server != null)
|
||||
this.gm.displayGuiScreen(new GuiServer(server));
|
||||
}
|
||||
else if(button == this.copyButton) {
|
||||
ServerInfo server = this.getSelected();
|
||||
if(server != null) {
|
||||
this.setSelected(-1);
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo(server.name, server.address, server.port, server.user, server.password, server.access, -1L)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
397
client/src/main/java/client/gui/GuiConsole.java
Normal file
397
client/src/main/java/client/gui/GuiConsole.java
Normal file
|
@ -0,0 +1,397 @@
|
|||
package client.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Fill;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.FieldAction;
|
||||
import client.gui.element.Field;
|
||||
import client.gui.element.FieldCallback;
|
||||
import client.network.ClientPlayer;
|
||||
import client.vars.BoolVar;
|
||||
import client.vars.CVar;
|
||||
import client.gui.element.TransparentArea;
|
||||
import client.window.Keysym;
|
||||
import common.collect.Lists;
|
||||
import common.color.TextColor;
|
||||
import common.network.IPlayer;
|
||||
import common.packet.CPacketComplete;
|
||||
import common.util.BlockPos;
|
||||
import common.util.ExtMath;
|
||||
import common.util.HitPosition;
|
||||
|
||||
public class GuiConsole extends Gui implements FieldCallback {
|
||||
public static final GuiConsole INSTANCE = new GuiConsole();
|
||||
|
||||
private final List<String> sentMessages = Lists.<String>newArrayList();
|
||||
|
||||
private boolean full;
|
||||
|
||||
private String historyBuffer = "";
|
||||
private int sentHistoryCursor = -1;
|
||||
private boolean playerNamesFound;
|
||||
private boolean waitingOnAutocomplete;
|
||||
private boolean reverse;
|
||||
private String prefixFirst;
|
||||
private int autocompleteIndex;
|
||||
private List<String> foundPlayerNames = Lists.<String>newArrayList();
|
||||
private Field inputField;
|
||||
private TransparentArea logBox;
|
||||
|
||||
public GuiConsole setFull(boolean full) {
|
||||
this.full = full;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
if(this.full) {
|
||||
this.addSelector("con_autoclose", 0, 0, 160, 24);
|
||||
this.addSelector("con_timestamps", 160, 0, 160, 24);
|
||||
this.addSelector("con_loglevel", 320, 0, 160, 24);
|
||||
this.add(new ActButton(480, 0, 160, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiConsole.this.reset();
|
||||
GuiConsole.this.setLog(GuiConsole.this.gm.getBuffer());
|
||||
}
|
||||
}, "Löschen"));
|
||||
}
|
||||
this.logBox = this.add(new TransparentArea(0, this.full ? 24 : 0, width, height - (this.full ? 48 : 24), this.gm.getBuffer(), this.gm.world != null && !this.gm.charEditor));
|
||||
if(this.full)
|
||||
this.add(new Fill(640, 0, width - 640, 24));
|
||||
this.inputField = this.add(new Field(0, height - 24, width, 24, IPlayer.MAX_CMD_LENGTH, this, ""));
|
||||
this.inputField.setSelected();
|
||||
this.sentHistoryCursor = this.sentMessages.size();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Konsole / Chat";
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.gm.reset();
|
||||
this.sentMessages.clear();
|
||||
this.sentHistoryCursor = -1;
|
||||
}
|
||||
|
||||
public void setLog(String buffer) {
|
||||
if(this.logBox != null)
|
||||
this.logBox.setText(buffer);
|
||||
}
|
||||
|
||||
public void drawMainBackground() {
|
||||
if(this.gm.world == null || this.gm.charEditor)
|
||||
super.drawMainBackground();
|
||||
}
|
||||
|
||||
public void key(Keysym key, boolean ctrl, boolean shift) {
|
||||
super.key(key, ctrl, shift);
|
||||
// this.waitingOnAutocomplete = false;
|
||||
if(key != Keysym.TAB && key != Keysym.LEFT_SHIFT && key != Keysym.RIGHT_SHIFT)
|
||||
this.playerNamesFound = false;
|
||||
}
|
||||
|
||||
public void use(Field elem, FieldAction value)
|
||||
{
|
||||
this.waitingOnAutocomplete = false;
|
||||
|
||||
if (value == FieldAction.FORWARD || value == FieldAction.BACKWARD)
|
||||
{
|
||||
this.reverse = value == FieldAction.BACKWARD;
|
||||
this.autocompletePlayerNames();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playerNamesFound = false;
|
||||
}
|
||||
|
||||
if(value == FieldAction.PREVIOUS)
|
||||
this.getSentHistory(-1);
|
||||
else if (value == FieldAction.NEXT)
|
||||
this.getSentHistory(1);
|
||||
if(value == FieldAction.SEND)
|
||||
{
|
||||
String s = this.inputField.getText().trim();
|
||||
|
||||
if (s.length() > 0)
|
||||
{
|
||||
if(this.sentMessages.isEmpty() || !((String)this.sentMessages.get(this.sentMessages.size() - 1)).equals(s))
|
||||
this.sentMessages.add(s);
|
||||
this.sentHistoryCursor = this.sentMessages.size();
|
||||
this.gm.exec(s);
|
||||
// if(this.gm.thePlayer != null)
|
||||
// this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketMessage(CPacketMessage.Type.CHAT, s));
|
||||
}
|
||||
|
||||
this.inputField.setText("");
|
||||
if((this.gm.conAutoclose || !this.full) && this.gm.world != null)
|
||||
this.gm.displayGuiScreen(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setText(String newChatText, boolean shouldOverwrite)
|
||||
{
|
||||
if (shouldOverwrite)
|
||||
{
|
||||
this.inputField.setText(newChatText);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.inputField.insertText(newChatText);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMessage(String msg) {
|
||||
String buffer = this.gm.getBuffer();
|
||||
if((buffer.length() + msg.length() + 2) > Client.LOG_BUFFER) {
|
||||
int offset = (msg.length() + 2) > 1024 ? (msg.length() + 2) : 1024;
|
||||
int nl = buffer.indexOf('\n', offset);
|
||||
buffer = nl >= 0 ? buffer.substring(nl + 1) : "";
|
||||
}
|
||||
this.setLog(buffer + "\n" + TextColor.RESET + msg);
|
||||
}
|
||||
|
||||
public void autocompletePlayerNames()
|
||||
{
|
||||
if (this.playerNamesFound)
|
||||
{
|
||||
this.inputField.deleteSpaceToCur();
|
||||
|
||||
if (this.autocompleteIndex >= this.foundPlayerNames.size())
|
||||
{
|
||||
this.autocompleteIndex = 0;
|
||||
}
|
||||
else if (this.autocompleteIndex < 0)
|
||||
{
|
||||
this.autocompleteIndex = this.foundPlayerNames.size() - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = this.inputField.getSpaceBeforeCur();
|
||||
this.foundPlayerNames.clear();
|
||||
this.autocompleteIndex = 0;
|
||||
// String s = this.inputField.getText().substring(i).toLowerCase();
|
||||
String s1 = this.inputField.getText().substring(0, this.inputField.getCursorPos());
|
||||
String[] localMatches = this.sendAutocompleteRequest(s1);
|
||||
if(localMatches != null) {
|
||||
this.onAutocompleteResponse(localMatches);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.foundPlayerNames.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.playerNamesFound = true;
|
||||
this.inputField.deleteSpaceToCur();
|
||||
}
|
||||
|
||||
if (this.foundPlayerNames.size() > 1)
|
||||
{
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
|
||||
for (String s2 : this.foundPlayerNames)
|
||||
{
|
||||
if (stringbuilder.length() > 0)
|
||||
{
|
||||
stringbuilder.append(", ");
|
||||
}
|
||||
|
||||
stringbuilder.append(s2);
|
||||
}
|
||||
|
||||
this.addMessage(stringbuilder.toString());
|
||||
}
|
||||
|
||||
this.inputField.insertText((String)this.foundPlayerNames.get(this.autocompleteIndex));
|
||||
this.autocompleteIndex += this.reverse ? -1 : 1;
|
||||
}
|
||||
|
||||
private String[] complete(String s) {
|
||||
List<String> list = Lists.<String>newArrayList();
|
||||
String[] argv = s.split(" ", -1);
|
||||
String pre = argv[0];
|
||||
s = argv[argv.length - 1];
|
||||
Iterable<String> res = pre.startsWith("#") ?
|
||||
(argv.length == 1 ? this.gm.getVars() : (argv.length == 2 ? getVarCompletion(argv[0].substring(1)) : Lists.newArrayList())) :
|
||||
(this.gm.player == null ? Lists.newArrayList() : ((ClientPlayer)this.gm.player.client).getPlayerNames());
|
||||
if(argv.length == 1 && pre.startsWith("#"))
|
||||
s = s.substring(1);
|
||||
for(String s1 : res) {
|
||||
if(s1.regionMatches(true, 0, s, 0, s.length()))
|
||||
list.add((argv.length == 1 && pre.startsWith("#") ? "#" : "") + s1);
|
||||
}
|
||||
return list.isEmpty() ? null : list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
private List<String> getVarCompletion(String var) {
|
||||
CVar cv = this.gm.getVar(var);
|
||||
if(cv == null)
|
||||
return Lists.newArrayList();
|
||||
if(cv instanceof BoolVar)
|
||||
return Boolean.parseBoolean(cv.format()) ? Lists.newArrayList("false", "true") : Lists.newArrayList("true", "false");
|
||||
else
|
||||
return Lists.newArrayList(cv.getDefault());
|
||||
// return Lists.newArrayList();
|
||||
}
|
||||
|
||||
private String[] sendAutocompleteRequest(String currentText)
|
||||
{
|
||||
if (currentText.length() >= 1)
|
||||
{
|
||||
BlockPos blockpos = null;
|
||||
int eid = -1;
|
||||
if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.BLOCK)
|
||||
{
|
||||
blockpos = this.gm.pointed.block;
|
||||
}
|
||||
else if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.ENTITY)
|
||||
{
|
||||
eid = this.gm.pointed.entity.getId();
|
||||
blockpos = new BlockPos(this.gm.pointed.entity);
|
||||
}
|
||||
if(currentText.startsWith("/")) {
|
||||
if(this.gm.player != null) {
|
||||
currentText = currentText.substring(1);
|
||||
this.prefixFirst = currentText.split(" ", -1).length == 1 ? "/" : null;
|
||||
this.gm.player.client.addToSendQueue(new CPacketComplete(currentText, eid, blockpos));
|
||||
this.waitingOnAutocomplete = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String[] comp = this.complete(currentText);
|
||||
this.prefixFirst = null;
|
||||
if(comp != null)
|
||||
this.waitingOnAutocomplete = true;
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void getSentHistory(int msgPos)
|
||||
{
|
||||
int i = this.sentHistoryCursor + msgPos;
|
||||
int j = this.sentMessages.size();
|
||||
i = ExtMath.clampi(i, 0, j);
|
||||
|
||||
if (i != this.sentHistoryCursor)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
this.sentHistoryCursor = j;
|
||||
this.inputField.setText(this.historyBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.sentHistoryCursor == j)
|
||||
{
|
||||
this.historyBuffer = this.inputField.getText();
|
||||
}
|
||||
|
||||
this.inputField.setText(this.sentMessages.get(i));
|
||||
this.sentHistoryCursor = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onAutocompleteResponse(String[] choices)
|
||||
{
|
||||
if (this.waitingOnAutocomplete)
|
||||
{
|
||||
this.playerNamesFound = false;
|
||||
this.foundPlayerNames.clear();
|
||||
|
||||
for (int z = 0; z < choices.length; z++)
|
||||
{
|
||||
String s = choices[z];
|
||||
if(this.prefixFirst != null)
|
||||
choices[z] = s = this.prefixFirst + s;
|
||||
if (s.length() > 0)
|
||||
{
|
||||
this.foundPlayerNames.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
String s1 = this.inputField.getText().substring(this.inputField.getSpaceBeforeCur());
|
||||
String s2 = getCommonPrefix(choices);
|
||||
|
||||
if (s2.length() > 0 && !s1.equalsIgnoreCase(s2))
|
||||
{
|
||||
this.inputField.deleteSpaceToCur();
|
||||
this.inputField.insertText(s2);
|
||||
}
|
||||
else if (this.foundPlayerNames.size() > 0)
|
||||
{
|
||||
this.playerNamesFound = true;
|
||||
this.autocompletePlayerNames();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCommonPrefix(String[] strs) {
|
||||
if (strs != null && strs.length != 0) {
|
||||
int smallestIndexOfDiff = indexOfDifference(strs);
|
||||
if (smallestIndexOfDiff == -1) {
|
||||
return strs[0] == null ? "" : strs[0];
|
||||
} else {
|
||||
return smallestIndexOfDiff == 0 ? "" : strs[0].substring(0, smallestIndexOfDiff);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static int indexOfDifference(CharSequence[] css) {
|
||||
if (css != null && css.length > 1) {
|
||||
boolean anyStringNull = false;
|
||||
boolean allStringsNull = true;
|
||||
int arrayLen = css.length;
|
||||
int shortestStrLen = Integer.MAX_VALUE;
|
||||
int longestStrLen = 0;
|
||||
|
||||
int firstDiff;
|
||||
for (firstDiff = 0; firstDiff < arrayLen; ++firstDiff) {
|
||||
if (css[firstDiff] == null) {
|
||||
anyStringNull = true;
|
||||
shortestStrLen = 0;
|
||||
} else {
|
||||
allStringsNull = false;
|
||||
shortestStrLen = Math.min(css[firstDiff].length(), shortestStrLen);
|
||||
longestStrLen = Math.max(css[firstDiff].length(), longestStrLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
|
||||
return -1;
|
||||
} else if (shortestStrLen == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
firstDiff = -1;
|
||||
|
||||
for (int stringPos = 0; stringPos < shortestStrLen; ++stringPos) {
|
||||
char comparisonChar = css[0].charAt(stringPos);
|
||||
|
||||
for (int arrayPos = 1; arrayPos < arrayLen; ++arrayPos) {
|
||||
if (css[arrayPos].charAt(stringPos) != comparisonChar) {
|
||||
firstDiff = stringPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return firstDiff == -1 && shortestStrLen != longestStrLen ? shortestStrLen : firstDiff;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
137
client/src/main/java/client/gui/GuiInfo.java
Normal file
137
client/src/main/java/client/gui/GuiInfo.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
package client.gui;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.TransparentArea;
|
||||
import common.Version;
|
||||
import common.color.TextColor;
|
||||
import common.log.Log;
|
||||
import common.util.Util;
|
||||
|
||||
public class GuiInfo extends Gui {
|
||||
private static final String VER =
|
||||
TextColor.GREEN + "" + Util.repeatString(TextColor.BUG, Version.RELEASE.getId()) + TextColor.DVIOLET + "|-| " + TextColor.VIOLET + Client.VERSION + TextColor.DVIOLET + " |-|" +
|
||||
TextColor.GREEN + Util.repeatString(TextColor.BUG, Version.RELEASE.getId());
|
||||
|
||||
private static final String INFO = "Ein Spiel zur Simulation, zum Testen, für Rollenspiele, Mehrspieler und vieles mehr." + "\n" +
|
||||
"Optimiert für Geschwindigkeit, Stabilität und" + TextColor.UNKNOWN + "" + TextColor.UNKNOWN + " [Speicherzugriffsfehler]";
|
||||
private static final String HACKED = "Ein weiterer Release von WAAAAAAAAAAAAAAAAAAAAAAAAAAAAGHDRIVE!!!1!!!ONEoneOnetyone!1!!!" + "\n" +
|
||||
"Update 0.2 - Läuft jetzt auch mit nur 512KB Fast-RAM!";
|
||||
|
||||
private static final String[] LIBRARIES = {
|
||||
"LWJGL 3.3.6+1 (GLFW + OpenGL)",
|
||||
"Netty 4.0.23-Final (modifiziert, verkleinert)"
|
||||
};
|
||||
private static final String[] CODE = {
|
||||
"Albert Pham - WorldEdit (Snippets)",
|
||||
"Joonas Vali - NameGenerator",
|
||||
"LWJGL 2.9.4-nightly-20150209 - Project, Vector*, Matrix*",
|
||||
"Guava 17.0 - collect, future, Predicates",
|
||||
"JOrbis 20101023 (JCraft) - jogg, jorbis, CodecJOrbis",
|
||||
"MC 1.8.9"
|
||||
};
|
||||
|
||||
public static final GuiInfo INSTANCE = new GuiInfo("Über dieses Programm", getFormat(false));
|
||||
public static final GuiInfo HAX = new GuiInfo("Üb3r d1es3n Cr4ck", getFormat(true));
|
||||
|
||||
private final String header;
|
||||
private final String info;
|
||||
|
||||
private static String getFormat(boolean hax) {
|
||||
return getInfo(hax) + "\n\n" + getCredits(hax) + "\n\n" + getLibraries(hax) + "\n\n" + getCode(hax) + "\n\n" + getOldCredits(hax) + "\n\n" + getColors();
|
||||
}
|
||||
|
||||
private static String getHeader(boolean hax, String normal, String hacked) {
|
||||
return (hax ? TextColor.RED : TextColor.YELLOW) + (hax ? hacked : normal) + "\n" +
|
||||
(hax ? TextColor.CYAN : TextColor.WHITE) + "==========================================+==========================================";
|
||||
}
|
||||
|
||||
private static void addLines(StringBuilder sb, boolean hax, String alternate, String category, String... authors) {
|
||||
sb.append("\n" + (hax ? TextColor.BLUE : TextColor.GRAY)
|
||||
+ (hax ? alternate : category) + "\n ");
|
||||
for(int z = 0; z < authors.length; z++) {
|
||||
if(z > 0)
|
||||
sb.append((hax ? TextColor.VIOLET : TextColor.GRAY) + ", ");
|
||||
sb.append((hax ? TextColor.DVIOLET : TextColor.WHITE) + authors[z]);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getInfo(boolean hax) {
|
||||
return getHeader(hax, VER, VER) + "\n" + (hax ? (TextColor.VIOLET + HACKED) : (TextColor.LGRAY + INFO));
|
||||
}
|
||||
|
||||
private static String getLibraries(boolean hax) {
|
||||
StringBuilder sb = new StringBuilder(getHeader(hax, "Verwendete Programmbibliotheken", "U$3d 3xpl0its"));
|
||||
for(String lib : LIBRARIES) {
|
||||
sb.append("\n" + TextColor.LGRAY + "-> " + TextColor.NEON + lib);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getCode(boolean hax) {
|
||||
StringBuilder sb = new StringBuilder(getHeader(hax, "Zusätzlicher Quellcode", "M0ar 3xpl01ts"));
|
||||
for(String lib : CODE) {
|
||||
sb.append("\n" + TextColor.LGRAY + "-> " + TextColor.NEON + lib);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getColors() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int num = 0;
|
||||
for(TextColor color : TextColor.values()) {
|
||||
if(num > 0)
|
||||
sb.append(' ');
|
||||
if((color.code >= Log.CHR_COLORS1 && color.code <= Log.CHR_COLORE1) || (color.code >= Log.CHR_COLORS2 && color.code <= Log.CHR_COLORE2)) {
|
||||
sb.append(color + "#" + (char)(num < 10 ? ('0' + num) : ('A' + (num - 10))));
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getOldCredits(boolean hax) {
|
||||
StringBuilder sb = new StringBuilder(getHeader(hax, "Ursprüngliche Mitwirkende", "Das Team -- Nicht TCQ"));
|
||||
|
||||
addLines(sb, hax, "Absolut größter Lamer des Universums", "Spielidee und ursprüngliche Umsetzung",
|
||||
"Markus Persson");
|
||||
addLines(sb, hax, "Crack und weitere Programmierung", "Spiel-Design, Programmierung und Grafiken",
|
||||
"Jens Bergensten", "Nathan Adams", "Ryan Holtz", "Michael Stoyke");
|
||||
addLines(sb, hax, "Entschlüsselung von Ressourcen", "Programmierung",
|
||||
"Erik Broes", "Paul Spooner", "Ryan Hitchman", "Elliot Segal");
|
||||
addLines(sb, hax, "Cracktro, Grafiken und Intromusik", "Töne und Geräusche",
|
||||
"Daniel Rosenfeld", "freesound.org");
|
||||
addLines(sb, hax, "Packing und Verbreitung", "Management, Administration und Spaß",
|
||||
"Carl Manneh", "Daniel Kaplan", "Lydia Winters");
|
||||
addLines(sb, hax, "Server und Hosting", "Zahlen und Statistiken",
|
||||
"Patrick Geuder");
|
||||
addLines(sb, hax, "Weiterer Dank und Grüße", "Entwickler von Mo' Creatures (Pferde usw.)",
|
||||
"John Olarte", "Kent Christian Jensen", "Dan Roque");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getCredits(boolean hax) {
|
||||
StringBuilder sb = new StringBuilder(getHeader(hax, "Mitwirkende dieses Programms", "Das Team -- TCQ"));
|
||||
|
||||
addLines(sb, hax, "Die dunklen Herrscher", "Quellcode, Design, Grafiken, Refactoring und Code-Cleanup",
|
||||
TextColor.CYAN + "Sen der \"kleine\" Dämon " + TextColor.CRIMSON + TextColor.DEMON + TextColor.BLACK + TextColor.BLKHEART,
|
||||
TextColor.RED + "Shen, Herrscher des Schattenlandes " + TextColor.CRIMSON + TextColor.IMP);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public GuiInfo(String header, String info) {
|
||||
this.header = header;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
this.add(new TransparentArea(10, 10, width - 20, height - 44, this.info, this.gm.world != null && !this.gm.charEditor));
|
||||
this.add(new NavButton(0, height - 24, width, 24, GuiMenu.INSTANCE, "Zurück"));
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.header;
|
||||
}
|
||||
}
|
118
client/src/main/java/client/gui/GuiLoading.java
Normal file
118
client/src/main/java/client/gui/GuiLoading.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
package client.gui;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.element.Bar;
|
||||
import client.gui.element.Label;
|
||||
|
||||
public class GuiLoading extends Gui {
|
||||
public static interface Callback {
|
||||
void poll(Client gm, GuiLoading gui);
|
||||
}
|
||||
|
||||
private final String message;
|
||||
private final Callback callback;
|
||||
|
||||
private Label headerLabel;
|
||||
private Label taskLabel;
|
||||
private Bar progressBar1;
|
||||
private Bar progressBar2;
|
||||
|
||||
public static GuiLoading makeServerTask(String message) {
|
||||
return new GuiLoading(message, new Callback() {
|
||||
public void poll(Client gm, GuiLoading gui) {
|
||||
int progress = gm.progress;
|
||||
if(progress < 0) {
|
||||
gui.resetBar();
|
||||
}
|
||||
else {
|
||||
gui.setBar(null, "Chunks", Math.max(1, gm.total));
|
||||
gui.setProgress(progress);
|
||||
}
|
||||
gui.setTask(gm.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static GuiLoading makeWaitTask(String message) {
|
||||
return new GuiLoading(message, new Callback() {
|
||||
public void poll(Client gm, GuiLoading gui) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public GuiLoading(String message, Callback callback) {
|
||||
this.message = message;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
this.taskLabel = this.add(new Label(0, 40, 500, 20, ""));
|
||||
this.progressBar1 = this.add(new Bar(0, 80, 500, 24));
|
||||
this.progressBar2 = this.add(new Bar(0, 120, 500, 24));
|
||||
this.shift();
|
||||
this.headerLabel = this.add(new Label(0, 40, width, 20, this.message));
|
||||
this.progressBar1.visible = false;
|
||||
this.progressBar2.visible = false;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public void setTask(String task) {
|
||||
this.taskLabel.setText(task == null ? "" : task);
|
||||
}
|
||||
|
||||
public void setBar(String desc) {
|
||||
this.progressBar1.visible = true;
|
||||
this.progressBar1.setDescription(desc);
|
||||
}
|
||||
|
||||
public void setBar(String desc, String unit, int total) {
|
||||
this.progressBar1.visible = true;
|
||||
this.progressBar1.setDescription(desc, unit, total);
|
||||
}
|
||||
|
||||
public void setBar(String desc, int total) {
|
||||
this.progressBar1.visible = true;
|
||||
this.progressBar1.setDescription(desc, total);
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
this.progressBar1.setProgress(progress);
|
||||
}
|
||||
|
||||
public void resetBar() {
|
||||
this.progressBar1.resetProgress();
|
||||
this.progressBar1.visible = false;
|
||||
}
|
||||
|
||||
public void setSub(String desc) {
|
||||
this.progressBar2.visible = true;
|
||||
this.progressBar2.setDescription(desc);
|
||||
}
|
||||
|
||||
public void setSub(String desc, String unit, int total) {
|
||||
this.progressBar2.visible = true;
|
||||
this.progressBar2.setDescription(desc, unit, total);
|
||||
}
|
||||
|
||||
public void setSub(String desc, int total) {
|
||||
this.progressBar2.visible = true;
|
||||
this.progressBar2.setDescription(desc, total);
|
||||
}
|
||||
|
||||
public void setSubProgress(float progress) {
|
||||
this.progressBar2.setProgress(progress);
|
||||
}
|
||||
|
||||
public void resetSub() {
|
||||
this.progressBar2.resetProgress();
|
||||
this.progressBar2.visible = false;
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(this.callback != null)
|
||||
this.callback.poll(this.gm, this);
|
||||
}
|
||||
}
|
300
client/src/main/java/client/gui/GuiMenu.java
Normal file
300
client/src/main/java/client/gui/GuiMenu.java
Normal file
|
@ -0,0 +1,300 @@
|
|||
package client.gui;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.character.GuiChar;
|
||||
import client.gui.character.GuiCharacters;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Label;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.options.GuiOptions;
|
||||
import client.renderer.Drawing;
|
||||
import client.window.Keysym;
|
||||
import common.color.TextColor;
|
||||
import common.rng.Random;
|
||||
import common.util.ExtMath;
|
||||
|
||||
public class GuiMenu extends Gui {
|
||||
public static final GuiMenu INSTANCE = new GuiMenu();
|
||||
|
||||
private GuiMenu() {
|
||||
}
|
||||
|
||||
public void drawMainBackground() {
|
||||
if(this.gm.world != null)
|
||||
super.drawMainBackground();
|
||||
else
|
||||
this.gm.renderGlobal.renderStarField(this.gm.fb_x, this.gm.fb_y, 0x000000, 0xffffff, (float)this.ticks + this.gm.getTickFraction(), this.rand);
|
||||
}
|
||||
|
||||
private final Random rand = new Random();
|
||||
|
||||
private Label splashLabel;
|
||||
private ActButton infoButton;
|
||||
|
||||
private int ticks;
|
||||
private int hacked;
|
||||
|
||||
private int animWidth = 32;
|
||||
private int animGrowth = 10;
|
||||
private int[] animGrow = new int[this.animWidth];
|
||||
private String animStr = "";
|
||||
private String animBack = "";
|
||||
private int animPos;
|
||||
private int animLen;
|
||||
private int animDir;
|
||||
private boolean animStep;
|
||||
|
||||
public void init(int width, int height) {
|
||||
if(this.gm.world == null) {
|
||||
this.ticks = 0;
|
||||
this.hacked = 0;
|
||||
this.resetAnimation();
|
||||
this.add(new ActButton(0, -28, 400, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiMenu.this.hacked == 9) {
|
||||
GuiMenu.this.hacked++;
|
||||
GuiMenu.this.splashLabel.setText(TextColor.VIOLET + "Hax!");
|
||||
}
|
||||
else {
|
||||
GuiMenu.this.gm.displayGuiScreen(GuiConnect.INSTANCE);
|
||||
}
|
||||
}
|
||||
}, "Server beitreten"));
|
||||
this.add(new NavButton(0, 0, 400, 24, GuiServer.INSTANCE, "Schnellverbindung"));
|
||||
this.add(new ActButton(0, 28, 400, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiMenu.this.hacked == 8)
|
||||
GuiMenu.this.hacked++;
|
||||
else
|
||||
GuiMenu.this.gm.displayGuiScreen(GuiOptions.getPage());
|
||||
}
|
||||
}, "Einstellungen"));
|
||||
this.infoButton = this.add(new ActButton(0, 56, 400, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiMenu.this.gm.displayGuiScreen(GuiMenu.this.hacked == 10 ? GuiInfo.HAX : GuiInfo.INSTANCE);
|
||||
}
|
||||
}, "Info / Über / Mitwirkende") {
|
||||
public void drawHover() {
|
||||
if(GuiMenu.this.hacked == 10) {
|
||||
Drawing.drawRect(this.pos_x, this.pos_y, this.size_x, this.size_y, 0x287f00ff);
|
||||
GuiMenu.this.rand.setSeed(((long)this.gm.mouse_x * 7652657L) ^ ((long)this.gm.mouse_y * 87262826276L));
|
||||
int width = Drawing.getWidth("Hax!");
|
||||
for(int z = 0; z < 64; z++) {
|
||||
Drawing.drawText("Hax!", GuiMenu.this.rand.zrange(Math.max(1, this.gm.fb_x - width)) +
|
||||
(int)(ExtMath.sin(((float)(GuiMenu.this.ticks + GuiMenu.this.rand.zrange(256)) + this.gm.getTickFraction()) / 100.0f * (float)Math.PI * 2.0f) * 16.0f),
|
||||
GuiMenu.this.rand.zrange(Math.max(1, this.gm.fb_y - Font.YGLYPH)) +
|
||||
(int)(ExtMath.sin(((float)(GuiMenu.this.ticks + GuiMenu.this.rand.zrange(256)) + this.gm.getTickFraction()) / 100.0f * (float)Math.PI * 2.0f) * 16.0f),
|
||||
0xff0000ff | (GuiMenu.this.rand.zrange(256) << 16));
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.drawHover();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.add(new ActButton(0, 102, 400, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiMenu.this.gm.interrupted = true;
|
||||
}
|
||||
}, "Client schließen"));
|
||||
this.shift();
|
||||
this.add(new Label(4, /* this.gm.fb_y - 2 */ 0, 200, 20, TextColor.VIOLET + Client.VERSION, true));
|
||||
this.splashLabel = this.add(new Label(0, 160, width, 24, ""));
|
||||
this.pickSplash();
|
||||
}
|
||||
else {
|
||||
this.add(new NavButton(0, 0, 400, 24, this.gm.charEditor ? GuiChar.INSTANCE : null, this.gm.charEditor ? "Zurück zum Charakter-Editor" : "Zurück zum Spiel"));
|
||||
this.add(new NavButton(0, 28, this.gm.charEditor ? 400 : 198, 24, GuiOptions.getPage(), "Einstellungen"));
|
||||
if(!this.gm.charEditor)
|
||||
this.add(new NavButton(202, 28, 198, 24, GuiCharacters.INSTANCE, "Charakter"));
|
||||
this.add(new ActButton(0, 102, 400, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiMenu.this.gm.unload(true);
|
||||
// GuiMenu.this.gm.displayGuiScreen(INSTANCE);
|
||||
}
|
||||
}, "Server verlassen und Verbindung trennen"));
|
||||
this.shift();
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.gm.world == null ? "Hauptmenü" : "Menü";
|
||||
}
|
||||
|
||||
private void pickSplash() {
|
||||
this.splashLabel.setText(TextColor.VIOLET + this.rand.pick(Splashes.SPLASHES));
|
||||
}
|
||||
|
||||
private void resetAnimation() {
|
||||
this.animStr = "";
|
||||
this.animBack = "";
|
||||
this.animPos = 0;
|
||||
this.animLen = 0;
|
||||
this.animDir = 0;
|
||||
this.animStep = false;
|
||||
this.animWidth = Math.max(5, (this.gm.fb_x - 5) / 10);
|
||||
this.animGrowth = this.animWidth / 15;
|
||||
this.animGrow = new int[this.animWidth];
|
||||
}
|
||||
|
||||
private void updateAnimation() {
|
||||
if(this.animLen == 0) {
|
||||
this.animDir = this.rand.zrange(3) - 1;
|
||||
this.animLen = this.animDir == 0 ? (2 + this.rand.zrange(2)) : (8 + this.rand.zrange(96));
|
||||
}
|
||||
else {
|
||||
this.animPos += this.animDir;
|
||||
if(this.animPos == -1) {
|
||||
this.animPos = 0;
|
||||
this.animDir = 1;
|
||||
}
|
||||
else if(this.animPos == this.animWidth - 3) {
|
||||
this.animPos = this.animWidth - 4;
|
||||
this.animDir = -1;
|
||||
}
|
||||
this.animLen--;
|
||||
}
|
||||
this.animStep = !this.animStep;
|
||||
StringBuilder sb = new StringBuilder(11);
|
||||
sb.append(TextColor.GRAY);
|
||||
sb.append("[");
|
||||
sb.append(TextColor.YELLOW);
|
||||
switch(this.animDir) {
|
||||
case -1:
|
||||
sb.append((this.animStep ? '>' : '-') + "' ");
|
||||
break;
|
||||
case 0:
|
||||
sb.append("`" + (this.animStep ? 'O' : 'o') + "'");
|
||||
break;
|
||||
case 1:
|
||||
sb.append(" `" + (this.animStep ? '<' : '-'));
|
||||
break;
|
||||
}
|
||||
sb.append(TextColor.GRAY);
|
||||
sb.append("]");
|
||||
this.animStr = sb.toString();
|
||||
for(int z = this.animPos; z < this.animPos + 4; z++) {
|
||||
this.animGrow[z] = 0;
|
||||
}
|
||||
for(int z = 0; z < this.animGrowth; z++) {
|
||||
this.animGrow[this.rand.zrange(this.animWidth)] += 1;
|
||||
}
|
||||
sb = new StringBuilder(this.animWidth + 2);
|
||||
sb.append(TextColor.DGREEN);
|
||||
for(int z = 0; z < this.animWidth; z++) {
|
||||
switch(this.animGrow[z] / 5) {
|
||||
case 0:
|
||||
sb.append(TextColor.BLACK);
|
||||
break;
|
||||
case 1:
|
||||
sb.append(TextColor.GRAY);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
sb.append(TextColor.LGRAY);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
sb.append(TextColor.WHITE);
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
sb.append(TextColor.MAGENTA);
|
||||
break;
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
sb.append(TextColor.DVIOLET);
|
||||
break;
|
||||
default:
|
||||
sb.append(TextColor.VIOLET);
|
||||
break;
|
||||
}
|
||||
sb.append(",.");
|
||||
}
|
||||
this.animBack = sb.toString();
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(this.gm.world == null) {
|
||||
this.ticks++;
|
||||
if(this.gm.shift())
|
||||
this.pickSplash();
|
||||
this.updateAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public void key(Keysym key, boolean ctrl, boolean shift) {
|
||||
super.key(key, ctrl, shift);
|
||||
if(this.gm.world == null) {
|
||||
if((key == Keysym.UP || key == Keysym.W) && (this.hacked == 0 || this.hacked == 1))
|
||||
this.hacked++;
|
||||
else if((key == Keysym.DOWN || key == Keysym.S) && (this.hacked == 2 || this.hacked == 3))
|
||||
this.hacked++;
|
||||
else if((key == Keysym.LEFT || key == Keysym.A) && (this.hacked == 4 || this.hacked == 6))
|
||||
this.hacked++;
|
||||
else if((key == Keysym.RIGHT || key == Keysym.D) && (this.hacked == 5 || this.hacked == 7))
|
||||
this.hacked++;
|
||||
else
|
||||
this.hacked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
protected void actionPerformed(Button button) throws IOException {
|
||||
if(button.id == 2 && this.hacked == 8) {
|
||||
this.hacked++;
|
||||
return;
|
||||
}
|
||||
else if(button.id == 1 && this.hacked == 9) {
|
||||
this.hacked++;
|
||||
return;
|
||||
}
|
||||
if(button.id != 3 || this.hacked != 10)
|
||||
this.hacked = 0;
|
||||
switch(button.id) {
|
||||
case 0:
|
||||
this.gm.displayGuiScreen(new GuiOptions(this));
|
||||
break;
|
||||
case 1:
|
||||
this.gm.displayGuiScreen(new GuiWorlds(this));
|
||||
break;
|
||||
case 2:
|
||||
this.gm.displayGuiScreen(new GuiMultiplayer(this));
|
||||
break;
|
||||
case 3:
|
||||
if(this.hacked == 10)
|
||||
Log.info("Hax!");
|
||||
this.gm.displayGuiScreen(new GuiCredits(this.hacked == 10));
|
||||
this.hacked = 0;
|
||||
break;
|
||||
// case 4:
|
||||
// this.gm.displayGuiScreen(new GuiLanguage());
|
||||
// break;
|
||||
case 4:
|
||||
this.gm.shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public void drawOverlays() {
|
||||
super.drawOverlays();
|
||||
if(this.gm.world == null) {
|
||||
int y = 164;
|
||||
int h = 16;
|
||||
int n = Drawing.getWidth(this.splashLabel.getText());
|
||||
Drawing.drawRect(0, y, this.gm.fb_x / 2 - n / 2 - 10, h, 0x7f7f00ff);
|
||||
Drawing.drawRect(this.gm.fb_x / 2 + n / 2 + 10, y, this.gm.fb_x - (this.gm.fb_x / 2 + n / 2 + 10), h, 0x7f7f00ff);
|
||||
Drawing.drawText(this.animBack, this.gm.fb_x - Drawing.getWidth(this.animBack), this.gm.fb_y - 18, 0xffffffff);
|
||||
Drawing.drawText(this.animStr, this.gm.fb_x - Drawing.getWidth(this.animStr) - 3 - ((this.animWidth - this.animPos - 4) * 10), this.gm.fb_y - 20, 0xffffffff);
|
||||
}
|
||||
}
|
||||
}
|
155
client/src/main/java/client/gui/GuiServer.java
Normal file
155
client/src/main/java/client/gui/GuiServer.java
Normal file
|
@ -0,0 +1,155 @@
|
|||
package client.gui;
|
||||
|
||||
import client.gui.GuiConnect.ServerInfo;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Label;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.FieldAction;
|
||||
import client.gui.element.Field;
|
||||
import client.gui.element.FieldCallback;
|
||||
import client.vars.CVarCategory;
|
||||
import client.vars.Variable;
|
||||
import common.color.TextColor;
|
||||
import common.network.IPlayer;
|
||||
|
||||
public class GuiServer extends Gui implements FieldCallback {
|
||||
public static final GuiServer INSTANCE = new GuiServer(null);
|
||||
|
||||
private final ServerInfo server;
|
||||
|
||||
private Field nameBox;
|
||||
private Field addrBox;
|
||||
private Field portBox;
|
||||
private Field userBox;
|
||||
private Field passBox;
|
||||
private Field accBox;
|
||||
private Label nameLabel;
|
||||
private Label addrLabel;
|
||||
private Label portLabel;
|
||||
private Label rangeLabel;
|
||||
private Label userLabel;
|
||||
private Label passLabel;
|
||||
private Label accLabel;
|
||||
|
||||
public GuiServer(ServerInfo server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Variable(name = "srv_last_address", category = CVarCategory.SYSTEM, min = 1, max = 128, display = "Letzte Server-Adresse")
|
||||
private String lastAddr = "";
|
||||
@Variable(name = "srv_last_port", category = CVarCategory.SYSTEM, min = 1024, max = 32767, display = "Letzter Server-Port")
|
||||
private int lastPort = -1;
|
||||
@Variable(name = "srv_last_user", category = CVarCategory.SYSTEM, max = IPlayer.MAX_USER_LENGTH, display = "Letzter Server-Nutzer", validator = IPlayer.UserValidator.class)
|
||||
private String lastUser = "";
|
||||
@Variable(name = "srv_last_password", category = CVarCategory.SYSTEM, max = IPlayer.MAX_PASS_LENGTH, display = "Letztes Server-Passwort")
|
||||
private String lastPass = "";
|
||||
@Variable(name = "srv_last_access", category = CVarCategory.SYSTEM, max = IPlayer.MAX_PASS_LENGTH, display = "Letzter Server-Zugang")
|
||||
private String lastAcc = "";
|
||||
|
||||
public void init(int width, int height) {
|
||||
if(this.server != null)
|
||||
this.nameBox = this.add(new Field(0, -50, 400, 24, 128, this, this.server.getName()));
|
||||
this.addrBox = this.add(new Field(0, 20, 400, 24, 128, this, this.server == null ? this.lastAddr : this.server.getAddress()));
|
||||
int port = this.server == null ? this.lastPort : this.server.getPort();
|
||||
this.portBox = this.add(new Field(404, 20, 76, 24, 5, this, port < 0 ? "" : "" + port));
|
||||
this.userBox = this.add(new Field(0, 70, 220, 24, IPlayer.MAX_USER_LENGTH, this, IPlayer.VALID_USER, this.server == null ? this.lastUser : this.server.getUser()));
|
||||
this.passBox = this.add(new Field(0, 120, 480, 24, IPlayer.MAX_PASS_LENGTH, this, this.server == null ? this.lastPass : this.server.getPassword()));
|
||||
this.accBox = this.add(new Field(0, 170, 480, 24, IPlayer.MAX_PASS_LENGTH, this, this.server == null ? this.lastAcc : this.server.getAccess()));
|
||||
this.add(new ActButton(0, 220, 480, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiServer.this.connect();
|
||||
}
|
||||
}, this.server == null ? "Verbinden" : (this.server.getName().isEmpty() ? "Hinzufügen" : "Übernehmen")));
|
||||
this.add(new NavButton(0, 250, 480, 24, this.server != null ? GuiConnect.INSTANCE : GuiMenu.INSTANCE, "Zurück"));
|
||||
if(this.server != null)
|
||||
this.nameLabel = this.add(new Label(0, -70, 410, 20, "Name", true));
|
||||
this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse", true));
|
||||
this.portLabel = this.add(new Label(404, 0, 76, 20, "Port", true));
|
||||
this.rangeLabel = this.add(new Label(370, 44, 110, 20, "[1024..32767]", true));
|
||||
this.userLabel = this.add(new Label(0, 50, 220, 20, "Nutzer", true));
|
||||
this.passLabel = this.add(new Label(0, 100, 480, 20, "Passwort", true));
|
||||
this.accLabel = this.add(new Label(0, 150, 480, 20, "Zugang", true));
|
||||
this.shift();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.server == null ? "Mit Server verbinden" : (this.server.getName().isEmpty() ? "Server hinzufügen" : "Server bearbeiten");
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
if(this.gm.world != null)
|
||||
return;
|
||||
String name = null;
|
||||
if(this.server != null) {
|
||||
name = this.nameBox.getText();
|
||||
if(name.isEmpty()) {
|
||||
this.nameLabel.setText(TextColor.RED + "Name");
|
||||
return;
|
||||
}
|
||||
}
|
||||
String addr = this.addrBox.getText();
|
||||
if(addr.isEmpty()) {
|
||||
this.addrLabel.setText(TextColor.RED + "Adresse");
|
||||
return;
|
||||
}
|
||||
int port = -1;
|
||||
if(this.portBox.getText().isEmpty()) {
|
||||
this.portLabel.setText(TextColor.RED + "Port");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
port = Integer.parseInt(this.portBox.getText());
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
this.rangeLabel.setText("[" + TextColor.RED + "1024..32767" + TextColor.RESET + "]");
|
||||
return;
|
||||
}
|
||||
if(port < 1024 || port > 32767) {
|
||||
this.rangeLabel.setText("[" + (port < 1024 ? TextColor.RED + "1024" + TextColor.RESET + "..32767" : "1024.." + TextColor.RED + "32767" + TextColor.RESET) + "]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
String user = this.userBox.getText();
|
||||
if(user.isEmpty()) {
|
||||
this.userLabel.setText(TextColor.RED + "Nutzer");
|
||||
return;
|
||||
}
|
||||
String pass = this.passBox.getText();
|
||||
String acc = this.accBox.getText();
|
||||
if(this.server == null) {
|
||||
this.lastAddr = addr;
|
||||
this.lastPort = port;
|
||||
this.lastUser = user;
|
||||
this.lastPass = pass;
|
||||
this.lastAcc = acc;
|
||||
this.gm.setDirty();
|
||||
this.gm.connect(addr, port, user, pass, acc);
|
||||
}
|
||||
else {
|
||||
this.server.setData(name, addr, port, user, pass, acc);
|
||||
GuiConnect.INSTANCE.applyServer(this.server);
|
||||
}
|
||||
}
|
||||
|
||||
public void use(Field elem, FieldAction value) {
|
||||
if(value == FieldAction.SEND) {
|
||||
elem.setDeselected();
|
||||
this.connect();
|
||||
}
|
||||
else if(value == FieldAction.FOCUS) {
|
||||
if(elem == this.addrBox)
|
||||
this.addrLabel.setText("Adresse");
|
||||
else if(elem == this.portBox) {
|
||||
this.portLabel.setText("Port");
|
||||
this.rangeLabel.setText("[1024..32767]");
|
||||
}
|
||||
else if(elem == this.userBox)
|
||||
this.userLabel.setText("Nutzer");
|
||||
else if(this.server != null && elem == this.nameBox)
|
||||
this.nameLabel.setText("Name");
|
||||
}
|
||||
}
|
||||
}
|
415
client/src/main/java/client/gui/Splashes.java
Normal file
415
client/src/main/java/client/gui/Splashes.java
Normal file
|
@ -0,0 +1,415 @@
|
|||
package client.gui;
|
||||
|
||||
public abstract class Splashes {
|
||||
public static final String[] SPLASHES = {
|
||||
"Aus der TV-Werbung!",
|
||||
"Toll!",
|
||||
"0% pur!",
|
||||
"Kann Nüsse enthalten!",
|
||||
"Besser als Crysis!",
|
||||
"Mehr Polygone!",
|
||||
"Sexy!",
|
||||
"Limitierte Edition!",
|
||||
"Blinkende Buchstaben!",
|
||||
"Erstellt von Satan!",
|
||||
"Es ist hier!",
|
||||
"Das Beste seiner Klasse!",
|
||||
"Es ist vollendet!",
|
||||
"Mehr oder weniger frei von Drachen!",
|
||||
"Aufregung!",
|
||||
"Weniger als -5 verkauft!",
|
||||
"Einzigartig!",
|
||||
"Einen Haufen Scheiße auf YouTube!",
|
||||
"Indev!",
|
||||
"Spinnen überall!",
|
||||
"Schau es dir an!",
|
||||
"Heilige Kuh, mann!",
|
||||
"Es ist ein Spiel!",
|
||||
"Hergestellt in Schweden!",
|
||||
"Benutzt LWJGL!",
|
||||
"Retikulierende Splinen!",
|
||||
"Meine Kraft!",
|
||||
"Hurraaa!",
|
||||
"Einzelspieler!",
|
||||
"Tastatur ist kompatibel!",
|
||||
"Undokumentiert!",
|
||||
"Barren!",
|
||||
"Explodierende Sonnen!",
|
||||
"Das ist ein Mond!",
|
||||
"l33t!",
|
||||
"Erschaffe!",
|
||||
"Überlebe!",
|
||||
"Verlies!",
|
||||
"Exklusiv!",
|
||||
"Die Knie der Biene!",
|
||||
"Weg mit O.P.P.!",
|
||||
"Mit Quellcode (mehr oder weniger)!",
|
||||
"Mit Klasse(n)!",
|
||||
"Wow!",
|
||||
"Immer noch nicht auf Steam - und das ist auch gut so!",
|
||||
"Oh, mann!",
|
||||
"Grauenvolle Community!",
|
||||
"Pixel!",
|
||||
"Teetsuuuuoooo!",
|
||||
"Kaaneeeedaaaa!",
|
||||
"Jetzt ohne Schwierigkeit!",
|
||||
"Verbessert!",
|
||||
"9% frei von Bugs!",
|
||||
"Schön!",
|
||||
"13 Kräuter und Gewürze!",
|
||||
"Fettfrei!",
|
||||
"Absolut keine Memes!",
|
||||
"Kostenlose Zähne!",
|
||||
"Fragen Sie Ihnen Arzt oder Apotheker!",
|
||||
"Alle Bergleute sind willkommen!",
|
||||
"Cloud-Computing!",
|
||||
"Legal in Finnland!",
|
||||
"Schwer zu beschreiben!",
|
||||
"Technisch gesehen gut!",
|
||||
"Bringe den Speck nach Hause!",
|
||||
"Indie!",
|
||||
"GOTY!",
|
||||
"Ceci n'est pas une title screen!",
|
||||
"Euklidisch!",
|
||||
"Jetzt in 3D!",
|
||||
"Bietet Inspiration!",
|
||||
"Herregud!",
|
||||
"Komplexe Zellvorgänge!",
|
||||
"Ja, Sir!",
|
||||
"Von Cowboys gespielt!",
|
||||
"OpenGL 1.5 oder höher!",
|
||||
"Tausende von Farben!",
|
||||
"Probiere es!",
|
||||
"Age of Wonders ist besser!",
|
||||
"Probiere die Pilzsuppe!",
|
||||
"Sensationell!",
|
||||
"Heiße Tamale, heiße heiße Tamale!",
|
||||
"Spiele ihn runter, Klavierkatze!",
|
||||
"Garantiert!",
|
||||
"Makroskopisch!",
|
||||
"Dann komm doch her!",
|
||||
"Zufälliger Text!",
|
||||
"Ruf deine Mutter an!",
|
||||
"Monster-Streitigkeiten!",
|
||||
"Von Melonen geliebt!",
|
||||
"Ultimative Edition!",
|
||||
"Merkwürdig!",
|
||||
"Du hast einen nagelneuen Schlüssel bekommen!",
|
||||
"Wasserfest!",
|
||||
"Nicht brennbar!",
|
||||
"Oha, du!",
|
||||
"Alles inklusive!",
|
||||
"Sag es deinen Freunden!",
|
||||
"NP ist nicht in P!",
|
||||
"Musik von C418 (DLC)!",
|
||||
"Viel zu oft live gestreamt!",
|
||||
"Heimgesucht!",
|
||||
"Polynomial!",
|
||||
"Terrestrisch!",
|
||||
"Alles ist voller Zerstörung!",
|
||||
"Voll mit Sternen, Planeten und Monden!",
|
||||
"Wissenschaftlich!",
|
||||
"Nicht so cool wie Spock!",
|
||||
"Trage nix bei und höre weg!",
|
||||
"Grabe niemals nach unten, wenn du keine Erze brauchst!",
|
||||
"Mache nie Pause!",
|
||||
"Nicht linear!",
|
||||
"Han hat zuerst geschossen!",
|
||||
"Schön dich zu sehen!",
|
||||
"Eimer mit Lava!",
|
||||
"Reite auf dem Schwein!",
|
||||
"Größer als die Erde!",
|
||||
"sqrt(-1)ch liebe dich!",
|
||||
"Phobos-Anomalie!",
|
||||
"Holz schlagen!",
|
||||
"Von Klippen fallen!",
|
||||
"0% Zucker!",
|
||||
"150% hyperbol!",
|
||||
"Synecdoche!",
|
||||
"Lasst uns tanzne!",
|
||||
"Geheeimes Freitags-Update!",
|
||||
"Referenz-Implementation!",
|
||||
"Frei mit zwei.. äähhh fünf Typen mit Essen!",
|
||||
"Küsse den Himmel!",
|
||||
"20 GOTO 10!",
|
||||
"Verlet-Intregration!",
|
||||
"Peter Griffin!",
|
||||
"Verteile die Erde gut!",
|
||||
"Cogito ergo sum!",
|
||||
"4815162342 Zeilen Quellcode (287228 am 30.7.)!",
|
||||
"Ein Skelett fiel heraus!",
|
||||
"Das Werk von Luzifer!",
|
||||
"Die Summe seiner Teile!",
|
||||
"BTAF war mal gut!",
|
||||
"Ich vermisse ADOM!",
|
||||
"umop-apisdn!",
|
||||
"GTX750Ti!",
|
||||
"Bringe mir Mentos und Cola!",
|
||||
"Finger-leckend!",
|
||||
"Thematisch!",
|
||||
"Pneumatisch!",
|
||||
"Erhaben!",
|
||||
"Achteckig!",
|
||||
"Une baguette!",
|
||||
"Gargamel spielt es!",
|
||||
"Rita ist der neue beste Hund!",
|
||||
"SWM für immer!",
|
||||
"Repräsentiert Edsbyn!",
|
||||
"Matt Damon!",
|
||||
"Supercalifragilisticexpialidocious!",
|
||||
"Vollende V's!",
|
||||
"Kuh-Werkzeuge!",
|
||||
"Doppelt gepuffert!",
|
||||
"Fan-Fiction!",
|
||||
"Flaxkikare!",
|
||||
"Jason! Jason! Jason!",
|
||||
"Heißer als die Sonne!",
|
||||
"Internet-Funktionalität!",
|
||||
"Autonom!",
|
||||
"Engagiere!",
|
||||
"Fantasie!",
|
||||
"DRR! DRR! DRR!",
|
||||
"Stoß es Wurzel runter!",
|
||||
"Regionale Ressourcen!",
|
||||
"Jaa, facepunch!",
|
||||
"Jaa, somethingawful!",
|
||||
"Jaa, /v/!",
|
||||
"Jaa, tigsource!",
|
||||
"Jaa, weinkraftforum!",
|
||||
"Jaa, worldofweinkraft!",
|
||||
"Buu, reddit!",
|
||||
"Jaa, 2pp!",
|
||||
"Goggle anllyticsed:DD :DDD:D!",
|
||||
"Unterstützt jetzt äöü!",
|
||||
"Gebt uns Gordon!",
|
||||
"Gib deinem Kellner Trinkgeld!",
|
||||
"Macht viel Spaß!",
|
||||
"12345 ist ein schlechtes Passwort!",
|
||||
"Stimme für Netz-Neutralität!",
|
||||
"Lebt in einer Ananas unter dem Meer!",
|
||||
"MAP11 hat zwei Namen!",
|
||||
"Allmächtig!",
|
||||
"Huch!",
|
||||
"...!",
|
||||
"Bienen, Bienen, Bienen, Bienen!",
|
||||
"Jag känner en bot!",
|
||||
"Dieser Text ist schwer bei der Standard-Auflösung zu lesen, aber auf 1080p ist es in Ordnung!",
|
||||
"Haha, LOL!",
|
||||
"Hampsterdance!",
|
||||
"Schalter und Erze!",
|
||||
"Menger-Schwamm!",
|
||||
"idspispopd!",
|
||||
"Eple (originale Version)!",
|
||||
"So frisch, so sauber!",
|
||||
"Schnell reagierende Portale!",
|
||||
"Probiere den Warp aus!",
|
||||
"Schaue nicht direkt auf die Bugs!",
|
||||
"Oh, ok, NPCs!",
|
||||
"Endlich mit Leitern!",
|
||||
"Gruselig!",
|
||||
"Spiele Minenkraft, schaue Topgear, bekomme Schwein!",
|
||||
"Darüber gewittert!",
|
||||
"Spring hoch, spring hoch, und komme runter!",
|
||||
"Joel ist klasse!",
|
||||
"Ein Rätsel, in einen Mythos verwoben!",
|
||||
"Riesige Landeszüge voll mit TNT!",
|
||||
"Willkommen zu deinem Ende! Muahahahahahaha!",
|
||||
"Bleib ein Bisschen, bleib für immer!",
|
||||
"Bleib ein Bisschen und höre zu!",
|
||||
"Behandlung für Ihren Hautausschlag!",
|
||||
"\"Autologisch\" ist!",
|
||||
"Informationen wollen frei sein!",
|
||||
"\"Fast nie\" ist ein interessantes Konzept!",
|
||||
"Eine Menge Wahrheitigkeit!",
|
||||
"Der TNT-Block ist ein Spion!",
|
||||
"Turing-vollständig!",
|
||||
"Es ist bahnbrechend!",
|
||||
"Lasst unsere Schlachten beginnen!",
|
||||
"Der Himmel ist die Grenze - oder auch nicht!",
|
||||
"Dein PC hat tolle Haare, mach das Ding mal sauber!",
|
||||
"Ryan hat auch tolle Haare!",
|
||||
"Gelegentliches Spielen!",
|
||||
"Unbesiegt!",
|
||||
"Ein Bisschen wie Lemmings!",
|
||||
"Folge dem Zug, CJ!",
|
||||
"Macht von Synergie Verwendung!",
|
||||
"Diese Nachricht sollte niemals als Splash-Text erscheinen, ist das nicht komisch? Trololololol!",
|
||||
"DungeonQuest ist unfair!",
|
||||
"0815!",
|
||||
"666!",
|
||||
"Geh zu den fernen Ländern und weiter!",
|
||||
"Tyrion würde es lieben!",
|
||||
"Probiere auch Stellaris!",
|
||||
"Probiere auch Garry's Mod!",
|
||||
"Probiere auch GZDoom!",
|
||||
"Probiere auch OpenTTD!",
|
||||
"Probiere auch Kaffee!",
|
||||
"Probiere auch Vodka!",
|
||||
"Probiere auch Tee!",
|
||||
"Probiere auch Wasser!",
|
||||
"Probiere auch Saft!",
|
||||
"Das ist super!",
|
||||
"Brot ist Schmerz!",
|
||||
"Lese mehr Bücher!",
|
||||
"Khaaaaaaaaan!",
|
||||
"Weniger süchtig machend als TV Tropes!",
|
||||
"Mehr süchtig machend als Limonade!",
|
||||
"Größer als eine Brotkiste!",
|
||||
"Millionen von Pfirsichen!",
|
||||
"Fnord!",
|
||||
"Dies ist meine echte Gestalt! Muahahahaha!",
|
||||
"Habe Dre vollkommen vergessen!",
|
||||
"Verschwende keine Zeit mit den Klonen!",
|
||||
"Kürbiskopf!",
|
||||
"Hobo humping slobo babe!",
|
||||
"Erstellt von einer Katze!",
|
||||
"Hat kein Ende!",
|
||||
"Endlich vollständig!",
|
||||
"Voll mit Features!",
|
||||
"Stiefel mit dem Fell!",
|
||||
"Stop, hammertime!",
|
||||
"Testificates!",
|
||||
"Nicht konventionell!",
|
||||
"Homeomorphisch zu einer 3-Kugel!",
|
||||
"Vermeidet nicht doppelte Verneinung!",
|
||||
"Platziere ALL die Blöcke!",
|
||||
"Macht Walzen!",
|
||||
"Erfüllt Erwartungen!",
|
||||
"Spielen am PC seit 1873!",
|
||||
"Ghoughpteighbteau tchoghs!",
|
||||
"Deja vu!",
|
||||
"Deja vu!",
|
||||
"Hab deine Nase!",
|
||||
"Haley liebt Elan!",
|
||||
"Hat keine Angst vor der großen, schwarzen Fledermaus!",
|
||||
"Benutzt nicht das U-Wort!",
|
||||
"Nicht wirklich leicht!",
|
||||
"Bis nächsten Freitag oder so!",
|
||||
"Von den Straßen von Södermalm!",
|
||||
"150 BPM für 400000 Minuten!",
|
||||
"Technologisch!",
|
||||
"Funk Soul Bruder!",
|
||||
"Pumpa kungen!",
|
||||
"Hallo Japan!",
|
||||
"Hallo Korea!",
|
||||
"Hallo Wales!",
|
||||
"Hallo Polen!",
|
||||
"Hallo China!",
|
||||
"Hallo Russland!",
|
||||
"Hallo Griechenland!",
|
||||
"Mein Leben für Aiur!",
|
||||
"Lenny lenny = new Lenny(\"(°^°)\");",
|
||||
"Ich sehe dein Wortschatz hat sich verbessert!",
|
||||
"Wer hat es dort hin getan?",
|
||||
"Das kannst du nicht erklären! - Oder etwa doch??",
|
||||
"if not ok then return end",
|
||||
"Mehrfarbig!",
|
||||
"FUNKY LOL",
|
||||
"SOPA bedeutet LOSER in Schwedisch!",
|
||||
"Große Spitze Zähne!",
|
||||
"Mein Shizun bewacht das Tor!",
|
||||
"Mmmph, mmph!",
|
||||
"Füttere keine Avocados an Papageien!",
|
||||
"Schwerter für alle!",
|
||||
"Bitteee antworte meinem Tweet! (Nutzer wurde gebannt)",
|
||||
".party()!",
|
||||
"Nehme ihr Kissen!",
|
||||
"Lege diesen Keks weg!",
|
||||
"Extrem gruselig!",
|
||||
"Ich habe einen Vorschlag.",
|
||||
"Jetzt mit extra Sprengstoff!",
|
||||
"Nicht kompatibel zu Java 6!",
|
||||
"Oha.",
|
||||
"HURNERJSGER?",
|
||||
"Was'n los, Doc?",
|
||||
"Enthält jetzt 0 zufällige tägliche Katzen!",
|
||||
"Das ist Numberwang!",
|
||||
"((pls rt)) -- Der Vogel ist tot!",
|
||||
"Willst du meinem Server beitreten?",
|
||||
"Mach einen großen Zaun drum herum! Oder du wirst v-",
|
||||
"Lege eine Landmine drüber!",
|
||||
"Eines Tages, irgendwann in der Zukunft, wird mein Werk zitiert werden!",
|
||||
"Jetzt mit zusätzlichem Zeug!",
|
||||
"Zusätzliche Dinge!",
|
||||
"Hurra, Atombomben für alle!",
|
||||
"So süß, wie ein schöner Bon-Bon!",
|
||||
"Poppende Tags!",
|
||||
"Sehr einflussreich in seinem Kreis!",
|
||||
"Jetzt mit Mehrspieler!",
|
||||
"Stehe aus deinem Grab auf!",
|
||||
"Warnung! Ein großes Kampfschiff \"SHEN\" nähert sich schnell!",
|
||||
"Der blaue Krieger hat das Essen beschossen!",
|
||||
"Renn, Feigling! Ich hunger!",
|
||||
"Geschmack ohne Würze!",
|
||||
"Seltsam, aber nicht fremd!",
|
||||
"Härter als Diamanten, Reich wie Creme!",
|
||||
"Mach dich bereit zum Ruinieren!",
|
||||
"Mach dich bereit zum Experimentieren!",
|
||||
"Mach dich bereit zum Kollabieren!",
|
||||
"Mach dich bereit zum Explodieren!",
|
||||
"Mach dich bereit zum Implodieren!",
|
||||
"Mach dich bereit zum Implizieren!",
|
||||
"Es schwingt, es veräppelt!",
|
||||
"Fahre Straßen entlang für Gold!",
|
||||
"Nimm einen Schneebesen und haue ihn gegen eine Bratpfanne!",
|
||||
"Bau mir einen Tisch, einen funkigen Tisch!",
|
||||
"Nehm den Aufzug in die Hölle!",
|
||||
"Hör auf vernünftig zu sein, das hier ist das Internet!",
|
||||
"/give @a tnt 67108864 7",
|
||||
"Das ist gut für 3D Realms.",
|
||||
"Jeder Computer ist ein Laptop, wenn du tapfer genug bist!",
|
||||
"Mach es alles, jede Sache!",
|
||||
"Wo ist kein Licht, da kann Spinne!",
|
||||
"GNU Terry Pratchett",
|
||||
"Jetzt Java 8!",
|
||||
"MeinKraft!",
|
||||
"Immer noch zu viele Bugs!",
|
||||
"Wird nicht laggen!",
|
||||
"Er hat es ruiniert!",
|
||||
"Maus nicht kompatibel!",
|
||||
"OpenGL 2.0+ (definitiv nicht unterstützt)!",
|
||||
"Keine Segfaults (nicht) möglich!",
|
||||
"Keine Abstürze (un)möglich!",
|
||||
"Alpha!",
|
||||
"Enthält Bugs!",
|
||||
"Enthält Mäuse!",
|
||||
"Enthält Gewalt!",
|
||||
"Grabe immer nach unten >:)>!",
|
||||
"Weg mit O.O.P.!",
|
||||
"Du hattest eine. aufgabe.",
|
||||
"Spinnen können TNT1 A 0 sein!",
|
||||
"RTFM!",
|
||||
"Vorherrschaft des Imperiums!",
|
||||
"Vorherrschaft der Eldar!",
|
||||
"Vorherrschaft der Drukhari!",
|
||||
"Vorherrschaft der Necrons!",
|
||||
"Vorherrschaft der Orks!",
|
||||
"Jeder Laptop ist ein Tablet, wenn du tapfer genug bist!",
|
||||
"Jedes Handy ist ein Klapphandy, wenn du tapfer genug bist!",
|
||||
"Quadcores altern wie feiner Wein (außer mit JS)!",
|
||||
"Speicherzugriffsfehler (Speicherzug im Riff stehen geblieben)!",
|
||||
"Eingedeutscht (naja fast)!",
|
||||
"Ketzerei!",
|
||||
"WAAAGH!",
|
||||
"WAAAAGH!",
|
||||
"WAAAAAGH!",
|
||||
"WAAAAAAGH!",
|
||||
"WAAAAAAAGH!",
|
||||
"WAAAAAAAAGH!",
|
||||
"WAAAAAAAAAGH!",
|
||||
"WAAAAAAAAAAGH!",
|
||||
"X ist nix!",
|
||||
"Quadratisch, praktisch, gut!",
|
||||
"Rund, unpraktisch, schlecht!",
|
||||
"Verschreibungspflichtig!",
|
||||
"Grüne, radioaktive Blöcke!",
|
||||
"Blaue, nicht radioaktive Blöcke!",
|
||||
"Exterminatus!",
|
||||
"Nein! Doch! Ohh!",
|
||||
"Eimer mit Wasser!",
|
||||
"Hergestellt in Deutschland!",
|
||||
"Hergestellt in China!",
|
||||
"Jetzt ohne Einzelspieler!",
|
||||
"Jetzt mit tieferen Schluchten!"
|
||||
};
|
||||
}
|
103
client/src/main/java/client/gui/Style.java
Normal file
103
client/src/main/java/client/gui/Style.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
package client.gui;
|
||||
|
||||
import client.vars.CVarCategory;
|
||||
import client.vars.Variable;
|
||||
import client.vars.Variable.IntType;
|
||||
import common.util.Displayable;
|
||||
import common.util.Identifyable;
|
||||
|
||||
public enum Style implements Identifyable, Displayable {
|
||||
DEFAULT("default", "Standard"), SHINY("shiny", "Glänzend"), GRAY("gray", "Grau"), BLUE("blue", "Blau"), CUSTOM("custom", "Angepasst");
|
||||
|
||||
public final String id;
|
||||
public final String name;
|
||||
|
||||
private Style(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Variable(type = IntType.COLOR, name = "color_border_top", category = CVarCategory.GUI, display = "Umrahmung oben / l.")
|
||||
public int brdr_top;
|
||||
@Variable(type = IntType.COLOR, name = "color_border_btm", category = CVarCategory.GUI, display = "Umrahmung unten / r.")
|
||||
public int brdr_btm;
|
||||
|
||||
@Variable(type = IntType.COLOR, name = "color_button_top", category = CVarCategory.GUI, display = "Knopf oben")
|
||||
public int fill_top;
|
||||
@Variable(type = IntType.COLOR, name = "color_button_btm", category = CVarCategory.GUI, display = "Knopf unten")
|
||||
public int fill_btm;
|
||||
@Variable(type = IntType.COLOR, name = "color_textbox_top", category = CVarCategory.GUI, display = "Textfeld oben")
|
||||
public int field_top;
|
||||
@Variable(type = IntType.COLOR, name = "color_textbox_btm", category = CVarCategory.GUI, display = "Textfeld unten")
|
||||
public int field_btm;
|
||||
|
||||
@Variable(type = IntType.COLOR, name = "color_label_text", category = CVarCategory.GUI, display = "Beschriftung")
|
||||
public int text_label;
|
||||
@Variable(type = IntType.COLOR, name = "color_button_text", category = CVarCategory.GUI, display = "Knopf Text")
|
||||
public int text_base;
|
||||
@Variable(type = IntType.COLOR, name = "color_textbox_text", category = CVarCategory.GUI, display = "Textfeld Text")
|
||||
public int text_field;
|
||||
|
||||
static {
|
||||
DEFAULT
|
||||
.border(0xa0a0a0, 0x202020)
|
||||
.base(0x606060, 0x404040, 0xffffff, 0xefefef)
|
||||
.field(0x000000, 0x101010, 0xffffff);
|
||||
|
||||
SHINY
|
||||
.border(0xffffff, 0x3f3f3f)
|
||||
.base(0x404040, 0x000000, 0xffffff, 0xefefef)
|
||||
.field(0x000000, 0x202020, 0xdfdfdf);
|
||||
|
||||
GRAY
|
||||
.border(0x000000, 0x202020)
|
||||
.base(0x808080, 0x000000, 0xffffff, 0xffffff)
|
||||
.field(0x404040, 0x808080, 0xffffff);
|
||||
|
||||
BLUE
|
||||
.border(0x0000df, 0x300020)
|
||||
.base(0x2020a0, 0x000020, 0x8fffaf, 0x00cfaf)
|
||||
.field(0x505090, 0x406060, 0xcfdfff);
|
||||
|
||||
CUSTOM
|
||||
.border(0x000000, 0x000000)
|
||||
.base(0x808080, 0x808080, 0xffffff, 0xffffff)
|
||||
.field(0x808080, 0x808080, 0xffffff);
|
||||
}
|
||||
|
||||
private Style border(int top, int btm) {
|
||||
this.brdr_top = top | 0xff000000;
|
||||
this.brdr_btm = btm | 0xff000000;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Style base(int top, int btm, int text, int label) {
|
||||
this.fill_top = top | 0xff000000;
|
||||
this.fill_btm = btm | 0xff000000;
|
||||
this.text_base = text | 0xff000000;
|
||||
this.text_label = label | 0xff000000;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Style field(int top, int btm, int text) {
|
||||
this.field_top = top | 0xff000000;
|
||||
this.field_btm = btm | 0xff000000;
|
||||
this.text_field = text | 0xff000000;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void copyToCustom() {
|
||||
CUSTOM
|
||||
.border(this.brdr_top, this.brdr_btm)
|
||||
.base(this.fill_top, this.fill_btm, this.text_base, this.text_label)
|
||||
.field(this.field_top, this.field_btm, this.text_field);
|
||||
}
|
||||
}
|
635
client/src/main/java/client/gui/character/GuiChar.java
Executable file
635
client/src/main/java/client/gui/character/GuiChar.java
Executable file
|
@ -0,0 +1,635 @@
|
|||
package client.gui.character;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import client.Client;
|
||||
import client.Client.FileMode;
|
||||
import client.gui.FileCallback;
|
||||
import client.gui.GuiLoading;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.Element;
|
||||
import client.gui.element.GuiList;
|
||||
import client.gui.element.Label;
|
||||
import client.gui.element.ListEntry;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.Slider;
|
||||
import client.gui.element.SliderCallback;
|
||||
import client.gui.element.FieldAction;
|
||||
import client.gui.element.Area;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Field;
|
||||
import client.gui.element.FieldCallback;
|
||||
import client.gui.element.TransparentArea;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.GlState;
|
||||
import client.renderer.ItemRenderer;
|
||||
import client.renderer.entity.RenderManager;
|
||||
import client.renderer.texture.EntityTexManager;
|
||||
import client.util.FileUtils;
|
||||
import client.util.SkinConverter;
|
||||
import client.vars.CVarCategory;
|
||||
import client.vars.EnumVar;
|
||||
import client.vars.Variable;
|
||||
import client.vars.EnumVar.EnumFunction;
|
||||
import client.window.Button;
|
||||
import common.collect.Lists;
|
||||
import common.dimension.DimType;
|
||||
import common.dimension.Dimension;
|
||||
import common.entity.npc.Alignment;
|
||||
import common.entity.npc.CharacterInfo;
|
||||
import common.entity.npc.EntityHuman;
|
||||
import common.entity.npc.EntityNPC;
|
||||
import common.entity.npc.SpeciesInfo;
|
||||
import common.entity.types.EntityLiving;
|
||||
import common.init.EntityEggInfo;
|
||||
import common.init.EntityRegistry;
|
||||
import common.init.SpeciesRegistry;
|
||||
import common.init.UniverseRegistry;
|
||||
import common.init.SpeciesRegistry.ModelType;
|
||||
import common.log.Log;
|
||||
import common.network.IPlayer;
|
||||
import common.packet.CPacketAction;
|
||||
import common.packet.CPacketMessage;
|
||||
import common.packet.CPacketSkin;
|
||||
import common.rng.Random;
|
||||
import common.util.Displayable;
|
||||
import common.util.Identifyable;
|
||||
import common.util.Util;
|
||||
|
||||
public class GuiChar extends GuiList<GuiChar.SkinEntry>
|
||||
{
|
||||
protected class SkinEntry implements ListEntry
|
||||
{
|
||||
private final File skinFile;
|
||||
private final String id;
|
||||
private final ModelType model;
|
||||
private final CharacterInfo charinfo;
|
||||
private final BufferedImage skinImage;
|
||||
private final int dynId;
|
||||
|
||||
protected SkinEntry(String id, File file, CharacterInfo charinfo, BufferedImage image, ModelType model)
|
||||
{
|
||||
this.skinFile = file;
|
||||
this.charinfo = charinfo;
|
||||
this.id = id;
|
||||
this.model = model;
|
||||
if(this.skinFile != null) {
|
||||
this.skinImage = image;
|
||||
int w = this.skinImage.getWidth();
|
||||
int h = this.skinImage.getHeight();
|
||||
int[] data = new int[w * h];
|
||||
this.skinImage.getRGB(0, 0, w, h, data, 0, w);
|
||||
this.dynId = 0xffff0000 + GuiChar.this.elements.size();
|
||||
EntityTexManager.setTexture(this.dynId, EntityTexManager.imageToComp(data, model), model);
|
||||
}
|
||||
else {
|
||||
this.skinImage = null;
|
||||
this.dynId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int mouseX, int mouseY, boolean hovered)
|
||||
{
|
||||
String str =
|
||||
(this.skinFile != null ? this.skinFile.getName() : (
|
||||
(this.charinfo.species.prefix && this.charinfo.type != null && !this.charinfo.type.toString().isEmpty() ?
|
||||
this.charinfo.type.toString() :
|
||||
EntityRegistry.getEntityName(this.charinfo.species.id))
|
||||
+ (this.charinfo.name.isEmpty() ? "" : (" " + this.charinfo.name))));
|
||||
|
||||
Drawing.drawText(str, x + 64 + 3, y, 0xff000000 | (this.charinfo == null ?
|
||||
0xffffff : this.charinfo.color1 | this.charinfo.color2));
|
||||
if(this.charinfo != null)
|
||||
Drawing.drawText(this.charinfo.skin, x + 64 + 3, y + 18, 0xffc0c0c0);
|
||||
|
||||
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
if (hovered)
|
||||
Drawing.drawRect(x, y, 64, 64, -1601138544);
|
||||
|
||||
this.drawTextureAt(x, y, EntityTexManager.getSkin(this.dynId, this.charinfo != null ? this.charinfo.skin : null, this.model));
|
||||
}
|
||||
|
||||
protected void drawTextureAt(int x, int y, String tex)
|
||||
{
|
||||
GlState.enableBlend();
|
||||
GlState.enableDepth();
|
||||
boolean flag = GuiChar.this.gm.cameraUsed;
|
||||
GuiChar.this.gm.cameraUsed = true;
|
||||
EntityTexManager.altTexture = tex;
|
||||
EntityTexManager.altLayer = this.dynId;
|
||||
EntityTexManager.altNpcLayer = this.dynId == -1 && this.charinfo != null ? this.charinfo.skin : null;
|
||||
drawEntity(x + 32, y + 60, 28.0f
|
||||
* Math.min(1.8f / GuiChar.this.gm.player.height, 1.5f / GuiChar.this.gm.player.width), -45.0f, -20.0f, GuiChar.this.gm.player);
|
||||
GuiChar.this.gm.cameraUsed = flag;
|
||||
EntityTexManager.altTexture = null;
|
||||
EntityTexManager.altLayer = -1;
|
||||
EntityTexManager.altNpcLayer = null;
|
||||
GlState.disableBlend();
|
||||
GlState.disableDepth();
|
||||
}
|
||||
|
||||
public void deleteTexture() {
|
||||
if(this.dynId != -1) {
|
||||
EntityTexManager.setTexture(this.dynId, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void select(boolean dclick, int mx, int my)
|
||||
{
|
||||
// BufferedImage img = this.skinImage;
|
||||
// if(this.charinfo != null) {
|
||||
// try {
|
||||
// img = TextureUtil.readImage(FileUtils.getResource(
|
||||
// EntityNPC.getSkinTexture(this.charinfo.skin)));
|
||||
// }
|
||||
// catch(IOException e) {
|
||||
// if(e instanceof FileNotFoundException)
|
||||
// Log.JNI.warn("Textur für Skin ist nicht vorhanden: " +
|
||||
// EntityNPC.getSkinTexture(this.charinfo.skin));
|
||||
// else
|
||||
// Log.JNI.error(e, "Konnte Textur nicht laden");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
GuiChar.this.templateButton.enabled = this.charinfo != null;
|
||||
if(this.skinImage == null) {
|
||||
GuiChar.this.gm.getNetHandler().addToSendQueue(new CPacketSkin(null, this.charinfo.skin));
|
||||
}
|
||||
else {
|
||||
int[] img = new int[this.model.texWidth * this.model.texHeight];
|
||||
this.skinImage.getRGB(0, 0, this.skinImage.getWidth(), this.skinImage.getHeight(), img, 0, this.skinImage.getWidth());
|
||||
GuiChar.this.gm.getNetHandler().addToSendQueue(new CPacketSkin(EntityTexManager.imageToComp(img, this.model), null));
|
||||
}
|
||||
// GuiChar.this.gm.getNetHandler().addToSendQueue(new CPacketSkin(this.skinImage, this.skinImage != null ? null : this.charinfo.skin, this.model));
|
||||
GuiChar.this.currentSkin = this.skinFile != null ? this.skinFile.getName() : this.charinfo.skin;
|
||||
GuiChar.this.waiting = false;
|
||||
}
|
||||
|
||||
public String getLocation()
|
||||
{
|
||||
return this.charinfo == null ? null : this.charinfo.skin;
|
||||
}
|
||||
}
|
||||
|
||||
private class DragAdjust extends Element {
|
||||
private int mouseX;
|
||||
private int mouseY;
|
||||
private float yawOffset;
|
||||
private float pitchOffset;
|
||||
|
||||
public DragAdjust(int x, int y, int w, int h) {
|
||||
super(x, y, w, h, null);
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
Drawing.drawRect(this.pos_x, this.pos_y, this.size_x, this.size_y, 0x20ffffff);
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
GuiChar.this.yaw = this.yawOffset + (this.mouseX - x) * 2.0f;
|
||||
GuiChar.this.pitch = this.pitchOffset + (this.mouseY - y) * 2.0f;
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
this.mouseX = x;
|
||||
this.mouseY = y;
|
||||
this.yawOffset = GuiChar.this.yaw;
|
||||
this.pitchOffset = GuiChar.this.pitch;
|
||||
}
|
||||
|
||||
public boolean canHover() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum FilterType implements Identifyable, Displayable {
|
||||
ALL("all", "Alle anzeigen"), CUSTOM("custom", "Nur eigene"), NPC("preset", "Nur vorgegebene"), SPECIES("species", "Nur Spezies"), SPECIES_CUSTOM("species_custom", "Spezies und eigene");
|
||||
|
||||
private final String name;
|
||||
private final String display;
|
||||
|
||||
private FilterType(String name, String display) {
|
||||
this.name = name;
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return this.display;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilterFunction implements EnumFunction<FilterType> {
|
||||
public void apply(EnumVar cv, FilterType value) {
|
||||
if(Client.CLIENT.open instanceof GuiChar)
|
||||
Client.CLIENT.displayGuiScreen(Client.CLIENT.open);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiChar INSTANCE = new GuiChar();
|
||||
private static final File TEXTURE_FOLDER = new File("skins");
|
||||
|
||||
private ActButton templateButton;
|
||||
private DragAdjust adjust;
|
||||
private ActButton dimButton;
|
||||
private TransparentArea descLines;
|
||||
private float yaw = -15.0f;
|
||||
private float pitch = -15.0f;
|
||||
private boolean waiting = true;
|
||||
private int dimension;
|
||||
private String currentSkin;
|
||||
|
||||
@Variable(name = "char_filter_species", category = CVarCategory.GUI, display = "Filtern", callback = FilterFunction.class, switched = true)
|
||||
private FilterType filterSpecies = FilterType.ALL;
|
||||
|
||||
private GuiChar() {
|
||||
}
|
||||
|
||||
public void init(int width, int height)
|
||||
{
|
||||
super.init(width, height);
|
||||
this.waiting = true;
|
||||
this.setDimensions(400, height, 32, height - 32);
|
||||
if(this.gm.getRenderManager().gm == null) {
|
||||
this.unload();
|
||||
this.adjust = null;
|
||||
return;
|
||||
}
|
||||
this.currentSkin = this.gm.player != null && !EntityTexManager.hasCustomSkin(this.gm.player.getId()) ? this.gm.player.getChar() : null;
|
||||
this.load(this.gm.player == null ? ModelType.HUMANOID : this.gm.player.getModel(), this.gm.player != null ? this.gm.player.getSpecies() : SpeciesRegistry.CLASSES.get(EntityHuman.class));
|
||||
this.add(new ActButton(4, 4, 194, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiChar.this.gm.showFileDialog(FileMode.FILE_LOAD_MULTI, "Skin konvertieren", TEXTURE_FOLDER, new FileCallback() {
|
||||
public void selected(File file) {
|
||||
if(SkinConverter.convertSkin(file, TEXTURE_FOLDER, false))
|
||||
GuiChar.this.gm.displayGuiScreen(GuiChar.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "Importieren: Standard"));
|
||||
this.add(new ActButton(202, 4, 194, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiChar.this.gm.showFileDialog(FileMode.FILE_LOAD_MULTI, "Skin konvertieren (schlank)", TEXTURE_FOLDER, new FileCallback() {
|
||||
public void selected(File file) {
|
||||
if(SkinConverter.convertSkin(file, TEXTURE_FOLDER, true))
|
||||
GuiChar.this.gm.displayGuiScreen(GuiChar.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "Importieren: Schlank"));
|
||||
this.addSelector("char_filter_species", 400, 4, 300, 24);
|
||||
this.add(new ActButton(4, height - 28, 194, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiChar.this.gm.displayGuiScreen(GuiChar.this);
|
||||
}
|
||||
}, "Neu laden"));
|
||||
this.templateButton = this.add(new ActButton(202, height - 28, 194, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
SkinEntry skin = GuiChar.this.getSelected();
|
||||
if(skin != null && skin.getLocation() != null) {
|
||||
String loc = skin.getLocation();
|
||||
File file = new File(TEXTURE_FOLDER, loc + ".png");
|
||||
int z = 1;
|
||||
while(file.exists()) {
|
||||
file = new File(TEXTURE_FOLDER, loc + "_" + (++z) + ".png");
|
||||
}
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = FileUtils.getResource(EntityNPC.getSkinTexture(loc));
|
||||
Files.copy(in, file.toPath());
|
||||
}
|
||||
catch(Exception e) {
|
||||
if(e instanceof FileNotFoundException)
|
||||
Log.IO.warn("Textur ist nicht zum Kopieren vorhanden: " + EntityNPC.getSkinTexture(loc));
|
||||
else
|
||||
Log.IO.error(e, "Konnte Textur nicht kopieren");
|
||||
}
|
||||
finally {
|
||||
if(in != null) {
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch(Throwable e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
GuiChar.this.gm.displayGuiScreen(GuiChar.this);
|
||||
}
|
||||
}
|
||||
}, "Vorlage kopieren"));
|
||||
this.adjust = this.add(new DragAdjust(width / 2 - 230, height - 64 - 640, 460, 640));
|
||||
|
||||
this.add(new Label(width - 396, 36, 392, 20, "Spezies: " + (this.gm.player == null ? "<?>" : this.gm.player.getSpecies().name), true));
|
||||
this.add(new NavButton(width - 396, 56, 392, 24, GuiSpecies.INSTANCE, "Spezies ändern"));
|
||||
this.add(new Label(width - 396, 36 + 92, 392, 20, "Klasse: " + (this.gm.player == null || this.gm.player.getSpecies().classEnum == null || this.gm.player.getNpcClass() == null || this.gm.player.getNpcClass().toString().isEmpty() ? "<Keine>" : this.gm.player.getNpcClass().toString()), true))
|
||||
.enabled = this.gm.player != null && this.gm.player.getSpecies().classEnum != null;
|
||||
this.add(new NavButton(width - 396, 56 + 92, 392, 24, GuiClass.INSTANCE, "Klasse ändern"))
|
||||
.enabled = this.gm.player != null && this.gm.player.getSpecies().classEnum != null;
|
||||
|
||||
final ActButton[] alignBtns = new ActButton[Alignment.values().length];
|
||||
for (int z = 0; z < Alignment.values().length; z++)
|
||||
{
|
||||
final Alignment align = Alignment.values()[z];
|
||||
alignBtns[z] = this.add(new ActButton(width - 396 + (z % 3) * 132, height - 32 - 28 * 3 + 28 * (z / 3), 128, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiChar.this.gm.player != null) {
|
||||
GuiChar.this.waiting = false;
|
||||
GuiChar.this.gm.player.client.addToSendQueue(new CPacketAction(CPacketAction.Action.SET_ALIGN, align.ordinal()));
|
||||
for(ActButton btn : alignBtns) {
|
||||
btn.enabled = btn != elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, align.color + align.display));
|
||||
alignBtns[z].enabled = this.gm.player == null || this.gm.player.getAlignment() != align;
|
||||
}
|
||||
this.add(new Slider(width / 2 - 200, height - 28, 400, 24, 1, this.gm.player == null ? 120 : this.gm.player.getMinSize(), this.gm.player == null ? 320 : this.gm.player.getMaxSize(), this.gm.player == null ? 180 : this.gm.player.getDefaultSize(), this.gm.player == null ? 180 : this.gm.player.getCurrentSize(), new SliderCallback() {
|
||||
public void use(Slider elem, int value) {
|
||||
if(GuiChar.this.gm.player != null) {
|
||||
GuiChar.this.waiting = false;
|
||||
GuiChar.this.gm.player.client.addToSendQueue(new CPacketAction(CPacketAction.Action.SET_HEIGHT, value));
|
||||
}
|
||||
}
|
||||
}, "Spieler-Größe", "cm")).enabled = this.gm.player == null || this.gm.player.getMinSize() != this.gm.player.getMaxSize();
|
||||
this.add(new Label(width / 2 - 200, 36, 400, 20, "Name", true));
|
||||
this.add(new Label(width - 396, height - 384, 392, 20, "Beschreibung", true));
|
||||
final Area descField = this.add(new Area(width - 396, height - 364, 392, 130, IPlayer.MAX_INFO_LENGTH, ""));
|
||||
this.add(new ActButton(width - 198, height - 28, 194, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiChar.this.gm.player != null) {
|
||||
GuiChar.this.gm.displayGuiScreen(GuiLoading.makeWaitTask("Lade Welt ..."));
|
||||
Dimension dim = UniverseRegistry.getBaseDimensions().get(GuiChar.this.dimension);
|
||||
GuiChar.this.gm.player.client.addToSendQueue(new CPacketMessage(CPacketMessage.Type.INFO, descField.getText()));
|
||||
GuiChar.this.gm.player.client.addToSendQueue(new CPacketAction(CPacketAction.Action.CLOSE_EDITOR, dim.getDimensionId()));
|
||||
}
|
||||
}
|
||||
}, "Charakter erstellen"));
|
||||
this.add(new Field(width / 2 - 200, 36 + 20, 400, 24, IPlayer.MAX_NICK_LENGTH, new FieldCallback() {
|
||||
public void use(Field elem, FieldAction value) {
|
||||
if(value == FieldAction.SEND || value == FieldAction.UNFOCUS) {
|
||||
String name = elem.getText();
|
||||
if(name.isEmpty())
|
||||
elem.setText(GuiChar.this.gm.player == null ? "..." : GuiChar.this.gm.player.getCustomNameTag());
|
||||
else if(GuiChar.this.gm.player != null) {
|
||||
GuiChar.this.waiting = false;
|
||||
GuiChar.this.gm.player.client.addToSendQueue(new CPacketMessage(CPacketMessage.Type.DISPLAY, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, IPlayer.VALID_NICK, this.gm.player == null ? "" : this.gm.player.getCustomNameTag()));
|
||||
this.templateButton.enabled = false;
|
||||
this.dimension = new Random().zrange(UniverseRegistry.getBaseDimensions().size());
|
||||
EntityEggInfo egg = EntityRegistry.SPAWN_EGGS.get(this.gm.player == null ? EntityRegistry.getEntityString(EntityHuman.class) : EntityRegistry.getEntityString(this.gm.player));
|
||||
if(egg != null && egg.origin != null) {
|
||||
Dimension dim = UniverseRegistry.getDimension(egg.origin);
|
||||
if(dim != null) {
|
||||
for(int z = 0; z < UniverseRegistry.getBaseDimensions().size(); z++) {
|
||||
if(UniverseRegistry.getBaseDimensions().get(z).getDimensionId() == dim.getDimensionId()) {
|
||||
this.dimension = z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dimButton = this.add(new ActButton(width - 396, height - 220, 392, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType mode) {
|
||||
if(mode == PressType.TERTIARY) {
|
||||
GuiChar.this.dimension = new Random().zrange(UniverseRegistry.getBaseDimensions().size());
|
||||
}
|
||||
else if(mode == PressType.SECONDARY) {
|
||||
if(--GuiChar.this.dimension < 0)
|
||||
GuiChar.this.dimension = UniverseRegistry.getBaseDimensions().size() - 1;
|
||||
}
|
||||
else {
|
||||
if(++GuiChar.this.dimension >= UniverseRegistry.getBaseDimensions().size())
|
||||
GuiChar.this.dimension = 0;
|
||||
}
|
||||
GuiChar.this.setDimButton();
|
||||
}
|
||||
}, ""));
|
||||
this.descLines = this.add(new TransparentArea(width - 396, height - 220 + 24, 392, 66, "", false));
|
||||
this.setDimButton();
|
||||
}
|
||||
|
||||
private void setDimButton() {
|
||||
Dimension dim = UniverseRegistry.getBaseDimensions().get(this.dimension);
|
||||
this.dimButton.setText((dim.getType() == DimType.PLANET ? "Heimplanet" : "Heimdimension") + ": " + dim.getFormattedName(false));
|
||||
String name = dim.getFormattedName(true);
|
||||
int index = name.indexOf(" / ");
|
||||
this.descLines.setText(index >= 0 ? Util.buildLines(name.substring(index + " / ".length()).split(" / ")) : "");
|
||||
}
|
||||
|
||||
public void onGuiClosed()
|
||||
{
|
||||
this.unload();
|
||||
}
|
||||
|
||||
public void drawOverlays()
|
||||
{
|
||||
if(this.adjust != null) {
|
||||
float factor = this.gm.player.width > 2.15f ? 2.15f / this.gm.player.width : 1.0f;
|
||||
factor = this.gm.player.height > 3.0f && 3.0f / this.gm.player.height < factor ? 3.0f / this.gm.player.height : factor;
|
||||
drawEntity(400 + (this.gm.fb_x - 400 - 400) / 2, this.gm.fb_y - 160, 160.0f * factor
|
||||
, this.yaw, this.pitch, this.gm.player);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(this.adjust == null && this.gm.getRenderManager().gm != null)
|
||||
this.gm.displayGuiScreen(this);
|
||||
}
|
||||
|
||||
public void checkReopen() {
|
||||
if(this.adjust != null && this.waiting) {
|
||||
this.waiting = false;
|
||||
this.gm.displayGuiScreen(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Charakter anpassen";
|
||||
}
|
||||
|
||||
public static BufferedImage loadSkin(File file)
|
||||
{
|
||||
BufferedImage img = null;
|
||||
try {
|
||||
img = ImageIO.read(file);
|
||||
}
|
||||
catch(IOException e) {
|
||||
return null;
|
||||
}
|
||||
if(img == null) {
|
||||
return null;
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
public void load(ModelType model, SpeciesInfo speciesOnly)
|
||||
{
|
||||
this.unload();
|
||||
TEXTURE_FOLDER.mkdirs();
|
||||
File[] files = this.filterSpecies == FilterType.NPC || this.filterSpecies == FilterType.SPECIES ? null : TEXTURE_FOLDER.listFiles(new FileFilter() {
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.isFile() && pathname.getName().endsWith(".png");
|
||||
}
|
||||
});
|
||||
int pos = 0;
|
||||
// this.elements.add(new SkinEntry("default", null, null, null, model));
|
||||
// if("default".equals(currentSkin))
|
||||
// this.setSelected(pos);
|
||||
// pos++;
|
||||
if(files != null) {
|
||||
Arrays.sort(files);
|
||||
for(File file : files)
|
||||
{
|
||||
BufferedImage img = loadSkin(file);
|
||||
if(img != null) {
|
||||
if(img.getWidth() == model.texWidth && img.getHeight() == model.texHeight) {
|
||||
this.elements.add(new SkinEntry(file.getName(), file, null, img, model));
|
||||
if(file.getName().equals(this.currentSkin))
|
||||
this.setSelected(pos);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.filterSpecies == FilterType.CUSTOM)
|
||||
return;
|
||||
for(SpeciesInfo species : this.filterSpecies == FilterType.SPECIES || this.filterSpecies == FilterType.SPECIES_CUSTOM ? Lists.newArrayList(speciesOnly) : SpeciesRegistry.SPECIMEN) {
|
||||
for(CharacterInfo charinfo : species.chars) {
|
||||
if(charinfo.species.renderer == model) {
|
||||
this.elements.add(new SkinEntry(charinfo.skin, null, charinfo, null, charinfo.species.renderer));
|
||||
if(charinfo.skin.equals(this.currentSkin))
|
||||
this.setSelected(pos);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unload()
|
||||
{
|
||||
for (SkinEntry entry : this.elements)
|
||||
{
|
||||
entry.deleteTexture();
|
||||
}
|
||||
|
||||
this.elements.clear();
|
||||
}
|
||||
|
||||
public int getListWidth()
|
||||
{
|
||||
return 400 - 20;
|
||||
}
|
||||
|
||||
public int getSlotHeight()
|
||||
{
|
||||
return 64 + 4;
|
||||
}
|
||||
|
||||
|
||||
// public static void drawEntityOnScreen(int posX, int posY, float scale, float mouseX, float mouseY, EntityLiving ent)
|
||||
// {
|
||||
// GlState.enableColorMaterial();
|
||||
// SKC.glPushMatrix();
|
||||
// SKC.glTranslatef((float)posX, (float)posY, 50.0F);
|
||||
// SKC.glScalef(-scale, scale, scale);
|
||||
// SKC.glRotatef(180.0F, 0.0F, 0.0F, 1.0F);
|
||||
// float f = ent.yawOffset;
|
||||
// float f1 = ent.rotYaw;
|
||||
// float f2 = ent.rotPitch;
|
||||
// float f3 = ent.prevHeadYaw;
|
||||
// float f4 = ent.headYaw;
|
||||
// SKC.glRotatef(135.0F, 0.0F, 1.0F, 0.0F);
|
||||
// ItemRenderer.enableStandardItemLighting();
|
||||
// SKC.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F);
|
||||
// SKC.glRotatef(-((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F);
|
||||
// ent.yawOffset = (float)Math.atan((double)(mouseX / 40.0F)) * 20.0F;
|
||||
// ent.rotYaw = (float)Math.atan((double)(mouseX / 40.0F)) * 40.0F;
|
||||
// ent.rotPitch = -((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F;
|
||||
// ent.headYaw = ent.rotYaw;
|
||||
// ent.prevHeadYaw = ent.rotYaw;
|
||||
// SKC.glTranslatef(0.0F, 0.0F, 0.0F);
|
||||
// RenderManager rendermanager = Game.getGame().getRenderManager();
|
||||
// rendermanager.setPlayerViewY(180.0F);
|
||||
//// rendermanager.setRenderShadow(false);
|
||||
// rendermanager.renderEntity(ent, 0.0D, 0.0D, 0.0D, 1.0F);
|
||||
//// rendermanager.setRenderShadow(true);
|
||||
// ent.yawOffset = f;
|
||||
// ent.rotYaw = f1;
|
||||
// ent.rotPitch = f2;
|
||||
// ent.prevHeadYaw = f3;
|
||||
// ent.headYaw = f4;
|
||||
// SKC.glPopMatrix();
|
||||
// ItemRenderer.disableStandardItemLighting();
|
||||
// GlState.disableRescaleNormal();
|
||||
// GlState.setActiveTexture(SKC.GL_TEXTURE1);
|
||||
// GlState.disableTexture2D();
|
||||
// GlState.setActiveTexture(SKC.GL_TEXTURE0);
|
||||
// }
|
||||
|
||||
public static void drawEntity(int posX, int posY, float scale, float yaw, float pitch, EntityLiving ent)
|
||||
{
|
||||
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlState.enableDepth();
|
||||
GlState.enableColorMaterial();
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslatef((float)posX, (float)posY, 200.0F);
|
||||
GL11.glScalef(-scale, scale, scale);
|
||||
GL11.glRotatef(180.0F, 0.0F, 0.0F, 1.0F);
|
||||
float f = ent.yawOffset;
|
||||
float f1 = ent.rotYaw;
|
||||
float f2 = ent.rotPitch;
|
||||
float f3 = ent.prevHeadYaw;
|
||||
float f4 = ent.headYaw;
|
||||
GL11.glRotatef(135.0F, 0.0F, 1.0F, 0.0F);
|
||||
ItemRenderer.enableStandardItemLighting();
|
||||
GL11.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F);
|
||||
GL11.glTranslatef(0.0F, ent.height / 2, 0.0F);
|
||||
GL11.glRotatef(-pitch, 1.0F, 0.0F, 0.0F);
|
||||
ent.yawOffset = yaw;
|
||||
ent.rotYaw = yaw;
|
||||
ent.rotPitch = 0.0f;
|
||||
ent.headYaw = ent.rotYaw;
|
||||
ent.prevHeadYaw = ent.rotYaw;
|
||||
GL11.glTranslatef(0.0F, -(ent.height / 2), 0.0F);
|
||||
RenderManager rendermanager = Client.CLIENT.getRenderManager();
|
||||
rendermanager.setPlayerViewY(180.0F);
|
||||
rendermanager.renderEntity(ent, 0.0D, 0.0D, 0.0D, 1.0F);
|
||||
// GL11.glTranslatef(0.0F, 0.0F, 0.0F);
|
||||
ent.yawOffset = f;
|
||||
ent.rotYaw = f1;
|
||||
ent.rotPitch = f2;
|
||||
ent.prevHeadYaw = f3;
|
||||
ent.headYaw = f4;
|
||||
GL11.glPopMatrix();
|
||||
ItemRenderer.disableStandardItemLighting();
|
||||
GlState.disableRescaleNormal();
|
||||
GlState.setActiveTexture(GL13.GL_TEXTURE1);
|
||||
GlState.disableTexture2D();
|
||||
GlState.setActiveTexture(GL13.GL_TEXTURE0);
|
||||
GlState.disableDepth();
|
||||
}
|
||||
}
|
||||
|
123
client/src/main/java/client/gui/character/GuiCharacters.java
Normal file
123
client/src/main/java/client/gui/character/GuiCharacters.java
Normal file
|
@ -0,0 +1,123 @@
|
|||
package client.gui.character;
|
||||
|
||||
import client.gui.GuiConfirm;
|
||||
import client.gui.GuiMenu;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.GuiList;
|
||||
import client.gui.element.ListEntry;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.TransparentArea;
|
||||
import client.renderer.Drawing;
|
||||
import common.color.TextColor;
|
||||
import common.entity.npc.PlayerCharacter;
|
||||
import common.packet.CPacketAction;
|
||||
|
||||
public class GuiCharacters extends GuiList<GuiCharacters.CharacterEntry> implements ButtonCallback
|
||||
{
|
||||
protected class CharacterEntry implements ListEntry
|
||||
{
|
||||
private final PlayerCharacter character;
|
||||
private final boolean initial;
|
||||
|
||||
protected CharacterEntry(PlayerCharacter character, boolean initial)
|
||||
{
|
||||
this.character = character;
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int mouseX, int mouseY, boolean hovered)
|
||||
{
|
||||
if(this.initial)
|
||||
Drawing.drawRect(x, y, 1, 36, 0xffaf0000);
|
||||
String str = this.character == null ? TextColor.BLUE + "[" + TextColor.CYAN + "+" + TextColor.BLUE + "]" :
|
||||
String.format(TextColor.GREEN + "Level " + TextColor.DGREEN + "%d " + TextColor.YELLOW + "%s " + TextColor.VIOLET + "%s" + TextColor.GRAY + " [%s%s" + TextColor.GRAY + "]",
|
||||
character.level, character.type, character.name, character.align.color, character.align.display);
|
||||
String pos = this.character == null ? TextColor.BROWN + "Neuen Charakter erstellen" :
|
||||
String.format(TextColor.NEON + "%s " + TextColor.GRAY + "bei " + TextColor.ACID + "%d" + TextColor.GRAY + ", " + TextColor.ACID + "%d" + TextColor.GRAY + ", " + TextColor.ACID + "%d",
|
||||
character.dim, character.pos.getX(), character.pos.getY(), character.pos.getZ());
|
||||
Drawing.drawText(str, x + 3, y, 0xffffffff);
|
||||
Drawing.drawText(pos, x + 3, y + 16, 0xffffffff);
|
||||
}
|
||||
|
||||
public void select(boolean dclick, int mx, int my)
|
||||
{
|
||||
if(dclick)
|
||||
GuiCharacters.this.use(GuiCharacters.this.actionButtom, PressType.PRIMARY);
|
||||
GuiCharacters.this.updateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiCharacters INSTANCE = new GuiCharacters();
|
||||
|
||||
private TransparentArea descField;
|
||||
private ActButton actionButtom;
|
||||
private ActButton deleteButtom;
|
||||
|
||||
private GuiCharacters() {
|
||||
}
|
||||
|
||||
private void updateButtons() {
|
||||
CharacterEntry entry = this.getSelected();
|
||||
this.descField.setText(entry == null ? "" : (entry.character == null ? "*neuer Charakter*" : (entry.character.info == null ? "*keine Beschreibung vorhanden*" : this.getSelected().character.info)));
|
||||
this.actionButtom.setText(entry != null && entry.character == null ? "Charakter erstellen" : "Charakter spielen");
|
||||
this.actionButtom.enabled = entry != null && !entry.initial;
|
||||
this.deleteButtom.enabled = entry != null && entry.character != null && !entry.initial;
|
||||
}
|
||||
|
||||
public void init(int width, int height)
|
||||
{
|
||||
super.init(width, height);
|
||||
this.setDimensions(600, height, 32, height - 32);
|
||||
this.elements.clear();
|
||||
if(this.gm.getNetHandler() != null) {
|
||||
int initialSelection = this.gm.getNetHandler().getSelectedCharacter();
|
||||
for(PlayerCharacter character : this.gm.getNetHandler().getCharacterList()) {
|
||||
this.elements.add(new CharacterEntry(initialSelection == this.elements.size() ? new PlayerCharacter(character.name, character.info, character.align, this.gm.player.worldObj.dimension.getFormattedName(false), this.gm.player.getPosition(), character.type, this.gm.player.experienceLevel) : character, initialSelection == this.elements.size()));
|
||||
}
|
||||
this.elements.add(new CharacterEntry(null, false));
|
||||
this.setSelected(initialSelection);
|
||||
}
|
||||
this.descField = this.add(new TransparentArea(width - 390, 62, 380, height - 124, "", false));
|
||||
this.deleteButtom = this.add(new ActButton(width / 2 - 304, height - 28, 200, 24, this, "Charakter löschen"));
|
||||
this.actionButtom = this.add(new ActButton(width / 2 - 100, height - 28, 200, 24, this, ""));
|
||||
this.add(new NavButton(width / 2 + 104, height - 28, 200, 24, GuiMenu.INSTANCE, "Abbrechen"));
|
||||
this.updateButtons();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Charakter anpassen";
|
||||
}
|
||||
|
||||
public int getListWidth()
|
||||
{
|
||||
return 560;
|
||||
}
|
||||
|
||||
public int getSlotHeight()
|
||||
{
|
||||
return 36 + 4;
|
||||
}
|
||||
|
||||
public void use(ActButton elem, PressType action) {
|
||||
CharacterEntry entry = GuiCharacters.this.getSelected();
|
||||
if(entry != null && GuiCharacters.this.gm.getNetHandler() != null) {
|
||||
if(elem == this.actionButtom) {
|
||||
if(entry.character == null)
|
||||
this.gm.getNetHandler().addToSendQueue(new CPacketAction(CPacketAction.Action.OPEN_EDITOR));
|
||||
else
|
||||
this.gm.getNetHandler().addToSendQueue(new CPacketAction(CPacketAction.Action.SELECT_CHARACTER, this.selectedElement));
|
||||
}
|
||||
else if(elem == this.deleteButtom && entry.character != null) {
|
||||
this.gm.displayGuiScreen(new GuiConfirm(new GuiConfirm.Callback() {
|
||||
public void confirm(boolean confirmed) {
|
||||
if(confirmed)
|
||||
GuiCharacters.this.gm.getNetHandler().addToSendQueue(new CPacketAction(CPacketAction.Action.DELETE_CHARACTER, GuiCharacters.this.selectedElement));
|
||||
GuiCharacters.this.gm.displayGuiScreen(GuiCharacters.this);
|
||||
}
|
||||
}, "Möchtest du diesen Charakter wirklich löschen?", "Der Fortschritt, die Gegenstände und die Historie von \"" + entry.character.name + "\" werden für imer verloren sein!", "Löschen", "Abbrechen"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
client/src/main/java/client/gui/character/GuiClass.java
Normal file
78
client/src/main/java/client/gui/character/GuiClass.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
package client.gui.character;
|
||||
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.GuiList;
|
||||
import client.gui.element.ListEntry;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.renderer.Drawing;
|
||||
import common.packet.CPacketAction;
|
||||
|
||||
public class GuiClass extends GuiList<GuiClass.ClassEntry> implements ButtonCallback
|
||||
{
|
||||
protected class ClassEntry implements ListEntry
|
||||
{
|
||||
private final Enum clazz;
|
||||
|
||||
protected ClassEntry(Enum clazz)
|
||||
{
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int mouseX, int mouseY, boolean hovered)
|
||||
{
|
||||
if(GuiClass.this.gm.player != null && this.clazz == GuiClass.this.gm.player.getNpcClass())
|
||||
Drawing.drawRect(x, y, 1, 44, 0xffaf0000);
|
||||
Drawing.drawText(this.clazz.toString().isEmpty() ? "<Keine>" : this.clazz.toString(), x + 3, y, 0xffffffff);
|
||||
}
|
||||
|
||||
public void select(boolean dclick, int mx, int my)
|
||||
{
|
||||
if((GuiClass.this.selectButton.enabled = GuiClass.this.gm.player == null || this.clazz != GuiClass.this.gm.player.getNpcClass()) && dclick)
|
||||
GuiClass.this.use(GuiClass.this.selectButton, PressType.PRIMARY);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiClass INSTANCE = new GuiClass();
|
||||
|
||||
private ActButton selectButton;
|
||||
|
||||
private GuiClass() {
|
||||
}
|
||||
|
||||
public void init(int width, int height)
|
||||
{
|
||||
super.init(width, height);
|
||||
this.setDimensions(400, height, 32, height - 32);
|
||||
this.elements.clear();
|
||||
if(this.gm.player != null && this.gm.player.getSpecies().classEnum != null)
|
||||
for(Enum clazz : this.gm.player.getSpecies().classEnum.getEnumConstants()) {
|
||||
this.elements.add(new ClassEntry(clazz));
|
||||
}
|
||||
this.add(new NavButton(width - 198 * 2, height - 28, 194, 24, GuiChar.INSTANCE, "Zurück"));
|
||||
this.selectButton = this.add(new ActButton(width - 198, height - 28, 194, 24, this, "Klasse ändern"));
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Klasse wählen";
|
||||
}
|
||||
|
||||
public int getListWidth()
|
||||
{
|
||||
return 400 - 20;
|
||||
}
|
||||
|
||||
public int getSlotHeight()
|
||||
{
|
||||
return 44 + 4;
|
||||
}
|
||||
|
||||
public void use(ActButton elem, PressType action) {
|
||||
ClassEntry entry = this.getSelected();
|
||||
if(entry != null && GuiClass.this.gm.player != null) {
|
||||
GuiClass.this.gm.player.client.addToSendQueue(new CPacketAction(CPacketAction.Action.SET_CLASS, entry.clazz.ordinal()));
|
||||
this.gm.displayGuiScreen(GuiChar.INSTANCE);
|
||||
}
|
||||
}
|
||||
}
|
80
client/src/main/java/client/gui/character/GuiSpecies.java
Normal file
80
client/src/main/java/client/gui/character/GuiSpecies.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package client.gui.character;
|
||||
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.GuiList;
|
||||
import client.gui.element.ListEntry;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.renderer.Drawing;
|
||||
import common.entity.npc.SpeciesInfo;
|
||||
import common.init.EntityRegistry;
|
||||
import common.init.SpeciesRegistry;
|
||||
import common.packet.CPacketAction;
|
||||
|
||||
public class GuiSpecies extends GuiList<GuiSpecies.SpeciesEntry> implements ButtonCallback
|
||||
{
|
||||
protected class SpeciesEntry implements ListEntry
|
||||
{
|
||||
private final SpeciesInfo species;
|
||||
|
||||
protected SpeciesEntry(SpeciesInfo species)
|
||||
{
|
||||
this.species = species;
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int mouseX, int mouseY, boolean hovered)
|
||||
{
|
||||
if(GuiSpecies.this.gm.player != null && this.species == GuiSpecies.this.gm.player.getSpecies())
|
||||
Drawing.drawRect(x, y, 1, 44, 0xffaf0000);
|
||||
Drawing.drawText(this.species.name, x + 3, y, 0xff000000 | this.species.color1 | this.species.color2);
|
||||
if(this.species.classEnum != null)
|
||||
Drawing.drawText(this.species.classEnum.getEnumConstants().length + " Klassen", x + 3, y + 18, 0xffc0c0c0);
|
||||
}
|
||||
|
||||
public void select(boolean dclick, int mx, int my)
|
||||
{
|
||||
if((GuiSpecies.this.selectButton.enabled = GuiSpecies.this.gm.player == null || this.species != GuiSpecies.this.gm.player.getSpecies()) && dclick)
|
||||
GuiSpecies.this.use(GuiSpecies.this.selectButton, PressType.PRIMARY);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiSpecies INSTANCE = new GuiSpecies();
|
||||
|
||||
private ActButton selectButton;
|
||||
|
||||
private GuiSpecies() {
|
||||
}
|
||||
|
||||
public void init(int width, int height)
|
||||
{
|
||||
super.init(width, height);
|
||||
this.setDimensions(400, height, 32, height - 32);
|
||||
this.elements.clear();
|
||||
for(SpeciesInfo species : SpeciesRegistry.SPECIMEN) {
|
||||
this.elements.add(new SpeciesEntry(species));
|
||||
}
|
||||
this.add(new NavButton(width - 198 * 2, height - 28, 194, 24, GuiChar.INSTANCE, "Zurück"));
|
||||
this.selectButton = this.add(new ActButton(width - 198, height - 28, 194, 24, this, "Spezies ändern"));
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "Spezies wählen";
|
||||
}
|
||||
|
||||
public int getListWidth()
|
||||
{
|
||||
return 400 - 20;
|
||||
}
|
||||
|
||||
public int getSlotHeight()
|
||||
{
|
||||
return 44 + 4;
|
||||
}
|
||||
|
||||
public void use(ActButton elem, PressType action) {
|
||||
SpeciesEntry entry = this.getSelected();
|
||||
if(entry != null && GuiSpecies.this.gm.player != null)
|
||||
GuiSpecies.this.gm.player.client.addToSendQueue(new CPacketAction(CPacketAction.Action.SET_SPECIES, EntityRegistry.getEntityID(entry.species.clazz)));
|
||||
}
|
||||
}
|
50
client/src/main/java/client/gui/container/GuiBrewing.java
Executable file
50
client/src/main/java/client/gui/container/GuiBrewing.java
Executable file
|
@ -0,0 +1,50 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.inventory.ContainerBrewingStand;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
|
||||
|
||||
public class GuiBrewing extends GuiContainer
|
||||
{
|
||||
// private static final String brewingStandGuiTextures = "textures/gui/brewing_stand.png";
|
||||
|
||||
/** The player inventory bound to this GUI. */
|
||||
private final InventoryPlayer playerInventory;
|
||||
private IInventory tileBrewingStand;
|
||||
|
||||
public GuiBrewing(InventoryPlayer playerInv, IInventory p_i45506_2_)
|
||||
{
|
||||
super(new ContainerBrewingStand(playerInv, p_i45506_2_));
|
||||
this.playerInventory = playerInv;
|
||||
this.tileBrewingStand = p_i45506_2_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
String s = this.tileBrewingStand.getCommandName();
|
||||
this.drawString(s, 8, 6);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Args : renderPartialTicks, mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerBackgroundLayer()
|
||||
{
|
||||
int k = this.tileBrewingStand.getField(0);
|
||||
|
||||
if (k > 0)
|
||||
{
|
||||
int l = (int)(28.0F * (1.0F - (float)k / 400.0F));
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
this.rect(97, 16, 9, l, 0xffff20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
client/src/main/java/client/gui/container/GuiChest.java
Executable file
53
client/src/main/java/client/gui/container/GuiChest.java
Executable file
|
@ -0,0 +1,53 @@
|
|||
package client.gui.container;
|
||||
|
||||
import client.Client;
|
||||
import common.inventory.ContainerChest;
|
||||
import common.inventory.IInventory;
|
||||
|
||||
|
||||
public class GuiChest extends GuiContainer
|
||||
{
|
||||
// /** The ResourceLocation containing the chest GUI texture. */
|
||||
// private static final String CHEST_GUI_TEXTURE = "textures/gui/generic_54.png";
|
||||
private IInventory upperChestInventory;
|
||||
private IInventory lowerChestInventory;
|
||||
|
||||
/**
|
||||
* window height is calculated with these values; the more rows, the heigher
|
||||
*/
|
||||
private int inventoryRows;
|
||||
|
||||
public GuiChest(IInventory upperInv, IInventory lowerInv)
|
||||
{
|
||||
super(new ContainerChest(upperInv, lowerInv, Client.CLIENT.player));
|
||||
this.upperChestInventory = upperInv;
|
||||
this.lowerChestInventory = lowerInv;
|
||||
// this.allowUserInput = false;
|
||||
int i = 222;
|
||||
int j = i - 108;
|
||||
this.inventoryRows = lowerInv.getSizeInventory() / 9;
|
||||
this.ySize = j + this.inventoryRows * 18;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString(this.lowerChestInventory.getCommandName(), 8, 6);
|
||||
this.drawString(this.upperChestInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Args : renderPartialTicks, mouseX, mouseY
|
||||
*/
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.inventoryRows * 18 + 17);
|
||||
//// this.rect(i, j + this.inventoryRows * 18 + 17, 0, 126, this.xSize, 96);
|
||||
// }
|
||||
}
|
1211
client/src/main/java/client/gui/container/GuiContainer.java
Executable file
1211
client/src/main/java/client/gui/container/GuiContainer.java
Executable file
File diff suppressed because it is too large
Load diff
22
client/src/main/java/client/gui/container/GuiCrafting.java
Executable file
22
client/src/main/java/client/gui/container/GuiCrafting.java
Executable file
|
@ -0,0 +1,22 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.block.tech.BlockWorkbench;
|
||||
import common.inventory.ContainerWorkbench;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.util.BlockPos;
|
||||
import common.world.World;
|
||||
|
||||
public class GuiCrafting extends GuiContainer {
|
||||
private final BlockWorkbench type;
|
||||
|
||||
public GuiCrafting(InventoryPlayer playerInv, World worldIn, BlockWorkbench type) {
|
||||
super(new ContainerWorkbench(playerInv, worldIn, BlockPos.ORIGIN, type));
|
||||
this.type = type;
|
||||
this.ySize = 112 + 18 * this.type.getSize();
|
||||
}
|
||||
|
||||
public void drawGuiContainerForegroundLayer() {
|
||||
this.drawString("Handwerk (" + this.type.getDisplay() + ")", 26, 6);
|
||||
this.drawString("Inventar", 8, this.ySize - 96 + 2);
|
||||
}
|
||||
}
|
46
client/src/main/java/client/gui/container/GuiDispenser.java
Executable file
46
client/src/main/java/client/gui/container/GuiDispenser.java
Executable file
|
@ -0,0 +1,46 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.inventory.ContainerDispenser;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
|
||||
|
||||
public class GuiDispenser extends GuiContainer
|
||||
{
|
||||
// private static final String dispenserGuiTextures = "textures/gui/dispenser.png";
|
||||
|
||||
/** The player inventory bound to this GUI. */
|
||||
private final InventoryPlayer playerInventory;
|
||||
|
||||
/** The inventory contained within the corresponding Dispenser. */
|
||||
public IInventory dispenserInventory;
|
||||
|
||||
public GuiDispenser(InventoryPlayer playerInv, IInventory dispenserInv)
|
||||
{
|
||||
super(new ContainerDispenser(playerInv, dispenserInv));
|
||||
this.playerInventory = playerInv;
|
||||
this.dispenserInventory = dispenserInv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
String s = this.dispenserInventory.getCommandName();
|
||||
this.drawString(s, 8, 6);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Args : renderPartialTicks, mouseX, mouseY
|
||||
// */
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(dispenserGuiTextures);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
// }
|
||||
}
|
288
client/src/main/java/client/gui/container/GuiEnchant.java
Executable file
288
client/src/main/java/client/gui/container/GuiEnchant.java
Executable file
|
@ -0,0 +1,288 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.color.TextColor;
|
||||
import common.enchantment.Enchantment;
|
||||
import common.inventory.ContainerEnchantment;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.rng.Random;
|
||||
import common.tileentity.IWorldNameable;
|
||||
import common.world.World;
|
||||
|
||||
public class GuiEnchant extends GuiContainer
|
||||
{
|
||||
/** The ResourceLocation containing the Enchantment GUI texture location */
|
||||
// private static final String ENCHANTMENT_TABLE_GUI_TEXTURE = "textures/gui/enchanting_table.png";
|
||||
private static final String[] NAMES = "the elder scrolls klaatu berata niktu xyzzy bless curse light darkness fire air earth water hot dry cold wet ignite snuff embiggen twist shorten stretch fiddle destroy imbue galvanize enchant free limited range of towards inside sphere cube self other ball mental physical grow shrink demon elemental spirit animal creature beast humanoid undead fresh stale ".split(" ");
|
||||
|
||||
/** The player inventory currently bound to this GuiEnchantment instance. */
|
||||
private final InventoryPlayer playerInventory;
|
||||
private final Random nameRand = new Random();
|
||||
private final Random random = new Random();
|
||||
private final ContainerEnchantment container;
|
||||
private final IWorldNameable table;
|
||||
|
||||
// public int field_147073_u;
|
||||
// public float field_147071_v;
|
||||
// public float field_147069_w;
|
||||
// public float field_147082_x;
|
||||
// public float field_147081_y;
|
||||
// public float field_147080_z;
|
||||
// public float field_147076_A;
|
||||
// ItemStack field_147077_B;
|
||||
|
||||
public GuiEnchant(InventoryPlayer inventory, World worldIn, IWorldNameable table)
|
||||
{
|
||||
super(new ContainerEnchantment(inventory, worldIn));
|
||||
this.playerInventory = inventory;
|
||||
this.container = (ContainerEnchantment)this.inventorySlots;
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString(this.table.getCommandName(), 12, 5);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Called from the main game loop to update the screen.
|
||||
// */
|
||||
// public void updateScreen()
|
||||
// {
|
||||
// super.updateScreen();
|
||||
// this.updateAnimation();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton
|
||||
*/
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton)
|
||||
{
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
int l = mouseX - 60;
|
||||
int i1 = mouseY - (14 + 19 * k);
|
||||
|
||||
if (l >= 0 && i1 >= 0 && l < 108 && i1 < 19 && this.container.enchantItem(this.gm.player, k))
|
||||
{
|
||||
this.gm.controller.sendEnchantPacket(this.container.windowId, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addButtons() {
|
||||
super.addButtons();
|
||||
this.button(60, 14 + 19 * 0, 108, 19);
|
||||
this.button(60, 14 + 19 * 1, 108, 19);
|
||||
this.button(60, 14 + 19 * 2, 108, 19);
|
||||
}
|
||||
|
||||
/**
|
||||
* Args : renderPartialTicks, mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerBackgroundLayer()
|
||||
{
|
||||
this.nameRand.setSeed((long)this.container.xpSeed);
|
||||
|
||||
for (int l = 0; l < 3; ++l)
|
||||
{
|
||||
int i1 = 60;
|
||||
int j1 = i1 + 20;
|
||||
String s = this.getRandomName();
|
||||
int l1 = this.container.enchantLevels[l];
|
||||
|
||||
if (l1 == 0)
|
||||
{
|
||||
this.rect(i1, 14 + 19 * l, 108, 19, 0x404040);
|
||||
}
|
||||
else
|
||||
{
|
||||
String s1 = "" + l1;
|
||||
int i2 = 6839882;
|
||||
|
||||
if (/* (k < l + 1 || */ this.gm.player.experienceLevel < l1) // && !this.gm.thePlayer.creative)
|
||||
{
|
||||
this.rect(i1, 14 + 19 * l, 108, 19, 0x400000);
|
||||
this.rect(i1 + 1, 15 + 19 * l, 16, 16, 0x200000);
|
||||
this.drawString(s, j1, 16 + 19 * l); // , /*k1,*/ (i2 & 16711422) >> 1);
|
||||
i2 = 4226832;
|
||||
}
|
||||
else
|
||||
{
|
||||
// int j2 = SKC.getMouseX() - this.guiLeft - 60;
|
||||
// int k2 = SKC.getMouseY() - this.guiTop - (14 + 19 * l);
|
||||
|
||||
// if (j2 >= 0 && k2 >= 0 && j2 < 108 && k2 < 19)
|
||||
// {
|
||||
// this.rect(i1, 14 + 19 * l, 108, 19, 0x20ff20);
|
||||
// i2 = 16777088;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
this.rect(i1, 14 + 19 * l, 108, 19, 0x20ff20);
|
||||
// }
|
||||
|
||||
this.rect(i1 + 1, 15 + 19 * l, 16, 16, 0x008000);
|
||||
this.drawString(s, j1, 16 + 19 * l);
|
||||
i2 = 8453920;
|
||||
}
|
||||
|
||||
this.drawString(s1, j1 + 86 - this.getStringWidth(s1), 16 + 19 * l + 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it. Args : mouseX, mouseY, renderPartialTicks
|
||||
*/
|
||||
public void drawScreen(int mouseX, int mouseY)
|
||||
{
|
||||
super.drawScreen(mouseX, mouseY);
|
||||
// boolean flag = this.gm.thePlayer.creative;
|
||||
// int i = this.container.getLapisAmount();
|
||||
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
int k = this.container.enchantLevels[j];
|
||||
int l = this.container.enchantmentIds[j];
|
||||
int i1 = j + 1;
|
||||
|
||||
if (this.isPointInRegion(60, 14 + 19 * j, 108, 17, mouseX, mouseY) && k > 0 && l >= 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (l >= 0 && Enchantment.getEnchantmentById(l & 255) != null)
|
||||
{
|
||||
String s = Enchantment.getEnchantmentById(l & 255).getFormattedName((l & 65280) >> 8);
|
||||
sb.append(TextColor.WHITE + s + " . . . ?");
|
||||
}
|
||||
|
||||
// if (!flag)
|
||||
// {
|
||||
// if (l >= 0 && sb.length() != 0)
|
||||
// {
|
||||
// sb.append("\n");
|
||||
// }
|
||||
|
||||
if (this.gm.player.experienceLevel < k)
|
||||
{
|
||||
sb.append((sb.length() != 0 ? "\n" : "") + TextColor.RED + String.format("Erfahrungsstufe %d erforderlich", this.container.enchantLevels[j]));
|
||||
}
|
||||
else
|
||||
{
|
||||
String s1 = "";
|
||||
|
||||
// if (i1 == 1)
|
||||
// {
|
||||
// s1 = I18n.format("container.enchant.lapis.one");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// s1 = I18n.format("container.enchant.lapis.many", i1);
|
||||
// }
|
||||
//
|
||||
// if (i >= i1)
|
||||
// {
|
||||
// list.add(ChatFormat.GRAY.toString() + "" + s1);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// list.add(ChatFormat.RED.toString() + "" + s1);
|
||||
// }
|
||||
|
||||
if (i1 == 1)
|
||||
{
|
||||
s1 = "1 Erfahrungsstufe";
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = String.format("%d Erfahrungsstufen", i1);
|
||||
}
|
||||
|
||||
sb.append((sb.length() != 0 ? "\n" : "") + TextColor.LGRAY.toString() + "" + s1);
|
||||
}
|
||||
// }
|
||||
|
||||
this.hover(sb.toString(), mouseX, mouseY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getRandomName()
|
||||
{
|
||||
int i = this.nameRand.zrange(2) + 3;
|
||||
String s = "";
|
||||
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
s = s + " ";
|
||||
}
|
||||
|
||||
String name = NAMES[this.nameRand.zrange(NAMES.length)];
|
||||
for(int z = 0; z < name.length(); z++) {
|
||||
s += (char)(name.charAt(z) - 0x61 + 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// private void updateAnimation()
|
||||
// {
|
||||
// ItemStack itemstack = this.inventorySlots.getSlot(0).getStack();
|
||||
//
|
||||
// if (!ItemStack.areItemStacksEqual(itemstack, this.field_147077_B))
|
||||
// {
|
||||
// this.field_147077_B = itemstack;
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// this.field_147082_x += (float)(this.random.zrange(4) - this.random.zrange(4));
|
||||
//
|
||||
// if (this.field_147071_v > this.field_147082_x + 1.0F || this.field_147071_v < this.field_147082_x - 1.0F)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ++this.field_147073_u;
|
||||
// this.field_147069_w = this.field_147071_v;
|
||||
// this.field_147076_A = this.field_147080_z;
|
||||
// boolean flag = false;
|
||||
//
|
||||
// for (int i = 0; i < 3; ++i)
|
||||
// {
|
||||
// if (this.container.enchantLevels[i] != 0)
|
||||
// {
|
||||
// flag = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (flag)
|
||||
// {
|
||||
// this.field_147080_z += 0.2F;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.field_147080_z -= 0.2F;
|
||||
// }
|
||||
//
|
||||
// this.field_147080_z = ExtMath.clampf(this.field_147080_z, 0.0F, 1.0F);
|
||||
// float f1 = (this.field_147082_x - this.field_147071_v) * 0.4F;
|
||||
// float f = 0.2F;
|
||||
// f1 = ExtMath.clampf(f1, -f, f);
|
||||
// this.field_147081_y += (f1 - this.field_147081_y) * 0.9F;
|
||||
// this.field_147071_v += this.field_147081_y;
|
||||
// }
|
||||
}
|
71
client/src/main/java/client/gui/container/GuiFurnace.java
Executable file
71
client/src/main/java/client/gui/container/GuiFurnace.java
Executable file
|
@ -0,0 +1,71 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.inventory.ContainerFurnace;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.tileentity.TileEntityFurnace;
|
||||
|
||||
|
||||
public class GuiFurnace extends GuiContainer
|
||||
{
|
||||
// private static final String furnaceGuiTextures = "textures/gui/furnace.png";
|
||||
|
||||
/** The player inventory bound to this GUI. */
|
||||
private final InventoryPlayer playerInventory;
|
||||
private IInventory tileFurnace;
|
||||
|
||||
public GuiFurnace(InventoryPlayer playerInv, IInventory furnaceInv)
|
||||
{
|
||||
super(new ContainerFurnace(playerInv, furnaceInv));
|
||||
this.playerInventory = playerInv;
|
||||
this.tileFurnace = furnaceInv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
String s = this.tileFurnace.getCommandName();
|
||||
this.drawString(s, 8, 6);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Args : renderPartialTicks, mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerBackgroundLayer()
|
||||
{
|
||||
this.rect(58, 36, 12, 14, 0x202020);
|
||||
if (TileEntityFurnace.isBurning(this.tileFurnace))
|
||||
{
|
||||
int k = this.getBurnLeftScaled(13);
|
||||
k = Math.min(k, 13);
|
||||
this.rect(58, 36 + 13 - k, 12, k + 1, 0xff7f00);
|
||||
}
|
||||
|
||||
int l = this.getCookProgressScaled(24);
|
||||
this.rect(79, 39, 24, 8, 0x606060);
|
||||
if(l > 0)
|
||||
this.rect(79, 39, l + 1, 8, 0xffaf00);
|
||||
}
|
||||
|
||||
private int getCookProgressScaled(int pixels)
|
||||
{
|
||||
int i = this.tileFurnace.getField(2);
|
||||
int j = this.tileFurnace.getField(3);
|
||||
return j != 0 && i != 0 ? i * pixels / j : 0;
|
||||
}
|
||||
|
||||
private int getBurnLeftScaled(int pixels)
|
||||
{
|
||||
int i = this.tileFurnace.getField(1);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
i = 200;
|
||||
}
|
||||
|
||||
return this.tileFurnace.getField(0) * pixels / i;
|
||||
}
|
||||
}
|
49
client/src/main/java/client/gui/container/GuiHopper.java
Executable file
49
client/src/main/java/client/gui/container/GuiHopper.java
Executable file
|
@ -0,0 +1,49 @@
|
|||
package client.gui.container;
|
||||
|
||||
import client.Client;
|
||||
import common.inventory.ContainerHopper;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
|
||||
|
||||
public class GuiHopper extends GuiContainer
|
||||
{
|
||||
// /** The ResourceLocation containing the gui texture for the hopper */
|
||||
// private static final String HOPPER_GUI_TEXTURE = "textures/gui/hopper.png";
|
||||
|
||||
/** The player inventory currently bound to this GUI instance */
|
||||
private IInventory playerInventory;
|
||||
|
||||
/** The hopper inventory bound to this GUI instance */
|
||||
private IInventory hopperInventory;
|
||||
|
||||
public GuiHopper(InventoryPlayer playerInv, IInventory hopperInv)
|
||||
{
|
||||
super(new ContainerHopper(playerInv, hopperInv, Client.CLIENT.player));
|
||||
this.playerInventory = playerInv;
|
||||
this.hopperInventory = hopperInv;
|
||||
// this.allowUserInput = false;
|
||||
this.ySize = 133;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString(this.hopperInventory.getCommandName(), 8, 6);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Args : renderPartialTicks, mouseX, mouseY
|
||||
// */
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(HOPPER_GUI_TEXTURE);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
// }
|
||||
}
|
79
client/src/main/java/client/gui/container/GuiHorse.java
Executable file
79
client/src/main/java/client/gui/container/GuiHorse.java
Executable file
|
@ -0,0 +1,79 @@
|
|||
package client.gui.container;
|
||||
|
||||
import client.Client;
|
||||
import common.entity.animal.EntityHorse;
|
||||
import common.inventory.ContainerHorseInventory;
|
||||
import common.inventory.IInventory;
|
||||
|
||||
|
||||
public class GuiHorse extends GuiContainer
|
||||
{
|
||||
// private static final String horseGuiTextures = "textures/gui/horse.png";
|
||||
|
||||
/** The player inventory bound to this GUI. */
|
||||
private IInventory playerInventory;
|
||||
|
||||
/** The horse inventory bound to this GUI. */
|
||||
private IInventory horseInventory;
|
||||
|
||||
// /** The EntityHorse whose inventory is currently being accessed. */
|
||||
// private EntityHorse horseEntity;
|
||||
|
||||
// /** The mouse x-position recorded during the last rendered frame. */
|
||||
// private float mousePosx;
|
||||
//
|
||||
// /** The mouse y-position recorded during the last renderered frame. */
|
||||
// private float mousePosY;
|
||||
|
||||
public GuiHorse(IInventory playerInv, IInventory horseInv, EntityHorse horse)
|
||||
{
|
||||
super(new ContainerHorseInventory(playerInv, horseInv, horse, Client.CLIENT.player));
|
||||
this.playerInventory = playerInv;
|
||||
this.horseInventory = horseInv;
|
||||
// this.horseEntity = horse;
|
||||
// this.allowUserInput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString(this.horseInventory.getCommandName(), 8, 6);
|
||||
this.drawString(this.playerInventory.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Args : renderPartialTicks, mouseX, mouseY
|
||||
// */
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(horseGuiTextures);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
//
|
||||
//// if (this.horseEntity.isChested())
|
||||
//// {
|
||||
//// this.rect(i + 79, j + 17, 0, this.ySize, 90, 54);
|
||||
//// }
|
||||
//
|
||||
//// if (this.horseEntity.canWearArmor())
|
||||
//// {
|
||||
//// this.rect(i + 7, j + 35, 0, this.ySize + 54, 18, 18);
|
||||
//// }
|
||||
//
|
||||
//// GuiInventory.drawEntityOnScreen(i + 51, j + 60, 17, (float)(i + 51) - this.mousePosx, (float)(j + 75 - 50) - this.mousePosY, this.horseEntity);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Draws the screen and all the components in it. Args : mouseX, mouseY, renderPartialTicks
|
||||
// */
|
||||
// public void drawScreen(int mouseX, int mouseY)
|
||||
// {
|
||||
// this.mousePosx = (float)mouseX;
|
||||
// this.mousePosY = (float)mouseY;
|
||||
// super.drawScreen(mouseX, mouseY);
|
||||
// }
|
||||
}
|
58
client/src/main/java/client/gui/container/GuiInventory.java
Executable file
58
client/src/main/java/client/gui/container/GuiInventory.java
Executable file
|
@ -0,0 +1,58 @@
|
|||
package client.gui.container;
|
||||
|
||||
import common.entity.npc.EntityNPC;
|
||||
|
||||
public class GuiInventory extends GuiContainer
|
||||
{
|
||||
// private final GuiCheat cheat;
|
||||
// private float oldMouseX;
|
||||
// private float oldMouseY;
|
||||
|
||||
public GuiInventory(EntityNPC player)
|
||||
{
|
||||
super(player.inventoryContainer);
|
||||
// this.allowUserInput = true;
|
||||
// this.cheat = cheat;
|
||||
}
|
||||
|
||||
// public void updateScreen()
|
||||
// {
|
||||
// this.updateActivePotionEffects();
|
||||
// }
|
||||
|
||||
// public void initGui()
|
||||
// {
|
||||
//// this.buttonList.clear();
|
||||
// super.initGui();
|
||||
// if(this.cheat != null)
|
||||
// this.buttonList.add(new Button(1, this.guiLeft + this.xSize - 16, this.guiTop + 4, 12, 12, "X"));
|
||||
// }
|
||||
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString("Handwerk", 86, 16);
|
||||
}
|
||||
|
||||
// public void drawScreen(int mouseX, int mouseY, float partialTicks)
|
||||
// {
|
||||
// super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
// this.oldMouseX = (float)mouseX;
|
||||
// this.oldMouseY = (float)mouseY;
|
||||
// }
|
||||
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(inventoryBackground);
|
||||
// int i = this.guiLeft;
|
||||
// int j = this.guiTop;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
//// drawEntityOnScreen(i + 51, j + 75, 30, (float)(i + 51) - this.oldMouseX, (float)(j + 75 - 50) - this.oldMouseY, this.gm.thePlayer);
|
||||
// }
|
||||
|
||||
// public void actionPerformed(int button)
|
||||
// {
|
||||
// if(button == 1 && this.cheat != null && this.gm.thePlayer.inventory.getItemStack() == null)
|
||||
// this.gm.displayGuiScreen(this.cheat);
|
||||
// }
|
||||
}
|
44
client/src/main/java/client/gui/container/GuiMachine.java
Executable file
44
client/src/main/java/client/gui/container/GuiMachine.java
Executable file
|
@ -0,0 +1,44 @@
|
|||
package client.gui.container;
|
||||
|
||||
import client.Client;
|
||||
import common.inventory.ContainerMachine;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.tileentity.TileEntityMachine;
|
||||
|
||||
|
||||
public class GuiMachine extends GuiContainer
|
||||
{
|
||||
// private final String texture;
|
||||
private final IInventory playerInv;
|
||||
private final IInventory machineInv;
|
||||
private final TileEntityMachine machine;
|
||||
|
||||
public GuiMachine(InventoryPlayer player, IInventory inv, TileEntityMachine machine)
|
||||
{
|
||||
super(new ContainerMachine(player, machine, inv, Client.CLIENT.player));
|
||||
this.playerInv = player;
|
||||
this.machineInv = machine;
|
||||
// this.allowUserInput = false;
|
||||
this.ySize = 153;
|
||||
// this.texture = "textures/gui/" + texture + ".png";
|
||||
this.machine = machine;
|
||||
}
|
||||
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
this.drawString(this.machine.getStatus().color + this.machineInv.getCommandName() + " - " + this.machine.getStatus().name, 8, 6);
|
||||
this.drawString(this.playerInv.getCommandName(), 8, this.ySize - 96 + 2);
|
||||
this.drawString(String.format("Temperatur: %d °", this.machine.getTemperature()), 8, 18);
|
||||
this.drawString(this.machine.formatDisplay(), 8, 28);
|
||||
}
|
||||
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(this.texture);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
// }
|
||||
}
|
287
client/src/main/java/client/gui/container/GuiMerchant.java
Executable file
287
client/src/main/java/client/gui/container/GuiMerchant.java
Executable file
|
@ -0,0 +1,287 @@
|
|||
package client.gui.container;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import client.renderer.GlState;
|
||||
import client.renderer.ItemRenderer;
|
||||
import common.inventory.ContainerMerchant;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.item.ItemStack;
|
||||
import common.packet.CPacketAction;
|
||||
import common.village.MerchantRecipe;
|
||||
import common.village.MerchantRecipeList;
|
||||
import common.world.World;
|
||||
|
||||
public class GuiMerchant extends GuiContainer
|
||||
{
|
||||
// private static final String MERCHANT_GUI_TEXTURE = "textures/gui/trading.png";
|
||||
|
||||
private int selectedMerchantRecipe;
|
||||
private String chatComponent;
|
||||
|
||||
public GuiMerchant(InventoryPlayer inv, String name, World worldIn)
|
||||
{
|
||||
super(new ContainerMerchant(inv, null, worldIn));
|
||||
this.chatComponent = name != null ? name : "NSC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question. Called when the GUI is displayed and when the
|
||||
* window resizes, the buttonList is cleared beforehand.
|
||||
*/
|
||||
// public void initGui()
|
||||
// {
|
||||
// super.initGui();
|
||||
// }
|
||||
|
||||
public void addButtons() {
|
||||
super.addButtons();
|
||||
this.button(120 + 27, 24, 12, 16);
|
||||
this.button(36 - 19, 24, 12, 16);
|
||||
this.button(36 - 1, 24 - 1, 18, 18);
|
||||
this.button(62 - 1, 24 - 1, 18, 18);
|
||||
this.button(120 - 1, 24 - 1, 18, 18);
|
||||
}
|
||||
|
||||
public void mouseClicked(int mouseX, int mouseY, int mouseButton)
|
||||
{
|
||||
if (mouseButton == 0)
|
||||
{
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
if(mouseX >= 147 && mouseX < 147 + 12 && mouseY >= 24 && mouseY < 24 + 16) {
|
||||
this.switchTrade(true);
|
||||
return;
|
||||
}
|
||||
else if(mouseX >= 17 && mouseX < 17 + 12 && mouseY >= 24 && mouseY < 24 + 16) {
|
||||
this.switchTrade(false);
|
||||
return;
|
||||
}
|
||||
// this.buttonList.add(new Button(1, i + 120 + 27, j + 24 - 1, 12, 19, ">"));
|
||||
// this.buttonList.add(new Button(2, i + 36 - 19, j + 24 - 1, 12, 19, "<"));
|
||||
|
||||
}
|
||||
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
String s = this.chatComponent;
|
||||
this.drawString(s, 8, 6);
|
||||
this.drawString("Inventar", 8, this.ySize - 96 + 2);
|
||||
}
|
||||
|
||||
public void drawOverlays() {
|
||||
super.drawOverlays();
|
||||
MerchantRecipeList merchantrecipelist = this.getRecipes();
|
||||
if (merchantrecipelist != null && !merchantrecipelist.isEmpty()) {
|
||||
int k = this.selectedMerchantRecipe;
|
||||
MerchantRecipe merchantrecipe = (MerchantRecipe)merchantrecipelist.get(k);
|
||||
ItemStack itemstack = merchantrecipe.getItemToBuy();
|
||||
ItemStack itemstack1 = merchantrecipe.getSecondItemToBuy();
|
||||
ItemStack itemstack2 = merchantrecipe.getItemToSell();
|
||||
this.renderItemOverlayIntoGUI(itemstack, 36, 24, null);
|
||||
if(itemstack1 != null)
|
||||
this.renderItemOverlayIntoGUI(itemstack1, 62, 24, null);
|
||||
this.renderItemOverlayIntoGUI(itemstack2, 120, 24, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the controls from the buttonList when activated. (Mouse pressed for buttons)
|
||||
*/
|
||||
public void switchTrade(boolean forward)
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
if (forward)
|
||||
{
|
||||
++this.selectedMerchantRecipe;
|
||||
MerchantRecipeList merchantrecipelist = this.getRecipes();
|
||||
|
||||
if (merchantrecipelist != null && this.selectedMerchantRecipe >= merchantrecipelist.size())
|
||||
{
|
||||
this.selectedMerchantRecipe = merchantrecipelist.size() - 1;
|
||||
}
|
||||
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
--this.selectedMerchantRecipe;
|
||||
|
||||
if (this.selectedMerchantRecipe < 0)
|
||||
{
|
||||
this.selectedMerchantRecipe = 0;
|
||||
}
|
||||
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
((ContainerMerchant)this.inventorySlots).setCurrentRecipeIndex(this.selectedMerchantRecipe);
|
||||
// PacketBuffer packetbuffer = new PacketBuffer(Unpooled.buffer());
|
||||
// packetbuffer.writeInt(this.selectedMerchantRecipe);
|
||||
this.gm.getNetHandler().addToSendQueue(new CPacketAction(CPacketAction.Action.SELECT_TRADE,
|
||||
this.selectedMerchantRecipe));
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Args : renderPartialTicks, mouseX, mouseY
|
||||
// */
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(MERCHANT_GUI_TEXTURE);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
//// MerchantRecipeList merchantrecipelist = this.merchant.getRecipes(this.gm.thePlayer);
|
||||
//
|
||||
//// if (merchantrecipelist != null && !merchantrecipelist.isEmpty())
|
||||
//// {
|
||||
//// int k = this.selectedMerchantRecipe;
|
||||
////
|
||||
//// if (k < 0 || k >= merchantrecipelist.size())
|
||||
//// {
|
||||
//// return;
|
||||
//// }
|
||||
//
|
||||
//// MerchantRecipe merchantrecipe = (MerchantRecipe)merchantrecipelist.get(k);
|
||||
//
|
||||
//// if (merchantrecipe.isRecipeDisabled())
|
||||
//// {
|
||||
//// this.gm.getTextureManager().bindTexture(MERCHANT_GUI_TEXTURE);
|
||||
//// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
//// GlState.disableLighting();
|
||||
//// this.rect(this.guiLeft + 83, this.guiTop + 21, 212, 0, 28, 21);
|
||||
//// this.rect(this.guiLeft + 83, this.guiTop + 51, 212, 0, 28, 21);
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it. Args : mouseX, mouseY, renderPartialTicks
|
||||
*/
|
||||
public void drawScreen(int mouseX, int mouseY)
|
||||
{
|
||||
super.drawScreen(mouseX, mouseY);
|
||||
MerchantRecipeList merchantrecipelist = this.getRecipes();
|
||||
|
||||
if (merchantrecipelist != null && !merchantrecipelist.isEmpty())
|
||||
{
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
int k = this.selectedMerchantRecipe;
|
||||
MerchantRecipe merchantrecipe = (MerchantRecipe)merchantrecipelist.get(k);
|
||||
ItemStack itemstack = merchantrecipe.getItemToBuy();
|
||||
ItemStack itemstack1 = merchantrecipe.getSecondItemToBuy();
|
||||
ItemStack itemstack2 = merchantrecipe.getItemToSell();
|
||||
GL11.glPushMatrix();
|
||||
ItemRenderer.enableGUIStandardItemLighting();
|
||||
GlState.disableLighting();
|
||||
GlState.enableRescaleNormal();
|
||||
GlState.enableColorMaterial();
|
||||
GlState.enableLighting();
|
||||
this.itemRender.zLevel = 100.0F;
|
||||
this.itemRender.renderItemAndEffectIntoGUI(itemstack, 36, 24);
|
||||
// this.itemRender.renderItemOverlays(itemstack, 36, 24);
|
||||
|
||||
if (itemstack1 != null)
|
||||
{
|
||||
this.itemRender.renderItemAndEffectIntoGUI(itemstack1, 62, 24);
|
||||
// this.itemRender.renderItemOverlays(itemstack1, 62, 24);
|
||||
}
|
||||
|
||||
this.itemRender.renderItemAndEffectIntoGUI(itemstack2, 120, 24);
|
||||
// this.itemRender.renderItemOverlays(itemstack2, 120, 24);
|
||||
this.itemRender.zLevel = 0.0F;
|
||||
GlState.disableLighting();
|
||||
|
||||
if (this.isPointInRegion(36, 24, 16, 16, mouseX, mouseY) && itemstack != null)
|
||||
{
|
||||
this.renderToolTip(itemstack, mouseX, mouseY);
|
||||
}
|
||||
else if (itemstack1 != null && this.isPointInRegion(62, 24, 16, 16, mouseX, mouseY) && itemstack1 != null)
|
||||
{
|
||||
this.renderToolTip(itemstack1, mouseX, mouseY);
|
||||
}
|
||||
else if (itemstack2 != null && this.isPointInRegion(120, 24, 16, 16, mouseX, mouseY) && itemstack2 != null)
|
||||
{
|
||||
this.renderToolTip(itemstack2, mouseX, mouseY);
|
||||
}
|
||||
// else if (merchantrecipe.isRecipeDisabled() && (this.isPointInRegion(83, 21, 28, 21, mouseX, mouseY) || this.isPointInRegion(83, 51, 28, 21, mouseX, mouseY)))
|
||||
// {
|
||||
// this.drawCreativeTabHoveringText(I18n.format("merchant.deprecated"), mouseX, mouseY);
|
||||
// }
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GlState.enableLighting();
|
||||
GlState.enableDepth();
|
||||
ItemRenderer.enableStandardItemLighting();
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
// if(mouseX >= i + 147 && mouseX < i + 147 + 12 && mouseY >= j + 23 && mouseX < j + 23 + 19) {
|
||||
// SKC.highlight(i + 147, j + 23, 12, 19);
|
||||
// }
|
||||
// else if(mouseX >= i + 17 && mouseX < i + 17 + 12 && mouseY >= j + 23 && mouseX < j + 23 + 19) {
|
||||
// SKC.highlight(i + 17, j + 23, 12, 19);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
public void setRecipes(MerchantRecipeList recipes)
|
||||
{
|
||||
((ContainerMerchant)this.inventorySlots).getMerchantInventory().setRecipes(recipes);
|
||||
}
|
||||
|
||||
private MerchantRecipeList getRecipes()
|
||||
{
|
||||
return ((ContainerMerchant)this.inventorySlots).getMerchantInventory().getRecipes();
|
||||
}
|
||||
|
||||
// static class MerchantButton extends Button
|
||||
// {
|
||||
// private final boolean next;
|
||||
//
|
||||
// public MerchantButton(int buttonID, int x, int y, boolean isNext)
|
||||
// {
|
||||
// super(buttonID, x, y, 12, 19, "");
|
||||
// this.next = isNext;
|
||||
// }
|
||||
//
|
||||
// public void drawButton(Game gm, int mouseX, int mouseY)
|
||||
// {
|
||||
// if (this.visible)
|
||||
// {
|
||||
// gm.getTextureManager().bindTexture(GuiMerchant.MERCHANT_GUI_TEXTURE);
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// boolean flag = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height;
|
||||
// int i = 0;
|
||||
// int j = 176;
|
||||
//
|
||||
// if (!this.enabled)
|
||||
// {
|
||||
// j += this.width * 2;
|
||||
// }
|
||||
// else if (flag)
|
||||
// {
|
||||
// j += this.width;
|
||||
// }
|
||||
//
|
||||
// if (!this.next)
|
||||
// {
|
||||
// i += this.height;
|
||||
// }
|
||||
//
|
||||
// this.rect(this.xPosition, this.yPosition, j, i, this.width, this.height);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
218
client/src/main/java/client/gui/container/GuiRepair.java
Executable file
218
client/src/main/java/client/gui/container/GuiRepair.java
Executable file
|
@ -0,0 +1,218 @@
|
|||
package client.gui.container;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import client.Client;
|
||||
import common.inventory.Container;
|
||||
import common.inventory.ContainerRepair;
|
||||
import common.inventory.ICrafting;
|
||||
import common.inventory.IInventory;
|
||||
import common.inventory.InventoryPlayer;
|
||||
import common.item.ItemStack;
|
||||
import common.world.World;
|
||||
|
||||
public class GuiRepair extends GuiContainer implements ICrafting
|
||||
{
|
||||
// private static final String anvilResource = "textures/gui/anvil.png";
|
||||
|
||||
private ContainerRepair anvil;
|
||||
// private TextField nameField;
|
||||
private InventoryPlayer playerInventory;
|
||||
|
||||
public GuiRepair(InventoryPlayer inventoryIn, World worldIn)
|
||||
{
|
||||
super(new ContainerRepair(inventoryIn, worldIn, Client.CLIENT.player));
|
||||
this.playerInventory = inventoryIn;
|
||||
this.anvil = (ContainerRepair)this.inventorySlots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question. Called when the GUI is displayed and when the
|
||||
* window resizes, the buttonList is cleared beforehand.
|
||||
*/
|
||||
public void initGui()
|
||||
{
|
||||
super.initGui();
|
||||
// Keyboard.enableRepeatEvents(true);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
// this.nameField = new TextField(i + 62, j + 24, 103, 12);
|
||||
// this.nameField.setTextColor(-1);
|
||||
// this.nameField.setDisabledTextColour(-1);
|
||||
// this.nameField.setEnableBackgroundDrawing(false);
|
||||
// this.nameField.setMaxStringLength(30);
|
||||
this.inventorySlots.removeCraftingFromCrafters(this);
|
||||
this.inventorySlots.onCraftGuiOpened(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the screen is unloaded. Used to disable keyboard repeat events
|
||||
*/
|
||||
public void onGuiClosed()
|
||||
{
|
||||
super.onGuiClosed();
|
||||
// Keyboard.enableRepeatEvents(false);
|
||||
this.inventorySlots.removeCraftingFromCrafters(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the foreground layer for the GuiContainer (everything in front of the items). Args : mouseX, mouseY
|
||||
*/
|
||||
public void drawGuiContainerForegroundLayer()
|
||||
{
|
||||
// GlState.disableLighting();
|
||||
// GlState.disableBlend();
|
||||
this.drawString("Amboss", 60, 6);
|
||||
|
||||
if (this.anvil.maximumCost > 0)
|
||||
{
|
||||
int i = 8453920;
|
||||
boolean flag = true;
|
||||
String s = String.format("Erfahrungskosten: %d", this.anvil.maximumCost);
|
||||
|
||||
if (this.anvil.maximumCost >= 40) // && !this.gm.thePlayer.creative)
|
||||
{
|
||||
s = "Zu teuer!";
|
||||
i = 16736352;
|
||||
}
|
||||
else if (!this.anvil.getSlot(2).getHasStack())
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
else if (!this.anvil.getSlot(2).canTakeStack(this.playerInventory.player))
|
||||
{
|
||||
i = 16736352;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
int j = -16777216 | (i & 16579836) >> 2 | i & -16777216;
|
||||
int k = this.xSize - 8 - this.getStringWidth(s);
|
||||
int l = 67;
|
||||
|
||||
// if (FontRenderer.getUnicodeFlag())
|
||||
// {
|
||||
// drawRect(k - 3, l - 2, this.xSize - 7, l + 10, -16777216);
|
||||
// drawRect(k - 2, l - 1, this.xSize - 8, l + 9, -12895429);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
this.drawString(s, k, l + 1);
|
||||
this.drawString(s, k + 1, l);
|
||||
this.drawString(s, k + 1, l + 1);
|
||||
// }
|
||||
|
||||
this.drawString(s, k, l);
|
||||
}
|
||||
}
|
||||
|
||||
// GlState.enableLighting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a key is typed (except F11 which toggles full screen). This is the equivalent of
|
||||
* KeyListener.keyTyped(KeyEvent e). Args : character (character on the key), keyCode (lwjgl Keyboard key code)
|
||||
*/
|
||||
// protected void keyTyped(char typedChar, int keyCode)
|
||||
// {
|
||||
// if (this.nameField.textboxKeyTyped(typedChar, keyCode))
|
||||
//// {
|
||||
// this.renameItem();
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// super.keyTyped(typedChar, keyCode);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// private void renameItem()
|
||||
// {
|
||||
// String s = this.nameField.getText();
|
||||
// Slot slot = this.anvil.getSlot(0);
|
||||
//
|
||||
// if (slot != null && slot.getHasStack() && !slot.getStack().hasDisplayName() && s.equals(slot.getStack().getDisplayName()))
|
||||
// {
|
||||
// s = "";
|
||||
// }
|
||||
//
|
||||
// this.anvil.updateItemName(s);
|
||||
// this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketMessage(CPacketMessage.Type.ITEM, s));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton
|
||||
// */
|
||||
// protected void mouseClicked(int mouseX, int mouseY, int mouseButton)
|
||||
// {
|
||||
// super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
// this.nameField.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it. Args : mouseX, mouseY, renderPartialTicks
|
||||
*/
|
||||
// public void drawScreen(int mouseX, int mouseY, float partialTicks)
|
||||
// {
|
||||
// super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
// GlState.disableLighting();
|
||||
// GlState.disableBlend();
|
||||
// this.nameField.drawTextBox();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Args : renderPartialTicks, mouseX, mouseY
|
||||
// */
|
||||
// protected void drawGuiContainerBackgroundLayer(int mouseX, int mouseY)
|
||||
// {
|
||||
// GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
// this.gm.getTextureManager().bindTexture(anvilResource);
|
||||
// int i = (this.width - this.xSize) / 2;
|
||||
// int j = (this.height - this.ySize) / 2;
|
||||
//// this.rect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
//// this.rect(i + 59, j + 20, 0, this.ySize + (this.anvil.getSlot(0).getHasStack() ? 0 : 16), 110, 16);
|
||||
//
|
||||
//// if ((this.anvil.getSlot(0).getHasStack() || this.anvil.getSlot(1).getHasStack()) && !this.anvil.getSlot(2).getHasStack())
|
||||
//// {
|
||||
//// this.rect(i + 99, j + 45, this.xSize, 0, 28, 21);
|
||||
//// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* update the crafting window inventory with the items in the list
|
||||
*/
|
||||
public void updateCraftingInventory(Container containerToSend, List<ItemStack> itemsList)
|
||||
{
|
||||
this.sendSlotContents(containerToSend, 0, containerToSend.getSlot(0).getStack());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the contents of an inventory slot to the client-side Container. This doesn't have to match the actual
|
||||
* contents of that slot. Args: Container, slot number, slot contents
|
||||
*/
|
||||
public void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack)
|
||||
{
|
||||
// if (slotInd == 0)
|
||||
// {
|
||||
// this.nameField.setText(stack == null ? "" : stack.getDisplayName());
|
||||
// this.nameField.setEnabled(stack != null);
|
||||
//
|
||||
// if (stack != null)
|
||||
// {
|
||||
// this.renameItem();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends two ints to the client-side Container. Used for furnace burning time, smelting progress, brewing progress,
|
||||
* and enchanting level. Normally the first int identifies which variable to update, and the second contains the new
|
||||
* value. Both are truncated to shorts in non-local SMP.
|
||||
*/
|
||||
public void sendProgressBarUpdate(Container containerIn, int varToUpdate, int newValue)
|
||||
{
|
||||
}
|
||||
|
||||
public void sendAllWindowProperties(Container p_175173_1_, IInventory p_175173_2_)
|
||||
{
|
||||
}
|
||||
}
|
26
client/src/main/java/client/gui/element/ActButton.java
Normal file
26
client/src/main/java/client/gui/element/ActButton.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Formatter;
|
||||
import client.window.Button;
|
||||
|
||||
public class ActButton extends Element {
|
||||
private final ButtonCallback func;
|
||||
|
||||
public ActButton(int x, int y, int w, int h, ButtonCallback callback, Formatter<ActButton> formatter) {
|
||||
super(x, y, w, h, formatter);
|
||||
this.func = callback;
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public ActButton(int x, int y, int w, int h, ButtonCallback callback, String text) {
|
||||
super(x, y, w, h, null);
|
||||
this.func = callback;
|
||||
this.setText(text);
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
this.func.use(this, (ctrl || (btn == Button.MOUSE_MIDDLE)) ? PressType.TERTIARY : ((shift || (btn == Button.MOUSE_RIGHT)) ? PressType.SECONDARY : PressType.PRIMARY));
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
159
client/src/main/java/client/gui/element/Area.java
Normal file
159
client/src/main/java/client/gui/element/Area.java
Normal file
|
@ -0,0 +1,159 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Font;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.Drawing.Offset;
|
||||
import client.renderer.Drawing.Vec2i;
|
||||
import common.util.CharValidator;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Util;
|
||||
|
||||
public class Area extends Textbox {
|
||||
private int textHeight;
|
||||
private int scrollPos;
|
||||
private int cursorX;
|
||||
private int cursorY;
|
||||
|
||||
private Area(int x, int y, int w, int h, int cap, boolean editable, CharValidator validator, String text) {
|
||||
super(x, y, w, h, cap, editable, null, validator);
|
||||
this.setText(text);
|
||||
}
|
||||
|
||||
public Area(int x, int y, int w, int h, int cap, CharValidator validator, String text) {
|
||||
this(x, y, w, h, cap, true, validator, text);
|
||||
}
|
||||
|
||||
public Area(int x, int y, int w, int h, int cap, String text) {
|
||||
this(x, y, w, h, cap, true, null, text);
|
||||
}
|
||||
|
||||
public Area(int x, int y, int w, int h, String text) {
|
||||
this(x, y, w, h, Integer.MAX_VALUE, false, null, text);
|
||||
}
|
||||
|
||||
public void updateText() {
|
||||
this.textHeight = Drawing.txt_size(this.pos_x + this.margin_x1, this.pos_y + this.margin_y1,
|
||||
this.pos_x + this.margin_x1, this.pos_y + this.margin_y1,
|
||||
this.pos_x + (this.size_x - (this.margin_x1 + this.margin_x2)), Integer.MAX_VALUE, this.text).ypos;
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
if(scr_y != 0) {
|
||||
int limit = Font.YGLYPH + this.textHeight - (this.size_y - (this.margin_y1 + this.margin_y2));
|
||||
limit = ExtMath.clampi(limit, 0, 0x7fffffff);
|
||||
int prev = this.text_y;
|
||||
this.text_y += (scr_y < 0 ? -1 : 1) * (ctrl ? 1 : Font.YGLYPH) * this.gm.scrollLines * (shift ? 10 : 1);
|
||||
this.text_y = ExtMath.clampi(this.text_y, -limit, 0);
|
||||
if(this.sel_start >= 0)
|
||||
this.cursorY += (this.text_y - prev);
|
||||
}
|
||||
}
|
||||
|
||||
public void mouserel() {
|
||||
this.scrollPos = 0;
|
||||
}
|
||||
|
||||
public void onReturn(boolean shift) {
|
||||
insertText("\n");
|
||||
}
|
||||
|
||||
public void onSelection(boolean up) {
|
||||
if(!up && this.sel_start != this.sel_end) {
|
||||
this.sel_start = this.sel_drag = this.sel_end;
|
||||
}
|
||||
else if(up && this.sel_start != this.sel_end) {
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
}
|
||||
if(!up && this.sel_start >= 0) {
|
||||
if(this.sel_end < this.text.length()) {
|
||||
int nl = this.text.indexOf('\n', this.sel_end);
|
||||
this.sel_end = nl >= 0 ? nl + 1 : this.text.length();
|
||||
this.sel_start = this.sel_drag = this.sel_end;
|
||||
}
|
||||
else {
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
}
|
||||
gui_text_update_cur(this.sel_end, true);
|
||||
}
|
||||
else if(up && this.sel_start >= 0) {
|
||||
if(this.sel_start > 0) {
|
||||
int nl = this.text.lastIndexOf('\n', this.sel_start);
|
||||
this.sel_start = nl >= 0 ? nl : 0;
|
||||
}
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
gui_text_update_cur(this.sel_end, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(this.scrollPos != 0) {
|
||||
int n = this.updateScroll(this.scrollPos);
|
||||
this.text_y += n;
|
||||
if(n != 0)
|
||||
gui_text_clamp_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
public void shift(int shift_x, int shift_y) {
|
||||
super.shift(shift_x, shift_y);
|
||||
this.cursorX += shift_x;
|
||||
this.cursorY += shift_y;
|
||||
}
|
||||
|
||||
protected void gui_text_clamp_scroll() {
|
||||
int limit = Font.YGLYPH + this.textHeight - (this.size_y - (this.margin_y1 + this.margin_y2));
|
||||
limit = ExtMath.clampi(limit, 0, 0x7fffffff);
|
||||
this.text_y = ExtMath.clampi(this.text_y, -limit, 0);
|
||||
}
|
||||
|
||||
protected void updateCursor(int offset, boolean shift, int x1, int y1, int x2, int y2) {
|
||||
Vec2i coord = Drawing.txt_coord(offset, x1, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y, this.pos_x + x2, 0x7fffffff, this.text);
|
||||
this.cursorX = coord.xpos;
|
||||
this.cursorY = coord.ypos;
|
||||
if(shift) {
|
||||
if(this.cursorY < y1)
|
||||
this.text_y += y1 - this.cursorY;
|
||||
else if((this.cursorY + Font.YGLYPH) >= (y1 + y2))
|
||||
this.text_y -= (this.cursorY + Font.YGLYPH) - (y1 + y2);
|
||||
gui_text_update_cur(offset, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected int onCursorOffset(int x, int y, int x1, int y1, int x2, int y2) {
|
||||
Offset off = Drawing.txt_offset(x, y, x1, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y, this.pos_x + x2, 0x7fffffff, this.text);
|
||||
if(off != null) {
|
||||
this.cursorX = off.xpos;
|
||||
this.cursorY = off.ypos;
|
||||
}
|
||||
int offset = off == null ? 0 : off.offset;
|
||||
if(y < y1)
|
||||
this.scrollPos = y1 - y;
|
||||
else if(y >= (y1 + y2))
|
||||
this.scrollPos = -(y - (y1 + y2));
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.txt_draw(x1, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y,
|
||||
this.pos_x + x2, Integer.MAX_VALUE, this.enabled ? this.gm.style.text_field : Util.mulColor(this.gm.style.text_field, 0.5f), this.text);
|
||||
if(this.sel_start >= 0 && this.sel_end != this.sel_start)
|
||||
Drawing.txt_overlay(this.sel_start, this.sel_end, x1, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y,
|
||||
this.pos_x + x2, Integer.MAX_VALUE, this.enabled ? 0x808080ff : 0x80404040, this.text);
|
||||
}
|
||||
|
||||
protected char getNewline() {
|
||||
return '\n';
|
||||
}
|
||||
|
||||
protected int getCursorX(int x1, int x2) {
|
||||
return this.cursorX;
|
||||
}
|
||||
|
||||
protected int getCursorY(int y1, int y2) {
|
||||
return this.cursorY;
|
||||
}
|
||||
}
|
97
client/src/main/java/client/gui/element/Bar.java
Normal file
97
client/src/main/java/client/gui/element/Bar.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Util;
|
||||
|
||||
public class Bar extends Fill {
|
||||
private int color = 0x00ff00;
|
||||
private int progress = 0;
|
||||
private int total = 0;
|
||||
private String desc = "";
|
||||
private String unit = "";
|
||||
|
||||
public Bar(int x, int y, int w, int h, boolean top, boolean left) {
|
||||
super(x, y, w, h, "", top, left);
|
||||
}
|
||||
|
||||
public Bar(int x, int y, int w, int h, boolean left) {
|
||||
super(x, y, w, h, "", left);
|
||||
}
|
||||
|
||||
public Bar(int x, int y, int w, int h) {
|
||||
super(x, y, w, h, "");
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
if(this.progress > 0) {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradient(this.pos_x + 2, this.pos_y + 2, this.progress, this.size_y - 4, this.color | 0xff000000, Util.mixColor(this.color | 0xff000000, 0xff000000));
|
||||
else
|
||||
Drawing.drawGradient(this.pos_x + 2, this.pos_y + 2, this.progress, this.size_y - 4, Util.mulColor(this.color | 0xff000000, 0.5f), Util.mulColor(Util.mixColor(this.color | 0xff000000, 0xff000000), 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.drawText(this.text, x1 + this.text_x, y1 + this.text_y, this.enabled ? this.gm.style.text_label : Util.mulColor(this.gm.style.text_label, 0.5f));
|
||||
}
|
||||
|
||||
protected int getMarginX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int getMarginY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Bar setDescription(String desc, String unit, int total) {
|
||||
this.desc = desc == null ? "" : (desc + ": ");
|
||||
this.unit = unit == null ? "" : (" " + unit);
|
||||
this.total = total;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bar setDescription(String desc, int total) {
|
||||
return this.setDescription(desc, null, total);
|
||||
}
|
||||
|
||||
public Bar setDescription(String desc) {
|
||||
this.desc = desc == null ? "" : (desc + ": ");
|
||||
this.unit = "";
|
||||
this.total = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bar resetProgress() {
|
||||
this.setText("");
|
||||
this.progress = 0;
|
||||
this.setDescription(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bar setProgressFill(int progress) {
|
||||
this.progress = ExtMath.clampi(progress, 0, this.size_x - 4);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bar setProgressFill(float progress) {
|
||||
return this.setProgressFill((int)(progress * (float)(this.size_x - 4)));
|
||||
}
|
||||
|
||||
public Bar setProgress(float progress) {
|
||||
if(this.total == 0)
|
||||
this.setText(String.format("%s%.1f %%", this.desc, progress * 100.0f));
|
||||
else
|
||||
this.setText(String.format("%s%d/%d%s (%.1f %%)", this.desc, (int)progress, this.total, this.unit, (progress / (float)this.total) * 100.0f));
|
||||
return this.setProgressFill(this.total == 0 ? progress : (progress / (float)this.total));
|
||||
}
|
||||
|
||||
public Bar setColor(int color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface ButtonCallback {
|
||||
void use(ActButton elem, PressType action);
|
||||
}
|
122
client/src/main/java/client/gui/element/Dropdown.java
Normal file
122
client/src/main/java/client/gui/element/Dropdown.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Font;
|
||||
import client.gui.Formatter;
|
||||
import client.gui.Gui;
|
||||
import client.renderer.Drawing;
|
||||
import client.window.Button;
|
||||
import common.util.Displayable;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Util;
|
||||
|
||||
public class Dropdown<T> extends Element {
|
||||
public class Handle extends Element {
|
||||
private Handle(boolean up) {
|
||||
super(Dropdown.this.pos_x, Dropdown.this.pos_y + (up ? -(Font.YGLYPH * Dropdown.this.values.length + 2) : Dropdown.this.size_y), Dropdown.this.size_x, Font.YGLYPH * Dropdown.this.values.length + 2, null);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(T value : Dropdown.this.values) {
|
||||
if(sb.length() > 0)
|
||||
sb.append('\n');
|
||||
sb.append(value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString());
|
||||
}
|
||||
this.setText(sb.toString());
|
||||
this.visible = /* this.r_dirty = */ false;
|
||||
}
|
||||
|
||||
public void updateText() {
|
||||
}
|
||||
|
||||
// protected boolean isTextCenteredX() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// protected boolean isTextCenteredY() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public boolean canClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
this.visible = false;
|
||||
// this.r_dirty = true;
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
Dropdown drop = Dropdown.this;
|
||||
int prev = drop.value;
|
||||
drop.value = (y - (this.pos_y + this.margin_y1)) * drop.values.length / (this.size_y - (this.margin_y1 + this.margin_y2));
|
||||
drop.value = ExtMath.clampi(drop.value, 0, drop.values.length - 1);
|
||||
if(drop.value != prev) {
|
||||
drop.func.use(drop, drop.getValue());
|
||||
drop.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
this.visible = false;
|
||||
// this.r_dirty = true;
|
||||
}
|
||||
|
||||
public void drawHover() {
|
||||
int m = ((this.gm.mouse_y - (this.pos_y + this.margin_y1)) * Dropdown.this.values.length / (this.size_y - (this.margin_y1 + this.margin_y2)));
|
||||
// if((sys.mouse_y - this.pos_y) < (this.size_y - this.margin_y2))
|
||||
Drawing.drawRect(this.pos_x + this.margin_x1, this.pos_y + this.margin_y1 + ExtMath.clampi(m, 0, Dropdown.this.values.length - 1) * ((this.size_y - (this.margin_y1 + this.margin_y2)) / Dropdown.this.values.length), this.size_x - (this.margin_x1 + this.margin_x2), (this.size_y - (this.margin_y1 + this.margin_y2)) / Dropdown.this.values.length, Gui.HOVER_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
private final DropdownCallback<T> func;
|
||||
private final T[] values;
|
||||
private final Handle handle;
|
||||
private final int def;
|
||||
|
||||
private int value;
|
||||
|
||||
public Dropdown(int x, int y, int w, int h, boolean up, T[] values, T def, T init, DropdownCallback<T> callback, Formatter<Dropdown<T>> formatter) {
|
||||
super(x, y, w, h, formatter);
|
||||
this.func = callback;
|
||||
this.values = values;
|
||||
this.def = Util.indexOfChecked(this.values, def);
|
||||
this.value = Util.indexOfChecked(this.values, init);
|
||||
this.handle = new Handle(up);
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public Dropdown(int x, int y, int w, int h, boolean up, T[] values, T def, T init, DropdownCallback<T> callback, final String text) {
|
||||
this(x, y, w, h, up, values, def, init, callback, new Formatter<Dropdown<T>>() {
|
||||
public String use(Dropdown<T> elem) {
|
||||
T value = elem.getValue();
|
||||
return String.format("%s: %s", text, value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return this.values[this.value];
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
this.value = Util.indexOfChecked(this.values, value);
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
int prev = this.value;
|
||||
if(ctrl || (btn == Button.MOUSE_MIDDLE)) {
|
||||
if((this.value = this.def) != prev) {
|
||||
this.func.use(this, this.getValue());
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
else if(this.gui != null) {
|
||||
Handle drop = this.handle;
|
||||
drop.visible = true;
|
||||
// drop.r_dirty = true;
|
||||
this.gui.selected = drop;
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
|
||||
public Handle getHandle() {
|
||||
return this.handle;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface DropdownCallback<T> {
|
||||
void use(Dropdown<T> elem, T value);
|
||||
}
|
271
client/src/main/java/client/gui/element/Element.java
Normal file
271
client/src/main/java/client/gui/element/Element.java
Normal file
|
@ -0,0 +1,271 @@
|
|||
package client.gui.element;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.Formatter;
|
||||
import client.gui.Gui;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.Drawing.Vec2i;
|
||||
import client.window.Button;
|
||||
import client.window.Keysym;
|
||||
import common.init.SoundEvent;
|
||||
import common.sound.EventType;
|
||||
import common.sound.PositionedSound;
|
||||
import common.util.Util;
|
||||
|
||||
public abstract class Element {
|
||||
protected final Client gm = Client.CLIENT;
|
||||
|
||||
protected Gui gui;
|
||||
protected Formatter format;
|
||||
protected String text = "";
|
||||
|
||||
protected int pos_x;
|
||||
protected int pos_y;
|
||||
protected int size_x;
|
||||
protected int size_y;
|
||||
protected int text_x = 0;
|
||||
protected int text_y = 0;
|
||||
|
||||
protected final int margin_x1 = this.getMarginX();
|
||||
protected final int margin_y1 = this.getMarginY();
|
||||
protected final int margin_x2 = this.getMarginX();
|
||||
protected final int margin_y2 = this.getMarginY();
|
||||
|
||||
public boolean visible = true;
|
||||
public boolean enabled = true;
|
||||
|
||||
|
||||
public Element(int x, int y, int w, int h, Formatter formatter) {
|
||||
this.pos_x = x;
|
||||
this.pos_y = y;
|
||||
this.size_x = w;
|
||||
this.size_y = h;
|
||||
this.format = formatter;
|
||||
// gui_update_style(this, 1);
|
||||
// if(type != ElemType.SLIDER) {
|
||||
// this.margin_x1 = this.margin_x2 = (type == ElemType.FIELD || type == ElemType.DROPDOWN_HANDLE) ? this.border : 0;
|
||||
// this.margin_y1 = this.margin_y2 = (type == ElemType.FIELD || type == ElemType.DROPDOWN_HANDLE) ? this.border : 0;
|
||||
// }
|
||||
}
|
||||
|
||||
public void setGui(Gui gui) {
|
||||
if(gui == null)
|
||||
throw new NullPointerException("gui");
|
||||
if(this.gui != null)
|
||||
throw new IllegalStateException("GUI bereits gesetzt");
|
||||
this.gui = gui;
|
||||
}
|
||||
|
||||
protected int getMarginX() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected int getMarginY() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public final int getX() {
|
||||
return this.pos_x;
|
||||
}
|
||||
|
||||
public final int getY() {
|
||||
return this.pos_y;
|
||||
}
|
||||
|
||||
public final int getWidth() {
|
||||
return this.size_x;
|
||||
}
|
||||
|
||||
public final int getHeight() {
|
||||
return this.size_y;
|
||||
}
|
||||
|
||||
// protected boolean isTextCenteredX() {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// protected boolean isTextCenteredY() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// protected boolean hasLinebreak() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public boolean canHover() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canClick() {
|
||||
return this.canHover();
|
||||
}
|
||||
|
||||
public boolean inside(int x, int y) {
|
||||
return (x >= this.pos_x) && (x < (this.pos_x + this.size_x)) && (y >= this.pos_y) && (y < (this.pos_y + this.size_y));
|
||||
}
|
||||
|
||||
public boolean intersects(Element elem) {
|
||||
return (elem.pos_y + elem.size_y) > this.pos_y && elem.pos_y < (this.pos_y + this.size_y) && (elem.pos_x + elem.size_x) > this.pos_x && elem.pos_x < (this.pos_x + this.size_x);
|
||||
}
|
||||
|
||||
public void updateText() {
|
||||
Vec2i size = Drawing.getSize(this.text);
|
||||
this.text_x = (this.size_x - size.xpos) / 2;
|
||||
this.text_y = (this.size_y - size.ypos) / 2;
|
||||
}
|
||||
|
||||
public void setText(String str) {
|
||||
this.text = str;
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
protected void formatText() {
|
||||
if(this.format != null) {
|
||||
this.text = this.format.use(this);
|
||||
this.updateText();
|
||||
}
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
|
||||
}
|
||||
|
||||
public void mouserel() {
|
||||
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
|
||||
}
|
||||
|
||||
public void character(char code) {
|
||||
|
||||
}
|
||||
|
||||
public void key(Keysym key, boolean ctrl, boolean shift) {
|
||||
|
||||
}
|
||||
|
||||
public void select() {
|
||||
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
||||
}
|
||||
|
||||
public void setSelected() {
|
||||
if(this.gui != null)
|
||||
this.gui.select(this);
|
||||
}
|
||||
|
||||
public void setDeselected() {
|
||||
if(this.gui != null && this.gui.selected == this)
|
||||
this.gui.deselect();
|
||||
}
|
||||
|
||||
public void shift(int shift_x, int shift_y) {
|
||||
this.pos_x += shift_x;
|
||||
this.pos_y += shift_y;
|
||||
}
|
||||
|
||||
public void reformat() {
|
||||
if(this.format != null) {
|
||||
// boolean flag = this.r_dirty;
|
||||
this.formatText();
|
||||
// if(!flag && !this.visible)
|
||||
// this.r_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_top, 0.5f), Util.mulColor(this.gm.style.fill_btm, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
// Drawing.drawGradient2GradBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, 0xff000000,
|
||||
// this.gm.style.brdr_top, Drawing.mixColor(this.gm.style.brdr_top, this.gm.style.brdr_btm), Drawing.mixColor(this.gm.style.brdr_top, this.gm.style.brdr_btm), this.gm.style.brdr_btm);
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.drawText(this.text, x1 + this.text_x, y1 + this.text_y, this.enabled ? this.gm.style.text_base : Util.mulColor(this.gm.style.text_base, 0.5f));
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
// if(this.r_dirty) {
|
||||
if(this.visible) {
|
||||
// WCF.glScissor(this.pos_x, (this.gm.fb_y - (this.pos_y + this.size_y)) < 0 ? 0 : (this.gm.fb_y - (this.pos_y + this.size_y)), this.size_x, this.size_y);
|
||||
// WCF.glEnable(WCF.GL_SCISSOR_TEST);
|
||||
// WCF.glClear(WCF.GL_COLOR_BUFFER_BIT);
|
||||
// WCF.glDisable(WCF.GL_SCISSOR_TEST);
|
||||
this.drawBackground();
|
||||
// if(this.selected == this && this.type == ElemType.DROPDOWN_HANDLE)
|
||||
// continue;
|
||||
int x1 = this.pos_x + this.margin_x1;
|
||||
int y1 = this.pos_y + this.margin_y1;
|
||||
int x2 = this.size_x - (this.margin_x1 + this.margin_x2);
|
||||
int y2 = this.size_y - (this.margin_y1 + this.margin_y2);
|
||||
// if(elem.type == ElemType.FIELD) {
|
||||
GL11.glScissor(x1 < 0 ? 0 : x1, (this.gm.fb_y - (y1 + y2)) < 0 ? 0 : (this.gm.fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2);
|
||||
GL11.glEnable(GL11.GL_SCISSOR_TEST);
|
||||
// }
|
||||
// if(this.type == ElemType.CUSTOM)
|
||||
// this.func(this, 1);
|
||||
// else
|
||||
this.drawForeground(x1, y1, x2, y2);
|
||||
// logd("DBG", "%d @ %d %d -> %d %d", elem.id, x1, y1, elem.pos_x + x2, elem.pos_y + y2);
|
||||
// if(elem.type == ElemType.FIELD) {
|
||||
GL11.glDisable(GL11.GL_SCISSOR_TEST);
|
||||
// glScissor(0, 0, sys.fb_x, sys.fb_y);
|
||||
// }
|
||||
}
|
||||
// else {
|
||||
// WCF.glScissor(this.pos_x, (this.gm.fb_y - (this.pos_y + this.size_y)) < 0 ? 0 : (this.gm.fb_y - (this.pos_y + this.size_y)), this.size_x, this.size_y);
|
||||
// // logd("DBG", "%d @ %d %d -> %d %d", elem.id, elem.pos_x, elem.pos_y, elem.pos_x + elem.size_x, elem.pos_y + elem.size_y);
|
||||
// WCF.glEnable(WCF.GL_SCISSOR_TEST);
|
||||
//// if(this.type == ElemType.CUSTOM)
|
||||
//// this.func(this, 0);
|
||||
//// else
|
||||
// WCF.glClear(WCF.GL_COLOR_BUFFER_BIT);
|
||||
// WCF.glDisable(WCF.GL_SCISSOR_TEST);
|
||||
// this.r_dirty = false;
|
||||
// }
|
||||
// this.r_dirty = this.visible;
|
||||
// logd("DBG", "@ r");
|
||||
// if(this.visible) {
|
||||
// }
|
||||
// else {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void drawOverlay() {
|
||||
|
||||
}
|
||||
|
||||
public void drawHover() {
|
||||
Drawing.drawRect(this.pos_x, this.pos_y, this.size_x, this.size_y, Gui.HOVER_COLOR);
|
||||
}
|
||||
|
||||
public void drawPress() {
|
||||
Drawing.drawRect(this.pos_x, this.pos_y, this.size_x, this.size_y, Gui.PRESS_COLOR);
|
||||
}
|
||||
|
||||
public void playSound() {
|
||||
this.gm.getSoundManager().playSound(new PositionedSound(SoundEvent.CLICK, EventType.UI_INTERFACE));
|
||||
}
|
||||
}
|
194
client/src/main/java/client/gui/element/Field.java
Normal file
194
client/src/main/java/client/gui/element/Field.java
Normal file
|
@ -0,0 +1,194 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Font;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.Drawing.Offset;
|
||||
import client.renderer.Drawing.Vec2i;
|
||||
import common.util.CharValidator;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Util;
|
||||
|
||||
public class Field extends Textbox {
|
||||
private int textWidth;
|
||||
private int scrollPos;
|
||||
private int cursorPos;
|
||||
|
||||
private Field(int x, int y, int w, int h, int cap, boolean editable, FieldCallback callback, CharValidator validator, String text) {
|
||||
super(x, y, w, h, cap, editable, callback, validator);
|
||||
this.text_y = (this.size_y - (this.margin_y1 + this.margin_y2 + Font.YGLYPH)) / 2;
|
||||
this.setText(text);
|
||||
}
|
||||
|
||||
public Field(int x, int y, int w, int h, int cap, FieldCallback callback, CharValidator validator, String text) {
|
||||
this(x, y, w, h, cap, true, callback, validator, text);
|
||||
}
|
||||
|
||||
public Field(int x, int y, int w, int h, int cap, FieldCallback callback, String text) {
|
||||
this(x, y, w, h, cap, true, callback, null, text);
|
||||
}
|
||||
|
||||
public Field(int x, int y, int w, int h, String text) {
|
||||
this(x, y, w, h, Integer.MAX_VALUE, false, null, null, text);
|
||||
}
|
||||
|
||||
public void updateText() {
|
||||
this.textWidth = Drawing.txt_size(this.pos_x + this.margin_x1, this.pos_y + this.margin_y1,
|
||||
this.pos_x + this.margin_x1, this.pos_y + this.margin_y1,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE, this.text).xpos;
|
||||
}
|
||||
|
||||
public void mouserel() {
|
||||
this.scrollPos = 0;
|
||||
}
|
||||
|
||||
public void onReturn(boolean shift) {
|
||||
if(this.func != null) {
|
||||
this.func.use(this, shift ? FieldAction.LINE : FieldAction.SEND);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSelection(boolean up) {
|
||||
if(this.func != null) {
|
||||
this.func.use(this, up ? FieldAction.PREVIOUS : FieldAction.NEXT);
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(this.scrollPos != 0) {
|
||||
int n = this.updateScroll(this.scrollPos);
|
||||
this.text_x += n;
|
||||
if(n != 0)
|
||||
gui_text_clamp_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
public void shift(int shift_x, int shift_y) {
|
||||
super.shift(shift_x, shift_y);
|
||||
this.cursorPos += shift_x;
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
if(scr_y != 0 || scr_x != 0) {
|
||||
int limit = Font.XGLYPH + this.textWidth - (this.size_x - (this.margin_x1 + this.margin_x2));
|
||||
limit = ExtMath.clampi(limit, 0, 0x7fffffff);
|
||||
int prev = this.text_x;
|
||||
this.text_x += ((scr_y != 0 ? scr_y : (-scr_x)) < 0 ? -1 : 1) * (ctrl ? 1 : Font.XGLYPH) * this.gm.scrollLines * (shift ? 10 : 1);
|
||||
this.text_x = ExtMath.clampi(this.text_x, -limit, 0);
|
||||
if(this.sel_start >= 0)
|
||||
this.cursorPos += (this.text_x - prev);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getCursorX(int x1, int x2) {
|
||||
return this.cursorPos;
|
||||
}
|
||||
|
||||
protected int getCursorY(int y1, int y2) {
|
||||
return y1 + (y2 - Font.YGLYPH) / 2;
|
||||
}
|
||||
|
||||
protected void gui_text_clamp_scroll() {
|
||||
int limit = Font.XGLYPH + this.textWidth - (this.size_x - (this.margin_x1 + this.margin_x2));
|
||||
limit = ExtMath.clampi(limit, 0, 0x7fffffff);
|
||||
this.text_x = ExtMath.clampi(this.text_x, -limit, 0);
|
||||
}
|
||||
|
||||
protected void updateCursor(int offset, boolean shift, int x1, int y1, int x2, int y2) {
|
||||
Vec2i coord = Drawing.txt_coord(offset, x1 + this.text_x, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y, 0x7fffffff, 0x7fffffff, this.text);
|
||||
this.cursorPos = coord.xpos;
|
||||
if(shift) {
|
||||
if(this.cursorPos < x1)
|
||||
this.text_x += x1 - this.cursorPos;
|
||||
else if((this.cursorPos + Font.XGLYPH) >= (x1 + x2))
|
||||
this.text_x -= (this.cursorPos + Font.XGLYPH) - (x1 + x2);
|
||||
gui_text_update_cur(offset, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected int onCursorOffset(int x, int y, int x1, int y1, int x2, int y2) {
|
||||
Offset off = Drawing.txt_offset(x, y, x1 + this.text_x, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y, 0x7fffffff, 0x7fffffff, this.text);
|
||||
if(off != null) {
|
||||
this.cursorPos = off.xpos;
|
||||
}
|
||||
int offset = off == null ? 0 : off.offset;
|
||||
if(x < x1)
|
||||
this.scrollPos = x1 - x;
|
||||
else if(x >= (x1 + x2))
|
||||
this.scrollPos = -(x - (x1 + x2));
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.field_top, this.gm.style.field_btm, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.field_top, 0.5f), Util.mulColor(this.gm.style.field_btm, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.txt_draw(x1 + this.text_x, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE, this.enabled ? this.gm.style.text_field : Util.mulColor(this.gm.style.text_field, 0.5f), this.text);
|
||||
if(this.sel_start >= 0 && this.sel_end != this.sel_start)
|
||||
Drawing.txt_overlay(this.sel_start, this.sel_end, x1 + this.text_x, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE, this.enabled ? 0x808080ff : 0x80404040, this.text);
|
||||
}
|
||||
|
||||
protected char getNewline() {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void deleteSpaceToCur() {
|
||||
int num = this.getSpaceBeforeCur() - this.sel_start;
|
||||
if(this.text.length() != 0) {
|
||||
if(this.sel_start != this.sel_end) {
|
||||
this.insertText("");
|
||||
}
|
||||
else {
|
||||
// boolean flag = num < 0;
|
||||
int i = this.sel_start + num; // flag ? this.sel_start + num : this.sel_start;
|
||||
int j = this.sel_start; // flag ? this.sel_start : this.sel_start + num;
|
||||
String s = "";
|
||||
|
||||
if(i >= 0) {
|
||||
s = this.text.substring(0, i);
|
||||
}
|
||||
|
||||
if(j < this.text.length()) {
|
||||
s = s + this.text.substring(j);
|
||||
}
|
||||
|
||||
// this.setText(s);
|
||||
this.text = s;
|
||||
this.updateText();
|
||||
this.sel_start = this.sel_end = this.sel_drag = i;
|
||||
gui_text_update_cur(this.sel_start, true);
|
||||
//
|
||||
// if(flag) {
|
||||
// this.moveCursorBy(num);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getSpaceBeforeCur() {
|
||||
int i = this.sel_start;
|
||||
while(i > 0 && this.text.charAt(i - 1) != ' ') {
|
||||
--i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public int getCursorPos() {
|
||||
return this.sel_start == this.sel_end ? this.sel_start : -1;
|
||||
}
|
||||
}
|
5
client/src/main/java/client/gui/element/FieldAction.java
Normal file
5
client/src/main/java/client/gui/element/FieldAction.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public enum FieldAction {
|
||||
FOCUS, UNFOCUS, PREVIOUS, NEXT, FUNCTION, SEND, LINE, FORWARD, BACKWARD;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface FieldCallback extends TextCallback<Field> {
|
||||
void use(Field elem, FieldAction value);
|
||||
}
|
57
client/src/main/java/client/gui/element/Fill.java
Normal file
57
client/src/main/java/client/gui/element/Fill.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.Drawing.Vec2i;
|
||||
|
||||
public class Fill extends Element {
|
||||
private final boolean left;
|
||||
private final boolean top;
|
||||
|
||||
public Fill(int x, int y, int w, int h, String text, boolean top, boolean left) {
|
||||
super(x, y, w, h, null);
|
||||
this.top = top;
|
||||
this.left = left;
|
||||
this.setText(text);
|
||||
}
|
||||
|
||||
public Fill(int x, int y, int w, int h, String text, boolean left) {
|
||||
this(x, y, w, h, text, false, left);
|
||||
}
|
||||
|
||||
public Fill(int x, int y, int w, int h, String text) {
|
||||
this(x, y, w, h, text, false, false);
|
||||
}
|
||||
|
||||
public Fill(int x, int y, int w, int h, boolean top, boolean left) {
|
||||
this(x, y, w, h, "", top, left);
|
||||
}
|
||||
|
||||
public Fill(int x, int y, int w, int h, boolean left) {
|
||||
this(x, y, w, h, "", false, left);
|
||||
}
|
||||
|
||||
public Fill(int x, int y, int w, int h) {
|
||||
this(x, y, w, h, "", false, false);
|
||||
}
|
||||
|
||||
|
||||
public boolean canHover() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// protected boolean isTextCenteredX() {
|
||||
// return !this.left;
|
||||
// }
|
||||
//
|
||||
// protected boolean isTextCenteredY() {
|
||||
// return !this.top;
|
||||
// }
|
||||
|
||||
public void updateText() {
|
||||
Vec2i size = Drawing.getSize(this.text);
|
||||
if(!this.left)
|
||||
this.text_x = (this.size_x - size.xpos) / 2;
|
||||
if(!this.top)
|
||||
this.text_y = (this.size_y - size.ypos) / 2;
|
||||
}
|
||||
}
|
413
client/src/main/java/client/gui/element/GuiList.java
Executable file
413
client/src/main/java/client/gui/element/GuiList.java
Executable file
|
@ -0,0 +1,413 @@
|
|||
package client.gui.element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import client.gui.Gui;
|
||||
import client.renderer.DefaultVertexFormats;
|
||||
import client.renderer.Drawing;
|
||||
import client.renderer.GlState;
|
||||
import client.renderer.RenderBuffer;
|
||||
import client.renderer.Tessellator;
|
||||
import client.window.Button;
|
||||
import common.collect.Lists;
|
||||
import common.util.ExtMath;
|
||||
|
||||
public abstract class GuiList<T extends ListEntry> extends Gui
|
||||
{
|
||||
protected final List<T> elements = Lists.newArrayList();
|
||||
|
||||
protected int width;
|
||||
protected int height;
|
||||
|
||||
protected int top;
|
||||
protected int bottom;
|
||||
protected int right;
|
||||
protected int left;
|
||||
protected int mouseX;
|
||||
protected int mouseY;
|
||||
protected int initialClickY = -2;
|
||||
protected float scrollMultiplier;
|
||||
protected float amountScrolled;
|
||||
protected int selectedElement = -1;
|
||||
protected long lastClicked;
|
||||
|
||||
public abstract int getListWidth(); // 220
|
||||
|
||||
public abstract int getSlotHeight();
|
||||
|
||||
protected int getScrollBarX()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setDimensions(int widthIn, int heightIn, int topIn, int bottomIn)
|
||||
{
|
||||
this.width = widthIn;
|
||||
this.height = heightIn;
|
||||
this.top = topIn;
|
||||
this.bottom = bottomIn;
|
||||
this.left = 0;
|
||||
this.right = widthIn;
|
||||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
|
||||
this.selectedElement = -1;
|
||||
}
|
||||
|
||||
public void setSlotXBoundsFromLeft(int leftIn)
|
||||
{
|
||||
this.left = leftIn;
|
||||
this.right = leftIn + this.width;
|
||||
}
|
||||
|
||||
public final T getListEntry(int index) {
|
||||
return this.elements.get(index);
|
||||
}
|
||||
|
||||
public final T getSelected() {
|
||||
return this.selectedElement < 0 ? null : this.elements.get(this.selectedElement);
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return this.elements.size();
|
||||
}
|
||||
|
||||
public final void setSelected(int index) {
|
||||
this.selectedElement = index;
|
||||
}
|
||||
|
||||
protected int getContentHeight()
|
||||
{
|
||||
return this.getSize() * this.getSlotHeight();
|
||||
}
|
||||
|
||||
public int getSlotIndexFromScreenCoords(int x, int y)
|
||||
{
|
||||
int i = this.left + this.width / 2 - this.getListWidth() / 2;
|
||||
int j = this.left + this.width / 2 + this.getListWidth() / 2;
|
||||
int k = y - this.top + (int)this.amountScrolled - 4;
|
||||
int l = k / this.getSlotHeight();
|
||||
return this.isInList(x, y) && x >= i && x <= j && l >= 0 && k >= 0 && l < this.getSize() ? l : -1;
|
||||
}
|
||||
|
||||
protected boolean isInList(int x, int y)
|
||||
{
|
||||
return x >= this.getScrollBarX() + 6; // x < this.getScrollBarX();
|
||||
}
|
||||
|
||||
protected final boolean isSelected(int slotIndex)
|
||||
{
|
||||
return slotIndex == this.selectedElement;
|
||||
}
|
||||
|
||||
protected void bindAmountScrolled()
|
||||
{
|
||||
this.amountScrolled = ExtMath.clampf(this.amountScrolled, 0.0F, (float)this.getMaxScroll());
|
||||
}
|
||||
|
||||
public int getMaxScroll()
|
||||
{
|
||||
return Math.max(0, this.getContentHeight() - (this.bottom - this.top - 4));
|
||||
}
|
||||
|
||||
public int getAmountScrolled()
|
||||
{
|
||||
return (int)this.amountScrolled;
|
||||
}
|
||||
|
||||
public boolean isMouseYWithinSlotBounds(int p_148141_1_)
|
||||
{
|
||||
return p_148141_1_ >= this.top && p_148141_1_ <= this.bottom && this.mouseX >= this.left && this.mouseX <= this.right;
|
||||
}
|
||||
|
||||
public void scrollBy(int amount)
|
||||
{
|
||||
this.amountScrolled += (float)amount;
|
||||
this.bindAmountScrolled();
|
||||
this.initialClickY = -2;
|
||||
}
|
||||
|
||||
// public void actionPerformed(Button button)
|
||||
// {
|
||||
// if (button.enabled)
|
||||
// {
|
||||
// if (button.id == this.scrollUpButtonID)
|
||||
// {
|
||||
// this.amountScrolled -= (float)(this.slotHeight * 2 / 3);
|
||||
// this.initialClickY = -2;
|
||||
// this.bindAmountScrolled();
|
||||
// }
|
||||
// else if (button.id == this.scrollDownButtonID)
|
||||
// {
|
||||
// this.amountScrolled += (float)(this.slotHeight * 2 / 3);
|
||||
// this.initialClickY = -2;
|
||||
// this.bindAmountScrolled();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void draw()
|
||||
{
|
||||
int mouseXIn = this.gm.mouse_x;
|
||||
int mouseYIn = this.gm.mouse_y;
|
||||
this.mouseX = mouseXIn;
|
||||
this.mouseY = mouseYIn;
|
||||
this.drawBackground();
|
||||
int i = this.getScrollBarX();
|
||||
int j = i + 6;
|
||||
this.bindAmountScrolled();
|
||||
GlState.disableLighting();
|
||||
GlState.disableFog();
|
||||
GlState.enableTexture2D();
|
||||
RenderBuffer worldrenderer = Tessellator.getBuffer();
|
||||
this.gm.getTextureManager().bindTexture(Gui.DIRT_BACKGROUND);
|
||||
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
float f = 32.0F;
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)0, (double)this.bottom, 0.0D).tex((double)((float)0 / f), (double)((float)(this.bottom + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)this.bottom, 0.0D).tex((double)((float)this.gm.fb_x / f), (double)((float)(this.bottom + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)this.top, 0.0D).tex((double)((float)this.gm.fb_x / f), (double)((float)(this.top + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex();
|
||||
worldrenderer.pos((double)0, (double)this.top, 0.0D).tex((double)((float)0 / f), (double)((float)(this.top + (int)this.amountScrolled) / f)).color(32, 32, 32, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
|
||||
int x = this.left + this.width / 2 - this.getListWidth() / 2 + 2;
|
||||
int y = this.top + 4 - (int)this.amountScrolled;
|
||||
|
||||
this.drawSelectionBox(x, y, mouseXIn, mouseYIn);
|
||||
GlState.disableDepth();
|
||||
|
||||
this.overlayBackground(0, this.top, 255, 255);
|
||||
this.overlayBackground(this.bottom, this.height, 255, 255);
|
||||
|
||||
GlState.enableBlend();
|
||||
GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
GlState.disableAlpha();
|
||||
GlState.shadeModel(GL11.GL_SMOOTH);
|
||||
GlState.disableTexture2D();
|
||||
|
||||
int i1 = 4;
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)0, (double)(this.top + i1), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 0).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)(this.top + i1), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 0).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)0, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)0, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)this.gm.fb_x, (double)(this.bottom - i1), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 0).endVertex();
|
||||
worldrenderer.pos((double)0, (double)(this.bottom - i1), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 0).endVertex();
|
||||
Tessellator.draw();
|
||||
|
||||
int j1 = this.getMaxScroll();
|
||||
|
||||
if (j1 > 0)
|
||||
{
|
||||
int k1 = (this.bottom - this.top) * (this.bottom - this.top) / this.getContentHeight();
|
||||
k1 = ExtMath.clampi(k1, 32, this.bottom - this.top - 8);
|
||||
int l1 = (int)this.amountScrolled * (this.bottom - this.top - k1) / j1 + this.top;
|
||||
|
||||
if (l1 < this.top)
|
||||
{
|
||||
l1 = this.top;
|
||||
}
|
||||
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)i, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)j, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)j, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
worldrenderer.pos((double)i, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)i, (double)(l1 + k1), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double)j, (double)(l1 + k1), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double)j, (double)l1, 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
worldrenderer.pos((double)i, (double)l1, 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
worldrenderer.pos((double)i, (double)(l1 + k1 - 1), 0.0D).tex(0.0D, 1.0D).color(192, 192, 192, 255).endVertex();
|
||||
worldrenderer.pos((double)(j - 1), (double)(l1 + k1 - 1), 0.0D).tex(1.0D, 1.0D).color(192, 192, 192, 255).endVertex();
|
||||
worldrenderer.pos((double)(j - 1), (double)l1, 0.0D).tex(1.0D, 0.0D).color(192, 192, 192, 255).endVertex();
|
||||
worldrenderer.pos((double)i, (double)l1, 0.0D).tex(0.0D, 0.0D).color(192, 192, 192, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
}
|
||||
|
||||
GlState.enableTexture2D();
|
||||
GlState.shadeModel(GL11.GL_FLAT);
|
||||
GlState.enableAlpha();
|
||||
GlState.disableBlend();
|
||||
|
||||
super.draw();
|
||||
}
|
||||
|
||||
public void handleMouseInput()
|
||||
{
|
||||
if (this.isMouseYWithinSlotBounds(this.mouseY))
|
||||
{
|
||||
// if (Button.MOUSE_LEFT.isDown() && this.getEnabled())
|
||||
// {
|
||||
if (this.initialClickY == -1)
|
||||
{
|
||||
boolean flag1 = true;
|
||||
|
||||
if (this.mouseY >= this.top && this.mouseY <= this.bottom)
|
||||
{
|
||||
int j2 = (this.width - this.getListWidth()) / 2;
|
||||
int k2 = (this.width + this.getListWidth()) / 2;
|
||||
int l2 = this.mouseY - this.top + (int)this.amountScrolled - 4;
|
||||
int i1 = l2 / this.getSlotHeight();
|
||||
|
||||
if (i1 < this.getSize() && this.mouseX >= j2 && this.mouseX <= k2 && i1 >= 0 && l2 >= 0)
|
||||
{
|
||||
}
|
||||
else if (this.mouseX >= j2 && this.mouseX <= k2 && l2 < 0)
|
||||
{
|
||||
flag1 = false;
|
||||
}
|
||||
|
||||
int i3 = this.getScrollBarX();
|
||||
int j1 = i3 + 6;
|
||||
|
||||
if (this.mouseX >= i3 && this.mouseX <= j1)
|
||||
{
|
||||
this.scrollMultiplier = -1.0F;
|
||||
int k1 = this.getMaxScroll();
|
||||
|
||||
if (k1 < 1)
|
||||
{
|
||||
k1 = 1;
|
||||
}
|
||||
|
||||
int l1 = (int)((float)((this.bottom - this.top) * (this.bottom - this.top)) / (float)this.getContentHeight());
|
||||
l1 = ExtMath.clampi(l1, 32, this.bottom - this.top - 8);
|
||||
this.scrollMultiplier /= (float)(this.bottom - this.top - l1) / (float)k1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.scrollMultiplier = 1.0F;
|
||||
}
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
this.initialClickY = this.mouseY;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.initialClickY = -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.initialClickY = -2;
|
||||
}
|
||||
}
|
||||
else if (this.initialClickY >= 0)
|
||||
{
|
||||
this.amountScrolled -= (float)(this.mouseY - this.initialClickY) * this.scrollMultiplier;
|
||||
this.initialClickY = this.mouseY;
|
||||
}
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.initialClickY = -1;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawSelectionBox(int x, int y, int mouseXIn, int mouseYIn)
|
||||
{
|
||||
int size = this.getSize();
|
||||
RenderBuffer rb = Tessellator.getBuffer();
|
||||
|
||||
for (int z = 0; z < size; z++)
|
||||
{
|
||||
int y1 = y + z * this.getSlotHeight();
|
||||
int h = this.getSlotHeight() - 4;
|
||||
|
||||
if (this.isSelected(z))
|
||||
{
|
||||
int x1 = this.left + (this.width / 2 - this.getListWidth() / 2);
|
||||
int x2 = this.left + this.width / 2 + this.getListWidth() / 2;
|
||||
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlState.disableTexture2D();
|
||||
rb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
rb.pos((double)x1, (double)(y1 + h + 2), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex();
|
||||
rb.pos((double)x2, (double)(y1 + h + 2), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex();
|
||||
rb.pos((double)x2, (double)(y1 - 2), 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
rb.pos((double)x1, (double)(y1 - 2), 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex();
|
||||
rb.pos((double)(x1 + 1), (double)(y1 + h + 1), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
rb.pos((double)(x2 - 1), (double)(y1 + h + 1), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
|
||||
rb.pos((double)(x2 - 1), (double)(y1 - 1), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
rb.pos((double)(x1 + 1), (double)(y1 - 1), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
|
||||
Tessellator.draw();
|
||||
GlState.enableTexture2D();
|
||||
}
|
||||
|
||||
boolean hover = this.getSlotIndexFromScreenCoords(mouseXIn, mouseYIn) == z;
|
||||
this.getListEntry(z).draw(x, y1, mouseXIn - x, mouseYIn - y1, hover);
|
||||
if(hover)
|
||||
Drawing.drawRect(x - 2, y1 - 2, this.getListWidth(), this.getSlotHeight(), Gui.HOVER_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
protected void overlayBackground(int startY, int endY, int startAlpha, int endAlpha)
|
||||
{
|
||||
RenderBuffer rb = Tessellator.getBuffer();
|
||||
this.gm.getTextureManager().bindTexture(Gui.DIRT_BACKGROUND);
|
||||
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
float f = 32.0F;
|
||||
rb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
rb.pos((double)0, (double)endY, 0.0D).tex(0.0D, (double)((float)endY / 32.0F)).color(64, 64, 64, endAlpha).endVertex();
|
||||
rb.pos((double)this.gm.fb_x, (double)endY, 0.0D).tex((double)((float)this.gm.fb_x / 32.0F), (double)((float)endY / 32.0F)).color(64, 64, 64, endAlpha).endVertex();
|
||||
rb.pos((double)this.gm.fb_x, (double)startY, 0.0D).tex((double)((float)this.gm.fb_x / 32.0F), (double)((float)startY / 32.0F)).color(64, 64, 64, startAlpha).endVertex();
|
||||
rb.pos((double)0, (double)startY, 0.0D).tex(0.0D, (double)((float)startY / 32.0F)).color(64, 64, 64, startAlpha).endVertex();
|
||||
Tessellator.draw();
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift)
|
||||
{
|
||||
super.mouse(btn, x, y, ctrl, shift);
|
||||
if (this.isMouseYWithinSlotBounds(y))
|
||||
{
|
||||
int i = this.getSlotIndexFromScreenCoords(x, y);
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
int j = this.left + this.width / 2 - this.getListWidth() / 2 + 2;
|
||||
int k = this.top + 4 - this.getAmountScrolled() + i * this.getSlotHeight();
|
||||
int l = x - j;
|
||||
int i1 = y - k;
|
||||
|
||||
boolean flag = i == this.selectedElement && System.currentTimeMillis() - this.lastClicked < (long)this.gm.dclickDelay;
|
||||
this.selectedElement = i;
|
||||
this.lastClicked = System.currentTimeMillis();
|
||||
|
||||
this.getListEntry(i).select(flag, l, i1);
|
||||
}
|
||||
}
|
||||
if(btn == Button.MOUSE_LEFT && this.clicked(x, y) == null)
|
||||
this.handleMouseInput();
|
||||
}
|
||||
|
||||
public void mouserel(Button btn, int x, int y) {
|
||||
super.mouserel(btn, x, y);
|
||||
if(btn == Button.MOUSE_LEFT)
|
||||
this.initialClickY = -1;
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
super.scroll(scr_x, scr_y, x, y, ctrl, shift);
|
||||
if(scr_y != 0 && this.clicked(x, y) == null)
|
||||
this.amountScrolled -= (float)(ExtMath.clampi(scr_y, -1, 1) * this.getSlotHeight() / 2);
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
super.drag(x, y);
|
||||
if(this.selected == null && Button.MOUSE_LEFT.isDown())
|
||||
this.handleMouseInput();
|
||||
}
|
||||
}
|
17
client/src/main/java/client/gui/element/InventoryButton.java
Normal file
17
client/src/main/java/client/gui/element/InventoryButton.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
|
||||
public class InventoryButton extends Element {
|
||||
public InventoryButton(int x, int y, int w, int h) {
|
||||
super(x, y, w, h, null);
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
// Drawing.drawRect2Border(this.pos_x, this.pos_y, this.size_x, this.size_y, 0xff6f6f6f, 0xffafafaf);
|
||||
Drawing.drawRectBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, 0xff6f6f6f, 0xff000000, 0xffafafaf, 0xff4f4f4f);
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
}
|
||||
}
|
33
client/src/main/java/client/gui/element/Label.java
Normal file
33
client/src/main/java/client/gui/element/Label.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
import common.util.Util;
|
||||
|
||||
public class Label extends Fill {
|
||||
public Label(int x, int y, int w, int h, String text, boolean top, boolean left) {
|
||||
super(x, y, w, h, text, top, left);
|
||||
}
|
||||
|
||||
public Label(int x, int y, int w, int h, String text, boolean left) {
|
||||
super(x, y, w, h, text, left);
|
||||
}
|
||||
|
||||
public Label(int x, int y, int w, int h, String text) {
|
||||
super(x, y, w, h, text);
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.drawText(this.text, x1 + this.text_x, y1 + this.text_y, this.enabled ? this.gm.style.text_label : Util.mulColor(this.gm.style.text_label, 0.5f));
|
||||
}
|
||||
|
||||
protected int getMarginX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int getMarginY() {
|
||||
return 0;
|
||||
}
|
||||
}
|
7
client/src/main/java/client/gui/element/ListEntry.java
Normal file
7
client/src/main/java/client/gui/element/ListEntry.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface ListEntry
|
||||
{
|
||||
void draw(int x, int y, int mouseX, int mouseY, boolean hovered);
|
||||
void select(boolean dclick, int mx, int my);
|
||||
}
|
30
client/src/main/java/client/gui/element/NavButton.java
Normal file
30
client/src/main/java/client/gui/element/NavButton.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.Gui;
|
||||
import client.renderer.Drawing;
|
||||
import common.util.Util;
|
||||
|
||||
public class NavButton extends ActButton {
|
||||
private final Gui navGui;
|
||||
|
||||
public NavButton(int x, int y, int w, int h, Gui gui, String text) {
|
||||
super(x, y, w, h, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
Client.CLIENT.displayGuiScreen(gui);
|
||||
}
|
||||
}, text);
|
||||
this.navGui = gui;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.gm.open == this.navGui) {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
else
|
||||
super.drawBackground();
|
||||
}
|
||||
}
|
20
client/src/main/java/client/gui/element/PasswordField.java
Normal file
20
client/src/main/java/client/gui/element/PasswordField.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
import common.util.Util;
|
||||
|
||||
public class PasswordField extends Field {
|
||||
public PasswordField(int x, int y, int w, int h, int cap, FieldCallback callback, String text) {
|
||||
super(x, y, w, h, cap, callback, text);
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
Drawing.txt_draw(x1 + this.text_x, y1 + this.text_y,
|
||||
x1 + this.text_x, y1 + this.text_y,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE, this.enabled ? this.gm.style.text_field : Util.mulColor(this.gm.style.text_field, 0.5f), this.text.isEmpty() ? "" : "****");
|
||||
}
|
||||
|
||||
protected int getCursorX(int x1, int x2) {
|
||||
return x1;
|
||||
}
|
||||
}
|
5
client/src/main/java/client/gui/element/PressType.java
Normal file
5
client/src/main/java/client/gui/element/PressType.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public enum PressType {
|
||||
PRIMARY, SECONDARY, TERTIARY;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
import common.util.Util;
|
||||
|
||||
public class SelectableButton extends ActButton {
|
||||
private boolean selected;
|
||||
|
||||
public SelectableButton(int x, int y, int w, int h, ButtonCallback callback, String text, boolean selected) {
|
||||
super(x, y, w, h, callback, text);
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.selected) {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
else
|
||||
super.drawBackground();
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
}
|
166
client/src/main/java/client/gui/element/Slider.java
Normal file
166
client/src/main/java/client/gui/element/Slider.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Formatter;
|
||||
import client.renderer.Drawing;
|
||||
import client.window.Button;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Util;
|
||||
|
||||
public class Slider extends Element {
|
||||
private static final int SLIDER_WIDTH = 10;
|
||||
|
||||
private final SliderCallback func;
|
||||
private final int def;
|
||||
private final int min;
|
||||
private final int max;
|
||||
private final int precision;
|
||||
private final int handle;
|
||||
|
||||
private int value;
|
||||
private int position;
|
||||
|
||||
public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, Formatter<Slider> formatter) {
|
||||
super(x, y, w, h, formatter);
|
||||
this.handle = ((this.size_y * SLIDER_WIDTH) / 24) & ~1;
|
||||
this.func = callback;
|
||||
this.precision = prec;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.def = def;
|
||||
this.value = init;
|
||||
this.position = gui_slider_pixel();
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, final String text) {
|
||||
this(x, y, w, h, prec, min, max, def, init, callback, new Formatter<Slider>() {
|
||||
public String use(Slider elem) {
|
||||
return String.format("%s: %d", text, elem.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, final String text, final String unit) {
|
||||
this(x, y, w, h, prec, min, max, def, init, callback, new Formatter<Slider>() {
|
||||
private final String format = unit.isEmpty() ? "%s: %d" : "%s: %d %s";
|
||||
|
||||
public String use(Slider elem) {
|
||||
return String.format(this.format, text, elem.value, unit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Slider(int x, int y, int w, int h, int prec, float min, float max, float def, float init, final SliderFloatCallback callback, Formatter<Slider> formatter) {
|
||||
this(x, y, w, h, prec, (int)(min * 1000.0f), (int)(max * 1000.0f), (int)(def * 1000.0f), (int)(init * 1000.0f), new SliderCallback() {
|
||||
public void use(Slider elem, int value) {
|
||||
callback.use(elem, (float)value / 1000.0f);
|
||||
}
|
||||
}, formatter);
|
||||
}
|
||||
|
||||
public Slider(int x, int y, int w, int h, final int prec, float min, float max, float def, float init, SliderFloatCallback callback, final String text, final String unit) {
|
||||
this(x, y, w, h, prec < 0 ? 0 : prec, min, max, def, init, callback, new Formatter<Slider>() {
|
||||
private final String format = "%s: " + (prec <= 0 ? "%d" : ("%." + prec + "f")) + (unit.isEmpty() ? "" : " %s");
|
||||
|
||||
public String use(Slider elem) {
|
||||
return prec <= 0 ? String.format(this.format, text, prec < 0 ? (int)((float)elem.value / 10.0f) : (elem.value / 1000), unit)
|
||||
: String.format(this.format, text, (float)elem.value / 1000.0f, unit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
|
||||
if(scr_y != 0) {
|
||||
int prev = this.value;
|
||||
this.value += (scr_y < 0 ? -1 : 1) * (ctrl ? (this.precision != 0 ? 1 : 10) : ((this.precision >= 2) ? 10 : (this.precision != 0 ? 100 : 1))) * (shift ? (this.precision != 0 ? 50 : 5) : 1);
|
||||
this.value = ExtMath.clampi(this.value, this.min, this.max);
|
||||
this.position = gui_slider_pixel();
|
||||
if(this.value != prev) {
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
int prev = this.value;
|
||||
if(ctrl || (btn == Button.MOUSE_MIDDLE)) {
|
||||
this.value = this.def;
|
||||
this.position = gui_slider_pixel();
|
||||
if(this.value != prev) {
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.position = x - this.pos_x;
|
||||
this.value = gui_slider_value();
|
||||
this.position = gui_slider_pixel();
|
||||
if(this.value != prev) {
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
x = (x < this.pos_x) ? this.pos_x : ((x >= (this.pos_x + this.size_x)) ? (this.pos_x - 1 + this.size_x) : x);
|
||||
int prev = this.value;
|
||||
this.position = x - this.pos_x;
|
||||
this.value = gui_slider_value();
|
||||
this.value = ExtMath.clampi(this.value, this.min, this.max);
|
||||
this.position = gui_slider_pixel();
|
||||
if(this.value != prev) {
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
}
|
||||
}
|
||||
|
||||
public void reformat() {
|
||||
this.position = gui_slider_pixel();
|
||||
// if(this.visible)
|
||||
// this.r_dirty = true;
|
||||
super.reformat();
|
||||
}
|
||||
|
||||
private int gui_slider_value() {
|
||||
int r = this.min + (int)(((float)(int)(this.position - (this.handle / 2))) * ((float)(int)(this.max - this.min)) / ((float)(int)(this.size_x + 1 - this.handle)));
|
||||
return ExtMath.clampi(r, this.min, this.max);
|
||||
}
|
||||
|
||||
private int gui_slider_pixel() {
|
||||
int r = ((int)(float)(((float)(int)(this.value - this.min)) * ((float)(int)(this.size_x + 1 - this.handle)) / ((float)(int)(this.max - this.min)))) + (this.handle / 2);
|
||||
return ExtMath.clampi(r, this.handle / 2, this.size_x - (this.handle / 2));
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
this.value = ExtMath.clampi(value, this.min, this.max);
|
||||
this.position = gui_slider_pixel();
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public void setFloatValue(float value) {
|
||||
this.setValue((int)(value * 1000.0f));
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return (float)this.value / 1000.0f;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.enabled) {
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
Drawing.drawGradientBorder(this.pos_x + this.position - (this.handle / 2), this.pos_y, this.handle, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
}
|
||||
else {
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
Drawing.drawGradientBorder(this.pos_x + this.position - (this.handle / 2), this.pos_y, this.handle, this.size_y, Util.mulColor(this.gm.style.fill_top, 0.5f), Util.mulColor(this.gm.style.fill_btm, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface SliderCallback {
|
||||
void use(Slider elem, int value);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface SliderFloatCallback {
|
||||
void use(Slider elem, float value);
|
||||
}
|
51
client/src/main/java/client/gui/element/Switch.java
Normal file
51
client/src/main/java/client/gui/element/Switch.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Formatter;
|
||||
import client.window.Button;
|
||||
import common.util.Displayable;
|
||||
import common.util.Util;
|
||||
|
||||
public class Switch<T> extends Element {
|
||||
private final SwitchCallback<T> func;
|
||||
private final T[] values;
|
||||
private final int def;
|
||||
|
||||
private int value;
|
||||
|
||||
public Switch(int x, int y, int w, int h, T[] values, T def, T init, SwitchCallback<T> callback, Formatter<Switch<T>> formatter) {
|
||||
super(x, y, w, h, formatter);
|
||||
this.func = callback;
|
||||
this.values = values;
|
||||
this.def = Util.indexOfChecked(this.values, def);
|
||||
this.value = Util.indexOfChecked(this.values, init);
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public Switch(int x, int y, int w, int h, T[] values, T def, T init, SwitchCallback<T> callback, final String text) {
|
||||
this(x, y, w, h, values, def, init, callback, new Formatter<Switch<T>>() {
|
||||
public String use(Switch<T> elem) {
|
||||
T value = elem.getValue();
|
||||
return String.format("%s: %s", text, value instanceof Displayable ? ((Displayable)value).getDisplay() : value.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return this.values[this.value];
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
this.value = Util.indexOfChecked(this.values, value);
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
int prev = this.value;
|
||||
this.value = (ctrl || (btn == Button.MOUSE_MIDDLE)) ? this.def : (this.value + ((shift || (btn == Button.MOUSE_RIGHT)) ? -1 : 1));
|
||||
this.value = (this.value == this.values.length) ? 0 : ((this.value == -1) ? (this.values.length - 1) : this.value);
|
||||
if(this.value != prev) {
|
||||
this.func.use(this, this.getValue());
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface SwitchCallback<T> {
|
||||
void use(Switch<T> elem, T value);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
interface TextCallback<T extends Textbox> {
|
||||
void use(T elem, FieldAction value);
|
||||
}
|
247
client/src/main/java/client/gui/element/Textbox.java
Normal file
247
client/src/main/java/client/gui/element/Textbox.java
Normal file
|
@ -0,0 +1,247 @@
|
|||
package client.gui.element;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import client.gui.Font;
|
||||
import client.renderer.Drawing;
|
||||
import client.window.Button;
|
||||
import client.window.Keysym;
|
||||
import client.window.Window;
|
||||
import common.util.CharValidator;
|
||||
import common.util.Util;
|
||||
|
||||
abstract class Textbox extends Element {
|
||||
protected final TextCallback func;
|
||||
protected final CharValidator validator;
|
||||
protected final int capacity;
|
||||
protected final boolean editable;
|
||||
|
||||
protected long tmr_scroll;
|
||||
protected long tmr_leftmb;
|
||||
protected int sel_start = -1;
|
||||
protected int sel_end = -1;
|
||||
protected int sel_drag = -1;
|
||||
|
||||
protected Textbox(int x, int y, int w, int h, int cap, boolean editable, TextCallback callback, CharValidator validator) {
|
||||
super(x, y, w, h, null);
|
||||
this.func = callback;
|
||||
this.validator = validator;
|
||||
this.capacity = cap;
|
||||
this.editable = editable;
|
||||
}
|
||||
|
||||
public abstract void updateText();
|
||||
protected abstract void onReturn(boolean shift);
|
||||
protected abstract void onSelection(boolean up);
|
||||
public abstract void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift);
|
||||
public abstract void update();
|
||||
protected abstract void gui_text_clamp_scroll();
|
||||
protected abstract void updateCursor(int offset, boolean shift, int x1, int y1, int x2, int y2);
|
||||
protected abstract char getNewline();
|
||||
protected abstract int getCursorX(int x1, int x2);
|
||||
protected abstract int getCursorY(int y1, int y2);
|
||||
protected abstract int onCursorOffset(int x, int y, int x1, int y1, int x2, int y2);
|
||||
protected abstract void drawForeground(int x1, int y1, int x2, int y2);
|
||||
|
||||
public boolean canHover() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int getMarginX() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public void setText(String str) {
|
||||
if(this.validator != null)
|
||||
str = this.validator.filter(str);
|
||||
this.text = str.length() > this.capacity ? str.substring(0, this.capacity) : str;
|
||||
this.updateText();
|
||||
this.sel_start = this.sel_end = this.sel_drag = this.text.length();
|
||||
gui_text_update_cur(this.sel_start, true);
|
||||
}
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
if(btn == Button.MOUSE_LEFT) {
|
||||
if(!shift && ((System.currentTimeMillis() - this.tmr_leftmb) <= (long)this.gm.dclickDelay)) {
|
||||
this.sel_start = this.sel_drag = 0;
|
||||
this.sel_end = this.text.length();
|
||||
}
|
||||
else {
|
||||
gui_text_select(x, y, shift);
|
||||
}
|
||||
this.tmr_leftmb = System.currentTimeMillis();
|
||||
}
|
||||
else if((btn == Button.MOUSE_MIDDLE) && this.func != null) {
|
||||
this.func.use(this, FieldAction.FUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
public void drag(int x, int y) {
|
||||
gui_text_select(x, y, true);
|
||||
}
|
||||
|
||||
public void character(char code) {
|
||||
if(this.editable)
|
||||
insertText(Character.toString(code));
|
||||
}
|
||||
|
||||
public void key(Keysym key, boolean ctrl, boolean shift) {
|
||||
if(ctrl && key == Keysym.A) {
|
||||
this.sel_start = this.sel_drag = 0;
|
||||
this.sel_end = this.text.length();
|
||||
}
|
||||
else if(ctrl && (key == Keysym.C) || (this.editable && (key == Keysym.X))) {
|
||||
if(this.sel_start >= 0 && this.sel_start != this.sel_end) { // fix empty
|
||||
String str = Util.strip(this.text, this.sel_start, this.sel_end - this.sel_start, '\n', (char)0, '?');
|
||||
Window.setClipboard(str);
|
||||
if(key == Keysym.X)
|
||||
insertText("");
|
||||
}
|
||||
}
|
||||
else if(this.editable && ctrl && key == Keysym.V) {
|
||||
insertText(Window.getClipboard());
|
||||
}
|
||||
else if(this.editable && !ctrl && key == Keysym.RETURN) {
|
||||
this.onReturn(shift);
|
||||
}
|
||||
else if(this.editable && (!ctrl) && (key == Keysym.BACKSPACE || key == Keysym.DELETE)) {
|
||||
if(this.sel_start != this.sel_end) {
|
||||
insertText("");
|
||||
}
|
||||
else if(key == Keysym.DELETE && this.sel_start >= 0) {
|
||||
if(this.sel_end < this.text.length()) {
|
||||
this.sel_end += 1;
|
||||
insertText("");
|
||||
}
|
||||
else {
|
||||
this.sel_end = this.sel_start;
|
||||
}
|
||||
}
|
||||
else if(key == Keysym.BACKSPACE && this.sel_start > 0) {
|
||||
this.sel_start -= 1;
|
||||
insertText("");
|
||||
}
|
||||
}
|
||||
else if(!ctrl && (key == Keysym.RIGHT || key == Keysym.LEFT)) {
|
||||
if(key == Keysym.RIGHT && this.sel_start != this.sel_end) {
|
||||
this.sel_start = this.sel_drag = this.sel_end;
|
||||
}
|
||||
else if(key == Keysym.LEFT && this.sel_start != this.sel_end) {
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
}
|
||||
if(key == Keysym.RIGHT && this.sel_start >= 0) {
|
||||
if(this.sel_end < this.text.length()) {
|
||||
this.sel_start = this.sel_drag = this.sel_end += 1;
|
||||
}
|
||||
else {
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
}
|
||||
gui_text_update_cur(this.sel_end, true);
|
||||
}
|
||||
else if(key == Keysym.LEFT && this.sel_start >= 0) {
|
||||
if(this.sel_start > 0)
|
||||
this.sel_start -= 1;
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
gui_text_update_cur(this.sel_end, true);
|
||||
}
|
||||
}
|
||||
else if(!ctrl && (key == Keysym.DOWN || key == Keysym.UP)) {
|
||||
this.onSelection(key == Keysym.UP);
|
||||
}
|
||||
else if((!ctrl) && key == Keysym.TAB) {
|
||||
if(this.func != null) {
|
||||
this.func.use(this, shift ? FieldAction.BACKWARD : FieldAction.FORWARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void select() {
|
||||
if(this.func != null) {
|
||||
this.func.use(this, FieldAction.FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
this.sel_start = this.sel_end = this.sel_drag = -1;
|
||||
this.tmr_leftmb = 0L;
|
||||
if(this.func != null) {
|
||||
this.func.use(this, FieldAction.UNFOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
protected int updateScroll(int value) {
|
||||
if(value != 0) {
|
||||
int n = (int)((float)((float)this.tmr_scroll) / 1000000.0f * 4.0f * ((float)value));
|
||||
if((((long)n) * 1000000L) <= this.tmr_scroll)
|
||||
this.tmr_scroll -= ((long)n) * 1000000L;
|
||||
else
|
||||
this.tmr_scroll = 0L;
|
||||
this.tmr_scroll += this.gm.getPassedTime();
|
||||
return n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void gui_text_update_cur(int offset, boolean shift) {
|
||||
int x1 = this.pos_x + this.margin_x1;
|
||||
int y1 = this.pos_y + this.margin_y1;
|
||||
int x2 = this.size_x - (this.margin_x1 + this.margin_x2);
|
||||
int y2 = this.size_y - (this.margin_y1 + this.margin_y2);
|
||||
gui_text_clamp_scroll();
|
||||
this.updateCursor(offset, shift, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
public void insertText(String str) {
|
||||
if(str == null || (this.sel_start == -1))
|
||||
return;
|
||||
str = Util.strip(str, 0, str.length(), this.getNewline(), ' ', (char)0);
|
||||
if(this.validator != null)
|
||||
str = this.validator.filter(str);
|
||||
if((str.length() + this.text.length() - (this.sel_end - this.sel_start)) > this.capacity)
|
||||
return;
|
||||
this.text = this.text.substring(0, this.sel_start) + str + this.text.substring(this.sel_end);
|
||||
this.sel_start += str.length();
|
||||
this.sel_end = this.sel_drag = this.sel_start;
|
||||
this.updateText();
|
||||
gui_text_update_cur(this.sel_end, true);
|
||||
}
|
||||
|
||||
private void gui_text_select(int x, int y, boolean drag) {
|
||||
int x1 = this.pos_x + this.margin_x1;
|
||||
int y1 = this.pos_y + this.margin_y1;
|
||||
int x2 = this.size_x - (this.margin_x1 + this.margin_x2);
|
||||
int y2 = this.size_y - (this.margin_y1 + this.margin_y2);
|
||||
int offset = this.onCursorOffset(x, y, x1, y1, x2, y2);
|
||||
if(!drag) {
|
||||
this.sel_drag = this.sel_start = this.sel_end = offset;
|
||||
}
|
||||
else if(drag && this.sel_drag >= 0 && offset >= this.sel_drag) {
|
||||
this.sel_start = this.sel_drag;
|
||||
this.sel_end = offset;
|
||||
}
|
||||
else if(drag && this.sel_drag >= 0 && offset < this.sel_drag) {
|
||||
this.sel_start = offset;
|
||||
this.sel_end = this.sel_drag;
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.field_top, this.gm.style.field_btm, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.field_top, 0.5f), Util.mulColor(this.gm.style.field_btm, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
|
||||
public void drawOverlay() {
|
||||
if(this.editable && this.sel_start >= 0 && this.sel_end == this.sel_start && Util.ftime() % 1.0f < 0.5f) {
|
||||
int x1 = this.pos_x + this.margin_x1;
|
||||
int y1 = this.pos_y + this.margin_y1;
|
||||
int x2 = this.size_x - (this.margin_x1 + this.margin_x2);
|
||||
int y2 = this.size_y - (this.margin_y1 + this.margin_y2);
|
||||
GL11.glScissor(x1 < 0 ? 0 : x1, (this.gm.fb_y - (y1 + y2)) < 0 ? 0 : (this.gm.fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2);
|
||||
GL11.glEnable(GL11.GL_SCISSOR_TEST);
|
||||
Drawing.drawRect(this.getCursorX(x1, x2), this.getCursorY(y1, y2), 1, Font.YGLYPH, 0xff000000 | (~Util.mixColor(this.gm.style.field_top, this.gm.style.field_btm)));
|
||||
GL11.glDisable(GL11.GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
53
client/src/main/java/client/gui/element/Toggle.java
Normal file
53
client/src/main/java/client/gui/element/Toggle.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.gui.Formatter;
|
||||
import client.renderer.Drawing;
|
||||
import client.window.Button;
|
||||
import common.util.Util;
|
||||
|
||||
public class Toggle extends Element {
|
||||
private final ToggleCallback func;
|
||||
private final boolean def;
|
||||
|
||||
private boolean value;
|
||||
|
||||
public Toggle(int x, int y, int w, int h, boolean def, boolean init, ToggleCallback callback, Formatter<Toggle> formatter) {
|
||||
super(x, y, w, h, formatter);
|
||||
this.func = callback;
|
||||
this.def = def;
|
||||
this.value = init;
|
||||
this.formatText();
|
||||
}
|
||||
|
||||
public Toggle(int x, int y, int w, int h, boolean def, boolean init, ToggleCallback callback, final String text) {
|
||||
this(x, y, w, h, def, init, callback, new Formatter<Toggle>() {
|
||||
public String use(Toggle elem) {
|
||||
return String.format("%s: %s", text, elem.value ? "An" : "Aus");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
|
||||
boolean prev = this.value;
|
||||
if((this.value = (ctrl || (btn == Button.MOUSE_MIDDLE)) ? this.def : !this.value) != prev) {
|
||||
// this.type = this.value != 0 ? ElemType.TOGGLE_ON : ElemType.TOGGLE_OFF;
|
||||
// gui_update_style(this, 1);
|
||||
// this.r_dirty = true;
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.value) {
|
||||
if(this.enabled)
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
|
||||
else
|
||||
Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
|
||||
}
|
||||
else
|
||||
super.drawBackground();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package client.gui.element;
|
||||
|
||||
public interface ToggleCallback {
|
||||
void use(Toggle elem, boolean value);
|
||||
}
|
17
client/src/main/java/client/gui/element/TransparentArea.java
Normal file
17
client/src/main/java/client/gui/element/TransparentArea.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package client.gui.element;
|
||||
|
||||
import client.renderer.Drawing;
|
||||
|
||||
public class TransparentArea extends Area {
|
||||
private final boolean background;
|
||||
|
||||
public TransparentArea(int x, int y, int w, int h, String text, boolean background) {
|
||||
super(x, y, w, h, text);
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
if(this.background)
|
||||
Drawing.drawRect(this.pos_x, this.pos_y, this.size_x, this.size_y, 0x3f000000);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue