diff --git a/src/snes/snes.hpp b/src/snes/snes.hpp index 52ccb267..c2c88391 100644 --- a/src/snes/snes.hpp +++ b/src/snes/snes.hpp @@ -1,4 +1,4 @@ -static const char bsnesVersion[] = "064.01"; +static const char bsnesVersion[] = "064.02"; static const char bsnesTitle[] = "bsnes"; static const unsigned bsnesSerializerVersion = 10; diff --git a/src/ui_python/bsnes-gtk.py b/src/ui_python/bsnes-gtk.py index e33ff75b..98c9e553 100644 --- a/src/ui_python/bsnes-gtk.py +++ b/src/ui_python/bsnes-gtk.py @@ -1,4 +1,200 @@ #!/usr/bin/python -from mainwindow import MainWindow +import sys, time, array, ctypes, os, ao +import pygtk +pygtk.require("2.0") +import gtk, gobject +from libsnes import SNES + +snes = SNES() + +class MainWindow(gtk.Window): + def __init__(self): + gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) + + self.keystate_up = 0 + self.keystate_down = 0 + self.keystate_left = 0 + self.keystate_right = 0 + self.keystate_a = 0 + self.keystate_b = 0 + self.keystate_x = 0 + self.keystate_y = 0 + self.keystate_l = 0 + self.keystate_r = 0 + self.keystate_select = 0 + self.keystate_start = 0 + + self.set_title("bsnes/PyGTK") + self.set_position(gtk.WIN_POS_CENTER) + self.set_resizable(False) + self.connect("key-press-event", self.key_press) + self.connect("key-release-event", self.key_release) + self.connect("destroy", self.destroy) + + self.box = gtk.VBox() + self.add(self.box) + + self.menu = gtk.MenuBar() + + self.system_menu = gtk.Menu() + self.system_menuitem = gtk.MenuItem("System") + self.system_menuitem.set_submenu(self.system_menu) + + self.system_load = gtk.MenuItem("Load Cartridge") + self.system_load.connect("activate", self.load_cartridge) + self.system_menu.append(self.system_load) + + self.system_quit = gtk.MenuItem("Quit") + self.system_quit.connect("activate", gtk.main_quit) + self.system_menu.append(self.system_quit) + + self.settings_menu = gtk.Menu() + self.settings_menuitem = gtk.MenuItem("Settings") + self.settings_menuitem.set_submenu(self.settings_menu) + + self.tools_menu = gtk.Menu() + self.tools_menuitem = gtk.MenuItem("Tools") + self.tools_menuitem.set_submenu(self.tools_menu) + + self.help_menu = gtk.Menu() + self.help_menuitem = gtk.MenuItem("Help") + self.help_menuitem.set_submenu(self.help_menu) + + self.menu.append(self.system_menuitem) + self.menu.append(self.settings_menuitem) + self.menu.append(self.tools_menuitem) + self.menu.append(self.help_menuitem) + self.box.pack_start(self.menu, False, False, 0) + + self.canvas = gtk.DrawingArea() + self.canvas.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0)) + self.canvas.set_size_request(512, 448) + self.box.pack_start(self.canvas) + + self.videobuffer = array.array('B', [0] * 512 * 448 * 4) + self.audiobuffer = array.array('H', [0] * 256 * 2) + self.audiolength = 0 + self.audio = ao.AudioDevice("alsa", bits = 16, rate = 32000, channels = 2) + + self.show_all() + + snes.init() + snes.set_video_refresh(self.video_refresh) + snes.set_audio_sample(self.audio_sample) + snes.set_input_poll(self.input_poll) + snes.set_input_state(self.input_state) + + colortable = array.array('I', [0] * 32 * 32 * 32) + offset = 0 + for r in xrange(32): + for g in xrange(32): + for b in xrange(32): + colortable[offset] = (r << 19) + (g << 11) + (b << 3) + offset += 1 + snes.set_colortable(colortable) + + if len(sys.argv) == 2: + snes.load_cartridge_normal(sys.argv[1]) + + def key_press(self, widget, event): + if event.keyval == 65362: self.keystate_up = 1 + if event.keyval == 65364: self.keystate_down = 1 + if event.keyval == 65361: self.keystate_left = 1 + if event.keyval == 65363: self.keystate_right = 1 + if event.keyval == 122: self.keystate_b = 1 + if event.keyval == 120: self.keystate_a = 1 + if event.keyval == 97: self.keystate_y = 1 + if event.keyval == 115: self.keystate_x = 1 + if event.keyval == 100: self.keystate_l = 1 + if event.keyval == 99: self.keystate_r = 1 + if event.keyval == 39: self.keystate_select = 1 + if event.keyval == 65293: self.keystate_start = 1 + + def key_release(self, widget, event): + if event.keyval == 65362: self.keystate_up = 0 + if event.keyval == 65364: self.keystate_down = 0 + if event.keyval == 65361: self.keystate_left = 0 + if event.keyval == 65363: self.keystate_right = 0 + if event.keyval == 122: self.keystate_b = 0 + if event.keyval == 120: self.keystate_a = 0 + if event.keyval == 97: self.keystate_y = 0 + if event.keyval == 115: self.keystate_x = 0 + if event.keyval == 100: self.keystate_l = 0 + if event.keyval == 99: self.keystate_r = 0 + if event.keyval == 39: self.keystate_select = 0 + if event.keyval == 65293: self.keystate_start = 0 + + def destroy(self, widget, data=None): + snes.term() + gtk.main_quit() + + def load_cartridge(self, widget): + dialog = gtk.FileChooserDialog("Load Cartridge", None, gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + + filter = gtk.FileFilter() + filter.set_name("SNES cartridges") + filter.add_pattern("*.sfc") + filter.add_pattern("*.smc") + filter.add_pattern("*.swc") + filter.add_pattern("*.fig") + dialog.add_filter(filter) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + snes.unload() + snes.load_cartridge_normal(dialog.get_filename()) + + dialog.destroy() + + def run(self): + if snes.loaded == True: + snes.run() + + def video_refresh(self, data, width, height): + # ignore overscan region to guarantee 1:1 pixel scaling + if height == 239: height = 224 + if height == 478: height = 448 + pitch = 2048 + if height >= 448: pitch = 1024 + + drawable = self.canvas.window + gc = self.canvas.get_style().fg_gc[gtk.STATE_NORMAL] + snes.blit(self.videobuffer, 2048, 512, 448, data, pitch, width, height) + drawable.draw_rgb_32_image(gc, 0, 0, 512, 448, gtk.gdk.RGB_DITHER_NONE, self.videobuffer, -1) + + def audio_sample(self, left, right): + self.audiobuffer[self.audiolength] = left; self.audiolength += 1 + self.audiobuffer[self.audiolength] = right; self.audiolength += 1 + if self.audiolength == 256 * 2: + self.audio.play(self.audiobuffer, 256 * 2 * 2) + self.audiolength = 0 + + def input_poll(self): + pass + + def input_state(self, port, device, index, identifier): + if port == 1: return 0 + + if self.keystate_up == 1 and self.keystate_down == 1: self.keystate_down = 0 + if self.keystate_left == 1 and self.keystate_right == 1: self.keystate_right = 0 + + if identifier == 0: return self.keystate_b + if identifier == 1: return self.keystate_y + if identifier == 2: return self.keystate_select + if identifier == 3: return self.keystate_start + if identifier == 4: return self.keystate_up + if identifier == 5: return self.keystate_down + if identifier == 6: return self.keystate_left + if identifier == 7: return self.keystate_right + if identifier == 8: return self.keystate_a + if identifier == 9: return self.keystate_x + if identifier == 10: return self.keystate_l + if identifier == 11: return self.keystate_r + + return 0 mainWindow = MainWindow() +timer = gobject.timeout_add(10, lambda: mainWindow.run() or True) +gtk.main() diff --git a/src/ui_python/bsnes-qt.py b/src/ui_python/bsnes-qt.py new file mode 100644 index 00000000..bfb08928 --- /dev/null +++ b/src/ui_python/bsnes-qt.py @@ -0,0 +1,135 @@ +#!/usr/bin/python +import sys, time, array, ctypes, os, ao +from PyQt4 import QtCore +from PyQt4 import QtGui +from PyQt4 import QtOpenGL +from OpenGL.GL import * +from libsnes import SNES + +snes = SNES() + +class Canvas(QtOpenGL.QGLWidget): + def __init__(self, parent = None): + self.videobuffer = array.array('I', [0] * 512 * 512) + self.colortable = array.array('I', [0] * 32 * 32 * 32) + offset = 0 + for r in xrange(32): + for g in xrange(32): + for b in xrange(32): + self.colortable[offset] = (b << 19) + (g << 11) + (r << 3) + offset += 1 + snes.set_colortable(self.colortable) + + self.rasterWidth = 256 + self.rasterHeight = 224 + + QtOpenGL.QGLWidget.__init__(self, parent) + self.setMinimumSize(512, 448) + + def videoRefresh(self, data, width, height): + pitch = 2048 + if height >= 448: pitch = 1024 + if height == 239: height = 224 + if height == 478: height = 448 + + self.rasterWidth = width + self.rasterHeight = height + + snes.blit(self.videobuffer, 2048, width, height, data, pitch, width, height) + self.update() + + def paintGL(self): + outputWidth = self.width() + outputHeight = self.height() + + textureWidth = 512 + textureHeight = 512 + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0, outputWidth, 0, outputHeight, -1.0, 1.0) + glViewport(0, 0, outputWidth, outputHeight) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, self.rasterWidth, self.rasterHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, self.videobuffer.tostring()) + + w = 1.0 * self.rasterWidth / textureWidth + h = 1.0 * self.rasterHeight / textureHeight + u = outputWidth + v = outputHeight + + glBegin(GL_TRIANGLE_STRIP) + glTexCoord2f(0, 0); glVertex3i(0, v, 0) + glTexCoord2f(w, 0); glVertex3i(u, v, 0) + glTexCoord2f(0, h); glVertex3i(0, 0, 0) + glTexCoord2f(w, h); glVertex3i(u, 0, 0) + glEnd() + + def initializeGL(self): + glDisable(GL_ALPHA_TEST) + glDisable(GL_BLEND) + glDisable(GL_DEPTH_TEST) + glDisable(GL_POLYGON_SMOOTH) + glDisable(GL_STENCIL_TEST) + glEnable(GL_DITHER) + glEnable(GL_TEXTURE_2D) + glClearColor(0.0, 0.0, 0.0, 0.0) + + glBindTexture(GL_TEXTURE_2D, glGenTextures(1)) + glPixelStorei(GL_UNPACK_ROW_LENGTH, 512) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, self.videobuffer.tostring()) + +class MainWindow(QtGui.QMainWindow): + def __init__(self, parent = None): + QtGui.QMainWindow.__init__(self, parent) + self.setWindowTitle("bsnes/PyQt") + + self.menu_system = self.menuBar().addMenu("&System") + + self.menu_system_loadCartridge = QtGui.QAction("Load Cartridge ...", self) + self.connect(self.menu_system_loadCartridge, QtCore.SIGNAL('triggered()'), self.loadCartridgeEvent) + self.menu_system.addAction(self.menu_system_loadCartridge) + + self.menu_system_quit = QtGui.QAction("Quit", self) + self.connect(self.menu_system_quit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) + self.menu_system.addAction(self.menu_system_quit) + + self.menu_settings = self.menuBar().addMenu("S&ettings") + self.menu_tools = self.menuBar().addMenu("&Tools") + self.menu_help = self.menuBar().addMenu("&Help") + + self.canvas = Canvas() + self.setCentralWidget(self.canvas) + + self.resize(0, 0) + self.show() + + self.audio = ao.AudioDevice("alsa", bits = 16, rate = 32000, channels = 2) + + snes.init() + snes.set_video_refresh(self.canvas.videoRefresh) + snes.set_audio_sample(self.audioSample) + + if len(sys.argv) == 2: + snes.load_cartridge_normal(sys.argv[1]) + + def audioSample(self, left, right): + self.audio.play(array.array('H', [left, right]), 4) + + def loadCartridgeEvent(self): + filename = QtGui.QFileDialog.getOpenFileName(self, "Load SNES Cartridge", "", "SNES cartridges (*.sfc)") + if len(filename) > 0: + snes.load_cartridge_normal(filename) + +app = QtGui.QApplication(sys.argv) +mainWindow = MainWindow() +while mainWindow.isVisible() == True: + app.processEvents() + if snes.loaded == True: + snes.run() diff --git a/src/ui_python/libsnes.pyc b/src/ui_python/libsnes.pyc new file mode 100644 index 00000000..8d3b79b3 Binary files /dev/null and b/src/ui_python/libsnes.pyc differ diff --git a/src/ui_python/mainwindow.py b/src/ui_python/mainwindow.py deleted file mode 100644 index 256b6bea..00000000 --- a/src/ui_python/mainwindow.py +++ /dev/null @@ -1,198 +0,0 @@ -import sys, time, array, ctypes, os, ao -import pygtk -pygtk.require("2.0") -import gtk, gobject -from libsnes import SNES - -snes = SNES() - -class MainWindow(gtk.Window): - def __init__(self): - gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) - - self.keystate_up = 0 - self.keystate_down = 0 - self.keystate_left = 0 - self.keystate_right = 0 - self.keystate_a = 0 - self.keystate_b = 0 - self.keystate_x = 0 - self.keystate_y = 0 - self.keystate_l = 0 - self.keystate_r = 0 - self.keystate_select = 0 - self.keystate_start = 0 - - self.set_title("bsnes/PyGTK") - self.set_position(gtk.WIN_POS_CENTER) - self.set_resizable(False) - self.connect("key-press-event", self.key_press) - self.connect("key-release-event", self.key_release) - self.connect("destroy", self.destroy) - - self.box = gtk.VBox() - self.add(self.box) - - self.menu = gtk.MenuBar() - - self.system_menu = gtk.Menu() - self.system_menuitem = gtk.MenuItem("System") - self.system_menuitem.set_submenu(self.system_menu) - - self.system_load = gtk.MenuItem("Load Cartridge") - self.system_load.connect("activate", self.load_cartridge) - self.system_menu.append(self.system_load) - - self.system_quit = gtk.MenuItem("Quit") - self.system_quit.connect("activate", gtk.main_quit) - self.system_menu.append(self.system_quit) - - self.settings_menu = gtk.Menu() - self.settings_menuitem = gtk.MenuItem("Settings") - self.settings_menuitem.set_submenu(self.settings_menu) - - self.tools_menu = gtk.Menu() - self.tools_menuitem = gtk.MenuItem("Tools") - self.tools_menuitem.set_submenu(self.tools_menu) - - self.help_menu = gtk.Menu() - self.help_menuitem = gtk.MenuItem("Help") - self.help_menuitem.set_submenu(self.help_menu) - - self.menu.append(self.system_menuitem) - self.menu.append(self.settings_menuitem) - self.menu.append(self.tools_menuitem) - self.menu.append(self.help_menuitem) - self.box.pack_start(self.menu, False, False, 0) - - self.canvas = gtk.DrawingArea() - self.canvas.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0)) - self.canvas.set_size_request(512, 448) - self.box.pack_start(self.canvas) - - self.videobuffer = array.array('B', [0] * 512 * 448 * 4) - self.audiobuffer = array.array('H', [0] * 256 * 2) - self.audiolength = 0 - self.audio = ao.AudioDevice("alsa", bits = 16, rate = 32000, channels = 2) - - self.show_all() - - snes.init() - snes.set_video_refresh(self.video_refresh) - snes.set_audio_sample(self.audio_sample) - snes.set_input_poll(self.input_poll) - snes.set_input_state(self.input_state) - - colortable = array.array('I', [0] * 32 * 32 * 32) - offset = 0 - for r in xrange(32): - for g in xrange(32): - for b in xrange(32): - colortable[offset] = (r << 19) + (g << 11) + (b << 3) - offset += 1 - snes.set_colortable(colortable) - - if len(sys.argv) == 2: - snes.load_cartridge_normal(sys.argv[1]) - - self.timer = gobject.timeout_add(10, lambda: self.run() or True) - gtk.main() - - def key_press(self, widget, event): - if event.keyval == 65362: self.keystate_up = 1 - if event.keyval == 65364: self.keystate_down = 1 - if event.keyval == 65361: self.keystate_left = 1 - if event.keyval == 65363: self.keystate_right = 1 - if event.keyval == 122: self.keystate_b = 1 - if event.keyval == 120: self.keystate_a = 1 - if event.keyval == 97: self.keystate_y = 1 - if event.keyval == 115: self.keystate_x = 1 - if event.keyval == 100: self.keystate_l = 1 - if event.keyval == 99: self.keystate_r = 1 - if event.keyval == 39: self.keystate_select = 1 - if event.keyval == 65293: self.keystate_start = 1 - - def key_release(self, widget, event): - if event.keyval == 65362: self.keystate_up = 0 - if event.keyval == 65364: self.keystate_down = 0 - if event.keyval == 65361: self.keystate_left = 0 - if event.keyval == 65363: self.keystate_right = 0 - if event.keyval == 122: self.keystate_b = 0 - if event.keyval == 120: self.keystate_a = 0 - if event.keyval == 97: self.keystate_y = 0 - if event.keyval == 115: self.keystate_x = 0 - if event.keyval == 100: self.keystate_l = 0 - if event.keyval == 99: self.keystate_r = 0 - if event.keyval == 39: self.keystate_select = 0 - if event.keyval == 65293: self.keystate_start = 0 - - def destroy(self, widget, data=None): - snes.term() - gtk.main_quit() - - def load_cartridge(self, widget): - dialog = gtk.FileChooserDialog("Load Cartridge", None, gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - - filter = gtk.FileFilter() - filter.set_name("SNES cartridges") - filter.add_pattern("*.sfc") - filter.add_pattern("*.smc") - filter.add_pattern("*.swc") - filter.add_pattern("*.fig") - dialog.add_filter(filter) - - response = dialog.run() - if response == gtk.RESPONSE_OK: - snes.unload() - snes.load_cartridge_normal(dialog.get_filename()) - - dialog.destroy() - - def run(self): - if snes.loaded == True: - snes.run() - - def video_refresh(self, data, width, height): - # ignore overscan region to guarantee 1:1 pixel scaling - if height == 239: height = 224 - if height == 478: height = 448 - pitch = 2048 - if height >= 448: pitch = 1024 - - drawable = self.canvas.window - gc = self.canvas.get_style().fg_gc[gtk.STATE_NORMAL] - snes.blit(self.videobuffer, 2048, 512, 448, data, pitch, width, height) - drawable.draw_rgb_32_image(gc, 0, 0, 512, 448, gtk.gdk.RGB_DITHER_NONE, self.videobuffer, -1) - - def audio_sample(self, left, right): - self.audiobuffer[self.audiolength] = left; self.audiolength += 1 - self.audiobuffer[self.audiolength] = right; self.audiolength += 1 - if self.audiolength == 256 * 2: - self.audio.play(self.audiobuffer, 256 * 2 * 2) - self.audiolength = 0 - - def input_poll(self): - pass - - def input_state(self, port, device, index, identifier): - if port == 1: return 0 - - if self.keystate_up == 1 and self.keystate_down == 1: self.keystate_down = 0 - if self.keystate_left == 1 and self.keystate_right == 1: self.keystate_right = 0 - - if identifier == 0: return self.keystate_b - if identifier == 1: return self.keystate_y - if identifier == 2: return self.keystate_select - if identifier == 3: return self.keystate_start - if identifier == 4: return self.keystate_up - if identifier == 5: return self.keystate_down - if identifier == 6: return self.keystate_left - if identifier == 7: return self.keystate_right - if identifier == 8: return self.keystate_a - if identifier == 9: return self.keystate_x - if identifier == 10: return self.keystate_l - if identifier == 11: return self.keystate_r - - return 0