package com.pixelutilitys.arcade.emulators.AEPgb;
/**
* this source file released under the GNU Public Licence.
* see the accompanying copyright.txt for more information
* Copyright (C) 2000-2001 Ben Mazur
* modified by retroK, XTale and baka0815 2004 http://aepgb.aep-emu.de/
*/
import java.applet.Applet;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class AEPgb extends Applet
implements KeyListener, WindowListener, ActionListener, ItemListener, Runnable {
public static boolean applet;
public JFrame frame;
public Container container;
public Thread cpuThread;
public PgbMemory mem;
public PgbCpu cpu;
public PgbCart cart;
public PgbVideo video;
public PgbJoypad joy;
public PgbNetplay net;
public PgbVideoOutput vidout;
public PgbDirectVideoOutput directvidout;
public String curfile;
public String curpath;
public PgbMenuBar menubar;
public AEPgb(){
frame = new JFrame("AEPgb " + PgbSettings.version);
container = frame.getContentPane();
// load settings, if possible
PgbSettings.load();
// initialize...
curfile = "";
curpath = "";
// init menu bar
menubar = new PgbMenuBar(this, this);
// init emulation
cart = new PgbCart();
video = new PgbCachedVideo();
joy = new PgbJoypad();
net = new PgbNetplay();
mem = new PgbMemory(cart, video, joy, net);
cpu = new PgbCpu(mem);
vidout = getPgbVideoOutput(video);
// setup frame stuff
frame.setMenuBar(menubar);
frame.setResizable(false);
frame.addWindowListener(this);
frame.addKeyListener(this);
frame.addKeyListener(joy);
//addFocusListener(this);
}
public static void main(String[] args) {
System.out.println("Pgb" + " (c) 2000-2001 Ben Mazur");
System.out.println(
"AEPgb Version " + PgbSettings.version + " (c) 2004 retroK, XTale, baka0815");
AEPgb pgb = new AEPgb();
pgb.parseCommandLine(args);
pgb.go();
}
public void start() {
applet = true;
Thread p = new Thread(this);
addKeyListener(this);
//runningAsApplet = true;
System.out.println(
"AEPgb Version "
+ PgbSettings.version
+ " (c) 2004 retroK & XTale(applet)");
this.requestFocus();
vidout = getPgbVideoOutput(video);
cpuThread = new Thread(this);
//conformToSettings();
//frame.pack();
vidout.setGraphics();
//frame.setVisible(true);
PgbSettings.paused = true;
PgbSettings.active = true;
cart.loadApplet("file.gb",this);
if (cart.loaded()) {
reset();
unpause();
}
System.out.println("starting cputhread");
p.start();
cpuThread.start();
}
public void go() {
cpuThread = new Thread(this);
conformToSettings(); // once
frame.pack();
vidout.setGraphics();
frame.setVisible(true);
PgbSettings.paused = true;
PgbSettings.active = true;
cart.load(curpath, curfile);
if (cart.loaded()) {
setSystem(PgbSettings.desiredsystem);
PgbSettings.gamestring = cart.getName();
reset();
unpause();
}
cpuThread.start();
}
/**
* Shuts down the emulator, killing off all threads and
* saving the battery and settings, if needed.
*/
public void shutdown() {
cpuThread = null;
PgbSettings.save(frame);
cart.saveBattery(curfile);
// System.exit(0);
}
/**
* Pauses the cpu emulation process.
*/
public synchronized void pause() {
if (!PgbSettings.paused) {
PgbSettings.paused = true;
}
menubar.cpu_paused.setState(PgbSettings.paused);
}
/**
* Unpauses the cpu emulation process.
*/
public synchronized void unpause() {
if (PgbSettings.paused) {
PgbSettings.paused = false;
notifyAll();
}
menubar.cpu_paused.setState(PgbSettings.paused);
}
/**
* Resets all aspects of emulation.
*/
public synchronized void reset() {
pause();
video.reset();
vidout.reset();
cart.reset();
joy.reset();
mem.reset();
cpu.reset();
unpause();
}
public void parseCommandLine(String[] args) {
if (args.length > 0) {
// file is last argument
curfile = args[args.length - 1];
}
}
public PgbVideoOutput getPgbVideoOutput(PgbVideo video) {
// check if they can use directx
if (applet) {
return new PgbDirectVideoOutput(video,this);
}
if (PgbSettings.videooutput == PgbSettings.VIDOUT_DIRECTX
&& !PgbSettings.usedirectx) {
PgbSettings.videooutput = PgbSettings.VIDOUT_DEFAULT;
}
switch (PgbSettings.videooutput) {
case PgbSettings.VIDOUT_DEFAULT :
return new PgbIndexedVideoOutput(video);
case PgbSettings.VIDOUT_DIRECT :
return new PgbDirectVideoOutput(video);
case PgbSettings.VIDOUT_INDEXED :
default :
return new PgbIndexedVideoOutput(video);
}
}
public void conformToSettings() {
setSgbBorder(PgbSettings.sgbborder);
setColorMute(PgbSettings.colormute);
frame.setLocation(PgbSettings.winloc);
setDebugLevel(PgbSettings.debuglevel);
setFrameskip(PgbSettings.frameskip);
setPriority(PgbSettings.priority);
setVideoOutput(PgbSettings.videooutput);
setSystem(PgbSettings.desiredsystem);
setLcdSize(PgbSettings.lcdsize);
}
void setPriority(int priority) {
PgbSettings.priority = priority;
menubar.priority_low.setState(priority == Thread.MIN_PRIORITY);
menubar.priority_normal.setState(priority == Thread.NORM_PRIORITY);
menubar.priority_high.setState(
priority == ((Thread.NORM_PRIORITY + Thread.MAX_PRIORITY) / 2));
menubar.priority_max.setState(priority == Thread.MAX_PRIORITY);
cpuThread.setPriority(priority);
}
// by retroK
void setSound(boolean usesound) {
PgbSettings.usesound = usesound;
menubar.sound.setState(usesound);
mem.soundChip.channel1Enable = menubar.sound.getState();
menubar.soundChannel1Enable.setState(menubar.sound.getState());
mem.soundChip.channel2Enable = menubar.sound.getState();
menubar.soundChannel2Enable.setState(menubar.sound.getState());
mem.soundChip.channel3Enable = menubar.sound.getState();
menubar.soundChannel3Enable.setState(menubar.sound.getState());
mem.soundChip.channel4Enable = menubar.sound.getState();
menubar.soundChannel4Enable.setState(menubar.sound.getState());
}
void setChannelEnable() {
if (menubar.soundChannel1Enable.getState()
|| menubar.soundChannel2Enable.getState()
|| menubar.soundChannel3Enable.getState()
|| menubar.soundChannel4Enable.getState()) {
menubar.sound.setState(true);
}
mem.soundChip.channel1Enable = menubar.soundChannel1Enable.getState();
mem.soundChip.channel2Enable = menubar.soundChannel2Enable.getState();
mem.soundChip.channel3Enable = menubar.soundChannel3Enable.getState();
mem.soundChip.channel4Enable = menubar.soundChannel4Enable.getState();
}
void setSoundFreq(int frequency) {
if (frequency == 11025) {
menubar.soundFreq11.setState(true);
menubar.soundFreq22.setState(false);
menubar.soundFreq44.setState(false);
}
if (frequency == 22050) {
menubar.soundFreq22.setState(true);
menubar.soundFreq11.setState(false);
menubar.soundFreq44.setState(false);
}
if (frequency == 44100) {
menubar.soundFreq44.setState(true);
menubar.soundFreq11.setState(false);
menubar.soundFreq22.setState(false);
}
mem.soundChip.setSampleRate(frequency);
}
void setBufferLength(int bufferlength) {
if (bufferlength == 200) {
menubar.soundBuffer200.setState(true);
menubar.soundBuffer300.setState(false);
menubar.soundBuffer400.setState(false);
}
if (bufferlength == 300) {
menubar.soundBuffer300.setState(true);
menubar.soundBuffer200.setState(false);
menubar.soundBuffer400.setState(false);
}
if (bufferlength == 400) {
menubar.soundBuffer400.setState(true);
menubar.soundBuffer200.setState(false);
menubar.soundBuffer300.setState(false);
}
mem.soundChip.setBufferLength(bufferlength);
}
// end by retroK
void setLcdSize(int size) {
// grr, due to a bug, this will not work on a window
// until it is visible and has been resized...
Dimension lcdsize;
PgbSettings.lcdsize = size;
menubar.size_1.setState(size == 1);
menubar.size_2.setState(size == 2);
menubar.size_3.setState(size == 3);
menubar.size_4.setState(size == 4);
if (PgbSettings.sgbborder) {
lcdsize = new Dimension(256 * size, 224 * size);
} else {
lcdsize = new Dimension(160 * size, 144 * size);
}
vidout.setSize(lcdsize);
frame.setSize(
frame.getInsets().right + lcdsize.width + frame.getInsets().left,
frame.getInsets().top + lcdsize.height + frame.getInsets().bottom);
}
void setVideoOutput(int videooutput) {
// check if they can use directx
if (videooutput == PgbSettings.VIDOUT_DIRECTX
&& !PgbSettings.usedirectx) {
videooutput = PgbSettings.VIDOUT_DEFAULT;
}
// then set up the menus as normal
PgbSettings.videooutput = videooutput;
if (videooutput == PgbSettings.VIDOUT_DEFAULT) {
menubar.vidout_default.setState(true);
if (PgbSettings.usedirectx) {
menubar.vidout_directx.setState(true);
menubar.vidout_indexed.setState(false);
menubar.vidout_direct.setState(false);
} else {
menubar.vidout_directx.setState(false);
menubar.vidout_indexed.setState(true);
menubar.vidout_direct.setState(false);
}
} else {
menubar.vidout_default.setState(
videooutput == PgbSettings.VIDOUT_DEFAULT);
menubar.vidout_directx.setState(
videooutput == PgbSettings.VIDOUT_DIRECTX);
menubar.vidout_indexed.setState(
videooutput == PgbSettings.VIDOUT_INDEXED);
menubar.vidout_direct.setState(
videooutput == PgbSettings.VIDOUT_DIRECT);
}
pause();
PgbVideoOutput oldVidout = vidout;
// add new video
PgbVideoOutput newVidout = getPgbVideoOutput(video);
newVidout.addKeyListener(this);
newVidout.addKeyListener(joy);
// remove old video, add new one
// old vidout, please die peacefully...
frame.remove(oldVidout);
frame.getContentPane().add(newVidout);
frame.validate();
if (frame.isVisible()) {
newVidout.reset();
newVidout.requestFocus();
}
this.vidout = newVidout;
unpause();
}
void setColorMute(boolean muted) {
PgbSettings.colormute = muted;
menubar.color_mute.setState(muted);
}
void setSgbBorder(boolean border) {
PgbSettings.sgbborder = border;
menubar.sgb_border.setState(border);
}
void setFrameskip(int skip) {
PgbSettings.frameskip = skip;
menubar.auto_wait.setState(PgbSettings.autowait);
menubar.fs_0.setState(skip == 0);
menubar.fs_1.setState(skip == 1);
menubar.fs_2.setState(skip == 2);
menubar.fs_3.setState(skip == 3);
menubar.fs_4.setState(skip == 4);
menubar.fs_5.setState(skip == 5);
}
void setDebugLevel(int level) {
PgbSettings.debuglevel = level;
menubar.debug_0.setState(level == 0);
menubar.debug_1.setState(level == 1);
menubar.debug_2.setState(level == 2);
menubar.debug_3.setState(level == 3);
menubar.debug_4.setState(level == 4);
menubar.debug_5.setState(level == 5);
}
void setSystem(int sys) {
PgbSettings.desiredsystem = sys;
menubar.sys_gb.setState(sys == PgbSettings.SYS_GB);
menubar.sys_gbp.setState(sys == PgbSettings.SYS_GBP);
menubar.sys_sgb.setState(sys == PgbSettings.SYS_SGB);
menubar.sys_gbc.setState(sys == PgbSettings.SYS_GBC);
if (sys == PgbSettings.SYS_GBC && !cart.getGbc()) {
sys = PgbSettings.SYS_SGB;
}
if (sys == PgbSettings.SYS_SGB && !cart.getSgb()) {
sys = PgbSettings.SYS_GBP;
}
PgbSettings.system = sys;
}
synchronized void loadCart() {
FileDialog fd;
cart.saveBattery(curfile);
fd = new FileDialog(frame, curpath, FileDialog.LOAD);
fd.setTitle("Load ROM...");
fd.setFilenameFilter(cart);
fd.setVisible(true);
if (fd.getFile() == null) {
return;
}
curfile = fd.getDirectory()+fd.getFile();
curpath = fd.getDirectory();
//fd.dispose();
if (cart.load(curpath, curfile)) {
setSystem(PgbSettings.desiredsystem);
PgbSettings.gamestring = cart.getName();
net.sendInfo();
reset();
unpause();
}
}
/**
* WindowListener
*/
public void windowClosing(WindowEvent ev) {
shutdown();
}
public void windowOpened(WindowEvent ev) {
}
public void windowClosed(WindowEvent ev) {
}
public synchronized void windowDeiconified(WindowEvent ev) {
if (!PgbSettings.active) {
PgbSettings.active = true;
notifyAll();
}
}
public synchronized void windowActivated(WindowEvent ev) {
/*
if(!PgbSettings.active) {
PgbSettings.active = true;
notify();
}
*/
}
public synchronized void windowIconified(WindowEvent ev) {
if (PgbSettings.active) {
PgbSettings.active = false;
}
}
public synchronized void windowDeactivated(WindowEvent ev) {
/*
if(PgbSettings.active) {
PgbSettings.active = false;
}
*/
}
/**
* KeyListener
*/
public void keyReleased(KeyEvent ev) {
}
public void keyPressed(KeyEvent ev) {
if (ev.getKeyCode() == KeyEvent.VK_SPACE) {
cpu.exec(1);
}
if (ev.getKeyCode() == PgbSettings.key_screen) {
vidout.makeScreenshot();
}
}
public void keyTyped(KeyEvent ev) {
}
/**
* ActionListener
*/
public synchronized void actionPerformed(ActionEvent ev) {
switch (ev.getActionCommand())
{
case "file_about":
String message = "Pgb (c) 2000-2001 Ben Mazur\nAEPgb Version "+PgbSettings.version+" (c) 2004 retroK, XTale, baka0815\nhttp://aepgb.aep-emu.de/";
JOptionPane.showMessageDialog(frame, message, "About AEPgb", JOptionPane.INFORMATION_MESSAGE);
break;
case "file_load":
loadCart();
break;
case "file_exit":
shutdown();
break;
case "cpu_reset":
reset();
break;
case "cpu_paused":
if (PgbSettings.paused) {
unpause();
} else {
pause();
}
break;
case "serial_connect":
net.popNetDialog(frame);
break;
case "options_setkeys":
PgbSettings.popKeysDialog(frame);
break;
}
}
/**
* ItemListener
*/
public synchronized void itemStateChanged(ItemEvent ev) {
if (ev.getItemSelectable().equals(menubar.cpu_paused)) {
if (PgbSettings.paused) {
unpause();
} else {
pause();
}
return;
}
if (ev.getItemSelectable().equals(menubar.vidout_default)) {
setVideoOutput(PgbSettings.VIDOUT_DEFAULT);
return;
}
if (ev.getItemSelectable().equals(menubar.vidout_directx)) {
setVideoOutput(PgbSettings.VIDOUT_DIRECTX);
return;
}
if (ev.getItemSelectable().equals(menubar.vidout_indexed)) {
setVideoOutput(PgbSettings.VIDOUT_INDEXED);
return;
}
if (ev.getItemSelectable().equals(menubar.vidout_direct)) {
setVideoOutput(PgbSettings.VIDOUT_DIRECT);
return;
}
if (ev.getItemSelectable().equals(menubar.sound)) {
setSound(menubar.sound.getState());
return;
}
if (ev.getItemSelectable().equals(menubar.soundChannel1Enable)
|| ev.getItemSelectable().equals(menubar.soundChannel2Enable)
|| ev.getItemSelectable().equals(menubar.soundChannel3Enable)
|| ev.getItemSelectable().equals(menubar.soundChannel4Enable)) {
setChannelEnable();
return;
}
if (ev.getItemSelectable().equals(menubar.soundBuffer200)) {
setBufferLength(200);
return;
}
if (ev.getItemSelectable().equals(menubar.soundBuffer300)) {
setBufferLength(300);
return;
}
if (ev.getItemSelectable().equals(menubar.soundBuffer400)) {
setBufferLength(400);
return;
}
if (ev.getItemSelectable().equals(menubar.soundFreq11)) {
setSoundFreq(11025);
return;
}
if (ev.getItemSelectable().equals(menubar.soundFreq22)) {
setSoundFreq(22050);
return;
}
if (ev.getItemSelectable().equals(menubar.soundFreq44)) {
setSoundFreq(44100);
return;
}
if (ev.getItemSelectable().equals(menubar.size_1)) {
setLcdSize(1);
return;
}
if (ev.getItemSelectable().equals(menubar.size_2)) {
setLcdSize(2);
return;
}
if (ev.getItemSelectable().equals(menubar.size_3)) {
setLcdSize(3);
return;
}
if (ev.getItemSelectable().equals(menubar.size_4)) {
setLcdSize(4);
return;
}
if (ev.getItemSelectable().equals(menubar.color_mute)) {
setColorMute(menubar.color_mute.getState());
return;
}
if (ev.getItemSelectable().equals(menubar.sgb_border)) {
setSgbBorder(menubar.sgb_border.getState());
setLcdSize(PgbSettings.lcdsize);
return;
}
if (ev.getItemSelectable().equals(menubar.auto_wait)) {
PgbSettings.autowait = !PgbSettings.autowait;
setFrameskip(PgbSettings.frameskip);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_0)) {
setFrameskip(0);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_1)) {
setFrameskip(1);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_2)) {
setFrameskip(2);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_3)) {
setFrameskip(3);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_4)) {
setFrameskip(4);
return;
}
if (ev.getItemSelectable().equals(menubar.fs_5)) {
setFrameskip(5);
return;
}
if (ev.getItemSelectable().equals(menubar.priority_low)) {
setPriority(Thread.MIN_PRIORITY);
return;
}
if (ev.getItemSelectable().equals(menubar.priority_normal)) {
setPriority(Thread.NORM_PRIORITY);
return;
}
if (ev.getItemSelectable().equals(menubar.priority_high)) {
setPriority((Thread.NORM_PRIORITY + Thread.MAX_PRIORITY) / 2);
return;
}
if (ev.getItemSelectable().equals(menubar.priority_max)) {
setPriority(Thread.MAX_PRIORITY);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_0)) {
setDebugLevel(0);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_1)) {
setDebugLevel(1);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_2)) {
setDebugLevel(2);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_3)) {
setDebugLevel(3);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_4)) {
setDebugLevel(4);
return;
}
if (ev.getItemSelectable().equals(menubar.debug_5)) {
setDebugLevel(5);
return;
}
if (ev.getItemSelectable().equals(menubar.sys_gb)) {
setSystem(PgbSettings.SYS_GB);
reset();
}
if (ev.getItemSelectable().equals(menubar.sys_gbp)) {
setSystem(PgbSettings.SYS_GBP);
reset();
}
if (ev.getItemSelectable().equals(menubar.sys_sgb)) {
setSystem(PgbSettings.SYS_SGB);
reset();
}
if (ev.getItemSelectable().equals(menubar.sys_gbc)) {
setSystem(PgbSettings.SYS_GBC);
reset();
}
}
/**
* Runnable
*/
public final void run() {
int cyclecount = 0;
long lasttime = System.currentTimeMillis(),
lastframe = video.framecount;
long interval = 1;
long thistime, time, frames;
int framereal, frametarget;
Thread currentThread = Thread.currentThread();
while (cpuThread == currentThread) {
try {
Thread.sleep(interval);
synchronized (this) {
while ((PgbSettings.paused || !PgbSettings.active)
&& cpuThread == currentThread) {
wait();
}
}
} catch (InterruptedException ex) {
// duh?
}
cpu.exec((int) (PgbSettings.clockspeed * 100000));
if (cyclecount++ == 10) {
// calculate
thistime = System.currentTimeMillis();
time = thistime - lasttime;
frames = video.framecount - lastframe;
framereal = (int) (frames * (1000.0 / time));
frametarget = 60;
// adjust
if (PgbSettings.autowait) {
// attempt to regulate speed...
// it doesn't adjust fast, but it doesn't overadjust
if (frametarget - framereal > 5) {
interval = Math.max(interval - 4, 1);
}
if (framereal - frametarget > 5) {
interval += 4;
}
} else {
interval = 1;
}
// display
frame.setTitle(
"AEPgb : "
+ framereal
+ "/"
+ frametarget
+ " fps, wait="
+ interval);
// get ready for next time
cyclecount = 0;
lasttime = thistime;
lastframe = video.framecount;
}
}
}
}