]> localhost Git - glBoy.git/commitdiff
Taking a backup before including libzipper submodule
authorMichael McMaster <email@michaelmcmaster.name>
Thu, 1 Sep 2011 07:06:35 +0000 (17:06 +1000)
committerMichael McMaster <email@michaelmcmaster.name>
Thu, 1 Sep 2011 07:06:35 +0000 (17:06 +1000)
23 files changed:
.gitignore
ALU.hh [changed mode: 0755->0644]
Config.cc [new file with mode: 0644]
GameboyCart.cc
GameboyCart.hh
GameboyJoypad.cc
GameboyJoypad.hh
InstructionSet.opcode [changed mode: 0755->0644]
Main.cc
Makefile [deleted file]
Makefile.am [new file with mode: 0644]
MemoryMap.cc
MemoryMap.hh
NEWS [new file with mode: 0644]
README
Unzip.cc [new file with mode: 0644]
VERSION
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
glBoy.config [new file with mode: 0644]
glBoy.hh
hq4x.cc
makeOpcodes.pl

index 7533894ddec4b210f69e7b8e3360d124d621c5e7..e25d00d0def0306408b78dd5f2905d5c09463c2a 100644 (file)
@@ -4,6 +4,6 @@
 *.bin
 InstructionSet_Opcodes.cc
 InstructionSet_Tables.cc
-awesomeBoy
+glBoy
 test
 
diff --git a/ALU.hh b/ALU.hh
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/Config.cc b/Config.cc
new file mode 100644 (file)
index 0000000..3ced34d
--- /dev/null
+++ b/Config.cc
@@ -0,0 +1,291 @@
+//     Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+//
+//     This file is part of glBoy.
+//
+//     glBoy is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+//
+//     glBoy is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+//
+//     You should have received a copy of the GNU General Public License
+//     along with glBoy.  If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "glBoy.hh"
+#include "Core.hh"
+#include "GameboyCart.hh"
+#include "GameboyGraphics.hh"
+#include "GameboyJoypad.hh"
+#include "GameboySound.hh"
+#include "GameboyTimer.hh"
+#include "RAM.hh"
+#include "ROM.hh"
+#include "Log.hh"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_opengl.h>
+#include <SDL/SDL_video.h>
+
+#include <cassert>
+#include <set>
+#include <sstream>
+
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace
+{
+       SDL_Surface*
+       initOpenGL(double xScale, double yScale, bool fullscreen)
+       {
+               glBoy::Log::Instance()(glBoy::Log::DBG_STAT) << "Enabling OpenGL" << std::endl;
+
+               SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+               unsigned int options(SDL_OPENGL);
+               if (fullscreen)
+               {
+                       options |= SDL_FULLSCREEN;
+               }
+
+               SDL_Surface* surface(
+                       SDL_SetVideoMode(160*xScale, 144*yScale, 32, options)
+                       );
+
+               glEnable(GL_TEXTURE_2D);
+               glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+               glClear(GL_COLOR_BUFFER_BIT);
+               glDisable(GL_DEPTH_TEST);
+               glMatrixMode(GL_PROJECTION);
+               glLoadIdentity();
+               glOrtho(0.0f, 160, 144, 0.0f, -1.0f, 1.0f);
+               glMatrixMode(GL_MODELVIEW);
+               glLoadIdentity();
+
+               return surface;
+       }
+
+       void usage(const std::string& exe)
+       {
+               std::cout <<
+                       "Usage: " << exe << " "
+                               "[--scale ratio] [--width w] [--height h] \n"
+                               //"\t\t    [--resample-method={bilinear|nearest} \n"
+                               //"\t\t[--scaling-method={hq4x|scale2x|none}] "
+                               "rom.gb" << std::endl <<
+                       std::endl <<
+                               "\t--scale\t(Default=4.0)" << std::endl <<
+                                       "\t\tMultiplier applied to the display output dimensions." << std::endl <<
+                               "\t--width" << std::endl <<
+                                       "\t\tSet the display output dimensions directly" << std::endl <<
+                               "\t--height" << std::endl <<
+                                       "\t\tSet the display output dimensions directly" << std::endl;
+                               /*"\t--scaling-method\n\t\t\t(Default=\"hq4x\")" << std::endl <<
+                                       "\t\tSets the upscaling interpolation method." << std::endl <<
+                               "\t--resample-method\n\t\t\t(Default=\"bilinear\")" << std::endl <<
+                                       "\t\tSets the resampling method." << std::endl;*/
+       }
+}
+
+int main(int argc, char** argv)
+{
+       static struct option longOptions[] = 
+       {
+               {"video", 1, NULL, 'v'},
+               {"scale", 1, NULL, 's'},
+               {"width", 1, NULL, 'w'},
+               {"height", 1, NULL, 'h'},
+               //{"resample-method", 1, NULL, 'r'},
+               //{"scaling-method", 1, NULL, 'm'},
+               {NULL, 0, NULL, 0}
+       };
+
+       std::string filename("tetris.gb");
+       glBoy::GameboyGraphics::PixelScaler scaler(glBoy::GameboyGraphics::Scaler_hq4x);
+       glBoy::GameboyGraphics::ResampleMethod resampler(glBoy::GameboyGraphics::Resample_Bilinear);
+       bool fullscreen(false);
+       double scaleX(4.0);
+       double scaleY(4.0);
+
+       int optionIndex(0);
+       int c;
+       while (
+               (c = getopt_long(argc, argv, "s:w:h:", &longOptions[0], &optionIndex))
+                       != -1)
+       {
+               switch (c)
+               {
+                       case 'h':
+                       {
+                               int height(160);
+                               std::stringstream convert(optarg);
+                               convert >> height;
+                               if (convert && height > 14 && height < 1440)
+                               {
+                                       scaleY = height / 144.0;
+                               }
+                       }; break;
+                       case 'r':
+                       {
+                               if (std::string(optarg) == "bilinear")
+                               {
+                                       resampler = glBoy::GameboyGraphics::Resample_Bilinear;
+                               }
+                               else
+                               {
+                                       resampler = glBoy::GameboyGraphics::Resample_Nearest;
+                               }
+                       }; break;
+                       case 's':
+                       {
+                               double scale(1);
+                               std::stringstream convert(optarg);
+                               convert >> scale;
+                               if (convert && scale > 0.1 && scale < 10)
+                               {
+                                       scaleX = scale;
+                                       scaleY = scale;
+                               }
+                       }; break;
+                       case 'm':
+                       {
+                               if (std::string(optarg) == "hq4x")
+                               {
+                                       scaler = glBoy::GameboyGraphics::Scaler_hq4x;
+                               }
+                               else if (std::string(optarg) == "scale2x")
+                               {
+                                       scaler = glBoy::GameboyGraphics::Scaler_Scale2x;
+                               }
+                               else
+                               {
+                                       scaler = glBoy::GameboyGraphics::Scaler_None;
+                               }
+                       }; break;
+                       case 'w':
+                       {
+                               int width(160);
+                               std::stringstream convert(optarg);
+                               convert >> width;
+                               if (convert && width > 16 && width < 1600)
+                               {
+                                       scaleX = width / 160.0;
+                               }
+                       }; break;
+
+                       case '?':
+                               usage(argv[0]);
+                               exit(1);
+                               break;
+
+                       default:
+                               abort();
+               };
+       }
+
+       if (optind < argc)
+       {
+               filename = argv[optind++];
+       }
+
+       if (access(filename.c_str(), R_OK) != 0)
+       {
+               char* error(strerror(errno));
+               std::cerr << "Could not read file " << filename <<
+                       "(" << error << ")" << std::endl;
+               exit(1);
+       }
+
+       glBoy::Core core;
+       glBoy::MemoryMap& map(core.getMemoryMap());
+
+       SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO);
+
+       SDL_Surface* surface(initOpenGL(scaleX, scaleY, fullscreen));
+
+       glBoy::GameboyGraphics graphics(core, surface, scaler, resampler);
+
+       // Map the cart memory.
+       int fd(open(filename.c_str(), O_RDONLY));
+       assert(fd >= 0);
+
+       struct stat buf;
+       if (fstat(fd, &buf))
+       {
+               assert(!"Failed fstat");
+       }
+       uint8_t* cart = new uint8_t[buf.st_size];
+       read(fd, cart, buf.st_size);
+       close(fd);
+
+       glBoy::GameboyCart tmp(core, cart, buf.st_size);
+
+
+/*
+       int biosFd(open("DMG_ROM.bin", O_RDONLY));
+       uint8_t bios[256];
+       read(biosFd, bios, 256);
+       std::shared_ptr<glBoy::MemoryMap::Memory> biosMem(new glBoy::ROM(bios, 256));
+       map.map(0, 256, biosMem);
+*/
+
+       // Map the cart mem.
+       // Map the standard internal RAM, plus shadow.
+       {
+               std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(8192));
+               map.map(0xC000, 8192, mem);
+               map.map(0xE000, 7680, mem);
+       }
+       // Map the "zero-page" high-speed internal ram.
+       // Most interaction between GB hardware and the program occurs here.
+       {
+               std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(128));
+               map.map(0xFF80, 128, mem);
+       }
+
+       // Map the Interrupt flags. Currently handled in Core.cc
+       {
+               std::shared_ptr<glBoy::MemoryMap::Memory> mem(new glBoy::RAM(1));
+               mem->write8(0, 0);
+               map.map(0xFF0F, 1, mem);
+       }
+
+       // Map other devices
+       std::shared_ptr<glBoy::GameboyJoypad> joypad(new glBoy::GameboyJoypad(core));
+       map.map(0xFF00, 1, joypad);
+       std::shared_ptr<glBoy::GameboyTimer> timer(
+               new glBoy::GameboyTimer(
+                       core,
+                       std::bind(&glBoy::GameboyGraphics::setFrameSkip, &graphics),
+                       std::bind(&glBoy::GameboyGraphics::clearFrameSkip, &graphics)
+                       )
+               );
+       map.map(0xFF04, 4, timer);
+       std::shared_ptr<glBoy::GameboySound> sound(new glBoy::GameboySound(core));
+       map.map(0xFF10, 48, sound);
+
+       // Cart starts from offset 0x100 with a NOP; JP
+       core.getRegisters().PC = glBoy::htoz(0x100);
+       core.getRegisters().SP = glBoy::htoz(0xFFFE);
+       core.getRegisters().AF = glBoy::htoz(0x01B0);
+       core.getRegisters().BC = glBoy::htoz(0x0013);
+       core.getRegisters().DE = glBoy::htoz(0x00D8);
+       core.getRegisters().HL = glBoy::htoz(0x014D);
+
+       core.run();
+
+       std::cerr << "Done" << std::endl;
+
+       SDL_FreeSurface(surface);
+       SDL_Quit();
+}
+
index f0566ec87137c6930aa045e76816b7454722d887..28badebb911e7f1d83ac4c65ba96a71f1486c6c4 100644 (file)
@@ -30,7 +30,7 @@ namespace
        class MBC1 : public MemoryMap::Memory
        {
        public:
-               MBC1(GameboyCart* parent, uint8_t* begin, uint8_t* end) :
+               MBC1(GameboyCart* parent, const uint8_t* begin, const uint8_t* end) :
                        m_parent(parent),
                        m_rom(begin, end),
                        m_mode(ROM_SELECT),
@@ -117,11 +117,11 @@ assert(m_romOffset < m_rom.size());
 }
 
 GameboyCart::GameboyCart(
-       Core& core, uint8_t* rom, size_t size
+       Core& core, const std::vector<uint8_t>& rom
        ) :
        m_core(core)
 {
-       if (size < 16384)
+       if (rom.size() < 16384)
        {
                std::cerr << "Invalid ROM (too small)" << std::endl;
                abort();
@@ -137,7 +137,7 @@ GameboyCart::GameboyCart(
                mbc = "None";
 
                shared_ptr<MemoryMap::Memory> mem(
-                       new MBC1(this, rom, rom + size)
+                       new MBC1(this, &rom[0], &rom[0] + rom.size())
                        );
 /*             shared_ptr<MemoryMap::Memory> mem(
                        new ROM(rom, size)
@@ -152,7 +152,7 @@ GameboyCart::GameboyCart(
        {
                mbc = "MBC1";
                shared_ptr<MemoryMap::Memory> mem(
-                       new MBC1(this, rom, rom + size)
+                       new MBC1(this, &rom[0], &rom[0] + rom.size())
                        );
                m_core.getMemoryMap().map(0, 0x8000, mem);
                m_romBanks.push_back(mem);
@@ -209,7 +209,7 @@ GameboyCart::GameboyCart(
                cerr << "Invalid RAM size" << endl;
        }
 
-       string title(rom + 0x134, rom + 0x134 + 11);
+       string title(&rom[0x134], &rom[0x134 + 11]);
        cout << "Loading Cart" << endl;
        cout << "\tTitle:\t\t" << title << endl;
        cout << "\tRegion:\t\t" << (rom[0x14A] ? "Worldwide" : "Japan") << endl;
index d67493195f16fae2a224ceab252173f01b2a20cc..0588cd1c39f44455475bd038cd4b7983eb0043a8 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "glBoy.hh"
 #include "Core.hh"
+#include <vector>
 
 namespace glBoy
 {
@@ -27,7 +28,7 @@ namespace glBoy
 class GameboyCart
 {
 public:
-       GameboyCart(Core& core, uint8_t* rom, size_t size);
+       GameboyCart(Core& core, const std::vector<uint8_t>& rom);
 
        void setRamBank(size_t bank);
 private:
index 96cb6813339240ab228b00f151c12a07712edf63..73868dd2d840ea6a1254d602150204cfc9c4e5ea 100644 (file)
@@ -27,11 +27,47 @@ using namespace glBoy;
 
 // TODO implement interrupt! 
 
+namespace
+{
+       void setConfiguredKey(
+               const std::map<std::string, int>& keyMap,
+               const libconfig::Config& config,
+               const std::string& configParam,
+               int& mappedKey
+               )
+       {
+               if (config.exists(configParam))
+               {
+                       std::string value;
+                       config.lookupValue(configParam, value);
+                       std::map<std::string, int>::const_iterator it(
+                               keyMap.find(value)
+                               );
+                       if (!value.empty() && it != keyMap.end())
+                       {
+                               mappedKey = it->second;
+                       }
+               }
+       }
+}
 
-GameboyJoypad::GameboyJoypad(Core& core) :
+GameboyJoypad::GameboyJoypad(Core& core, const libconfig::Config& config) :
        m_state(Joypad_Off)
 {
+       std::map<std::string, int> sdlKeyMap;
+
+       for (int i = SDLK_FIRST; i < SDLK_LAST; ++i)
+       {
+               std::string keyName = SDL_GetKeyName(static_cast<SDLKey>(i));
+               if (keyName.find("SDLK_") == 0)
+               {
+                       keyName = keyName.substr(5);
+               }
+               sdlKeyMap[keyName] = i;
+       }
+
        m_inputs[DOWN].sdlKey = SDLK_DOWN;
+       //m_inputs[DOWN].sdlJoystick = 0 or none or something;
        m_inputs[UP].sdlKey = SDLK_UP;
        m_inputs[LEFT].sdlKey = SDLK_LEFT;
        m_inputs[RIGHT].sdlKey = SDLK_RIGHT;
@@ -40,6 +76,15 @@ GameboyJoypad::GameboyJoypad(Core& core) :
        m_inputs[A].sdlKey = SDLK_a;
        m_inputs[B].sdlKey = SDLK_s;
 
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.up", m_inputs[UP].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.down", m_inputs[DOWN].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.left", m_inputs[LEFT].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.right", m_inputs[RIGHT].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.start", m_inputs[START].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.select", m_inputs[SELECT].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.a", m_inputs[A].sdlKey);
+       setConfiguredKey(sdlKeyMap, config, "glBoy.keys.b", m_inputs[B].sdlKey);
+
        pollInput(0);
 
        using namespace std::placeholders;
@@ -104,6 +149,11 @@ GameboyJoypad::pollInput(Core::CallbackId)
                        case SDL_KEYUP:
                        case SDL_KEYDOWN:
                        {
+                               if (event.key.keysym.sym == SDLK_ESCAPE)
+                               {
+                                       exit(0);
+                               }
+
                                for (int i = 0; i < 8; ++i)
                                {
                                        if (event.key.keysym.sym == m_inputs[i].sdlKey)
index 8fafbfd3fb1a7df60d274da10c29c60a8363fccf..8662875b8a3c17248e806b4523cfda32768f6612 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "MemoryMap.hh"
 
+#include <libconfig.h++>
 #include <SDL/SDL.h>
 
 namespace glBoy
@@ -31,7 +32,7 @@ namespace glBoy
 class GameboyJoypad : public MemoryMap::Memory
 {
 public:
-       GameboyJoypad(Core& core);
+       GameboyJoypad(Core& core, const libconfig::Config& config);
 
        void pollInput(Core::CallbackId id);
 
@@ -46,6 +47,7 @@ private:
        {
                Input() : sdlKey(0), depressed(false) {}
                int sdlKey;
+               int sdlJoystick;
                bool depressed;
        };
 
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/Main.cc b/Main.cc
index b4db93cf187e39b79987fc47e6f474bf219da391..c8c27860add7805389fa1c8b4814af3409ed07aa 100644 (file)
--- a/Main.cc
+++ b/Main.cc
@@ -15,7 +15,7 @@
 //     You should have received a copy of the GNU General Public License
 //     along with glBoy.  If not, see <http://www.gnu.org/licenses/>.
 
-
+#define GLX_GLXEXT_PROTOTYPES 1
 #include "glBoy.hh"
 #include "Core.hh"
 #include "GameboyCart.hh"
 #include "ROM.hh"
 #include "Log.hh"
 
+#include <GL/glext.h>
 #include <SDL/SDL.h>
 #include <SDL/SDL_opengl.h>
 #include <SDL/SDL_video.h>
 
+#include <libconfig.h++>
+#include <zipios++/zipfile.h>
+
 #include <cassert>
 #include <set>
 #include <sstream>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <pwd.h>
 
 namespace
 {
+       enum Constants
+       {
+               GLBOY_MIN_WIDTH = 16,
+               GLBOY_MAX_WIDTH = 1600,
+
+               GLBOY_MIN_HEIGHT = 14,
+               GLBOY_MAX_HEIGHT = 1440,
+       };
+
        SDL_Surface*
        initOpenGL(double xScale, double yScale, bool fullscreen)
        {
@@ -61,6 +75,9 @@ namespace
                        SDL_SetVideoMode(160*xScale, 144*yScale, 32, options)
                        );
 
+               // v-sync
+               //::glXSwapIntervalSGI(1);
+
                glEnable(GL_TEXTURE_2D);
                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                glClear(GL_COLOR_BUFFER_BIT);
@@ -94,10 +111,123 @@ namespace
                                "\t--resample-method\n\t\t\t(Default=\"bilinear\")" << std::endl <<
                                        "\t\tSets the resampling method." << std::endl;*/
        }
+
+       void readConfigFile(libconfig::Config& config)
+       {
+               // Grab the current user's home dir
+               struct passwd* entry(getpwuid(getuid()));
+               if (entry && entry->pw_dir)
+               {
+                       std::stringstream file;
+                       file << entry->pw_dir << "/" << ".glBoy";
+                       try
+                       {
+                               config.readFile(file.str().c_str());
+                       }
+                       catch (libconfig::FileIOException& e)
+                       {
+                               // Ignore. config file probably doesn't exist.
+                       }
+                       catch (libconfig::ParseException& e)
+                       {
+                               std::cerr << "Error while parsing file " <<
+                                       file.str() << std::endl <<
+                                       e.getError() << " at line " << e.getLine() <<
+                                       std::endl;
+
+                               // Continue with default options.
+                       }
+                       catch (libconfig::ConfigException& e)
+                       {
+                               std::cerr << "Error while reading config file " <<
+                                       file.str() << " : " << std::endl;
+
+                               // Continue with default options.
+                       }
+               }
+       }
+
+       std::vector<uint8_t> readCart(const std::string& filename)
+       {
+               std::vector<uint8_t> result;
+
+               // Map the cart memory.
+               int fd(open(filename.c_str(), O_RDONLY));
+               if (fd <= 0)
+               {
+                       char* err(strerror(errno));
+                       std::cerr << "Failed to load file " << filename << std::endl <<
+                               err << std::endl;
+                       exit(1);
+               }
+
+               struct stat buf;
+               if (fstat(fd, &buf))
+               {
+                       assert(!"Failed fstat");
+               }
+
+               if (buf.st_size > 1024*1024)
+               {
+                       // Probably not a rom at all.
+                       std::cerr << "Cart too large" << std::endl;
+                       exit(1);
+               }
+
+               char zipHeader[2] = {'\0', '\0'};
+               read(fd, zipHeader, sizeof(zipHeader));
+               lseek(fd, 0, SEEK_SET);
+
+               if (zipHeader[0] == 'P' && zipHeader[1] == 'K')
+               {
+                       // Unzip
+                       using namespace zipios;
+                       try
+                       {
+                               ZipFile zf(filename);
+                               ConstEntries entries(zf.entries());
+                               if (!entries.empty())
+                               {
+                                       glBoy::Log::Instance()(glBoy::Log::DBG_STAT) <<
+                                       "Uncompressing " << entries.front()->getName() << std::endl;
+                                       std::auto_ptr<std::istream> is(
+                                               zf.getInputStream(entries.front())
+                                               );
+std::cerr << "*" << std::endl;
+                                       result.resize(entries.front()->getSize());
+std::cerr << "*" << std::endl;
+                                       is->rdbuf()->sgetn(
+                                               reinterpret_cast<char*>(&result[0]),
+                                               result.size()
+                                               );
+std::cerr << "*" << std::endl;
+                               }
+                       } catch (std::exception& e)
+                       {
+                               std::cerr << "Error while reading file " << filename <<
+                                       std::endl <<
+                                       e.what() << std::endl;
+                       }
+               }
+               else
+               {
+                       result.resize(buf.st_size);
+                       read(fd, &result[0], result.size());
+               }
+               close(fd);
+
+               return result;
+       }
+
 }
 
 int main(int argc, char** argv)
 {
+       std::cout << PACKAGE_STRING << " <" << PACKAGE_BUGREPORT << ">" << std::endl;
+       libconfig::Config config;
+       config.setAutoConvert(true); // Allow conversions between int/float
+       readConfigFile(config);
+
        static struct option longOptions[] = 
        {
                {"video", 1, NULL, 'v'},
@@ -110,12 +240,33 @@ int main(int argc, char** argv)
        };
 
        std::string filename("tetris.gb");
+       config.lookupValue("glBoy.rom", filename);
+
        glBoy::GameboyGraphics::PixelScaler scaler(glBoy::GameboyGraphics::Scaler_hq4x);
        glBoy::GameboyGraphics::ResampleMethod resampler(glBoy::GameboyGraphics::Resample_Bilinear);
        bool fullscreen(false);
        double scaleX(4.0);
        double scaleY(4.0);
 
+       if (config.exists("glBoy.screen.width"))
+       {
+               int width(0);
+               config.lookupValue("glBoy.screen.width", width);
+               if (width >= GLBOY_MIN_WIDTH && width <= GLBOY_MAX_WIDTH)
+               {
+                       scaleX = width / 160.0;
+               }
+       }
+       if (config.exists("glBoy.screen.height"))
+       {
+               int height(0);
+               config.lookupValue("glBoy.screen.height", height);
+               if (height >= GLBOY_MIN_HEIGHT && height <= GLBOY_MAX_HEIGHT)
+               {
+                       scaleY = height / 144.0;
+               }
+       }
+
        int optionIndex(0);
        int c;
        while (
@@ -129,7 +280,9 @@ int main(int argc, char** argv)
                                int height(160);
                                std::stringstream convert(optarg);
                                convert >> height;
-                               if (convert && height > 14 && height < 1440)
+                               if (convert &&
+                                       height >= GLBOY_MIN_HEIGHT  && height <= GLBOY_MAX_HEIGHT
+                                       )
                                {
                                        scaleY = height / 144.0;
                                }
@@ -176,7 +329,9 @@ int main(int argc, char** argv)
                                int width(160);
                                std::stringstream convert(optarg);
                                convert >> width;
-                               if (convert && width > 16 && width < 1600)
+                               if (convert &&
+                                       width >= GLBOY_MIN_WIDTH && width <= GLBOY_MAX_WIDTH
+                                       )
                                {
                                        scaleX = width / 160.0;
                                }
@@ -197,6 +352,14 @@ int main(int argc, char** argv)
                filename = argv[optind++];
        }
 
+       if (access(filename.c_str(), R_OK) != 0)
+       {
+               char* error(strerror(errno));
+               std::cerr << "Could not read file " << filename <<
+                       " (" << error << ")" << std::endl;
+               exit(1);
+       }
+
        glBoy::Core core;
        glBoy::MemoryMap& map(core.getMemoryMap());
 
@@ -206,29 +369,12 @@ int main(int argc, char** argv)
 
        glBoy::GameboyGraphics graphics(core, surface, scaler, resampler);
 
-       // Map the cart memory.
-       int fd(open(filename.c_str(), O_RDONLY));
-       assert(fd >= 0);
+       SDL_WM_SetCaption("glBoy", "glBoy");
+       // TODO SDL_WM_SetIcon
 
-       struct stat buf;
-       if (fstat(fd, &buf))
-       {
-               assert(!"Failed fstat");
-       }
-       uint8_t* cart = new uint8_t[buf.st_size];
-       read(fd, cart, buf.st_size);
-       close(fd);
+       std::vector<uint8_t> cart(readCart(filename));
+       glBoy::GameboyCart tmp(core, cart);
 
-       glBoy::GameboyCart tmp(core, cart, buf.st_size);
-
-
-/*
-       int biosFd(open("DMG_ROM.bin", O_RDONLY));
-       uint8_t bios[256];
-       read(biosFd, bios, 256);
-       std::shared_ptr<glBoy::MemoryMap::Memory> biosMem(new glBoy::ROM(bios, 256));
-       map.map(0, 256, biosMem);
-*/
 
        // Map the cart mem.
        // Map the standard internal RAM, plus shadow.
@@ -252,7 +398,9 @@ int main(int argc, char** argv)
        }
 
        // Map other devices
-       std::shared_ptr<glBoy::GameboyJoypad> joypad(new glBoy::GameboyJoypad(core));
+       std::shared_ptr<glBoy::GameboyJoypad> joypad(
+               new glBoy::GameboyJoypad(core, config)
+               );
        map.map(0xFF00, 1, joypad);
        std::shared_ptr<glBoy::GameboyTimer> timer(
                new glBoy::GameboyTimer(
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index a348a23..0000000
--- a/Makefile
+++ /dev/null
@@ -1,71 +0,0 @@
-#      Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
-#
-#      This file is part of glBoy.
-#
-#      glBoy is free software: you can redistribute it and/or modify
-#      it under the terms of the GNU General Public License as published by
-#      the Free Software Foundation, either version 3 of the License, or
-#      (at your option) any later version.
-#
-#      glBoy is distributed in the hope that it will be useful,
-#      but WITHOUT ANY WARRANTY; without even the implied warranty of
-#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#      GNU General Public License for more details.
-#
-#      You should have received a copy of the GNU General Public License
-#      along with glBoy.  If not, see <http://www.gnu.org/licenses/>.
-
-VERSION=$(shell cat VERSION)
-
-all: glBoy
-
-OBJS = \
-       ALU.o \
-       Core.o \
-       GameboyCart.o \
-       GameboyGraphics.o \
-       GameboyJoypad.o \
-       GameboySound.o \
-       GameboyTimer.o \
-       hq4x.o \
-       Log.o \
-       Main.o \
-       MemoryMap.o \
-       RAM.o \
-       Registers.o \
-       ROM.o \
-
-DEFINES=
-# -DGLBOY_DEBUG
-
-CPPFLAGS=-DHOST_LITTLE_ENDIAN -I. $(DEFINES)
-CXXFLAGS=-g -O3 -march=native -W -Wall -Werror -std=c++0x
-
-LDFLAGS=-lSDL -lGL -lGLU -lglut
-
-glBoy: InstructionSet_Opcodes.cc $(OBJS)
-       $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJS)
-
-InstructionSet_Opcodes.cc: InstructionSet.opcode makeOpcodes.pl
-       perl ./makeOpcodes.pl
-
-Core.o: InstructionSet_Opcodes.cc
-
-test: InstructionSet_Opcodes.cc Test.cc ALU.cc
-       $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ Test.cc ALU.cc
-
-package:
-       git commit -a
-       git tag -a -f $(VERSION)
-       -mkdir /tmp/glBoy-$(VERSION)
-       -rm /tmp/glBoy-$(VERSION)/*
-       cp *.cc *.hh *.opcode *.pl Makefile COPYING README VERSION /tmp/glBoy-$(VERSION)/
-       tar cvf glBoy-$(VERSION).tar -C /tmp glBoy-$(VERSION)
-       gzip glBoy-$(VERSION).tar
-
-clean:
-       -rm -f *.o
-       -rm -f glBoy
-       -rm -f InstructionSet_Opcodes.cc
-       -rm -f InstructionSet_Tables.cc
-       -rm -f gmon.out
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..2d21f24
--- /dev/null
@@ -0,0 +1,92 @@
+#      Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+#
+#      This file is part of glBoy.
+#
+#      glBoy is free software: you can redistribute it and/or modify
+#      it under the terms of the GNU General Public License as published by
+#      the Free Software Foundation, either version 3 of the License, or
+#      (at your option) any later version.
+#
+#      glBoy is distributed in the hope that it will be useful,
+#      but WITHOUT ANY WARRANTY; without even the implied warranty of
+#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#      GNU General Public License for more details.
+#
+#      You should have received a copy of the GNU General Public License
+#      along with glBoy.  If not, see <http://www.gnu.org/licenses/>.
+
+check_PROGRAMS = \
+       test_alu
+
+TESTS = $(check_PROGRAMS)
+
+test_alu_SOURCES = Test.cc ALU.cc
+
+dist_noinst_SCRIPTS = autogen.sh
+
+EXTRA_DIST = \
+       configure.ac \
+       glBoy.config \
+       InstructionSet.opcode \
+       Makefile.am \
+       COPYING \
+       NEWS \
+       README \
+       VERSION
+
+bin_PROGRAMS = glBoy
+
+glBoy_SOURCES = \
+       ALU.hh \
+       ALU.cc \
+       Core.hh \
+       Core.cc \
+       DAA.hh \
+       DWORD.hh \
+       GameboyCart \
+       GameboyCart.cc \
+       GameboyGraphics.hh \
+       GameboyGraphics.cc \
+       GameboyJoypad.hh \
+       GameboyJoypad.cc \
+       GameboySound.hh \
+       GameboySound.cc \
+       GameboyTimer.hh \
+       GameboyTimer.cc \
+       glBoy.hh \
+       hq4x.hh \
+       hq4x.cc \
+       Log.hh \
+       Log.cc \
+       Main.cc \
+       MemoryMap.hh \
+       MemoryMap.cc \
+       RAM.hh \
+       RAM.cc \
+       Registers.hh \
+       Registers.cc \
+       ROM.hh \
+       ROM.cc \
+       util.hh
+
+BUILT_SOURCES = \
+       InstructionSet_Opcodes.cc
+
+nodist_glBoy_SOURCES =
+       InstructionSet_Opcodes.cc
+
+CLEANFILES = \
+       InstructionSet_Opcodes.cc \
+       InstructionSet_Tables.cc
+
+glBoy_LDFLAGS = -lGL -lGLU -lzipios
+
+CXXFLAGS=-g -O3 -march=native -W -Wall -Werror -std=c++0x
+
+InstructionSet_Opcodes.cc: InstructionSet.opcode makeOpcodes.pl
+       perl $(srcdir)/makeOpcodes.pl $<
+
+#package: clean
+#      git commit -a
+#      git tag -a -f $(VERSION)
+
index 62647562162809b3fe70a549b5f36cf759923ddd..caf563f2d3e31d9c312954d4c354ea9e756ac1b8 100644 (file)
@@ -82,7 +82,7 @@ MemoryMap::remove(
 }\r
 \r
 \r
-const MemoryMap::MappedArea&\r
+inline const MemoryMap::MappedArea&\r
 MemoryMap::get(uint16_t address) const\r
 {\r
 \r
@@ -122,6 +122,12 @@ MemoryMap::get(uint16_t address) const
                }\r
        }\r
 \r
+       return getFailed(address);\r
+}\r
+\r
+const MemoryMap::MappedArea&\r
+MemoryMap::getFailed(uint16_t address) const\r
+{\r
        Log::Instance()(Log::DBG_MEMORY) <<\r
                "Returning NULL memory for address " << glBoy::hex(address) << std::endl;\r
 \r
index 7e7eb8c9e4e96e5499bfaf5581d07e18877a4b32..e01041c07b4b06f276e1c24e1ff6a4730e20472b 100644 (file)
@@ -74,7 +74,8 @@ private:
 \r
                bool operator<(const MappedArea& b) const { return base < b.base; }\r
        };\r
-       const MappedArea& get(uint16_t address) const;\r
+       inline const MappedArea& get(uint16_t address) const;\r
+       const MappedArea& getFailed(uint16_t address) const;\r
 \r
        typedef std::vector<MappedArea> MapType;\r
        MapType m_map;\r
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..455df39
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,8 @@
+2011-FIXME     Version 1.0.1
+       - Increased performance for some NVidia Quadro cards (tested with NVS 290)
+       - Added configurable key mappings. Copy glBoy.config to ~/.glBoy to change
+               settings.
+
+2011-01-31     Version 1.0.0
+       - Initial release
+
diff --git a/README b/README
index e33c6daeed4e0c462a708af7d02dda2868901fe6..2b3ce97808492e7ae01db90b4d719fb72e5e3ffb 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 glBoy
-Original gameboy emulator.
+Original gameboy emulator by Michael McMaster <michael@codesrc.com>
 
 Usage:
 Usage: ./glBoy [--scale ratio] [--width w] [--height h] rom.gb
diff --git a/Unzip.cc b/Unzip.cc
new file mode 100644 (file)
index 0000000..2f102cf
--- /dev/null
+++ b/Unzip.cc
@@ -0,0 +1,129 @@
+//     Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
+//
+//     This file is part of glBoy.
+//
+//     glBoy is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+//
+//     glBoy is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+//
+//     You should have received a copy of the GNU General Public License
+//     along with glBoy.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "glBoy.hh"
+
+// Simple Unzip implementation
+// Limitations:
+// - Does not support spanned archives.
+// - Does not support spanned encryption.
+// - Does not support zip64
+
+
+uint32_t
+read32(const std::vector<uint8_t>& zipData, size_t pos)
+{
+       // Read 4 bytes in little-endian order.
+       // Return results in host-endian.
+       return uint32_t(
+               zipData[pos] |
+               (static_cast<uint32_t>(zipData[pos+1]) << 8) |
+               (static_cast<uint32_t>(zipData[pos+2]) << 16) |
+               (static_cast<uint32_t>(zipData[pos+3]) << 24)
+               );
+}
+
+uint16_t
+read16(const std::vector<uint8_t>& zipData, size_t pos)
+{
+       // Read 2 bytes in little-endian order.
+       // Return results in host-endian.
+       return uint16_t(
+               zipData[pos] |
+               (static_cast<uint16_t>(zipData[pos+1]) << 8) |
+               );
+}
+
+struct EndCentralDir
+{
+       size_t centralDirectoryBytes;
+       size_t centralDirectoryOffset;
+       size_t centralDirectoryEntries;
+       std::string zipFileComment;
+};
+
+TODO lets make this somewhat full-featured.
+Accept a CLASS as input, with a readZipBytes virtual method.
+And accept a different class with a writeUncompressedBytes method when
+uncompressing.
+EndCentralDir readEndRecord(const std::vector<uint8_t>& zipData)
+{
+       // Read the end of central directory record. This
+       // record enables us to find the remainding
+       // records without searching for record signatures.
+
+       enum
+       {
+               MinRecordBytes = 22, // Minimum size with no comment
+               MaxCommentBytes = 65535, // 2 bytes to store comment length
+               Signature = 0x06054b50
+       };
+
+       if (zipData.size() < MinRecordBytes)
+       {
+               throw ZipFormatException("Too small");
+       }
+
+       // Need to search for this record, as it ends in a variable-length
+       // comment field. Search backwards, with the assumption that the
+       // comment doesn't exist, or is much smaller than the maximum
+       // length
+       size_t end(0);
+       if (zipData.size() > MinRecordBytes + MaxCommentBytes)
+       {
+               end = zipData.size() - MinRecordBytes + MaxCommentBytes;
+       }
+       size_t start(zipData.size() - MinRecordBytes);
+
+       bool recordFound(false);
+       size_t pos(start);
+       for (; pos >= end; --pos)
+       {
+               recordFound = (read32(zipData, pos) == Signature);
+               break;
+       }
+
+       if (!recordFound)
+       {
+               throw ZipFormatException("ZIP directory records not found");
+       }
+
+       if (read16(zipData, pos + 4) != 1)
+       {
+               throw ZipUnsupportedException("Spanned disks not supported");
+       }
+
+       EndCentralDir result;
+       result.entralDirectoryBytes = read32(zipData, pos + 12);
+       result.centralDirectoryOffset = read32(zipData, pos + 16);
+       result.centralDirectoryEntries = read16(zipData, pos + 10);
+
+       size_t commentLength(read16(zipData, pos + 20));
+       size_t commentStart(pos + MinRecordBytes);
+       if (commentStart + commentLength > zipData.size())
+       {
+               throw ZipFormatException("ZIP comment is too long");
+       }
+       result.zipFileComment =
+               std::string(
+                       &zipData[commentStart],
+                       &zipData[commentStart + commentLength]
+                       );
+
+       return result;
+}
+
diff --git a/VERSION b/VERSION
index 3eefcb9dd5b38e2c1dc061052455dd97bcd51e6c..7dea76edb3dc51b6e5e8223e9f941a35c1e364d6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0
+1.0.1
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..3f026c4
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+autoreconf --force --install
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..0042776
--- /dev/null
@@ -0,0 +1,43 @@
+AC_INIT([glBoy], [1.0.1], [michael@codesrc.com])
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_HEADERS([autoconfig.h])
+AC_CONFIG_FILES([Makefile])
+
+AC_C_BIGENDIAN(
+       AC_DEFINE([HOST_BIG_ENDIAN], [], [Compile for big-endian host cpu]),
+       AC_DEFINE([HOST_LITTLE_ENDIAN], [], [Compile for litte-endian host cpu])
+       )
+
+AC_PROG_CXX
+
+SDL_VERSION=1.2.0
+AM_PATH_SDL(
+       $SDL_VERSION,
+       :,
+       AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!])
+       )
+CFLAGS="$CFLAGS $SDL_CFLAGS" LIBS="$LIBS $SDL_LIBS"
+
+#AC_ARG_ENABLE([GLBOY_DEBUG],
+#      AS_HELP_STRING([--enable-debug_trace],
+#              [Enable debug trace logging]),
+#              [AC_DEFINE(GLBOY_DEBUG),
+#FIXME
+#              [])
+
+PKG_CHECK_MODULES([LIBCONFIGXX], [libconfig++ >= 1.3],,
+       AC_MSG_ERROR([libconfig++ 1.3 or newer not found.])
+)
+CFLAGS="$CFLAGS $LIBCONFIGXX_CFLAGS" LIBS="$LIBS $LIBCONFIGXX_LIBS"
+
+#AX_CXXFLAGS_GCC_OPTION([-std=c++0x])
+#- warning flags
+#- opt flags ?
+#- debug flags ?
+#GL lib, GLU lib
+#flto!
+
+AC_OUTPUT
+
diff --git a/glBoy.config b/glBoy.config
new file mode 100644 (file)
index 0000000..5c8413c
--- /dev/null
@@ -0,0 +1,27 @@
+# glBoy example configuration file
+
+TODO list available keys here in a comment.
+change name to ~/.glBoy/config as we need a directory for saved games as well.
+
+glBoy:
+{
+       keys:
+       {
+               up = "UP";
+               down = "DOWN";
+               left = "LEFT";
+               right = "RIGHT";
+               start = "RETURN";
+               select = "BACKSPACE";
+               a = "z";
+               b = "x";
+       };
+
+       screen:
+       {
+               width = 160;
+               height = 144;
+       };
+
+       rom = "tetris.gb";
+};
index 0fb885c95c826ee81a169306516d63fc9f18e4f0..d81ff45f9a38231ac76030036c13592488728afe 100644 (file)
--- a/glBoy.hh
+++ b/glBoy.hh
@@ -18,6 +18,8 @@
 #ifndef GLBOY_HH\r
 #define GLBOY_HH\r
 \r
+#include "autoconfig.h"\r
+\r
 #include <cstdint>\r
 #include <iostream>\r
 \r
diff --git a/hq4x.cc b/hq4x.cc
index d5521add6740684f4273bf40ab334a7a6aa59160..278011c416fc8456ea612036e722443d77219499 100644 (file)
--- a/hq4x.cc
+++ b/hq4x.cc
@@ -65,6 +65,19 @@ s_FragmentSource =
 "\\r
 // Enable bitwise operators\n\\r
 #version 130\n\\r
+\n\\r
+#ifdef __GLSL_CG_DATA_TYPES\n\\r
+// NVidia specific\n\\r
+// These pragmas make a MASSIVE difference on some quadro cards.\n\\r
+// But no difference on my 6600.\n\\r
+#pragma optionNV(fastmath on)\n\\r
+#pragma optionNV(fastprecision on)\n\\r
+#pragma optionNV(ifcvt none)\n\\r
+#pragma optionNV(inline all)\n\\r
+#pragma optionNV(strict on)\n\\r
+#pragma optionNV(unroll all)\n\\r
+#endif\n\\r
+\n\\r
 \\r
 uniform sampler2D mmTexture;\n\\r
 uniform sampler2D mmLookup;\n\\r
index 2c4c5be7da4e8180c3905599fbe489872d756fde..05698d983e4913ba1ce3c22878cd41107ff753aa 100644 (file)
@@ -31,7 +31,7 @@ my $VARIANT = "gb80";
 
 # </ Ugly Globals >
 
-my $reader = new XML::LibXML::Reader(location => "InstructionSet.opcode")
+my $reader = new XML::LibXML::Reader(location => $ARGV[0])
        || die "Cannot read opcode file\n";
 
 open (TABLES, '>InstructionSet_Tables.cc') || die "Could not write to file\n";