Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
215 KB
Referenced Files
None
Subscribers
None
diff --git a/.gitignore b/.gitignore
index 26923617..115465f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.scon*
*.log
*.pyc
build
+lib
diff --git a/SConstruct b/SConstruct
index 659e6d43..d1747adb 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,23 +1,23 @@
import os
import scons.utils
import scons.checks
SetOption('num_jobs', scons.utils.detectCPUs())
includedir = '{0}/include'.format(os.getcwd())
env = Environment(ENV = os.environ, CPPPATH=includedir)
config = env.Configure(custom_tests = {'CheckAllegro5': scons.checks.checkAllegro5(False)})
config.CheckAllegro5()
env = config.Finish()
#TODO Need to do separate checks later
env.ParseConfig('freetype-config --libs --cflags')
build_dir = 'build'
options = {'networking': False,
'allegro5': True
}
env.VariantDir(build_dir, 'src')
-env.Library('r-tech1', env.SConscript('src/SConscript', variant_dir=build_dir, exports=['env', 'options']))
+env.Library('lib/r-tech1', env.SConscript('src/SConscript', variant_dir=build_dir, exports=['env', 'options']))
diff --git a/include/r-tech1/menu/menu.h b/include/r-tech1/menu/menu.h
index b46599dc..f15e583a 100644
--- a/include/r-tech1/menu/menu.h
+++ b/include/r-tech1/menu/menu.h
@@ -1,575 +1,575 @@
#ifndef _paintown_Menu_h
#define _paintown_Menu_h
#include <vector>
#include <string>
#include <map>
-#include "util/file-system.h"
-#include "util/pointer.h"
-#include "util/parameter.h"
-#include "util/input/input-map.h"
-#include "util/graphics/gradient.h"
-#include "font-info.h"
-
-#include "util/gui/animation.h"
-#include "util/gui/box.h"
-#include "util/gui/context-box.h"
-#include "util/gui/fadetool.h"
-#include "util/gui/popup-box.h"
-#include "util/gui/tabbed-box.h"
-#include "util/gui/widget.h"
-#include "util/gui/coordinate.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/pointer.h"
+#include "r-tech1/parameter.h"
+#include "r-tech1/input/input-map.h"
+#include "r-tech1/graphics/gradient.h"
+#include "r-tech1/menu/font-info.h"
+
+#include "r-tech1/gui/animation.h"
+#include "r-tech1/gui/box.h"
+#include "r-tech1/gui/context-box.h"
+#include "r-tech1/gui/fadetool.h"
+#include "r-tech1/gui/popup-box.h"
+#include "r-tech1/gui/tabbed-box.h"
+#include "r-tech1/gui/widget.h"
+#include "r-tech1/gui/coordinate.h"
#ifdef _MSC_VER
#ifndef uint32_t
typedef unsigned __int32 uint32_t;
#endif
#endif
class Font;
namespace Graphics{
class Bitmap;
}
class MenuOption;
class Token;
class TokenView;
namespace Menu{
extern Util::Parameter<Util::ReferenceCount<FontInfo> > menuFontParameter;
Effects::Gradient standardGradient();
class OptionFactory;
class Point{
public:
int x;
int y;
Point();
Point(int x, int y);
~Point();
};
class InfoBox: public Gui::Widget {
public:
InfoBox();
~InfoBox();
void act(const Font &);
virtual void render(const Graphics::Bitmap &);
void render(const Graphics::Bitmap &, const Font & font);
void open();
void close();
void setText(const std::string &);
inline bool isActive(){
return (this->state != NotActive);
}
/*
inline void setFont(const Util::ReferenceCount<FontInfo> & font){
this->font = font;
}
*/
virtual void initialize(const Font & font);
private:
enum State{
NotActive,
Opening,
Active,
Closing,
};
State state;
Gui::PopupBox popup;
// Util::ReferenceCount<FontInfo> font;
int fadeAlpha;
std::vector<std::string> text;
std::vector<int> padding;
};
class MenuException : public Exception::Base{
public:
MenuException(const std::string & file, int line, const std::string reason = "");
MenuException(const MenuException & copy);
MenuException(const Exception::Base & copy);
virtual ~MenuException() throw();
protected:
std::string reason;
virtual inline const std::string getReason() const {
return reason;
}
virtual Exception::Base * copy() const;
};
/* reload the current menu, usually thrown by some option */
class Reload: public MenuException {
public:
Reload(const std::string & file, int line, const std::string reason = "");
virtual ~Reload() throw();
protected:
virtual Exception::Base * copy() const;
};
class ValueHolder{
public:
ValueHolder(const std::string &);
ValueHolder(const ValueHolder &);
virtual ~ValueHolder();
virtual ValueHolder & operator=(const ValueHolder &);
virtual ValueHolder & operator<<(const std::string &);
virtual ValueHolder & operator<<(bool val);
virtual ValueHolder & operator<<(int val);
virtual ValueHolder & operator<<(double val);
virtual ValueHolder & operator<<(TokenView &);
virtual ValueHolder & operator>>(std::string &);
virtual ValueHolder & operator>>(bool &);
virtual ValueHolder & operator>>(int &);
virtual ValueHolder & operator>>(double &);
virtual inline const std::string & getName() const {
return this->name;
}
virtual const std::string getValues();
private:
std::string name;
std::vector<std::string> values;
unsigned int location;
void next();
};
/*! Menu actions */
enum Actions{
Up,
Down,
Left,
Right,
Select,
Back,
Cancel,
Modify,
Pause,
PlayAsteroids /* Hack for now, remove later */
};
class Context;
/*! Menu Renderer
* Allows menu to modify the way it displays it's contents
* ie regular menus, tab menus, specialized menu etc
*/
class Renderer{
public:
Renderer();
virtual ~Renderer();
enum Type{
Default,
Tabbed
};
//! Reader
virtual bool readToken(const Token *, const OptionFactory &)=0;
virtual Type getType() const = 0;
virtual void initialize(Context &)=0;
virtual void finish()=0;
virtual bool active()=0;
virtual void act(const Context &)=0;
virtual void render(const Graphics::Bitmap &, const Font & font)=0;
// Set font if applicable
// virtual void setFont(const Util::ReferenceCount<FontInfo> &);
//! Compatibility for now, remove later
virtual void addOption(MenuOption *)=0;
virtual std::vector<Util::ReferenceCount<MenuOption> > getOptions() const = 0;
/*! Handle action, with access to context
*/
virtual void doAction(const Actions &, Context &)=0;
/*! Invoke override */
virtual void invokeOverride(const Context &)=0;
virtual void setPosition(const Gui::Coordinate & coordinate) = 0;
protected:
/*! Info boxes */
std::vector <InfoBox *> info;
/*! Menu info box */
InfoBox menuInfo;
/*! Add info box */
virtual void addInfo(const std::string &, const Gui::Widget &, Context &, const Font &);
/*! act info box */
virtual void actInfo(const Font &);
/*! render info box */
virtual void renderInfo(const Graphics::Bitmap &, const Font & font);
};
/*! Regular Menu */
class DefaultRenderer: public Renderer {
public:
DefaultRenderer();
virtual ~DefaultRenderer();
// virtual void setFont(const Util::ReferenceCount<FontInfo> &);
virtual bool readToken(const Token *, const OptionFactory &);
virtual void initialize(Context &);
virtual void finish();
virtual bool active();
virtual void act(const Context &);
virtual void render(const Graphics::Bitmap &, const Font &);
virtual void addOption(MenuOption *);
virtual void doAction(const Actions &, Context &);
virtual std::vector<Util::ReferenceCount<MenuOption> > getOptions() const;
virtual void invokeOverride(const Context &);
virtual void setPosition(const Gui::Coordinate & coordinate);
virtual Type getType() const;
virtual const Gui::ContextBox & getBox() const {
return menu;
}
virtual Gui::ContextBox & getBox(){
return menu;
}
private:
/*! Options */
std::vector<Util::ReferenceCount<MenuOption> > options;
/*! Context Box */
Gui::ContextBox menu;
/*! Override */
bool hasOverride;
/*! Override index */
unsigned int overrideIndex;
};
/*! Tabbed Menu */
class TabInfo {
public:
TabInfo();
~TabInfo();
std::string name;
std::string info;
std::string menuInfo;
void act();
/*! Options */
std::vector<Util::ReferenceCount<MenuOption> > options;
};
class TabRenderer: public Renderer {
public:
TabRenderer();
virtual ~TabRenderer();
// virtual void setFont(const Util::ReferenceCount<FontInfo> &);
virtual bool readToken(const Token *, const OptionFactory &);
virtual void initialize(Context &);
virtual void finish();
virtual bool active();
virtual void act(const Context &);
virtual void render(const Graphics::Bitmap &, const Font &);
virtual void addOption(MenuOption *);
virtual void doAction(const Actions &, Context &);
virtual std::vector<Util::ReferenceCount<MenuOption> > getOptions() const;
virtual void invokeOverride(const Context &);
virtual void setPosition(const Gui::Coordinate & coordinate);
virtual Type getType() const;
virtual Gui::TabbedBox & getBox(){
return menu;
}
private:
/*! Tabs */
std::vector<TabInfo *> tabs;
/*! Tabbed Box */
Gui::TabbedBox menu;
/*! Override */
bool hasOverride;
/*! Override index */
unsigned int overrideIndex;
};
/*! Menu contexts
- Each menu has a context which it defaults to
- Sub menus will be passed the parents context when run
- Fader
- Backgrounds (No background will fall back onto a fill screen)
- Menu (options, ContextBox, etc)
- Contexts are settable to omit drawing certain items (usefull for things like in-game menus)
*/
class Context{
public:
Context();
Context(const Context &, const Context &);
virtual ~Context();
virtual void act();
/*! Pass the widget (Menu ContextBox in this case) to be drawn
* Allows for custom widget menus to be draw in place (ie for tabs or something)
*/
virtual void render(const Util::ReferenceCount<Renderer> &, const Graphics::Bitmap &) const;
virtual void renderBackground(const Graphics::Bitmap & bmp) const;
virtual void renderForeground(const Graphics::Bitmap & bmp) const;
/*! Parse data */
virtual void parseToken(const Token *);
//! Compatibility stuff
virtual void addBackground(const Token *);
virtual void addBackground(const std::string &);
virtual void addBackground(const Graphics::Bitmap & image);
virtual void addBackground(const Util::ReferenceCount<Gui::Animation> & animation);
/*! Initializes things like faders */
virtual void initialize();
/*! Closes things out like faders */
virtual void finish();
/*! Play sound */
virtual void playSound(const Actions &) const;
/*! Add sound */
virtual void addSound(const Actions &, const Filesystem::RelativePath &);
/*! Play music */
virtual void playMusic();
/*! set music */
virtual inline void setMusic(const Filesystem::RelativePath & music){
this->music = music;
}
/*! Current state */
enum State{
NotStarted,
Initializing,
Running,
Finishing,
Completed,
};
inline const State & getState() const {
return this->state;
}
virtual void setFadeTool(Gui::FadeTool *);
virtual inline Gui::FadeTool * getFadeTool(){
return this->fades;
}
/*
virtual void setBackground(Util::ReferenceCount<Gui::AnimationManager> background);
virtual inline Util::ReferenceCount<Gui::AnimationManager> getBackground(){
return this->background;
}
*/
virtual inline void setFont(const Util::ReferenceCount<FontInfo> & font){
this->font = font;
}
virtual bool hasFont() const;
virtual inline const Util::ReferenceCount<FontInfo> & getFont() const {
return this->font;
}
virtual inline const Util::ReferenceCount<FontInfo> & getFontInfo() const {
return this->font;
}
virtual inline void setInfoLocation(double x, double y){
this->infoLocation.set(x,y);
}
virtual inline const Gui::RelativePoint & getInfoLocation() const {
return this->infoLocation;
}
virtual inline void setMenuInfoLocation(double x, double y){
this->menuInfoLocation.set(x,y);
}
virtual inline const Gui::RelativePoint & getMenuInfoLocation() const {
return this->menuInfoLocation;
}
virtual inline void setMenuInfoText(const std::string & text){
this->menuInfo = text;
}
virtual inline const std::string & getMenuInfoText() const {
return this->menuInfo;
}
virtual std::vector<std::string> getLanguages() const;
virtual void setLanguages(const std::vector<std::string> & languages);
private:
/*! Require cleanup *default constructor only* */
bool cleanup;
/*! Current state */
State state;
/*! Fade Tool */
Gui::FadeTool * fades;
/*! Backgrounds */
Gui::AnimationManager background;
/*! Sounds */
std::map<Actions, Filesystem::RelativePath> sounds;
/*! Music */
Filesystem::RelativePath music;
/*! Font */
Util::ReferenceCount<FontInfo> font;
/*! Info Placement */
Gui::RelativePoint infoLocation;
/*! Menu Info Placement */
Gui::RelativePoint menuInfoLocation;
/*! Menu Info Text */
std::string menuInfo;
std::vector<std::string> languages;
};
/*! New Menu class */
class Menu{
public:
/* These two are basically the same but the Type version will create the renderer for you */
Menu(const Renderer::Type & type = Renderer::Default);
Menu(const Util::ReferenceCount<Renderer> & renderer);
Menu(const Filesystem::AbsolutePath &, const Renderer::Type & type = Renderer::Default);
Menu(const Filesystem::AbsolutePath &, const OptionFactory & factory, const Renderer::Type & type = Renderer::Default);
Menu(const Token *, const Renderer::Type & type = Renderer::Default);
Menu(const Token * token, const OptionFactory & factory, const Renderer::Type & type = Renderer::Default);
virtual ~Menu();
/*! Run Menu pass parent context */
virtual void run(const Context &);
/* Set position of the menu */
virtual void setPosition(const Gui::Coordinate & coordinate);
/*! Logic pass local context */
virtual void act(Context &);
/*! render pass local context and work */
virtual void render(const Context &, const Graphics::Bitmap &) const;
virtual void setRenderer(const Renderer::Type &);
virtual void setRenderer(const Util::ReferenceCount<Renderer> & renderer);
/* a list of languages (translations) supported by this menu */
virtual std::vector<std::string> getLanguages() const;
/*! Get Name */
virtual std::string getName();
virtual std::string getInfo();
virtual void setFont(const Util::ReferenceCount<FontInfo> &);
/*! Add option */
virtual void addOption(MenuOption * opt);
virtual inline Util::ReferenceCount<Renderer> getRenderer() const {
return renderer;
}
static const int Width = 640;
static const int Height = 480;
protected:
void setupDefaultLanguage(const Context & context, const Menu & parent);
virtual void openOptions();
virtual void closeOptions();
/*! Context */
Context context;
/*! Data holder */
std::map<std::string, ValueHolder *> data;
/*! Renderer */
Util::ReferenceCount<Renderer> renderer;
/*! load token */
void load(const Token * token, const OptionFactory & factory);
#if 0
/*! Handle Override
* There can only be one decleration of an override per file/token
* The first one found will be the one executed.
* If found it will return true so that the menu can handle it and avoid going to everything else
*/
virtual bool handleOverride(const Token *);
#endif
/*! Do current version */
virtual void handleCurrentVersion(const Token *);
/*! Prior token compatibility based on version Global::getVersion() */
virtual void handleCompatibility(const Token *, int version, const OptionFactory & factory);
/*! Add Data */
void addData(ValueHolder *);
/*! Keys */
InputMap<Actions> input;
/*! Type */
Renderer::Type type;
/*! Check type */
virtual Util::ReferenceCount<Renderer> rendererType(const Renderer::Type &);
std::vector<std::string> languages;
};
}
#endif
diff --git a/include/r-tech1/menu/menu_option.h b/include/r-tech1/menu/menu_option.h
index 1682c6e0..91fcaa2f 100644
--- a/include/r-tech1/menu/menu_option.h
+++ b/include/r-tech1/menu/menu_option.h
@@ -1,98 +1,98 @@
#ifndef _paintown_menu_option_h
#define _paintown_menu_option_h
#include <string>
#include <vector>
-#include "util/gui/box.h"
-#include "util/language-string.h"
-#include "util/gui/context-box.h"
-#include "util/gui/scroll-list.h"
+#include "r-tech1/gui/box.h"
+#include "r-tech1/language-string.h"
+#include "r-tech1/gui/context-box.h"
+#include "r-tech1/gui/scroll-list.h"
class Bitmap;
class Token;
namespace Menu {
class Context;
}
class MenuOption: public Gui::ContextItem {
public:
/* called when the menu containing this option is displayed to the user.
* default behavior is to do nothing.
*/
virtual void open();
/* called when the menu containing this option returns.
* default behavior is to do nothing.
*/
virtual void close();
/* Logic is executed every tick by the menu so you can do cool effects.
*/
virtual void logic() = 0;
/* Run is executed when the user selects this option */
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &) = 0;
// This is to pass paramaters to an option ie a bar or something
// return true to pause key input
virtual bool leftKey();
virtual bool rightKey();
enum state{
Selected = 0,
Deselected,
Run
};
enum OptionType{
Event = 0,
Option,
AdjustableOption
};
MenuOption(const Gui::ContextBox & parent, const Token *token);
/*
template <typename T>
Util::ReferenceCount<Gui::ScrollItem> getAsScrollItem(const Gui::ContextBox & parent){
Util::ReferenceCount<T> item = new T(this->getName(), parent);
return item.template convert<Gui::ScrollItem>();
}
*/
virtual ~MenuOption();
protected:
private:
state currentState;
OptionType mType;
LanguageString text;
LanguageString infoText;
bool runnable;
public:
inline void setState(const state s) { currentState = s; }
inline state getState() const { return currentState; }
inline void setType(const OptionType t) { mType = t; }
inline OptionType getType() const { return mType; }
inline void setInfoText(const LanguageString &t) { infoText = t; }
inline std::string getInfoText(){ return infoText.get(); }
inline void setRunnable(const bool r) { runnable = r; }
inline bool isRunnable() const { return runnable; }
public:
const std::string getName() const;
void addInfo(const Token *);
void addName(const Token *);
protected:
void readName(const Token * token, const std::string & matchType = "_/name");
void readInfo(const Token * token);
};
#endif
diff --git a/include/r-tech1/menu/options.h b/include/r-tech1/menu/options.h
index 5c43606a..52c67081 100644
--- a/include/r-tech1/menu/options.h
+++ b/include/r-tech1/menu/options.h
@@ -1,557 +1,557 @@
#ifndef _paintown_options_h
#define _paintown_options_h
-#include "menu_option.h"
-#include "util/gui/animation.h"
-#include "util/input/input-map.h"
-#include "util/file-system.h"
-#include "util/pointer.h"
-#include "font-info.h"
+#include "r-tech1/menu/menu_option.h"
+#include "r-tech1/gui/animation.h"
+#include "r-tech1/input/input-map.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/pointer.h"
+#include "r-tech1/menu/font-info.h"
class Token;
namespace Menu{
class OptionFactory;
}
/*! Handles key reconfiguration */
class OptionCredits: public MenuOption {
public:
enum CreditKey{
Exit
};
class Block{
public:
Block(const std::string &);
Block(const Token *);
Block(const Block &);
~Block();
const Block & operator=(const Block &);
void addCredit(const std::string &);
void act();
enum Justification{
Left,
Center,
Right,
};
int print(int x, int y, Graphics::Color defaultTitleColor, Graphics::Color defaultColor, const Font &, const Graphics::Bitmap &, const Justification &) const;
const int size(const Font &) const;
inline const bool empty() const {
return title.empty() && credits.empty();
}
protected:
std::string title;
std::vector<std::string> credits;
bool titleColorOverride;
Graphics::Color titleColor;
bool colorOverride;
Graphics::Color color;
// Before title
Util::ReferenceCount<Gui::Animation> topAnimation;
int topWidth, topHeight;
// After last credit
Util::ReferenceCount<Gui::Animation> bottomAnimation;
int bottomWidth, bottomHeight;
// Spacing at bottom
int spacing;
};
class Sequence {
public:
Sequence(const Token *);
Sequence(const Sequence &);
~Sequence();
const Sequence & operator=(const Sequence &);
void act();
void draw(Graphics::Color title, Graphics::Color color, const Graphics::Bitmap &);
void reset();
enum Type{
Primary,
Roll,
};
inline const bool isDone() const {
return this->done;
}
protected:
// Next for primary
void next();
Type type;
double x;
double y;
int startx;
int endx;
int starty;
int endy;
// Only used if both x's or y's are == to each other
int ticks;
int duration;
double speed;
int alpha;
double alphaMultiplier;
Block::Justification justification;
std::vector<Block> credits;
unsigned int current;
bool done;
int creditLength;
};
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
OptionCredits(const Gui::ContextBox & parent, const Token *token);
virtual ~OptionCredits();
private:
Util::ReferenceCount<Menu::Context> creditsContext;
std::vector<Sequence> sequences;
std::string music;
Graphics::Color color, title;
InputMap<CreditKey> input;
// Clear background (default black)
Graphics::Color clearColor;
};
/*! Dummy option, to allow place fillers in menus */
class OptionDummy: public MenuOption{
public:
OptionDummy(const Gui::ContextBox & parent, const Token *token);
OptionDummy(const Gui::ContextBox & parent, const std::string &name);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
virtual ~OptionDummy();
};
/*! Handles key reconfiguration */
class OptionFullscreen: public MenuOption{
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
virtual std::string getText() const;
// This is to pass paramaters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
OptionFullscreen(const Gui::ContextBox & parent, const Token *token);
virtual ~OptionFullscreen();
private:
int lblue, lgreen;
int rblue, rgreen;
};
/*! Handles joystick reconfiguration */
/*
class OptionJoystick: public MenuOption {
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
OptionJoystick(const Gui::ContextBox & parent, const Token *token);
virtual ~OptionJoystick();
//! keys
enum JoystickType{
Up = 0,
Down,
Left,
Right,
Jump,
Attack1,
Attack2,
Attack3,
Attack4,
Attack5,
Attack6,
Invalidkey
};
private:
//! name
std::string name;
int player;
JoystickType type;
int keyCode;
};
*/
/*! Handles key reconfiguration */
class OptionKey: public MenuOption{
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
OptionKey(const Gui::ContextBox & parent, const Token *token);
virtual ~OptionKey();
//! keys
enum keyType
{
up=0,
down,
left,
right,
jump,
attack1,
attack2,
attack3,
attack4,
attack5,
attack6,
invalidkey
};
private:
//! name
std::string name;
int player;
keyType type;
int keyCode;
};
/*! Handles key reconfiguration */
class OptionLevel: public MenuOption {
public:
OptionLevel(const Gui::ContextBox & parent, const Token *token, int * set, int value);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
virtual ~OptionLevel();
protected:
/* integer to set if this option is chosen */
int * set;
int value;
};
namespace Menu {
class Menu;
class Context;
}
/*! Handles sub menus */
class OptionMenu: public MenuOption {
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
OptionMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory);
virtual ~OptionMenu();
private:
//Menu *menu;
Menu::Menu *menu;
};
class OptionQuit : public MenuOption {
public:
OptionQuit(const Gui::ContextBox & parent, const Token *token);
OptionQuit(const Gui::ContextBox & parent, const std::string &name);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
virtual ~OptionQuit();
};
/* return to previous menu */
class OptionReturn: public MenuOption {
public:
OptionReturn(const Gui::ContextBox & parent, const Token * token);
virtual void logic();
virtual void run(const Menu::Context &);
virtual ~OptionReturn();
};
/* Sets the quality filter used to stretch the screen (xbr/hqx) */
class OptionQualityFilter: public MenuOption {
public:
OptionQualityFilter(const Gui::ContextBox & parent, const Token * token);
virtual void logic();
virtual void run(const Menu::Context &);
std::string getText() const;
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionQualityFilter();
protected:
std::string filter;
};
/* Change the fps */
class OptionFps: public MenuOption {
public:
OptionFps(const Gui::ContextBox & parent, const Token * token);
virtual void logic();
virtual void run(const Menu::Context &);
std::string getText() const;
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionFps();
};
/* continue the game */
class OptionContinue: public MenuOption {
public:
OptionContinue(const Gui::ContextBox & parent, const Token * token);
virtual void logic();
virtual void run(const Menu::Context &);
virtual ~OptionContinue();
};
struct ScreenSize{
ScreenSize(int w, int h):w(w), h(h){}
int w, h;
};
/*! Handles key reconfiguration */
class OptionScreenSize : public MenuOption {
public:
OptionScreenSize(const Gui::ContextBox & parent, const Token *token);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
// This is to pass paramaters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionScreenSize();
protected:
void setMode(int width, int height);
int findMode(int width, int height);
private:
// name
std::string name;
std::vector<ScreenSize> modes;
int lblue, lgreen;
int rblue, rgreen;
};
/*! Handles font selection */
class OptionSelectFont: public MenuOption {
public:
OptionSelectFont(const Gui::ContextBox & parent, const Token *token);
virtual void open();
virtual void close();
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
// This is to pass paramaters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionSelectFont();
protected:
private:
// Type of selector
enum Adjust{
fontName=0,
fontHeight,
fontWidth
};
// Current type of menu to adjust
Adjust typeAdjust;
int lblue, lgreen;
int rblue, rgreen;
std::vector<Util::ReferenceCount<Menu::FontInfo> > fonts;
void nextIndex(bool forward);
};
/*! Handles key reconfiguration */
class OptionSpeed: public MenuOption {
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
// This is to pass paramaters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
virtual std::string getText() const;
OptionSpeed(const Gui::ContextBox & parent, const Token *token);
virtual ~OptionSpeed();
private:
// name
std::string name;
int lblue, lgreen;
int rblue, rgreen;
};
/*! Handles sub menus */
class OptionTabMenu: public MenuOption {
public:
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
OptionTabMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory);
virtual ~OptionTabMenu();
private:
Menu::Menu *menu;
};
class OptionSound: public MenuOption {
public:
OptionSound(const Gui::ContextBox & parent, const Token *token);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
// This is to pass parameters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionSound();
protected:
void changeSound(int much);
private:
int lblue, lgreen;
int rblue, rgreen;
std::string originalName;
};
class OptionMusic: public MenuOption {
public:
OptionMusic(const Gui::ContextBox & parent, const Token *token);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
// This is to pass parameters to an option ie a bar or something
virtual bool leftKey();
virtual bool rightKey();
virtual ~OptionMusic();
protected:
void changeMusic(int much);
private:
int lblue, lgreen;
int rblue, rgreen;
std::string originalName;
};
class OptionLanguage: public MenuOption {
public:
OptionLanguage(const Gui::ContextBox & parent, const Token * token);
virtual void logic();
virtual void run(const Menu::Context &);
};
class OptionJoystick: public MenuOption {
public:
OptionJoystick(const Gui::ContextBox & parent, const Token *token);
// Do logic before run part
virtual void logic();
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &);
virtual ~OptionJoystick();
};
#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1870e73b..074d0b3a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,104 +1,104 @@
# -------------------------------------------------------
# util cmake build script for paintown.
# Written by: juvinious
# Modified by: kazzmir
# -------------------------------------------------------
# -------------------------------------------------------
# Source directories containing all the necessary .cpp files
# -------------------------------------------------------
set(UTIL_SRC
argument.cpp
configuration.cpp
network/network.cpp
network/chat.cpp
network/irc.cpp
token.cpp
resource.cpp
tokenreader.cpp
timedifference.cpp
debug.cpp
timer.cpp
init.cpp
utf.cpp
console.cpp
input/keyboard.cpp
loading.cpp
messages.cpp
graphics/bitmap.cpp
graphics/image.cpp
events.cpp
font.cpp
font_factory.cpp
graphics/fire.cpp
ftalleg.cpp
funcs.cpp
directory.cpp
file-system.cpp
graphics/gradient.cpp
ebox.cpp
regex.cpp
language-string.cpp
thread.cpp
input/input.cpp
input/text-input.cpp
input/input-manager.cpp
input/input-source.cpp
input/joystick.cpp
input/allegro5/joystick.cpp
xenon/xenon.cpp
libs/lz4/lz4.c
system.cpp
version.cpp
compress.cpp
message-queue.cpp
input/linux_joystick.cpp
exceptions/load_exception.cpp
windows/funcs.cpp
windows/system.cpp
nacl/module.cpp
nacl/network-system.cpp
exceptions/exception.cpp
menu/actionfactory.cpp
menu/action_speed.cpp
menu/menu.cpp
menu/font-info.cpp
menu/menu_action.cpp
menu/menu_option.cpp
menu/options.cpp
menu/optionfactory.cpp
gui/animation.cpp
gui/box.cpp
gui/container.cpp
gui/context-box.cpp
gui/coordinate.cpp
gui/cutscene.cpp
gui/fadetool.cpp
gui/lineedit.cpp
gui/list.cpp
gui/rectarea.cpp
gui/popup-box.cpp
gui/scroll-list.cpp
gui/select-list.cpp
gui/tab-container.cpp
gui/tabbed-box.cpp
gui/timer.cpp
gui/widget.cpp
sound/sound.cpp
sound/audio.cpp
sound/music-player.cpp
sound/music-renderer.cpp
sound/music.cpp
-../system/timer.cpp
-../system/allegro5/timer.cpp
-../system/allegro5/init.cpp)
+system/timer.cpp
+system/allegro5/timer.cpp
+system/allegro5/init.cpp)
# -------------------------------------------------------
# Include directory
# -------------------------------------------------------
#include_directories(include include/internal)
# -------------------------------------------------------
# module
# -------------------------------------------------------
add_library (util_module ${UTIL_SRC})
diff --git a/src/menu/options.cpp b/src/menu/options.cpp
index 4a6e0a2e..530ceb95 100644
--- a/src/menu/options.cpp
+++ b/src/menu/options.cpp
@@ -1,3128 +1,3128 @@
-#include "util/graphics/bitmap.h"
-
-#include "options.h"
-#include "util/token.h"
-#include "util/input/input-source.h"
-#include "util/parameter.h"
-#include "util/tokenreader.h"
-#include "menu.h"
-#include "util/configuration.h"
-#include "util/exceptions/load_exception.h"
-#include "menu-exception.h"
-#include "util/init.h"
-#include "util/events.h"
-#include "util/version.h"
-#include "optionfactory.h"
-
-#include "util/sound/music.h"
-
-#include "util/input/keyboard.h"
-#include "util/funcs.h"
-#include "util/file-system.h"
-#include "util/system.h"
-#include "util/font_factory.h"
-#include "util/exceptions/shutdown_exception.h"
-#include "util/exceptions/exception.h"
-#include "util/font.h"
-#include "util/gui/box.h"
-#include "util/thread.h"
-
-#include "util/loading.h"
-#include "util/input/input-map.h"
-#include "util/input/input-manager.h"
+#include "r-tech1/graphics/bitmap.h"
+
+#include "r-tech1/menu/options.h"
+#include "r-tech1/token.h"
+#include "r-tech1/input/input-source.h"
+#include "r-tech1/parameter.h"
+#include "r-tech1/tokenreader.h"
+#include "r-tech1/menu/menu.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/exceptions/load_exception.h"
+#include "r-tech1/menu/menu-exception.h"
+#include "r-tech1/init.h"
+#include "r-tech1/events.h"
+#include "r-tech1/version.h"
+#include "r-tech1/menu/optionfactory.h"
+
+#include "r-tech1/sound/music.h"
+
+#include "r-tech1/input/keyboard.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/system.h"
+#include "r-tech1/font_factory.h"
+#include "r-tech1/exceptions/shutdown_exception.h"
+#include "r-tech1/exceptions/exception.h"
+#include "r-tech1/font.h"
+#include "r-tech1/gui/box.h"
+#include "r-tech1/thread.h"
+
+#include "r-tech1/loading.h"
+#include "r-tech1/input/input-map.h"
+#include "r-tech1/input/input-manager.h"
#include <sstream>
#include <algorithm>
#include <time.h>
#include <math.h>
using namespace std;
using namespace Gui;
/* true if the arguments passed in match todays date.
* pass 0 for any argument that you don't care about (it will match any date)
*/
static bool todaysDate(int month, int day, int year){
time_t result = time(NULL);
struct tm * local = localtime(&result);
return (month == 0 || month == (local->tm_mon + 1)) &&
(day == 0 || day == local->tm_mday) &&
(year == 0 || year == local->tm_year + 1900);
}
static bool jonBirthday(){
return todaysDate(3, 25, 0);
}
static bool miguelBirthday(){
return todaysDate(8, 11, 0);
}
OptionCredits::Block::Block(const std::string & title):
title(title),
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
spacing(0){
}
OptionCredits::Block::Block(const Token * token):
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
topWidth(0),
topHeight(0),
bottomWidth(0),
bottomHeight(0),
spacing(0){
if ( *token != "block" ){
throw LoadException(__FILE__, __LINE__, "Not a credit block");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if ( *tok == "title" ) {
tok->view() >> title;
} else if (*tok == "credit"){
std::string credit;
tok->view() >> credit;
credits.push_back(credit);
} else if ( *tok == "titlecolor" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
titleColor = Graphics::makeColor( r, g, b );
titleColorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "color" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
colorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "animation" ) {
TokenView animView = tok->view();
while (animView.hasMore()){
const Token * animTok;
animView >> animTok;
if (*animTok == "top"){
tok->match("_/width", topWidth);
tok->match("_/height", topHeight);
topAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
} else if (*animTok == "bottom"){
tok->match("_/width", bottomWidth);
tok->match("_/height", bottomHeight);
bottomAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
}
}
} else if (*tok == "spacing"){
tok->view() >> spacing;
} else {
Global::debug( 3 ) <<"Unhandled Credit Block attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Block parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
OptionCredits::Block::Block(const OptionCredits::Block & copy):
title(copy.title),
credits(copy.credits),
titleColorOverride(copy.titleColorOverride),
titleColor(copy.titleColor),
colorOverride(copy.colorOverride),
color(copy.color),
topAnimation(copy.topAnimation),
topWidth(copy.topWidth),
topHeight(copy.topHeight),
bottomAnimation(copy.bottomAnimation),
bottomWidth(copy.bottomWidth),
bottomHeight(copy.bottomHeight),
spacing(copy.spacing){
}
OptionCredits::Block::~Block(){
}
const OptionCredits::Block & OptionCredits::Block::operator=(const OptionCredits::Block & copy){
title = copy.title;
credits = copy.credits;
titleColor = copy.titleColor;
titleColorOverride = copy.titleColorOverride;
color = copy.color;
colorOverride = copy.colorOverride;
topAnimation = copy.topAnimation;
topWidth =copy.topWidth;
topHeight = copy.topHeight;
bottomAnimation = copy.bottomAnimation;
bottomWidth = copy.bottomWidth;
bottomHeight = copy.bottomHeight;
spacing = copy.spacing;
return *this;
}
void OptionCredits::Block::addCredit(const std::string & credit){
credits.push_back(credit);
}
void OptionCredits::Block::act(){
// Top animation
if (topAnimation != NULL){
topAnimation->act();
}
// Bottom animation
if (bottomAnimation != NULL){
bottomAnimation->act();
}
}
int OptionCredits::Block::print(int x, int y, Graphics::Color defaultTitleColor, Graphics::Color defaultColor, const Font & font, const Graphics::Bitmap & work, const Justification & justification) const {
int currentY = y;
// Top animation
if (topAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = topWidth/2;
break;
case Right:
xmod = topWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap temp(topWidth, topHeight);
//topAnimation->draw(x - xmod, y, topWidth, topHeight, work);
topAnimation->draw(0, 0, topWidth, topHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY += topHeight;
}
if (!title.empty()){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(title.c_str())/2;
break;
case Right:
xmod = font.textLength(title.c_str());
break;
}
font.printf(x - xmod, currentY, (titleColorOverride ? titleColor : defaultTitleColor), work, title, 0);
currentY += font.getHeight();
}
for (std::vector<std::string>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const std::string & credit = *i;
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(credit.c_str())/2;
break;
case Right:
xmod = font.textLength(credit.c_str());
break;
}
font.printf(x - xmod, currentY, (colorOverride ? color : defaultColor), work, credit, 0);
currentY += font.getHeight();
}
// Bottom animation
if (bottomAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = bottomWidth/2;
break;
case Right:
xmod = bottomWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap temp(topWidth, topHeight);
//bottomAnimation->draw(x - xmod, y, bottomWidth, bottomHeight, work);
bottomAnimation->draw(0, 0, bottomWidth, bottomHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY += bottomHeight;
}
currentY += font.getHeight() + spacing;
return currentY;
}
const int OptionCredits::Block::size(const Font & font) const{
// Counts title and space in between
int total = 0;
if (topAnimation != NULL){
total += topHeight;
}
if (!title.empty()){
total+= font.getHeight();
}
total += credits.size() * font.getHeight();
if (bottomAnimation != NULL){
total += bottomHeight;
}
total += font.getHeight();
total += spacing;
return total;
}
OptionCredits::Sequence::Sequence(const Token * token):
type(Primary),
x(0),
y(0),
startx(0),
endx(0),
starty(0),
endy(0),
ticks(0),
duration(250),
speed(0),
alpha(0),
alphaMultiplier(0),
justification(Block::Center),
current(0),
done(false),
creditLength(0){
if ( *token != "sequence" ){
throw LoadException(__FILE__, __LINE__, "Not a credit sequence");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if (*tok == "type"){
std::string sequenceType;
tok->view() >> sequenceType;
if (sequenceType == "roll"){
type = Roll;
} else if (sequenceType == "primary"){
type = Primary;
}
} else if (*tok == "start-x"){
tok->view() >> startx;
} else if (*tok == "end-x"){
tok->view() >> endx;
} else if (*tok == "start-y"){
tok->view() >> starty;
} else if (*tok == "end-y"){
tok->view() >> endy;
} else if (*tok == "duration"){
tok->view() >> duration;
} else if (*tok == "speed"){
tok->view() >> speed;
} else if (*tok == "alpha-multiplier"){
tok->view() >> alphaMultiplier;
} else if ( *tok == "justification" ) {
std::string justify;
tok->view() >> justify;
if (justify == "left"){
justification = Block::Left;
} else if (justify == "center"){
justification = Block::Center;
} else if (justify == "right"){
justification = Block::Right;
}
} else if (*tok == "block"){
credits.push_back(Block(tok));
} else {
Global::debug( 3 ) <<"Unhandled Credit Sequence attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Sequence parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
// Initial
reset();
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
creditLength += block.size(Menu::menuFontParameter.current()->get());
}
}
OptionCredits::Sequence::Sequence(const Sequence & copy):
type(copy.type),
x(copy.x),
y(copy.y),
startx(copy.startx),
endx(copy.endx),
starty(copy.starty),
endy(copy.endy),
ticks(copy.ticks),
duration(copy.duration),
speed(copy.speed),
alpha(copy.alpha),
alphaMultiplier(copy.alphaMultiplier),
justification(copy.justification),
credits(copy.credits),
current(copy.current),
done(false),
creditLength(copy.creditLength){
}
OptionCredits::Sequence::~Sequence(){
}
const OptionCredits::Sequence & OptionCredits::Sequence::operator=(const OptionCredits::Sequence & copy){
type = copy.type;
x = copy.x;
y = copy.y;
startx = copy.startx;
endx = copy.endx;
starty = copy.starty;
endy = copy.endy;
ticks = copy.ticks;
duration = copy.duration;
speed = copy.speed;
alpha = copy.alpha;
alphaMultiplier = copy.alphaMultiplier;
justification = copy.justification;
credits = copy.credits;
current = copy.current;
done = false;
creditLength = copy.creditLength;
return *this;
}
static int alphaClamp(int x, double multiplier){
int clamp = x * multiplier;
if (clamp < 0){
clamp = 0;
} else if (clamp > 255){
clamp = 255;
}
return clamp;
}
void OptionCredits::Sequence::act(){
if (!done && !credits.empty()){
if (type == Roll){
y += speed;
if (starty > endy){
if ((y + (creditLength * 1.1)) < endy){
done = true;
}
} else if (starty < endy){
if ((y * 1.1) > endy){
done = true;
}
}
} else if (type == Primary){
credits[current].act();
if (startx != endx){
x += speed;
if (startx > endx){
const double midpoint = (startx+endx)/2;
const int mid = x > midpoint ? startx -x : x - endx;
alpha = alphaClamp(mid, alphaMultiplier);
if (x < endx){
next();
}
} else if (startx < endx){
const double midpoint = (startx+endx)/2;
const int mid = x < midpoint ? x - startx : endx - x;
alpha = alphaClamp(mid, alphaMultiplier);
//Global::debug(0) << "alpha: " << alpha << " midpoint: " << midpoint << " mid: " << mid << std::endl;
if (x > endx){
next();
}
}
} else {
const double midpoint = duration/2;
const int mid = ticks < midpoint ? ticks : duration - ticks;
alpha = alphaClamp(mid, alphaMultiplier);
ticks++;
if (ticks >= duration){
ticks = 0;
next();
}
}
}
}
}
void OptionCredits::Sequence::draw(Graphics::Color title, Graphics::Color color, const Graphics::Bitmap & work){
if (!done && !credits.empty()){
if (type == Roll){
int rollY = (int) y;
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
rollY = block.print(x, rollY, title, color, Menu::menuFontParameter.current()->get(), work, justification);
}
} else if (type == Primary){
Graphics::Bitmap::transBlender(0, 0, 0, alpha);
credits[current].print(x, y, title, color, Menu::menuFontParameter.current()->get(), work.translucent(), justification);
}
}
}
void OptionCredits::Sequence::reset(){
done = false;
current = 0;
ticks = 0;
if (!credits.empty()){
if (type == Roll){
x = startx;
y = starty;
} else if (type == Primary){
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
void OptionCredits::Sequence::next(){
if (type == Primary){
if (current < credits.size()){
current++;
if (current == credits.size()){
done = true;
} else {
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
}
static std::string defaultPositions(){
const int width = Configuration::getScreenWidth();
const int height = Configuration::getScreenHeight();
std::ostringstream out;
out << "(start-x " << width/2.3 << ") (end-x " << width/1.8 << ") (start-y " << height/2 << ") ";
//out << "(start-x " << width/2 << ") (end-x " << width/2 << ") (start-y " << height/2 << ") (duration 250) ";
return out.str();
}
OptionCredits::OptionCredits(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
creditsContext(new Menu::Context()),
music(""),
color(Graphics::makeColor(255,255,255)),
title(Graphics::makeColor(0,255,255)),
clearColor(Graphics::makeColor(0,0,0)){
std::string defaultSequence = "(sequence (type primary) (speed 0.3) (alpha-multiplier 20) (justification center) " + defaultPositions();
/* Always */
if (jonBirthday()){
defaultSequence += "(block (title \"Happy birthday, Jon!\"))";
}
if (miguelBirthday()){
defaultSequence += "(block (title \"Happy birthday, Miguel!\"))";
}
if (Storage::instance().exists(Filesystem::RelativePath("sprites/paintown.png"))){
defaultSequence += "(block (animation (top) (width 350) (height 65) (image 0 \"sprites/paintown.png\") (frame (image 0) (time -1))) (credit \"Version " + Version::getVersionString() + "\"))";
} else {
defaultSequence += "(block (title \"PAINTOWN\") (credit \"Version " + Version::getVersionString() + "\"))";
}
defaultSequence += "(block (title \"Programming\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Level design\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Contact\") (credit \"Website: http://paintown.org\") (credit \"Email: jon@rafkind.com\")))";
TokenReader reader;
Sequence sequence(reader.readTokenFromString(defaultSequence));
sequences.push_back(sequence);
//Global::debug(0) << defaultSequence << std::endl;
if ( *token != "credits" ){
throw LoadException(__FILE__, __LINE__, "Not a credit menu");
}
readName(token);
TokenView view = token->view();
// NOTE Use this to handle legacy additional blocks for the time being
Block legacyAdditional("");
bool additionalTitle = true;
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "music" ) {
/* Set music for credits */
tok->view() >> music;
} else if ( *tok == "background" ) {
/* Create an image and push it back on to vector */
std::string temp;
tok->view() >> temp;
creditsContext->addBackground(temp);
} else if ( *tok == "anim" || *tok == "animation" ){
creditsContext->addBackground(tok);
} else if ( *tok == "additional" ) {
std::string str;
TokenView additionalView = tok->view();
while (additionalView.hasMore()){
additionalView >> str;
if (additionalTitle){
legacyAdditional = Block(str);
additionalTitle = false;
} else {
legacyAdditional.addCredit(str);
}
}
} else if (*tok == "sequence"){
sequences.push_back(OptionCredits::Sequence(tok));
} else if ( *tok == "titlecolor" ) {
int r,b,g;
tok->view() >> r >> g >> b;
title = Graphics::makeColor( r, g, b );
} else if ( *tok == "color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
} else if ( *tok == "clear-color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
clearColor = Graphics::makeColor( r, g, b );
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
if (!legacyAdditional.empty()){
//creditsRoll.push_back(legacyAdditional);
}
input.set(Keyboard::Key_ESC, 0, true, Exit);
input.set(Joystick::Button2, 0, true, Exit);
}
OptionCredits::~OptionCredits(){
}
void OptionCredits::logic(){
}
class CreditsLogicDraw : public Util::Logic, public Util::Draw {
public:
CreditsLogicDraw(std::vector<OptionCredits::Sequence> & sequences, Graphics::Color clearColor, Graphics::Color title, Graphics::Color color, const Font & font, InputMap<OptionCredits::CreditKey> & input, Menu::Context & context):
sequences(sequences),
clearColor(clearColor),
title(title),
color(color),
font(font),
input(input),
quit(false),
context(context),
current(0){
}
std::vector<OptionCredits::Sequence> & sequences;
Graphics::Color clearColor, title, color;
const Font & font;
InputMap<OptionCredits::CreditKey> & input;
bool quit;
Menu::Context & context;
unsigned int current;
void run(){
vector<InputMap<OptionCredits::CreditKey>::InputEvent> out = InputManager::getEvents(input, InputSource(true));
for (vector<InputMap<OptionCredits::CreditKey>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<OptionCredits::CreditKey>::InputEvent & event = *it;
if (event.enabled){
if (event.out == OptionCredits::Exit){
quit = true;
context.finish();
}
}
}
sequences[current].act();
if (sequences[current].isDone()){
sequences[current].reset();
current++;
if (current >= sequences.size()){
current = 0;
}
}
context.act();
}
bool done(){
return quit;
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
void draw(const Graphics::Bitmap & buffer){
/* FIXME: hard coded resolution */
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::StretchedBitmap::NoClear, Graphics::qualityFilterName(Configuration::getQualityFilter()));
work.fill(clearColor);
work.start();
//background.Blit(work);
context.render(Util::ReferenceCount<Menu::Renderer>(NULL), work);
sequences[current].draw(title, color, work);
work.finish();
// buffer.BlitToScreen();
}
};
void OptionCredits::run(const Menu::Context & context){
Menu::Context localContext(context, *creditsContext);
localContext.initialize();
if (!music.empty()){
if (Music::loadSong(Storage::instance().find(Filesystem::RelativePath(music)).path())){
Music::pause();
Music::play();
}
}
const Font & vFont = Menu::menuFontParameter.current()->get();
CreditsLogicDraw loop(sequences, clearColor, title, color, vFont, input, localContext);
Util::standardLoop(loop, loop);
InputManager::waitForRelease(input, InputSource(true), Exit);
throw Menu::Reload(__FILE__, __LINE__);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "dummy" ){
throw LoadException(__FILE__, __LINE__, "Not dummy option");
}
readName(token);
if (getText().empty()){
this->setText("Dummy");
}
setRunnable(false);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to dummy");
}
this->setText(name);
setRunnable(false);
}
OptionDummy::~OptionDummy(){
}
void OptionDummy::logic(){
}
void OptionDummy::run(const Menu::Context & context){
}
OptionFullscreen::OptionFullscreen(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "fullscreen" )
throw LoadException(__FILE__, __LINE__, "Not fullscreen option");
readName(token);
}
OptionFullscreen::~OptionFullscreen()
{
// Nothing
}
std::string OptionFullscreen::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << (Configuration::getFullscreen() ? "Yes" : "No");
return out.str();
}
void OptionFullscreen::logic(){;
}
static void changeScreenMode(){
Configuration::setFullscreen(!Configuration::getFullscreen());
int gfx = (Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED);
Graphics::changeGraphicsMode(gfx, Graphics::Bitmap::getScreenWidth(), Graphics::Bitmap::getScreenHeight());
}
void OptionFullscreen::run(const Menu::Context & context){
changeScreenMode();
}
bool OptionFullscreen::leftKey(){
changeScreenMode();
return true;
}
bool OptionFullscreen::rightKey(){
changeScreenMode();
return true;
}
OptionFps::OptionFps(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
void OptionFps::logic(){
}
void OptionFps::run(const Menu::Context & context){
}
std::string OptionFps::getText() const {
ostringstream out;
out << "Frames per second: " << Global::TICS_PER_SECOND;
return out.str();
}
bool OptionFps::leftKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND - 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
bool OptionFps::rightKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND + 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
OptionFps::~OptionFps(){
}
OptionQualityFilter::OptionQualityFilter(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
std::string OptionQualityFilter::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getQualityFilter();
return out.str();
}
void OptionQualityFilter::logic(){
}
bool OptionQualityFilter::leftKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "hqx";
} else if (quality == "hqx"){
quality = "xbr";
} else if (quality == "xbr"){
quality = "none";
}
Configuration::setQualityFilter(quality);
return true;
}
bool OptionQualityFilter::rightKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "xbr";
} else if (quality == "hqx"){
quality = "none";
} else if (quality == "xbr"){
quality = "hqx";
}
Configuration::setQualityFilter(quality);
return true;
}
void OptionQualityFilter::run(const Menu::Context & context){
}
OptionQualityFilter::~OptionQualityFilter(){
}
#if 0
static OptionJoystick::JoystickType convertToKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionJoystick::Up;
if (temp == "down") return OptionJoystick::Down;
if (temp == "left") return OptionJoystick::Left;
/*
if (temp == "right") return OptionJoystick::Right;
if (temp == "jump") return OptionJoystick::Jump;
if (temp == "attack1") return OptionJoystick::Attack1;
if (temp == "attack2") return OptionJoystick::Attack2;
if (temp == "attack3") return OptionJoystick::Attack3;
if (temp == "attack4") return OptionJoystick::Attack4;
if (temp == "attack5") return OptionJoystick::Attack5;
if (temp == "attack6") return OptionJoystick::Attack6;
return OptionJoystick::Invalidkey;
}
static Configuration::JoystickInput getKey(int player, OptionJoystick::JoystickType k){
switch(k){
case OptionJoystick::Up:
return Joystick::Up;
case OptionJoystick::Down:
return Joystick::Down;
case OptionJoystick::Left:
return Joystick::Left;
case OptionJoystick::Right:
return Joystick::Right;
case OptionJoystick::Jump:
return Joystick::Button4;
case OptionJoystick::Attack1:
return Joystick::Button1;
case OptionJoystick::Attack2:
return Joystick::Button2;
case OptionJoystick::Attack3:
return Joystick::Button3;
case OptionJoystick::Attack4:
return Joystick::Button4;
case OptionJoystick::Attack5:
return Joystick::Button5;
case OptionJoystick::Attack6:
return Joystick::Button6;
default:
break;
}
return Joystick::Up;
}
static void setKey(int player, OptionJoystick::JoystickType k, Configuration::JoystickInput key){
/ *
switch(k){
case OptionJoystick::Up:
Configuration::setJoystickUp(player, key);
break;
case OptionJoystick::Down:
Configuration::setJoystickDown(player, key);
break;
case OptionJoystick::Left:
Configuration::setJoystickLeft(player, key);
break;
case OptionJoystick::Right:
Configuration::setJoystickRight(player, key);
break;
case OptionJoystick::Jump:
Configuration::setJoystickJump(player, key);
break;
case OptionJoystick::Attack1:
Configuration::setJoystickAttack1(player, key);
break;
case OptionJoystick::Attack2:
Configuration::setJoystickAttack2(player, key);
break;
case OptionJoystick::Attack3:
Configuration::setJoystickAttack3(player, key);
break;
case OptionJoystick::Attack4:
Configuration::setJoystickAttack4(player, key);
break;
case OptionJoystick::Attack5:
Configuration::setJoystickAttack5(player, key);
break;
case OptionJoystick::Attack6:
Configuration::setJoystickAttack6(player, key);
break;
default:
break;
}
*/
}
static Configuration::JoystickInput readJoystick(){
vector<Joystick::Key> keys;
keys.push_back(Joystick::Up);
keys.push_back(Joystick::Down);
keys.push_back(Joystick::Left);
keys.push_back(Joystick::Right);
keys.push_back(Joystick::Button1);
keys.push_back(Joystick::Button2);
keys.push_back(Joystick::Button3);
keys.push_back(Joystick::Button4);
keys.push_back(Joystick::Button5);
keys.push_back(Joystick::Button6);
InputMap<Joystick::Key> input;
for (vector<Joystick::Key>::iterator it = keys.begin(); it != keys.end(); it++){
input.set(*it, 0, true, *it);
}
input.set(Keyboard::Key_ESC, 0, true, Joystick::Invalid);
while (true){
InputManager::poll();
vector<InputMap<Joystick::Key>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (vector<InputMap<Joystick::Key>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<Joystick::Key>::InputEvent & event = *it;
if (event.enabled){
Global::debug(1) << "Press: " << event.out << std::endl;
if (event.out == Joystick::Invalid){
InputManager::waitForRelease(input, InputSource(), Joystick::Invalid);
throw Exception::Return(__FILE__, __LINE__);
}
return event.out;
}
}
Util::rest(1);
}
/* control probably shouldn't get here.. */
return Joystick::Up;
}
OptionJoystick::OptionJoystick(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(Invalidkey),
keyCode(0){
if (*token != "joystick"){
throw LoadException(__FILE__, __LINE__, "Not joystick option");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "name" ){
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
}
if (type == Invalidkey){
throw LoadException(__FILE__, __LINE__, "Invalid joystick button, should be up, down, left, right, up, down, jump, attack1-6!");
}
if (player == -1){
throw LoadException(__FILE__, __LINE__, "Player not specified in joystick configuration");
}
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
}
OptionJoystick::~OptionJoystick(){
// Nothing
}
void OptionJoystick::logic(){
/*
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Joystick::keyToName(getKey(player,type)));
setText(std::string(temp));
*/
}
void OptionJoystick::run(const Menu::Context & context){
/*
//int x, y, width, height;
const Font & vFont = Menu::menuFontParameter.current()->get();
const char * message = "Press a joystick button!";
const int width = vFont.textLength(message) + 10;
const int height = vFont.getHeight() + 10;
// const int x = (getParent()->getWork()->getWidth()/2) - (width/2);
// const int y = (getParent()->getWork()->getHeight()/2) - (height/2);
const int x = Menu::Menu::Width / 2 - width/2;
const int y = Menu::Menu::Height / 2 - height/2;
Box dialog;
dialog.location.setPosition(Gui::AbsolutePoint(0,0));
dialog.location.setDimensions(vFont.textLength(message) + 10, vFont.getHeight() + 10);
dialog.transforms.setRadius(0);
dialog.colors.body = Graphics::makeColor(0,0,0);
dialog.colors.bodyAlpha = 200;
dialog.colors.border = Graphics::makeColor(255,255,255);
dialog.colors.borderAlpha = 255;
Graphics::Bitmap temp = Graphics::Bitmap::temporaryBitmap(width,height);
dialog.render(temp, vFont);
vFont.printf( 5, 5, Graphics::makeColor(255,255,255), temp, message, -1);
temp.BlitToScreen(x,y);
setKey(player, type, readJoystick());
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
*/
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a joystick button!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a joystick button!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/*
if (keyDialog.isActive()){
InputManager::poll();
}
*/
tempContext.act();
tempContext.render(0, temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
setKey(player, type, readJoystick());
InputManager::waitForClear();
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
/*
Keyboard key;
keyCode = readKey(key);
setKey(player,type, keyCode);
*/
}
#endif
static OptionKey::keyType convertToKeyboardKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionKey::up;
if (temp == "down") return OptionKey::down;
if (temp == "left") return OptionKey::left;
if (temp == "right") return OptionKey::right;
if (temp == "jump") return OptionKey::jump;
if (temp == "attack1") return OptionKey::attack1;
if (temp == "attack2") return OptionKey::attack2;
if (temp == "attack3") return OptionKey::attack3;
if (temp == "attack4") return OptionKey::attack4;
if (temp == "attack5") return OptionKey::attack5;
if (temp == "attack6") return OptionKey::attack6;
return OptionKey::invalidkey;
}
static int getKey(int player, OptionKey::keyType k){
switch(k){
case OptionKey::up:
return Configuration::getUp(player);
break;
case OptionKey::down:
return Configuration::getDown(player);
break;
case OptionKey::left:
return Configuration::getLeft(player);
break;
case OptionKey::right:
return Configuration::getRight(player);
break;
case OptionKey::jump:
return Configuration::getJump(player);
break;
case OptionKey::attack1:
return Configuration::getAttack1(player);
break;
case OptionKey::attack2:
return Configuration::getAttack2(player);
break;
case OptionKey::attack3:
return Configuration::getAttack3(player);
break;
case OptionKey::attack4:
return Configuration::getAttack4(player);
case OptionKey::attack5:
return Configuration::getAttack5(player);
case OptionKey::attack6:
return Configuration::getAttack6(player);
default:
break;
}
return 0;
}
static void setKey(int player, OptionKey::keyType k, int key){
switch(k){
case OptionKey::up:
Configuration::setUp(player, key);
break;
case OptionKey::down:
Configuration::setDown(player, key);
break;
case OptionKey::left:
Configuration::setLeft(player, key);
break;
case OptionKey::right:
Configuration::setRight(player, key);
break;
case OptionKey::jump:
Configuration::setJump(player, key);
break;
case OptionKey::attack1:
Configuration::setAttack1(player, key);
break;
case OptionKey::attack2:
Configuration::setAttack2(player, key);
break;
case OptionKey::attack3:
Configuration::setAttack3(player, key);
break;
case OptionKey::attack4:
Configuration::setAttack4(player, key);
break;
case OptionKey::attack5:
Configuration::setAttack5(player, key);
break;
case OptionKey::attack6:
Configuration::setAttack6(player, key);
break;
default:
break;
}
}
/*
static int readKey( Keyboard & key ){
int k = key.readKey();
key.wait();
return k;
}
*/
OptionKey::OptionKey(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(invalidkey),
keyCode(0){
if ( *token != "key" )
throw LoadException(__FILE__, __LINE__, "Not key option");
TokenView view = token->view();
while (view.hasMore()) {
try {
const Token * tok;
view >> tok;
if ( *tok == "name" ) {
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKeyboardKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if(name.empty())throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
if(type == invalidkey)throw LoadException(__FILE__, __LINE__, "Invalid key, should be up, down, left, right, up, down, jump, attack1-6!");
if(player == -1)throw LoadException(__FILE__, __LINE__, "Player not specified in key configuration");
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
OptionKey::~OptionKey(){
// Nothing
}
void OptionKey::logic(){
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
void OptionKey::run(const Menu::Context & context){
// Do dialog
//Box::messageDialog(Menu::Menu::Width, Menu::Menu::Height, "Press a Key!",2);
class WaitForKey: public Util::Logic, public Util::Draw {
public:
WaitForKey(const Menu::Context & context):
font(Menu::menuFontParameter.current()->get()),
tempContext(context),
speed(30),
listener(*this),
quit(false),
out(Keyboard::Key_ESC),
startingTime(System::currentMilliseconds()),
maxTime(5000){
tempContext.initialize();
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = 320;
const int height = 240;
const int radius = 15;
keyDialog.setText("Press a Key!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a Key!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
Keyboard::pushRepeatState(false);
Keyboard::addListener(&listener);
vector<Graphics::BlendPoint> points;
points.push_back(Graphics::BlendPoint(Graphics::makeColor(255, 0, 0), 30));
points.push_back(Graphics::BlendPoint(Graphics::makeColor(0, 255, 0), 25));
points.push_back(Graphics::BlendPoint(Graphics::makeColor(255, 255, 255), 0));
colors = Graphics::blend_palette(points);
}
virtual ~WaitForKey(){
Keyboard::removeListener(&listener);
Keyboard::popRepeatState();
}
class Listener: public KeyboardListener {
public:
Listener(WaitForKey & parent):
parent(parent){
}
WaitForKey & parent;
virtual void press(Keyboard * keyboard, Keyboard::KeyType key, Keyboard::unicode_t code){
parent.press(key);
}
virtual void release(Keyboard * keyboard, Keyboard::KeyType key){
parent.release(key);
}
};
const Font & font;
Menu::Context tempContext;
Menu::InfoBox keyDialog;
const int speed;
Listener listener;
bool quit;
Keyboard::KeyType out;
/* keep track of how much time we are in this loop */
uint64_t startingTime;
/* maximum number of milliseconds to wait */
const uint64_t maxTime;
vector<Graphics::Color> colors;
virtual void press(Keyboard::KeyType key){
quit = true;
if (key != Keyboard::Key_ESC){
this->out = key;
}
}
virtual void release(Keyboard::KeyType key){
}
virtual void run(){
for (int i = 0; i < 90 / speed; i++){
tempContext.act();
keyDialog.act(font);
}
/* exit after 5 seconds */
quit = quit || (System::currentMilliseconds() - startingTime > maxTime);
}
virtual bool done(){
return quit;
}
virtual double ticks(double system){
return system * Global::ticksPerSecond(speed);
}
virtual void showTimeLeft(const Graphics::Bitmap & screen){
int x1 = 1;
int y1 = 1;
int x2 = screen.getWidth() * (1 - (double) (System::currentMilliseconds() - startingTime) / (double) maxTime);
if (x2 < x1){
x2 = x1;
}
int y2 = 10;
int color = (1.0 - (double) (System::currentMilliseconds() - startingTime) / maxTime) * colors.size();
if (color < 0){
color = 0;
}
if (color >= colors.size()){
color = colors.size() - 1;
}
screen.rectangleFill(x1, y1, x2, y2, colors[color]);
}
virtual void draw(const Graphics::Bitmap & screen){
Graphics::StretchedBitmap work(640, 480, screen);
work.start();
tempContext.render(Util::ReferenceCount<Menu::Renderer>(NULL), work);
keyDialog.render(work, font);
showTimeLeft(work);
work.finish();
}
};
WaitForKey run(context);
Util::standardLoop(run, run);
Keyboard::KeyType key = run.out;
if (key != Keyboard::Key_ESC){
setKey(player, type, key);
}
/*
Keyboard key;
key.wait();
*/
/*
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a Key!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a Key!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/ *
if (keyDialog.isActive()){
InputManager::poll();
}
* /
tempContext.act();
tempContext.render(Util::ReferenceCount<Menu::Renderer>(NULL), temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
keyCode = InputManager::readKey();
setKey(player,type, keyCode);
InputManager::waitForClear();
*/
}
OptionLevel::OptionLevel(const Gui::ContextBox & parent, const Token *token, int * set, int value):
MenuOption(parent, token),
set(set),
value(value){
// Nothing
}
OptionLevel::~OptionLevel(){
}
void OptionLevel::logic(){
}
void OptionLevel::run(const Menu::Context & context){
*set = value;
throw Menu::MenuException(__FILE__, __LINE__);
}
OptionMenu::OptionMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (*token != "menu"){
throw LoadException(__FILE__, __LINE__, "Not a menu");
}
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory);
} else {
menu = new Menu::Menu(token, factory);
}
this->setText(menu->getName());
this->setInfoText(menu->getInfo());
// Lets check if this menu is going bye bye
//if ( menu->checkRemoval() ) setForRemoval(true);
}
OptionMenu::~OptionMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionMenu::logic(){
// Nothing
}
void OptionMenu::run(const Menu::Context & context){
// Do our new menu
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionReturn::OptionReturn(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "return"){
throw LoadException(__FILE__, __LINE__, "Not a return option");
}
readName(token);
}
void OptionReturn::logic(){
}
/* maybe this option is misnamed, but its supposed to quit the current game
* and go back to the main menu
*/
void OptionReturn::run(const Menu::Context & context){
throw Exception::Quit(__FILE__, __LINE__);
}
OptionReturn::~OptionReturn(){
}
OptionContinue::OptionContinue(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "continue"){
throw LoadException(__FILE__, __LINE__, "Not a continue option");
}
readName(token);
}
void OptionContinue::logic(){
}
void OptionContinue::run(const Menu::Context & context){
throw Exception::Return(__FILE__, __LINE__);
}
OptionContinue::~OptionContinue(){
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "quit" ){
throw LoadException(__FILE__, __LINE__, "Not quit option");
}
readName(token);
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to quit");
}
this->setText(name);
}
OptionQuit::~OptionQuit(){
}
void OptionQuit::logic(){
}
void OptionQuit::run(const Menu::Context & context){
throw ShutdownException();
}
#if defined(WINDOWS) && defined(doesnt_work_yet)
#include <windows.h>
#include <stdio.h>
/* contributed by Roy Underthump from allegro.cc */
static vector<ScreenSize> getScreenResolutions(){
HWND hwnd;
HDC hdc;
// int iPixelFormat;
int descerr;
int retval;
DEVMODE d;
PIXELFORMATDESCRIPTOR pfd;
hwnd = GetDesktopWindow();
hdc = GetDC(hwnd);
vector<ScreenSize> modes;
for (int i = 0;; i++){
retval = EnumDisplaySettings(0,i,&d);
if (!retval){
break;
}
descerr = DescribePixelFormat(hdc, i+1, sizeof(pfd), &pfd);
if(!descerr){
continue;
}
/*
printf("\n#%d bpp %d width %d height %d colorbits %d fps %d",i,d.dmBitsPerPel,
d.dmPelsWidth, d.dmPelsHeight,pfd.cColorBits,d.dmDisplayFrequency);
if(pfd.dwFlags & PFD_SUPPORT_OPENGL)printf(" OGL OK");
*/
modes.push_back(ScreenSize(d.dmPelsWidth, d.dmPelsHeight));
}
if (modes.empty()){
modes.push_back(ScreenSize(640,480));
}
return modes;
}
#else
static vector<ScreenSize> getScreenResolutions(){
vector<ScreenSize> modes;
modes.push_back(ScreenSize(320, 240));
modes.push_back(ScreenSize(640, 480));
modes.push_back(ScreenSize(800, 600));
modes.push_back(ScreenSize(960, 720));
modes.push_back(ScreenSize(1024, 768));
modes.push_back(ScreenSize(1280, 960));
modes.push_back(ScreenSize(1600, 1200));
return modes;
}
#endif
static bool doSort(const ScreenSize & a, const ScreenSize & b){
return (a.w * a.h) < (b.w * b.h);
}
static vector<ScreenSize> sortResolutions(const vector<ScreenSize> & modes){
vector<ScreenSize> copy(modes);
std::sort(copy.begin(), copy.end(), doSort);
return copy;
}
OptionScreenSize::OptionScreenSize(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
Global::debug(1) << "Get screen resolution" << endl;
modes = sortResolutions(getScreenResolutions());
if (Global::getDebug() >= 1){
for (vector<ScreenSize>::iterator it = modes.begin(); it != modes.end(); it++){
Global::debug(1) << "Screen size: " << it->w << " x " << it->h << endl;
}
}
if ( *token != "screen-size" ){
throw LoadException(__FILE__, __LINE__, "Not a screen-size");
}
readName(token);
}
OptionScreenSize::~OptionScreenSize(){
// Nothing
}
void OptionScreenSize::logic(){
ostringstream temp;
temp << "Screen size: " << Configuration::getScreenWidth() << " x " << Configuration::getScreenHeight();
setText(temp.str());
}
void OptionScreenSize::run(const Menu::Context & context){
}
void OptionScreenSize::setMode(int width, int height){
if (width != Configuration::getScreenWidth() ||
height != Configuration::getScreenHeight()){
Global::debug(1) << "Changing mode to " << width << " x " << height << endl;
int gfx = Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED;
int ok = Graphics::changeGraphicsMode(gfx, width, height);
if (ok == 0){
Global::debug(1) << "Success" << endl;
Configuration::setScreenWidth(width);
Configuration::setScreenHeight(height);
} else {
Global::debug(1) << "Fail" << endl;
int ok = Graphics::changeGraphicsMode(gfx, Configuration::getScreenWidth(), Configuration::getScreenHeight());
Global::debug(1) << "Set mode back " << ok << endl;
}
}
}
/*
static int modes[][2] = {{640,480}, {800,600}, {1024,768}, {1280,1024}, {1600,1200}};
// static int max_modes = sizeof(modes) / sizeof(int[]);
static int max_modes = 5;
*/
int OptionScreenSize::findMode(int width, int height){
for (int mode = 0; mode < (int) modes.size(); mode++){
if (modes[mode].w == width && modes[mode].h == height){
return mode;
}
}
return -1;
}
bool OptionScreenSize::leftKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 1 && mode < (int)modes.size()){
mode -= 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
lblue = lgreen = 0;
return true;
}
bool OptionScreenSize::rightKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 0 && mode < (int)modes.size() - 1){
mode += 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
rblue = rgreen = 0;
return true;
}
static string joinPaths(const vector<Filesystem::AbsolutePath> & strings, const string & middle){
ostringstream out;
for (vector<Filesystem::AbsolutePath>::const_iterator it = strings.begin(); it != strings.end(); it++){
out << (*it).path() << middle;
}
return out.str();
}
static bool sortInfo(const Util::ReferenceCount<Menu::FontInfo> & info1,
const Util::ReferenceCount<Menu::FontInfo> & info2){
string name1 = Util::lowerCaseAll(info1->getName());
string name2 = Util::lowerCaseAll(info2->getName());
return name1 < name2;
}
static bool isWindows(){
#ifdef WINDOWS
return true;
#else
return false;
#endif
}
static bool isOSX(){
#ifdef MACOSX
return true;
#else
return false;
#endif
}
template <class X>
static vector<X> operator+(const vector<X> & v1, const vector<X> & v2){
vector<X> out;
for (typename vector<X>::const_iterator it = v1.begin(); it != v1.end(); it++){
out.push_back(*it);
}
for (typename vector<X>::const_iterator it = v2.begin(); it != v2.end(); it++){
out.push_back(*it);
}
return out;
}
static vector<Filesystem::AbsolutePath> findSystemFonts(){
if (isWindows()){
const char * windows = getenv("windir");
if (windows != NULL){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath(string(windows) + "/fonts"), "*.ttf");
}
return vector<Filesystem::AbsolutePath>();
} else if (isOSX()){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/Library/Fonts"), "*.ttf");
} else {
/* assume unix/linux conventions */
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/share/fonts/truetype"), "*.ttf") +
Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/local/share/fonts/truetype"), "*.ttf");
}
}
static vector<Util::ReferenceCount<Menu::FontInfo> > findFonts(){
vector<Util::ReferenceCount<Menu::FontInfo> > fonts;
try{
Filesystem::AbsolutePath fontsDirectory = Storage::instance().find(Filesystem::RelativePath("fonts"));
Global::debug(1, "fonts") << "Font directory " << fontsDirectory.path() << endl;
vector<Filesystem::AbsolutePath> ttfFonts = Storage::instance().getFiles(fontsDirectory, "*.ttf");
Global::debug(1, "fonts") << "Found ttf fonts " << joinPaths(ttfFonts, ", ") << endl;
vector<Filesystem::AbsolutePath> otfFonts = Storage::instance().getFiles(fontsDirectory, "*.otf");
Global::debug(1, "fonts") << "Found otf fonts " << joinPaths(otfFonts, ", ") << endl;
for (vector<Filesystem::AbsolutePath>::iterator it = ttfFonts.begin(); it != ttfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
for (vector<Filesystem::AbsolutePath>::iterator it = otfFonts.begin(); it != otfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
/* linux specific fonts */
vector<Filesystem::AbsolutePath> systemFonts = findSystemFonts();
for (vector<Filesystem::AbsolutePath>::iterator it = systemFonts.begin(); it != systemFonts.end(); it++){
Global::debug(1) << "Adding system font `" << (*it).path() << "'" << endl;
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::AbsoluteFontInfo(*it, Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
sort(fonts.begin(), fonts.end(), sortInfo);
// DEFAULT (blank)
// fonts.insert(fonts.begin(), new Menu::DefaultFontInfo());
fonts.insert(fonts.begin(), Util::ReferenceCount<Menu::FontInfo>(NULL));
} catch (const Filesystem::NotFound & e){
throw LoadException(__FILE__, __LINE__, e, "Could not load font");
}
return fonts;
}
OptionSelectFont::OptionSelectFont(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
typeAdjust(fontName),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "font-select" ){
throw LoadException(__FILE__, __LINE__, "Not a font selector");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "adjust" ){
std::string temp;
tok->view() >> temp;
if ( temp == "name" ) typeAdjust = fontName;
else if ( temp == "width" ) typeAdjust = fontWidth;
else if ( temp == "height" ) typeAdjust = fontHeight;
else throw LoadException(__FILE__, __LINE__, "Incorrect value \"" + temp + "\" in font-select");
} else {
Global::debug(3) << "Unhandled menu attribute: " << endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
}
void OptionSelectFont::open(){
// Find and set fonts now
if (typeAdjust == fontName){
fonts = findFonts();
}
}
void OptionSelectFont::close(){
if (typeAdjust == fontName){
/* the user probably loaded a bunch of different fonts that will
* never be used again, so clear the font cache
* TODO: dont clear the currently selected font
*/
FontFactory::clear();
}
}
OptionSelectFont::~OptionSelectFont(){
// Nothing
}
void OptionSelectFont::logic(){
/* FIXME Get current font and display info */
switch (typeAdjust){
case fontName:{
std::string name;
if (Configuration::hasMenuFont()){
name = Configuration::getMenuFont()->getName();
} else {
name = "Default";
}
setText("Current Font: " + name);
break;
}
case fontWidth:{
ostringstream temp;
temp << "Font Width: " << Configuration::getMenuFontWidth();
setText(temp.str());
break;
}
case fontHeight:{
ostringstream temp;
temp << "Font Height: " << Configuration::getMenuFontHeight();
setText(temp.str());
break;
}
default: break;
}
if (lblue < 255){
lblue += 5;
}
if (rblue < 255){
rblue += 5;
}
if (lgreen < 255){
lgreen += 5;
}
if (rgreen < 255){
rgreen += 5;
}
}
void OptionSelectFont::run(const Menu::Context & context){
// throw Menu::MenuException(__FILE__, __LINE__);
/* throw something to quit back to the previous menu */
}
bool OptionSelectFont::leftKey(){
switch (typeAdjust){
case fontName:
nextIndex(false);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() - 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() - 1);
break;
default:
break;
}
lblue = lgreen = 0;
return true;
}
bool OptionSelectFont::rightKey(){
switch (typeAdjust){
case fontName:
nextIndex(true);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() + 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() + 1);
break;
default:
break;
}
rblue = rgreen = 0;
return true;
}
static bool saneFont(const Util::ReferenceCount<Menu::FontInfo> & info){
class Context: public Loader::LoadingContext {
public:
Context(const Util::ReferenceCount<Menu::FontInfo> & info):
info(info),
isok(false){
}
bool ok(){
try{
const Font & font = info->get();
return font.textLength("A") != 0 &&
font.getHeight() != 0;
} catch (const Exception::Base & ignore){
return true;
}
}
virtual void load(){
isok = ok();
}
const Util::ReferenceCount<Menu::FontInfo> & info;
bool isok;
};
if (info == NULL){
return true;
}
Context context(info);
/* an empty Info object, we don't really care about it */
Loader::Info level("Loading Font", Filesystem::AbsolutePath());
Loader::loadScreen(context, level, Loader::SimpleCircle);
return context.isok;
}
void OptionSelectFont::nextIndex(bool forward){
if (fonts.size() == 0){
return;
}
int index = 0;
for (unsigned int i = 0 ; i < fonts.size() ; ++i){
if ((Configuration::getMenuFont() == NULL && fonts[i] == NULL) ||
((Configuration::getMenuFont() != NULL && fonts[i] != NULL) &&
(*Configuration::getMenuFont() == *fonts[i]))){
index = i;
}
}
if (forward){
index++;
if (index >= (int) fonts.size()){
index = 0;
}
} else {
index--;
if (index < 0){
index = (int)fonts.size()-1;
}
}
while (!saneFont(fonts[index])){
Global::debug(0) << "Warning: erasing font `" << fonts[index]->getName() << "'" << endl;
int where = 0;
vector<Util::ReferenceCount<Menu::FontInfo> >::iterator it;
for (it = fonts.begin(); it != fonts.end() && where != index; it++, where++){
}
fonts.erase(it);
if (index >= (int) fonts.size()){
index = fonts.size() - 1;
}
}
Configuration::setMenuFont(fonts[index]);
/* FIXME */
/*
if (fonts[index] == "Default"){
Configuration::setMenuFont("");
} else {
Configuration::setMenuFont(fonts[index]);
}
*/
}
OptionSpeed::OptionSpeed(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "speed" )
throw LoadException(__FILE__, __LINE__, "Not speed option");
readName(token);
}
OptionSpeed::~OptionSpeed(){
// Nothing
}
std::string OptionSpeed::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getGameSpeed();
return out.str();
}
void OptionSpeed::logic(){
/*
//ostringstream temp;
char temp[255];
sprintf( temp, "%s: %0.2f", name.c_str(), MenuGlobals::getGameSpeed() );
setText(std::string(temp));
*/
}
void OptionSpeed::run(const Menu::Context & context){
}
bool OptionSpeed::leftKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() - 0.05);
if (Configuration::getGameSpeed() < 0.1){
Configuration::setGameSpeed(0.1);
}
return false;
}
bool OptionSpeed::rightKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() + 0.05);
rblue = rgreen = 0;
return false;
}
OptionTabMenu::OptionTabMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory, Menu::Renderer::Tabbed);
} else {
menu = new Menu::Menu(token, factory, Menu::Renderer::Tabbed);
}
// this->setText(menu->getName());
// token->print("Menu: ");
const Token * tok = token->findToken("_/name");
if (tok != NULL){
std::string name;
tok->view() >> name;
// Global::debug(0, "menu") << "Menu name: " << name << endl;
this->setText(name);
} else {
// No name?
throw LoadException(__FILE__, __LINE__, "Menu has no name");
}
}
OptionTabMenu::~OptionTabMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionTabMenu::logic(){
// Nothing
}
void OptionTabMenu::run(const Menu::Context & context){
// Do our new menu
// menu->run(context);
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionSound::OptionSound(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "sound" ){
throw LoadException(__FILE__, __LINE__, "Not a sound option");
}
readName(token);
originalName = getName();
}
OptionSound::~OptionSound(){
}
void OptionSound::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getSoundVolume();
setText(temp.str());
}
void OptionSound::run(const Menu::Context & context){
}
void OptionSound::changeSound(int much){
int volume = Configuration::getSoundVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setSoundVolume(volume);
}
bool OptionSound::leftKey(){
changeSound(-1);
lblue = lgreen = 0;
return true;
}
bool OptionSound::rightKey(){
changeSound(+1);
rblue = rgreen = 0;
return true;
}
OptionMusic::OptionMusic(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "music" ){
throw LoadException(__FILE__, __LINE__, "Not a music option");
}
readName(token);
originalName = getName();
}
void OptionMusic::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getMusicVolume();
setText(temp.str());
}
void OptionMusic::run(const Menu::Context & context){
}
void OptionMusic::changeMusic(int much){
int volume = Configuration::getMusicVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setMusicVolume(volume);
Music::setVolume((double) volume / 100.0);
}
bool OptionMusic::leftKey(){
changeMusic(-1);
lblue = lgreen = 0;
return true;
}
bool OptionMusic::rightKey(){
changeMusic(+1);
lblue = lgreen = 0;
return true;
}
OptionMusic::~OptionMusic(){
}
OptionLanguage::OptionLanguage(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
#if 0
const Token * start = token->getRootParent();
vector<const Token*> tokens = start->findTokens("*/language");
vector<string> all;
for (vector<const Token*>::iterator it = tokens.begin(); it != tokens.end(); it++){
string language;
const Token * token = *it;
if (token->match("language", language)){
all.push_back(language);
}
}
sort(all.begin(), all.end());
unique_copy(all.begin(), all.end(), back_insert_iterator<vector<string> >(languages));
// Global::debug(0) << "Found " << languages.size() << " languages" << endl;
#endif
}
void OptionLanguage::run(const Menu::Context & context){
class LanguageOption: public MenuOption {
public:
LanguageOption(const Gui::ContextBox & parent, const string & language):
MenuOption(parent, NULL){
setText(language);
setInfoText(language);
}
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
Configuration::setLanguage(getText());
Configuration::saveConfiguration();
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
Util::NewReferenceCount<Menu::DefaultRenderer> renderer;
Menu::Menu temp(renderer);
Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Font::getDefaultFontPath(), 24, 24));
temp.setFont(info);
const Gui::ContextBox & box = renderer->getBox();
vector<string> languages = context.getLanguages();
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
temp.addOption(new LanguageOption(box, *it));
}
try {
temp.run(context);
} catch (const Exception::Return & ignore){
} catch (const Menu::MenuException & ex){
}
throw Menu::Reload(__FILE__, __LINE__);
// throw Exception::Return(__FILE__, __LINE__);
}
void OptionLanguage::logic(){
}
OptionJoystick::OptionJoystick(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
setRunnable(true);
if (*token != "joystick" ){
throw LoadException(__FILE__, __LINE__, "Not a joystick option");
}
readName(token);
}
void OptionJoystick::logic(){
}
class JoystickLogicDraw: public Util::Logic, public Util::Draw {
public:
enum Inputs{
Exit
};
static const int marginX = 20;
JoystickLogicDraw(int id, const Util::ReferenceCount<Joystick> & joystick, const ::Menu::Context & context):
id(id),
joystick(joystick),
quit(false),
context(context, Menu::Context()){
input.set(Keyboard::Key_ESC, Exit);
}
const int id;
Util::ReferenceCount<Joystick> joystick;
bool quit;
Menu::Context context;
InputMap<Inputs> input;
void doInput(){
vector<InputMap<Inputs>::InputEvent> out = InputManager::getEvents(input, InputSource(true));
for (vector<InputMap<Inputs>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<Inputs>::InputEvent & event = *it;
if (event.enabled){
if (event.out == Exit){
quit = true;
// context.finish();
}
}
}
}
virtual void run(){
doInput();
context.act();
}
bool done(){
return quit;
}
double ticks(double system){
return system * Global::ticksPerSecond(60);
}
void drawButtons(const Font & font, const Graphics::Bitmap & buffer, int y){
Graphics::Color color = Graphics::makeColor(255, 255, 255);
font.printf(marginX, y, color, buffer, "Up: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Down: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Left: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Right: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button1: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button2: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button3: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button4: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button5: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Button6: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Select: ", 0); y += font.getHeight() + 5;
font.printf(marginX, y, color, buffer, "Quit: ", 0); y += font.getHeight() + 5;
}
void draw(const Graphics::Bitmap & buffer){
const Font & font = Menu::menuFontParameter.current()->get();
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::StretchedBitmap::NoClear, Graphics::qualityFilterName(Configuration::getQualityFilter()));
work.start();
context.renderBackground(work);
/* FIXME: scale the joystck name down to fit */
font.printf(marginX, 1, Graphics::makeColor(255, 255, 255), work, "Joystick %d: %s", 0, id, joystick->getName().c_str());
drawButtons(font, work, 1 + font.getHeight() + 5);
context.renderForeground(work);
work.finish();
}
};
namespace{
struct Axis{
Axis():
stick(0),
axis(0),
first(0),
set(false),
last(0),
lastMotion(0){
}
int stick;
int axis;
/* first value from this axis. we assume that
* the first value is sufficiently close to 'zero' which
* can be any value, but most likely will either be
* -1, 0, or 1
*/
double first;
/* true if first has been set */
bool set;
/* keep track of last value for this axis */
double last;
/* last time an event was produced (or at least last
* time we read it). it might be better to get the actual
* time from the event itself.
*/
uint64_t lastMotion;
};
}
static void runJoystickMenu(int joystickId, const Util::ReferenceCount<Joystick> & joystick, const ::Menu::Context & context){
Util::NewReferenceCount<Menu::DefaultRenderer> renderer;
Menu::Menu menu(renderer);
Gui::ContextBox & box = renderer->getBox();
box.setListType(ContextBox::Normal);
Gui::ListValues attributes(box.getListValues());
attributes.setDistanceFade(false);
box.setListValues(attributes);
menu.setPosition(Gui::Coordinate(Gui::RelativePoint(-0.8, -0.3),
Gui::RelativePoint(0, 0.8)));
#define WAIT_TIME_MS (0.7 * 1000)
#define WAIT_TIME_AXIS_MS (1 * 1000)
#define AXIS_THRESHOLD 0.7
class JoystickButton: public MenuOption {
public:
JoystickButton(const Menu::Menu & menu, const Gui::ContextBox & parent, const Util::ReferenceCount<Joystick> & joystick, const string & name, Joystick::Key key):
MenuOption(parent, NULL),
menu(menu),
name(name),
joystick(joystick),
key(key){
setText(name);
setInfoText(name);
}
const Menu::Menu & menu;
string name;
Util::ReferenceCount<Joystick> joystick;
Joystick::Key key;
class ButtonListener: public JoystickListener {
public:
ButtonListener(const Util::ReferenceCount<Joystick> & joystick):
touched(false),
done(false),
chosen(-1),
chosenAxis(NULL){
map<int, map<int, double> > axisValues = joystick->getCurrentAxisValues();
for (map<int, map<int, double> >::iterator it = axisValues.begin(); it != axisValues.end(); it++){
int stick = it->first;
const map<int, double> & subMap = it->second;
for (map<int, double>::const_iterator it = subMap.begin(); it != subMap.end(); it++){
int axis = it->first;
double value = it->second;
Axis use;
use.stick = stick;
use.axis = axis;
use.first = value;
use.set = true;
use.last = value;
use.lastMotion = 0;
this->axis.push_back(use);
}
}
}
map<int, uint64_t> presses;
map<int, bool> pressed;
/* true if a button/axis is moved. flips to false when queried */
bool touched;
vector<Axis> axis;
bool done;
int chosen;
Axis * chosenAxis;
bool wasTouched(){
bool out = touched;
touched = false;
return out;
}
Axis & getAxis(int stick, int axis){
for (vector<Axis>::iterator it = this->axis.begin(); it != this->axis.end(); it++){
Axis & use = *it;
if (use.stick == stick && use.axis == axis){
return use;
}
}
Axis out;
out.stick = stick;
out.axis = axis;
this->axis.push_back(out);
return getAxis(stick, axis);
}
const vector<Axis> & getAllAxis() const {
return axis;
}
const map<int, uint64_t> & getPresses() const {
return presses;
}
int getButton() const {
return chosen;
}
Axis * getChosenAxis() const {
return chosenAxis;
}
virtual ~ButtonListener(){
}
bool isDone() const {
return (getButton() != -1 && !anyPressed()) ||
(getChosenAxis() != NULL);
}
void choose(){
uint64_t now = System::currentMilliseconds();
for (map<int, uint64_t>::const_iterator it = presses.begin(); it != presses.end(); it++){
uint64_t what = it->second;
if (what != 0 && now - what > WAIT_TIME_MS){
chosen = it->first;
}
}
for (vector<Axis>::iterator it = axis.begin(); it != axis.end(); it++){
Axis & use = *it;
if (fabs(use.last - use.first) > AXIS_THRESHOLD &&
now - use.lastMotion > WAIT_TIME_AXIS_MS){
chosenAxis = &use;
}
}
}
bool anyPressed() const {
for (map<int, bool>::const_iterator it = pressed.begin(); it != pressed.end(); it++){
if (it->second){
return true;
}
}
return false;
}
virtual void pressButton(Joystick * from, int button){
touched = true;
pressed[button] = true;
presses[button] = System::currentMilliseconds();
}
virtual void releaseButton(Joystick * from, int button){
presses[button] = 0;
pressed[button] = false;
}
/* either all increasing or all decreasing */
bool monotonic(const vector<double> & what){
if (what.size() == 0){
return true;
}
double first = what[0];
int direction = -1;
vector<double>::const_iterator it = what.begin();
it++;
for (/**/; it != what.end(); it++){
switch (direction){
case -1: {
if (*it < first){
direction = 1;
} else if (*it > first){
direction = 2;
}
first = *it;
break;
}
case 1: {
if (*it > first){
return false;
}
break;
}
case 2: {
if (*it < first){
return false;
}
break;
}
}
}
return true;
}
virtual void axisMotion(Joystick * from, int stick, int axis, double motion){
touched = true;
Axis & use = getAxis(stick, axis);
if (!use.set){
use.first = motion;
use.set = true;
}
use.last = motion;
use.lastMotion = System::currentMilliseconds();
/*
const double AXIS_THRESHOLD = 0.5;
Global::debug(0) << "stick " << stick << " axis " << axis << " first " << use.first << " last " << use.last << " diff " << fabs(use.last - use.first) << std::endl;
if (fabs(use.last - use.first) > AXIS_THRESHOLD){
Global::debug(0) << "stick " << stick << " axis " << axis << " motion " << motion << std::endl;
}
*/
}
virtual void hatMotion(Joystick * from, int motion){
}
};
void logic(){
ostringstream out;
int stick, axis;
double low, high;
if (joystick->getAxis(key, stick, axis, low, high)){
out << name << ": " << stick << "/" << axis << "/";
if (low < 0){
out << "-";
} else {
out << "+";
}
} else {
int button = joystick->getButton(key);
out << name << ": ";
if (button != -1){
out << joystick->getButton(key);
} else {
out << "unset";
}
}
setText(out.str());
}
void run(const Menu::Context & context){
class SetButton: public Util::Logic, public Util::Draw {
public:
SetButton(const Menu::Context & context, const Menu::Menu & menu, const string & name, const Util::ReferenceCount<Joystick> & joystick):
context(context),
menu(menu),
name(name),
listener(joystick),
joystick(joystick),
startingTime(System::currentMilliseconds()),
maxTime(5000){
input.set(Keyboard::Key_ESC, 0);
joystick->addListener(&listener);
vector<Graphics::BlendPoint> points;
points.push_back(Graphics::BlendPoint(Graphics::makeColor(255, 0, 0), 30));
points.push_back(Graphics::BlendPoint(Graphics::makeColor(0, 255, 0), 25));
points.push_back(Graphics::BlendPoint(Graphics::makeColor(255, 255, 255), 0));
colors = Graphics::blend_palette(points);
}
const Menu::Context & context;
const Menu::Menu & menu;
string name;
ButtonListener listener;
InputMap<int> input;
Util::ReferenceCount<Joystick> joystick;
vector<Graphics::Color> colors;
uint64_t startingTime;
const uint64_t maxTime;
virtual ~SetButton(){
joystick->removeListener(&listener);
}
virtual void showTimeLeft(const Graphics::Bitmap & screen){
int x1 = 1;
int y1 = 1;
int x2 = screen.getWidth() * (1 - (double) (System::currentMilliseconds() - startingTime) / (double) maxTime);
if (x2 < x1){
x2 = x1;
}
int y2 = 10;
int color = (1.0 - (double) (System::currentMilliseconds() - startingTime) / maxTime) * colors.size();
if (color < 0){
color = 0;
}
if (color >= colors.size()){
color = colors.size() - 1;
}
screen.rectangleFill(x1, y1, x2, y2, colors[color]);
}
void setButton(Joystick::Key key){
int button = listener.getButton();
if (button != -1){
Global::debug(1) << "Chosen button " << listener.getButton() << std::endl;
joystick->setCustomButton(listener.getButton(), key);
} else {
Axis * axis = listener.getChosenAxis();
double rangeLow = 0;
double rangeHigh = 0;
/* stick went negative and went to -1 */
if (axis->first <= 0 && axis->last < axis->first){
rangeLow = -1;
rangeHigh = -AXIS_THRESHOLD;
/* stick started at negative and went positive, possibly
* not above 0.
*/
} else if (axis->first < 0 && axis->last > axis->first){
rangeLow = 0;
rangeHigh = 1;
/* stick started positive and went to 1 */
} else if (axis->first >= 0 && axis->last > axis->first){
rangeLow = AXIS_THRESHOLD;
rangeHigh = 1;
/* stick started positive and went towards -1 */
} else if (axis->first > 0 && axis->last < axis->first){
rangeLow = -1;
rangeHigh = 0;
}
Global::debug(0) << "Set stick " << axis->stick << " axis " << axis->axis << " [" << rangeLow << ", " << rangeHigh << "]" << std::endl;
joystick->setCustomAxis(key, axis->stick, axis->axis, rangeLow, rangeHigh);
}
}
double ticks(double system){
return system * Global::ticksPerSecond(60);
}
bool done(){
return listener.isDone();
}
void run(){
vector<InputMap<int>::InputEvent> out = InputManager::getEvents(input, InputSource(true));
for (vector<InputMap<int>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<int>::InputEvent & event = *it;
if (event.enabled){
if (event.out == 0){
throw Exception::Return(__FILE__, __LINE__);
}
}
}
listener.choose();
if (listener.wasTouched()){
startingTime = System::currentMilliseconds();
}
if (System::currentMilliseconds() - startingTime >= maxTime){
throw Exception::Return(__FILE__, __LINE__);
}
}
void draw(const Graphics::Bitmap & buffer){
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::StretchedBitmap::NoClear, Graphics::qualityFilterName(Configuration::getQualityFilter()));
work.start();
menu.render(context, work);
const Font & font = Menu::menuFontParameter.current()->get();
Gui::RelativePoint start(0.2, -0.3);
Gui::RelativePoint end(0.85, 0.8);
int x = start.getX();
int y = start.getY();
// font.printfWrap(x, y - font.getHeight() * 2 - 5, Graphics::makeColor(255, 255, 255), work, end.getX() - start.getX(), "Press and hold a button", 0);
font.printf(x, y - 18 - 5, 18, 18, Graphics::makeColor(255, 255, 255), work, "Press and hold a button", 0);
work.translucent(0, 0, 0, 128).rectangleFill(x, y, end.getX(), end.getY(), Graphics::makeColor(0, 0, 0));
uint64_t now = System::currentMilliseconds();
const map<int, uint64_t> & presses = listener.getPresses();
for (map<int, uint64_t>::const_iterator it = presses.begin(); it != presses.end(); it++){
int button = it->first;
uint64_t time = it->second;
if (time > 0){
int delta = now - time;
if (delta > WAIT_TIME_MS){
delta = WAIT_TIME_MS;
}
/* this shouldn't happen... */
if (delta < 0){
delta = 0;
}
Graphics::Color color;
color = Graphics::makeColor((int)(255.0 * (double) delta / (WAIT_TIME_MS)),
0, 255);
if (button == listener.getButton()){
color = Graphics::makeColor(255, 255, 255);
}
ostringstream text;
text << name << ": " << button;
font.printf(x, y, color, work, text.str(), 0);
y += font.getHeight() + 5;
}
}
const vector<Axis> & axis = listener.getAllAxis();
for (vector<Axis>::const_iterator it = axis.begin(); it != axis.end(); it++){
const Axis & use = *it;
if (fabs(use.last - use.first) > AXIS_THRESHOLD){
int delta = now - use.lastMotion;
if (delta > WAIT_TIME_AXIS_MS){
delta = WAIT_TIME_AXIS_MS;
}
/* this shouldn't happen... */
if (delta < 0){
delta = 0;
}
Graphics::Color color;
color = Graphics::makeColor((int)(255.0 * (double) delta / (WAIT_TIME_AXIS_MS)),
0, 255);
if (&use == listener.getChosenAxis()){
color = Graphics::makeColor(255, 255, 255);
}
ostringstream text;
text << name << ": stick " << use.stick << " axis " << use.axis;
if (use.last > use.first){
text << " +";
} else {
text << " -";
}
font.printf(x, y, 18, 18, color, work, text.str(), 0);
y += font.getHeight() + 5;
}
}
showTimeLeft(work);
work.finish();
}
void wait(){
while (listener.anyPressed()){
InputManager::poll();
Util::rest(1);
}
}
};
Global::debug(1) << "Set button " << getName() << std::endl;
SetButton set(context, menu, name, joystick);
try{
Util::standardLoop(set, set);
set.setButton(key);
} catch (const Exception::Return & quit){
}
set.wait();
}
};
menu.addOption(new JoystickButton(menu, box, joystick, "Up", Joystick::Up));
menu.addOption(new JoystickButton(menu, box, joystick, "Down", Joystick::Down));
menu.addOption(new JoystickButton(menu, box, joystick, "Left", Joystick::Left));
menu.addOption(new JoystickButton(menu, box, joystick, "Right", Joystick::Right));
menu.addOption(new JoystickButton(menu, box, joystick, "Button1", Joystick::Button1));
menu.addOption(new JoystickButton(menu, box, joystick, "Button2", Joystick::Button2));
menu.addOption(new JoystickButton(menu, box, joystick, "Button3", Joystick::Button3));
menu.addOption(new JoystickButton(menu, box, joystick, "Button4", Joystick::Button4));
menu.addOption(new JoystickButton(menu, box, joystick, "Button5", Joystick::Button5));
menu.addOption(new JoystickButton(menu, box, joystick, "Button6", Joystick::Button6));
menu.addOption(new JoystickButton(menu, box, joystick, "Start", Joystick::Start));
menu.addOption(new JoystickButton(menu, box, joystick, "Quit", Joystick::Quit));
try {
menu.run(context);
} catch (const Exception::Return & ignore){
} catch (const Menu::MenuException & ex){
}
}
void OptionJoystick::run(const Menu::Context & context){
class JoystickOption: public MenuOption {
public:
JoystickOption(const Gui::ContextBox & parent, int id, const Util::ReferenceCount<Joystick> & joystick):
MenuOption(parent, NULL),
joystick(joystick),
id(id){
ostringstream out;
out << "Joystick " << (id + 1);
setText(out.str());
setInfoText(joystick->getName());
}
const Util::ReferenceCount<Joystick> joystick;
const int id;
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
runJoystickMenu(id, joystick, context);
/*
JoystickLogicDraw mainLoop(id, joystick, context);
Util::standardLoop(mainLoop, mainLoop);
*/
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
Util::NewReferenceCount<Menu::DefaultRenderer> renderer;
Menu::Menu menu(renderer);
/*
Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Global::DEFAULT_FONT, 24, 24));
temp.setFont(info);
*/
Gui::ContextBox & box = renderer->getBox();
box.setListType(ContextBox::Normal);
map<int, Util::ReferenceCount<Joystick> > joysticks = InputManager::getJoysticks();
for (map<int, Util::ReferenceCount<Joystick> >::iterator it = joysticks.begin(); it != joysticks.end(); it++){
menu.addOption(new JoystickOption(box, it->first, it->second));
}
if (joysticks.size() == 0){
menu.addOption(new OptionDummy(box, "No joysticks found!"));
}
try {
menu.run(context);
} catch (const Exception::Return & ignore){
} catch (const Menu::MenuException & ex){
}
}
OptionJoystick::~OptionJoystick(){
}
diff --git a/src/sound/audio.cpp b/src/sound/audio.cpp
index 44263cde..e5da8e51 100644
--- a/src/sound/audio.cpp
+++ b/src/sound/audio.cpp
@@ -1,265 +1,265 @@
#include <string.h>
-#include "audio.h"
-#include "../debug.h"
+#include "r-tech1/sound/audio.h"
+#include "r-tech1/debug.h"
namespace Util{
AudioConverter::AudioConverter(Encoding inputEncoding, int inputChannels, int inputFrequency,
Encoding outputEncoding, int outputChannels, int outputFrequency):
buffer(NULL),
bufferSize(0){
input.bytes = inputEncoding;
input.channels = inputChannels;
input.frequency = inputFrequency;
output.bytes = outputEncoding;
output.channels = outputChannels;
output.frequency = outputFrequency;
sizeRatio = (double) byteSize(output) * output.frequency / ((double) byteSize(input) * input.frequency);
}
int AudioConverter::byteSize(const Format & what){
return encodingBytes(what.bytes) * what.channels;
}
/* how many bytes an encoding takes up */
int AudioConverter::encodingBytes(Encoding what){
switch (what){
case Unsigned8: return 1;
case Signed16: return 2;
case Unsigned16: return 2;
case Float32: return 4;
}
return 1;
}
unsigned int AudioConverter::convertedLength(int length){
// return length * sizeRatio;
int total = length * sizeRatio;
/* make sure we get an even number of samples */
if (total % byteSize(output) != 0){
total -= total % byteSize(output);
}
return total;
}
double CubicInterpolate(double y0, double y1,
double y2, double y3,
double mu){
double a0,a1,a2,a3,mu2;
mu2 = mu*mu;
a0 = y3 - y2 - y0 + y1;
a1 = y0 - y1 - a0;
a2 = y2 - y0;
a3 = y1;
return (a0*mu*mu2+a1*mu2+a2*mu+a3);
}
template <class Input, class Output>
Output clamp(double input){
Output top = (1 << (sizeof(Output) * 8 - 1)) - 1;
Output bottom = -(1 << (sizeof(Output) * 8 - 1));
if (input > top){
return top;
}
if (input < bottom){
return bottom;
}
return input;
}
template <>
signed short clamp<unsigned char>(double input){
return ((input - 127) / 255) * (1 << (sizeof(signed short) * 8 - 1));
}
template <>
unsigned char clamp<unsigned char>(double input){
if (input > 255){
input = 255;
}
if (input < 0){
input = 0;
}
return input;
}
template <>
float clamp<float>(double input){
if (input > 1){
input = 1;
}
if (input < -1){
input = -1;
}
return input;
}
template <>
unsigned short clamp<signed short>(double input){
return (int) clamp<signed short, signed short>(input) + (int) (1 << (sizeof(signed short) * 8 - 1));
}
template <>
float clamp<short unsigned int>(double input){
double out = input / (1 << (sizeof(unsigned short) * 8));
if (out > 1){
return 1;
}
if (out < -1){
return -1;
}
return out;
}
template <>
float clamp<unsigned char>(double input){
double out = input / (1 << (sizeof(unsigned char) * 8));
if (out > 1){
return 1;
}
if (out < -1){
return -1;
}
return out;
}
template <>
unsigned char clamp<signed short>(double input){
double out = input / (1 << (sizeof(signed short) * 8 - 1));
if (out > 1){
return 1;
}
if (out < -1){
return -1;
}
/* -1,1 -> 0,255 */
return (unsigned char)((out + 1) * 128);
}
template <>
float clamp<signed short>(double input){
double out = input / (1 << (sizeof(signed short) * 8 - 1));
if (out > 1){
return 1;
}
if (out < -1){
return -1;
}
return out;
}
template <class SizeInput, class SizeOutput>
void doConvertRate(SizeInput * input, int inputSamples, int inputChannels, SizeOutput * buffer, int outputSamples, int outputChannels, double ratio){
for (int sample = 0; sample < outputSamples; sample += 1){
double inputSample = sample / ratio;
for (int channel = 0; channel < outputChannels; channel += 1){
int inputChannel = inputChannels > channel ? channel : inputChannels - 1;
int sample0 = ((int) inputSample - 1) * inputChannels + inputChannel;
int sample1 = ((int) inputSample + 0) * inputChannels + inputChannel;
int sample2 = ((int) inputSample + 1) * inputChannels + inputChannel;
int sample3 = ((int) inputSample + 2) * inputChannels + inputChannel;
if (sample0 < 0){
sample0 = sample1;
}
if (sample2 >= inputSamples * inputChannels){
sample2 = sample1;
}
if (sample3 >= inputSamples * inputChannels){
sample3 = sample2;
}
buffer[sample * outputChannels + channel] = clamp<SizeInput, SizeOutput>(CubicInterpolate(input[sample0], input[sample1], input[sample2], input[sample3], inputSample - (int) inputSample));
// Global::debug(0) << "Input[" << sample << "] " << channel << ": " << input[sample1] << " Output: " << buffer[sample * 2 + channel] << std::endl;
}
}
}
template <class Input, class Output>
void doConvert3(void * input, int inputLength, int inputChannels,
void * output, int outputLength, int outputChannels,
double ratio){
doConvertRate<Input, Output>((Input*) input, inputLength / sizeof(Input) / inputChannels, inputChannels,
(Output*) output, outputLength / sizeof(Output) / outputChannels, outputChannels,
ratio);
}
template <class Input>
void doConvert2(void * input, int inputLength, int inputChannels,
Encoding outputType, void * output, int outputLength, int outputChannels,
double ratio){
switch (outputType){
case Unsigned8: doConvert3<Input, unsigned char>(input, inputLength, inputChannels, output, outputLength, outputChannels, ratio); break;
case Signed16: doConvert3<Input, signed short>(input, inputLength, inputChannels, output, outputLength, outputChannels, ratio); break;
case Unsigned16: doConvert3<Input, unsigned short>(input, inputLength, inputChannels, output, outputLength, outputChannels, ratio); break;
case Float32: doConvert3<Input, float>(input, inputLength, inputChannels, output, outputLength, outputChannels, ratio); break;
}
}
void doConvert1(Encoding inputType, void * input, int inputLength, int inputChannels,
Encoding outputType, void * output, int outputLength, int outputChannels, double ratio){
switch (inputType){
case Unsigned8: doConvert2<unsigned char>(input, inputLength, inputChannels, outputType, output, outputLength, outputChannels, ratio); break;
case Signed16: doConvert2<signed short>(input, inputLength, inputChannels, outputType, output, outputLength, outputChannels, ratio); break;
case Unsigned16: doConvert2<unsigned short>(input, inputLength, inputChannels, outputType, output, outputLength, outputChannels, ratio); break;
case Float32: doConvert2<float>(input, inputLength, inputChannels, outputType, output, outputLength, outputChannels, ratio); break;
}
}
int AudioConverter::convert(void * input, int length){
/* no conversion needed */
if (this->input == this->output){
return length;
}
int total = convertedLength(length);
/*
if (total % byteSize(output) != 0){
total -= total % byteSize(output);
}
*/
/* cache the buffer for future use */
if (total > bufferSize){
delete[] buffer;
bufferSize = total;
buffer = new char[bufferSize];
}
double frequencyRatio = (double) output.frequency / (double) this->input.frequency;
doConvert1(this->input.bytes, input, length, this->input.channels, output.bytes, buffer, total, output.channels, frequencyRatio);
memcpy(input, buffer, total);
return total;
}
AudioConverter::~AudioConverter(){
delete[] buffer;
}
bool AudioConverter::Format::operator==(const AudioConverter::Format & him) const {
return this->bytes == him.bytes &&
this->channels == him.channels &&
this->frequency == him.frequency;
}
}
diff --git a/src/sound/music-player.cpp b/src/sound/music-player.cpp
index b3a9d7d6..d502ad7f 100644
--- a/src/sound/music-player.cpp
+++ b/src/sound/music-player.cpp
@@ -1,1363 +1,1363 @@
-#include "music-renderer.h"
-#include "music-player.h"
-#include "util/debug.h"
+#include "r-tech1/sound/music-renderer.h"
+#include "r-tech1/sound/music-player.h"
+#include "r-tech1/debug.h"
#include <iostream>
-#include "util/configuration.h"
-#include "sound.h"
-#include "music-exception.h"
-#include "../timedifference.h"
-#include "dumb/include/dumb.h"
-#include "gme/Music_Emu.h"
-#include "../exceptions/exception.h"
-#include "../file-system.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/sound/sound.h"
+#include "r-tech1/sound/music-exception.h"
+#include "r-tech1/timedifference.h"
+#include "../libs/dumb/include/dumb.h"
+#include "../libs/gme/Music_Emu.h"
+#include "r-tech1/exceptions/exception.h"
+#include "r-tech1/file-system.h"
#include <sstream>
#include <stdio.h>
#ifdef HAVE_MP3_MPG123
#include <mpg123.h>
#endif
#ifdef HAVE_MP3_MAD
#include <mad.h>
#endif
using std::string;
namespace Util{
static double scaleVolume(double start){
return start;
}
/* 1 for big endian (most significant byte)
* 0 for little endian (least significant byte)
*/
/* FIXME: move this to global or something and find a better #ifdef */
int bigEndian(){
#if defined(PS3) || defined(WII)
return 1;
#else
return 0;
#endif
}
MusicPlayer::MusicPlayer():
volume(1.0),
out(new MusicRenderer()){
}
MusicPlayer::~MusicPlayer(){
}
void MusicPlayer::setRenderer(const ReferenceCount<MusicRenderer> & what){
this->out = what;
}
void MusicPlayer::play(){
out->play(*this);
}
void MusicPlayer::pause(){
out->pause();
}
void MusicPlayer::poll(){
out->poll(*this);
}
static const char * typeToExtension( int i ){
switch (i){
case 0 : return ".xm";
case 1 : return ".s3m";
case 2 : return ".it";
case 3 : return ".mod";
default : return "";
}
}
DumbPlayer::DumbSystem::DumbSystem(){
}
DumbPlayer::DumbSystem::~DumbSystem(){
}
/* FIXME: Some code duplication between StreamingSystem and MemorySystem */
namespace DumbSystems{
class StreamingSystem: public DumbPlayer::DumbSystem {
public:
StreamingSystem(const Util::ReferenceCount<Storage::File> & file):
file(file),
dumb(NULL){
system.open = NULL;
system.skip = skip;
system.getc = getc;
system.getnc = getnc;
system.close = close;
}
int doSkip(long n){
file->seek(n, SEEK_CUR);
return 0;
}
static int skip(void *f, long n){
StreamingSystem * self = (StreamingSystem*) f;
return self->doSkip(n);
}
int doGetc(){
unsigned char x = 0;
file->readLine((char*) &x, 1);
return x;
}
static int getc(void *f){
StreamingSystem * self = (StreamingSystem*) f;
return self->doGetc();
}
int doGetnc(unsigned char * ptr, long n){
return file->readLine((char*) ptr, n);
}
static long getnc(unsigned char *ptr, long n, void *f){
StreamingSystem * self = (StreamingSystem*) f;
return self->doGetnc(ptr, n);
}
void doClose(){
}
static void close(void *f){
StreamingSystem * self = (StreamingSystem*) f;
return self->doClose();
}
void closeDumb(){
if (dumb != NULL){
dumbfile_close(dumb);
dumb = NULL;
}
}
void reset(){
file->reset();
file->seek(0, SEEK_SET);
}
DUH * load(DUH * (*reader)(DUMBFILE *)){
closeDumb();
reset();
dumb = dumbfile_open_ex(this, &system);
return reader(dumb);
}
virtual ~StreamingSystem(){
closeDumb();
}
/* Keep a reference so the file doesn't close */
Util::ReferenceCount<Storage::File> file;
DUMBFILE_SYSTEM system;
DUMBFILE * dumb;
DUH * loadDumbFile(){
DUH * what = NULL;
for (int i = 0; i < 4; i++){
/* the order of trying xm/s3m/it/mod matters because mod could be
* confused with one of the other formats, so load it last.
*/
switch (i){
case 0: {
what = load(dumb_read_xm_quick);
break;
}
case 1: {
what = load(dumb_read_s3m_quick);
break;
}
case 2: {
what = load(dumb_read_it_quick);
break;
}
case 3: {
what = load(dumb_read_mod_quick);
break;
}
}
if (what != NULL){
return what;
}
}
return NULL;
}
};
class MemorySystem: public DumbPlayer::DumbSystem {
public:
MemorySystem(const Util::ReferenceCount<Storage::File> & file):
memory(NULL),
position(0),
dumb(NULL){
length = file->getSize();
if (length == 0){
throw MusicException(__FILE__, __LINE__, "Length was 0");
}
memory = new unsigned char[length];
if (file->readLine((char*) memory, length) != length){
throw MusicException(__FILE__, __LINE__, "Could not read entire file");
}
system.open = NULL;
system.skip = skip;
system.getc = getc;
system.getnc = getnc;
system.close = close;
}
virtual ~MemorySystem(){
closeDumb();
delete[] memory;
}
unsigned char * memory;
int length;
int position;
DUMBFILE_SYSTEM system;
DUMBFILE * dumb;
int doSkip(long n){
position += n;
if (position > length){
position = length;
}
if (position < 0){
position = 0;
}
return 0;
}
static int skip(void *f, long n){
MemorySystem * self = (MemorySystem*) f;
return self->doSkip(n);
}
int doGetc(){
if (position < length){
unsigned char out = memory[position];
position += 1;
return out;
}
return -1;
}
static int getc(void *f){
MemorySystem * self = (MemorySystem*) f;
return self->doGetc();
}
int doGetnc(unsigned char * ptr, long n){
int actual = n;
if (actual + position >= length){
actual = length - position;
}
memcpy(ptr, memory + position, actual);
position += actual;
return actual;
}
static long getnc(unsigned char *ptr, long n, void *f){
MemorySystem * self = (MemorySystem*) f;
return self->doGetnc(ptr, n);
}
void doClose(){
}
static void close(void *f){
MemorySystem * self = (MemorySystem*) f;
return self->doClose();
}
void closeDumb(){
if (dumb != NULL){
dumbfile_close(dumb);
dumb = NULL;
}
}
void reset(){
position = 0;
}
DUH * load(DUH * (*reader)(DUMBFILE *)){
closeDumb();
reset();
dumb = dumbfile_open_ex(this, &system);
return reader(dumb);
}
DUH * loadDumbFile(){
DUH * what = NULL;
for (int i = 0; i < 4; i++){
/* the order of trying xm/s3m/it/mod matters because mod could be
* confused with one of the other formats, so load it last.
*/
switch (i){
case 0: {
what = load(dumb_read_xm_quick);
break;
}
case 1: {
what = load(dumb_read_s3m_quick);
break;
}
case 2: {
what = load(dumb_read_it_quick);
break;
}
case 3: {
what = load(dumb_read_mod_quick);
break;
}
}
if (what != NULL){
return what;
}
}
return NULL;
}
};
}
/* expects each sample to be 4 bytes, 2 bytes per sample * 2 channels */
DumbPlayer::DumbPlayer(const Filesystem::AbsolutePath & path){
Util::ReferenceCount<Storage::File> file = Storage::instance().open(path);
if (file == NULL){
throw MusicException(__FILE__, __LINE__, "Could not open " + path.path());
}
if (file->canStream()){
system = Util::ReferenceCount<DumbSystem>(new DumbSystems::StreamingSystem(file));
} else {
system = Util::ReferenceCount<DumbSystem>(new DumbSystems::MemorySystem(file));
}
music_file = system->loadDumbFile();
if (music_file == NULL){
std::ostringstream error;
error << "Could not load DUMB file " << path.path();
throw MusicException(__FILE__, __LINE__, error.str());
}
int n_channels = 2;
int position = 0;
renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
if (!renderer){
Global::debug(0) << "Could not create renderer" << std::endl;
throw Exception::Base(__FILE__, __LINE__);
}
}
void DumbPlayer::render(void * data, int samples){
double delta = 65536.0 / Sound::Info.frequency;
/* FIXME: use global music volume to scale the output here */
int n = duh_render(renderer, 16, 0, volume, delta, samples, data);
}
void DumbPlayer::setVolume(double volume){
this->volume = volume;
}
DumbPlayer::~DumbPlayer(){
duh_end_sigrenderer(renderer);
unload_duh(music_file);
}
GMEPlayer::GMEPlayer(string path):
emulator(NULL){
/* TODO: Put the gme thing in a class and use gme_open_data to load from raw memory */
gme_err_t fail = gme_open_file(path.c_str(), &emulator, Sound::Info.frequency);
if (fail != NULL){
Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
throw MusicException(__FILE__, __LINE__, "Could not load GME file");
}
emulator->start_track(0);
Global::debug(1) << "Loaded GME file " << path << std::endl;
}
void GMEPlayer::render(void * stream, int length){
/* length/2 to convert bytes to short */
emulator->play(length * 2, (short*) stream);
if (emulator->track_ended()){
gme_info_t * info;
gme_track_info(emulator, &info, 0);
int intro = info->intro_length;
emulator->start_track(0);
// Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
/* skip past the intro if there is a loop */
if (info->loop_length != 0){
emulator->seek(intro);
}
}
/* scale for volume */
for (int i = 0; i < length * 2; i++){
short & sample = ((short *) stream)[i];
sample *= volume;
}
/*
short large = 0;
short small = 0;
for (int i = 0; i < length / 2; i++){
// ((short *) stream)[i] *= 2;
short z = ((short *) stream)[i];
if (z < small){
small = z;
}
if (z > large){
large = z;
}
}
Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
*/
}
void GMEPlayer::setVolume(double volume){
this->volume = volume;
}
GMEPlayer::~GMEPlayer(){
delete emulator;
}
#ifdef HAVE_MP3_MPG123
struct Mpg123FileIO{
ssize_t (*read)(void *, void *, size_t);
off_t (*seek)(void *, off_t, int);
void (*close)(void *);
};
/* TODO: review this method, I'm not sure we need to reset the decoder after opening.
* Also do we need to close or will open_handle do it for us?
*/
static void openMpg123(mpg123_handle ** mp3, const Mpg123FileIO & fileIO, Mpg123Handler * handler){
int error = mpg123_replace_reader_handle(*mp3, fileIO.read, fileIO.seek, fileIO.close);
/* stream has progressed a little bit so reset it by opening it again */
error = mpg123_open_handle(*mp3, handler);
if (error == -1){
std::ostringstream fail;
fail << "Could not open mpg123 file " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
// error = mpg123_replace_reader_handle(*mp3, fileIO.read, fileIO.seek, fileIO.close);
/* FIXME end */
/* some of the native decoders aren't stable in older versions of mpg123
* so just use generic for now. 1.13.1 should work better
*/
error = mpg123_decoder(*mp3, "generic");
if (error != MPG123_OK){
std::ostringstream fail;
fail << "Could not use 'generic' mpg123 decoder for " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
}
static void initializeMpg123(mpg123_handle ** mp3, const Mpg123FileIO & fileIO, Mpg123Handler * handler){
/* Initialize */
if (mpg123_init() != MPG123_OK){
throw MusicException(__FILE__, __LINE__, "Could not initialize mpg123");
}
try{
*mp3 = mpg123_new(NULL, NULL);
if (*mp3 == NULL){
throw MusicException(__FILE__,__LINE__, "Could not allocate mpg handle");
}
mpg123_format_none(*mp3);
/* allegro wants unsigned samples but mpg123 can't actually provide unsigned
* samples even though it has an enum for it, MPG123_ENC_UNSIGNED_16. this
* was rectified in 1.13.0 or something, but for now signed samples are ok.
*/
int error = mpg123_format(*mp3, Sound::Info.frequency, MPG123_STEREO, MPG123_ENC_SIGNED_16);
if (error != MPG123_OK){
Global::debug(0) << "Could not set format for mpg123 handle" << std::endl;
}
error = mpg123_replace_reader_handle(*mp3, fileIO.read, fileIO.seek, fileIO.close);
if (error == -1){
std::ostringstream fail;
fail << "Could not open mpg123 file " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
/* FIXME workaround for libmpg issues with "generic" decoder frequency not being set */
/* These next two lines work around an uninitialized memory problem in mpg123 1.12.1. The issue does not exist in later versions of mpg123.
* Specifically in parse.c is the following code
* unsigned char *newbuf = fr->bsspace[fr->bsnum]+512;
* Without a call to frame_reset, fr->bsnum will be uninitialized. mpg123 1.12.1 did not call frame_reset() any time between mpg123_open_handle and mpg123_read().
* mpg123_open_fd on the other hand will call frame_reset() so we call mpg123_open_fd to force it. We make an extra mpg123_close call to undo the state changes associated with mpg123_open_fd.
*/
error = mpg123_open_fd(*mp3, 0);
mpg123_close(*mp3);
error = mpg123_open_handle(*mp3, handler);
if (error == -1){
std::ostringstream fail;
fail << "Could not open mpg123 file " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
/* reading a frame is the only surefire way to get mpg123 to set the
* sampling_frequency which it needs to set the decoder a few lines below
*/
size_t dont_care;
unsigned char tempBuffer[4096];
error = mpg123_read(*mp3, tempBuffer, sizeof(tempBuffer), &dont_care);
if (!(error == MPG123_OK || error == MPG123_NEW_FORMAT)){
std::ostringstream fail;
fail << "Could not read mpg123 file " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
mpg123_close(*mp3);
error = mpg123_replace_reader_handle(*mp3, fileIO.read, fileIO.seek, fileIO.close);
/* stream has progressed a little bit so reset it by opening it again */
error = mpg123_open_handle(*mp3, handler);
if (error == -1){
std::ostringstream fail;
fail << "Could not open mpg123 file " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
// error = mpg123_replace_reader_handle(*mp3, fileIO.read, fileIO.seek, fileIO.close);
/* FIXME end */
/* some of the native decoders aren't stable in older versions of mpg123
* so just use generic for now. 1.13.1 should work better
*/
error = mpg123_decoder(*mp3, "generic");
if (error != MPG123_OK){
std::ostringstream fail;
fail << "Could not use 'generic' mpg123 decoder for " << handler->name() << " error code " << error;
throw MusicException(__FILE__,__LINE__, fail.str());
}
// Global::debug(0) << "mpg support " << mpg123_format_support(mp3, Sound::FREQUENCY, MPG123_ENC_SIGNED_16) << std::endl;
/*
double base, really, rva;
mpg123_getvolume(*mp3, &base, &really, &rva);
// Global::debug(0) << "mpg volume base " << base << " really " << really << " rva " << rva << std::endl;
base_volume = base;
long rate;
int channels, encoding;
mpg123_getformat(*mp3, &rate, &channels, &encoding);
// Global::debug(0) << path << " rate " << rate << " channels " << channels << " encoding " << encoding << std::endl;
*/
} catch (const MusicException & fail){
if (*mp3 != NULL){
mpg123_close(*mp3);
mpg123_delete(*mp3);
*mp3 = NULL;
}
mpg123_exit();
throw;
}
}
/* initialize the mpg123 library and open up an mp3 file for reading */
static void initializeMpg123(mpg123_handle ** mp3, const Filesystem::AbsolutePath & path){
/* Initialize */
if (mpg123_init() != MPG123_OK){
throw MusicException(__FILE__, __LINE__, "Could not initialize mpg123");
}
try{
*mp3 = mpg123_new(NULL, NULL);
if (*mp3 == NULL){
throw MusicException(__FILE__,__LINE__, "Could not allocate mpg handle");
}
mpg123_format_none(*mp3);
/* allegro wants unsigned samples but mpg123 can't actually provide unsigned
* samples even though it has an enum for it, MPG123_ENC_UNSIGNED_16. this
* was rectified in 1.13.0 or something, but for now signed samples are ok.
*/
int error = mpg123_format(*mp3, Sound::Info.frequency, MPG123_STEREO, MPG123_ENC_SIGNED_16);
if (error != MPG123_OK){
Global::debug(0) << "Could not set format for mpg123 handle" << std::endl;
}
/* FIXME workaround for libmpg issues with "generic" decoder frequency not being set */
error = mpg123_open(*mp3, (char*) path.path().c_str());
if (error == -1){
std::ostringstream error;
error << "Could not open mpg123 file " << path.path() << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
/* reading a frame is the only surefire way to get mpg123 to set the
* sampling_frequency which it needs to set the decoder a few lines below
*/
size_t dont_care;
unsigned char tempBuffer[4096];
error = mpg123_read(*mp3, tempBuffer, sizeof(tempBuffer), &dont_care);
if (!(error == MPG123_OK || error == MPG123_NEW_FORMAT)){
std::ostringstream error;
error << "Could not read mpg123 file " << path.path() << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
mpg123_close(*mp3);
/* stream has progressed a little bit so reset it by opening it again */
error = mpg123_open(*mp3, (char*) path.path().c_str());
if (error == -1){
std::ostringstream error;
error << "Could not open mpg123 file " << path.path() << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
/* FIXME end */
/* some of the native decoders aren't stable in older versions of mpg123
* so just use generic for now. 1.13.1 should work better
*/
error = mpg123_decoder(*mp3, "generic");
if (error != MPG123_OK){
std::ostringstream error;
error << "Could not use 'generic' mpg123 decoder for " << path.path() << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
// Global::debug(0) << "mpg support " << mpg123_format_support(mp3, Sound::FREQUENCY, MPG123_ENC_SIGNED_16) << std::endl;
/*
double base, really, rva;
mpg123_getvolume(*mp3, &base, &really, &rva);
// Global::debug(0) << "mpg volume base " << base << " really " << really << " rva " << rva << std::endl;
base_volume = base;
long rate;
int channels, encoding;
mpg123_getformat(*mp3, &rate, &channels, &encoding);
// Global::debug(0) << path << " rate " << rate << " channels " << channels << " encoding " << encoding << std::endl;
*/
} catch (const MusicException & fail){
if (*mp3 != NULL){
mpg123_close(*mp3);
mpg123_delete(*mp3);
*mp3 = NULL;
}
mpg123_exit();
throw;
}
}
class StreamMpg123Handler: public Mpg123Handler {
public:
StreamMpg123Handler(const Util::ReferenceCount<Storage::File> & file):
file(file){
initializeMpg123(&mp3, mpg123IO(), this);
long rate = 0;
int channels = 0, encoding = 0;
mpg123_getformat(mp3, &rate, &channels, &encoding);
}
virtual ~StreamMpg123Handler(){
/* Close the mp3 here because the close hook in the mp3 structure
* will eventually call StreamMpg123Handler->doClose(). if the mp3
* is destroyed in the base class, Mpg123Handler, then the doClose
* method will be run after the StreamMpg123Handler class has
* already been destroyed and a segfault will occur when file->seek()
* is called.
*/
mpg123_close(mp3);
}
/* Keep a reference to the file so it doesn't close */
Util::ReferenceCount<Storage::File> file;
virtual void reopen(){
file->reset();
openMpg123(&mp3, mpg123IO(), this);
}
ssize_t doRead(char * buffer, size_t bytes){
return file->readLine(buffer, bytes);
}
static ssize_t readStream(void * handle, void * buffer, size_t bytes){
StreamMpg123Handler * self = (StreamMpg123Handler*) handle;
return self->doRead((char*) buffer, bytes);
}
off_t doSeek(off_t offset, int whence){
return file->seek(offset, whence);
}
static off_t seek(void * handle, off_t offset, int whence){
StreamMpg123Handler * self = (StreamMpg123Handler*) handle;
return self->doSeek(offset, whence);
}
void doClose(){
file->seek(0, SEEK_SET);
}
static void close(void * handle){
StreamMpg123Handler * self = (StreamMpg123Handler*) handle;
return self->doClose();
}
Mpg123FileIO mpg123IO(){
Mpg123FileIO io;
io.read = readStream;
io.seek = seek;
io.close = close;
return io;
}
virtual std::string name() const {
return "stream mp3";
}
};
class MemoryMpg123Handler: public Mpg123Handler {
public:
MemoryMpg123Handler(const Util::ReferenceCount<Storage::File> & file):
memory(NULL){
initializeMemory(file);
initializeMpg123(&mp3, mpg123IO(), this);
long rate = 0;
int channels = 0, encoding = 0;
mpg123_getformat(mp3, &rate, &channels, &encoding);
}
virtual ~MemoryMpg123Handler(){
mpg123_close(mp3);
delete[] memory;
}
virtual void reopen(){
position = 0;
openMpg123(&mp3, mpg123IO(), this);
}
void initializeMemory(const Util::ReferenceCount<Storage::File> & file){
length = file->getSize();
if (length == 0){
throw MusicException(__FILE__, __LINE__, "Length of file was 0");
}
memory = new char[length];
if (file->readLine(memory, length) != length){
throw MusicException(__FILE__, __LINE__, "Could not read entire file");
}
position = 0;
}
ssize_t doRead(char * buffer, size_t bytes){
int actual = bytes;
if (actual + position >= length){
actual = length - position;
}
memcpy(buffer, memory + position, actual);
position += actual;
return actual;
}
static ssize_t readStream(void * handle, void * buffer, size_t bytes){
MemoryMpg123Handler * self = (MemoryMpg123Handler*) handle;
return self->doRead((char*) buffer, bytes);
}
off_t doSeek(off_t offset, int whence){
switch (whence){
case SEEK_SET: position = offset; break;
case SEEK_CUR: position += offset; break;
case SEEK_END: position = length + offset; break;
}
if (position < 0){
position = 0;
}
if (position > length){
position = length;
}
return position;
}
static off_t seek(void * handle, off_t offset, int whence){
MemoryMpg123Handler * self = (MemoryMpg123Handler*) handle;
return self->doSeek(offset, whence);
}
void doClose(){
position = 0;
}
static void close(void * handle){
MemoryMpg123Handler * self = (MemoryMpg123Handler*) handle;
return self->doClose();
}
Mpg123FileIO mpg123IO(){
Mpg123FileIO io;
io.read = readStream;
io.seek = seek;
io.close = close;
return io;
}
virtual std::string name() const {
return "memory mp3";
}
char * memory;
int length;
int position;
};
Mpg123Handler::Mpg123Handler():
mp3(NULL){
}
void Mpg123Handler::read(void * data, int samples){
/* buffer * 4 for 16 bits per sample * 2 samples for stereo */
size_t out = 0;
if (mpg123_read(mp3, (unsigned char *) data, samples * 4, &out) == MPG123_DONE){
/* What if reopening fails? */
reopen();
/* Don't get into an infinite loop */
if (out != 0){
/* samples left = (total bytes - bytes read) / 4
* total bytes = samples * 4
* bytes read = out
*/
read((char*) data + out, (samples * 4 - out) / 4);
}
}
}
void Mpg123Handler::setVolume(double volume){
mpg123_volume(mp3, volume);
}
Mpg123Handler::~Mpg123Handler(){
mpg123_exit();
}
// static const int MPG123_BUFFER_SIZE = 1 << 11;
Mp3Player::Mp3Player(const Filesystem::AbsolutePath & path){
Util::ReferenceCount<Storage::File> file = Storage::instance().open(path);
if (file == NULL){
throw MusicException(__FILE__, __LINE__, "Could not open mp3 " + path.path());
}
if (file->canStream()){
handler = new StreamMpg123Handler(file);
} else {
handler = new MemoryMpg123Handler(file);
}
// handler = new MemoryMpg123Handler(file);
}
void Mp3Player::render(void * data, int samples){
handler->read(data, samples);
/*
long rate;
int channels, encoding;
mpg123_getformat(mp3, &rate, &channels, &encoding);
Global::debug(0) << "rate " << rate << " channels " << channels << " encoding " << encoding << std::endl;
*/
}
void Mp3Player::setVolume(double volume){
handler->setVolume(volume);
/*
this->volume = volume;
// mpg123_volume(mp3, volume * base_volume / 5000);
mpg123_volume(mp3, 0.0001);
*/
// mpg123_volume(mp3, volume);
}
Mp3Player::~Mp3Player(){
}
#endif /* MP3_MPG123 */
#ifdef HAVE_OGG
OggPlayer::Stream::Stream(){
}
OggPlayer::Stream::~Stream(){
}
size_t OggPlayer::Stream::read(void *ptr, size_t size, size_t nmemb, void *datasource){
Stream * self = (Stream*) datasource;
return self->doRead(ptr, size, nmemb);
}
int OggPlayer::Stream::seek(void *datasource, ogg_int64_t offset, int whence){
Stream * self = (Stream*) datasource;
return self->doSeek(offset, whence);
}
int OggPlayer::Stream::close(void *datasource){
Stream * self = (Stream*) datasource;
return self->doClose();
}
long OggPlayer::Stream::tell(void *datasource){
Stream * self = (Stream*) datasource;
return self->doTell();
}
int OGG_BUFFER_SIZE = 1024 * 32;
OggPlayer::OggPlayer(const Filesystem::AbsolutePath & path):
path(path){
stream = createStream(Storage::instance().open(path));
openOgg();
vorbis_info * info = ov_info(&ogg, -1);
frequency = info->rate;
channels = info->channels;
bits = 16;
length = ov_pcm_total(&ogg, -1);
/* Update the renderer because now we know what the rate and channels are */
setRenderer(Util::ReferenceCount<MusicRenderer>(new MusicRenderer(info->rate, info->channels)));
buffer = new OggPage();
buffer->buffer1.buffer = new char[OGG_BUFFER_SIZE];
fillPage(&buffer->buffer1);
}
class OggFileStream: public OggPlayer::Stream {
public:
OggFileStream(const ReferenceCount<Storage::File> & file):
file(file){
}
ReferenceCount<Storage::File> file;
ov_callbacks oggCallbacks(){
ov_callbacks out;
out.read_func = read;
out.seek_func = seek;
out.close_func = NULL;
out.tell_func = tell;
return out;
}
virtual void reset(){
file->reset();
file->seek(0, SEEK_SET);
}
virtual size_t doRead(void *ptr, size_t size, size_t nmemb){
return file->readLine((char*) ptr, size * nmemb) / size;
}
virtual int doSeek(ogg_int64_t offset, int whence){
return file->seek(offset, whence);
}
virtual int doClose(){
return 0;
}
virtual long doTell(){
return file->tell();
}
};
class OggMemoryStream: public OggPlayer::Stream {
public:
OggMemoryStream(const ReferenceCount<Storage::File> & file):
memory(NULL),
length(0),
position(0){
initializeMemory(file);
}
char * memory;
int length;
int position;
void initializeMemory(const ReferenceCount<Storage::File> & file){
length = file->getSize();
if (length == 0){
throw MusicException(__FILE__, __LINE__, "File had 0 length");
}
memory = new char[length];
if (file->readLine(memory, length) != length){
throw MusicException(__FILE__, __LINE__, "Could not read entire file");
}
position = 0;
}
virtual ~OggMemoryStream(){
delete[] memory;
}
ov_callbacks oggCallbacks(){
ov_callbacks out;
out.read_func = read;
out.seek_func = seek;
out.close_func = NULL;
out.tell_func = tell;
return out;
}
virtual void reset(){
position = 0;
}
virtual size_t doRead(void *ptr, size_t size, size_t nmemb){
int bytes = size * nmemb;
int actual = bytes;
if (actual + position >= length){
actual = length - position;
}
memcpy(ptr, memory + position, actual);
position += actual;
return actual / size;
}
virtual int doSeek(ogg_int64_t offset, int whence){
switch (whence){
case SEEK_SET: position = offset; break;
case SEEK_CUR: position += offset; break;
case SEEK_END: position = length + offset; break;
}
if (position < 0){
position = 0;
}
if (position > length){
position = length;
}
return position;
}
virtual int doClose(){
return 0;
}
virtual long doTell(){
return position;
}
};
OggPlayer::Stream * OggPlayer::createStream(const ReferenceCount<Storage::File> & file){
if (file->canStream()){
return new OggFileStream(file);
} else {
return new OggMemoryStream(file);
}
}
void OggPlayer::openOgg(){
/*
if (file != NULL){
fclose(file);
file = NULL;
}
file = fopen(path.path().c_str(), "rb");
if (!file){
throw MusicException(__FILE__, __LINE__, "Could not open file");
}
*/
stream->reset();
int ok = ov_open_callbacks(stream.raw(), &ogg, 0, 0, stream->oggCallbacks());
if (ok != 0){
throw MusicException(__FILE__, __LINE__, "Could not open ogg");
}
}
void OggPlayer::fillPage(OggPage::Page * page){
int dont_care;
page->position = 0;
page->max = 0;
while (page->max < OGG_BUFFER_SIZE){
/* ov_read might not read all available samples, I guess it stops
* reading on a page boundary. We just plow on through.
*/
int read = ov_read(&ogg, (char*) page->buffer + page->max,
OGG_BUFFER_SIZE - page->max,
bigEndian(), 2, 1, &dont_care);
/* if we hit the end of the file then re-open it and keep reading */
if (read == 0){
ov_clear(&ogg);
openOgg();
} else if (read == OV_HOLE){
throw MusicException(__FILE__, __LINE__, "Garbage in ogg file");
} else if (read == OV_EBADLINK){
throw MusicException(__FILE__, __LINE__, "Invalid stream section in ogg");
} else if (read == OV_EINVAL){
throw MusicException(__FILE__, __LINE__, "File headers are corrupt in ogg");
} else {
page->max += read;
}
}
}
void OggPlayer::doRender(char * data, int bytes){
OggPage::Page & page = buffer->buffer1;
if (page.max - page.position >= bytes){
memcpy(data, page.buffer + page.position, bytes);
page.position += bytes;
} else {
/* copy the rest, fill the page, switch to the other buffer */
memcpy(data, page.buffer + page.position, page.max - page.position);
int at = page.max - page.position;
int rest = bytes - (page.max - page.position);
fillPage(&page);
doRender(data + at, rest);
}
}
void OggPlayer::render(void * data, int length){
doRender((char*) data, length * 4);
}
void OggPlayer::setVolume(double volume){
this->volume = volume;
// Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}
OggPlayer::~OggPlayer(){
/* ov_clear will close the file */
ov_clear(&ogg);
/*
if (file != NULL){
fclose(file);
}
*/
}
#endif /* OGG */
#ifdef HAVE_MP3_MAD
Mp3Player::Mp3Player(const Filesystem::AbsolutePath & path):
available(NULL),
bytesLeft(0),
position(0),
raw(NULL){
Util::ReferenceCount<Storage::File> file = Storage::instance().open(path);
if (file == NULL){
throw MusicException(__FILE__, __LINE__, "Could not open mp3 " + path.path());
}
/* Mad can't stream so we just load the entire thing into memory */
rawLength = file->getSize();
raw = new unsigned char[rawLength];
if (file->readLine((char*) raw, rawLength) != rawLength){
throw MusicException(__FILE__, __LINE__, "Could not read entire mp3 " + path.path());
}
int rate = 44100, channels = 2;
discoverInfo(raw, rawLength, &rate, &channels);
setRenderer(Util::ReferenceCount<MusicRenderer>(new MusicRenderer(rate, channels)));
Global::debug(0) << "Opened mp3 file " << path.path() << " rate " << rate << " channels " << channels << std::endl;
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
mad_stream_buffer(&stream, raw, rawLength);
fill(4);
}
/* read the first frame and get the rate and channels from the header.
* assume all other frames use the same rate and channels
*/
void Mp3Player::discoverInfo(unsigned char * raw, int length, int * rate, int * channels){
mad_frame frame;
mad_stream stream;
mad_frame_init(&frame);
mad_stream_init(&stream);
mad_stream_buffer(&stream, raw, length);
int ok = mad_header_decode(&frame.header, &stream);
while (ok == -1){
if (MAD_RECOVERABLE(stream.error)){
ok = mad_header_decode(&frame.header, &stream);
} else {
throw MusicException(__FILE__, __LINE__, "Could not decode mp3 frame");
}
}
*rate = frame.header.samplerate;
switch (frame.header.mode){
case MAD_MODE_SINGLE_CHANNEL: *channels = 1; break;
case MAD_MODE_DUAL_CHANNEL: *channels = 2; break;
case MAD_MODE_JOINT_STEREO: *channels = 2; break;
case MAD_MODE_STEREO: *channels = 2; break;
}
mad_frame_finish(&frame);
mad_stream_finish(&stream);
}
mad_flow Mp3Player::error(void * data, mad_stream * stream, mad_frame * frame){
if (MAD_RECOVERABLE(stream->error)){
return MAD_FLOW_CONTINUE;
}
throw MusicException(__FILE__, __LINE__, "Error decoding mp3 stream");
}
static inline signed int mad_scale(mad_fixed_t sample){
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
void Mp3Player::output(mad_header const * header, mad_pcm * pcm){
unsigned int channels = pcm->channels;
unsigned int samples = pcm->length;
/*
mad_fixed_t const * left = pcm->samples[0];
mad_fixed_t const * right = pcm->samples[1];
*/
unsigned short * out = new unsigned short[samples * channels];
for (unsigned int index = 0; index < samples; index++){
for (int channel = 0; channel < channels; channel++){
mad_fixed_t const * left = pcm->samples[channel] + index;
out[index * channels + channel] = mad_scale(*left) & 0xffff;
// out[index * 2 + 1] = mad_scale(*right) & 0xffff;
}
// left += 1;
// right += 1;
}
/* N channels * 2 bytes per sample */
pages.push_back(Data((char*) out, samples * channels * 2));
}
mad_flow Mp3Player::input(void * data, mad_stream * stream){
/*
Mp3Player * player = (Mp3Player*) data;
if (!player->readMore){
return MAD_FLOW_STOP;
} else {
player->readMore = false;
}
int read = fread(player->raw, 1, RAW_SIZE, player->handle);
if (feof(player->handle)){
/ * start over * /
fseek(player->handle, 0, SEEK_SET);
}
mad_stream_buffer(stream, player->raw, read);
return MAD_FLOW_CONTINUE;
*/
return MAD_FLOW_CONTINUE;
}
void Mp3Player::fill(int frames){
for (int i = 0; i < frames; i++){
int headerError = mad_header_decode(&frame.header, &stream);
while (headerError == -1){
if (MAD_RECOVERABLE(stream.error)){
} else {
if (stream.error == MAD_ERROR_BUFLEN){
mad_stream_finish(&stream);
mad_frame_finish(&frame);
mad_synth_finish(&synth);
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
mad_stream_buffer(&stream, raw, rawLength);
}
}
headerError = mad_header_decode(&frame.header, &stream);
}
mad_frame_decode(&frame, &stream);
mad_synth_frame(&synth, &frame);
output(&frame.header, &synth.pcm);
}
/*
readMore = true;
int result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
*/
bytesLeft = 0;
for (std::vector<Data>::iterator it = pages.begin(); it != pages.end(); it++){
bytesLeft += it->length;
}
// Global::debug(0) << "Read " << bytesLeft << std::endl;
delete[] available;
available = new char[bytesLeft];
position = 0;
int here = 0;
for (std::vector<Data>::iterator it = pages.begin(); it != pages.end(); it++){
memcpy(available + here, it->data, it->length);
here += it->length;
delete[] it->data;
}
// Global::debug(0) << "Filled mp3 with " << bytesLeft << std::endl;
pages.clear();
}
void Mp3Player::render(void * data, int length){
length *= 4;
// Global::debug(0) << "Mp3 render " << length << " have " << bytesLeft << std::endl;
while (length > 0){
int left = length;
if (left > bytesLeft){
left = bytesLeft;
}
memcpy(data, available + position, left);
length -= left;
bytesLeft -= left;
position += left;
data = ((char*) data) + left;
if (bytesLeft == 0){
fill(2);
}
}
}
void Mp3Player::setVolume(double volume){
/* TODO */
}
Mp3Player::~Mp3Player(){
delete[] raw;
delete[] available;
mad_stream_finish(&stream);
mad_frame_finish(&frame);
mad_synth_finish(&synth);
// mad_decoder_finish(&decoder);
}
#endif /* MP3_MAD */
}
diff --git a/src/sound/music-renderer.cpp b/src/sound/music-renderer.cpp
index 1f8b8f10..075569b6 100644
--- a/src/sound/music-renderer.cpp
+++ b/src/sound/music-renderer.cpp
@@ -1,293 +1,297 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#ifdef USE_ALLEGRO5
#include <allegro5/allegro_audio.h>
#endif
+#if 0
+
#ifdef USE_ALLEGRO
-#include "dumb/include/aldumb.h"
+#include "../libs/dumb/include/aldumb.h"
#ifdef _WIN32
/* what do we need winalleg for?
* reason: ...
*/
#include <winalleg.h>
#endif
#endif
#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif
-#include "music-renderer.h"
-#include "music-player.h"
-#include "music-exception.h"
-#include "sound.h"
+#endif
+
+#include "r-tech1/sound/music-renderer.h"
+#include "r-tech1/sound/music-player.h"
+#include "r-tech1/sound/music-exception.h"
+#include "r-tech1/sound/sound.h"
#include <sstream>
namespace Util{
#ifdef USE_ALLEGRO5
const int DUMB_SAMPLES = 1024;
MusicRenderer::MusicRenderer(){
create(Sound::Info.frequency, 2);
}
MusicRenderer::MusicRenderer(int frequency, int channels){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
ALLEGRO_CHANNEL_CONF configuration = ALLEGRO_CHANNEL_CONF_2;
switch (channels){
case 1: configuration = ALLEGRO_CHANNEL_CONF_1; break;
case 2: configuration = ALLEGRO_CHANNEL_CONF_2; break;
case 3: configuration = ALLEGRO_CHANNEL_CONF_3; break;
case 4: configuration = ALLEGRO_CHANNEL_CONF_4; break;
case 5: configuration = ALLEGRO_CHANNEL_CONF_5_1; break;
case 6: configuration = ALLEGRO_CHANNEL_CONF_6_1; break;
case 7: configuration = ALLEGRO_CHANNEL_CONF_7_1; break;
default: configuration = ALLEGRO_CHANNEL_CONF_2; break;
}
stream = al_create_audio_stream(4, DUMB_SAMPLES, frequency, ALLEGRO_AUDIO_DEPTH_INT16, configuration);
if (!stream){
throw MusicException(__FILE__, __LINE__, "Could not create allegro5 audio stream");
}
queue = al_create_event_queue();
al_register_event_source(queue, al_get_audio_stream_event_source(stream));
}
void MusicRenderer::play(MusicPlayer & player){
al_attach_audio_stream_to_mixer(stream, al_get_default_mixer());
}
void MusicRenderer::pause(){
al_detach_audio_stream(stream);
}
MusicRenderer::~MusicRenderer(){
al_destroy_audio_stream(stream);
al_destroy_event_queue(queue);
}
void MusicRenderer::poll(MusicPlayer & player){
ALLEGRO_EVENT event;
while (al_get_next_event(queue, &event)){
if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) {
ALLEGRO_AUDIO_STREAM * stream = (ALLEGRO_AUDIO_STREAM *) event.any.source;
void * data = al_get_audio_stream_fragment(stream);
if (data != NULL){
player.render(data, al_get_audio_stream_length(stream));
al_set_audio_stream_fragment(stream, data);
}
}
}
}
#elif USE_SDL
#ifdef PS3
static const int BUFFER_SIZE = 1024 * 4;
#else
static const int BUFFER_SIZE = 1024 * 16;
#endif
// static const int BUFFER_SIZE = 65536 * 2;
Encoding formatType(int sdlFormat){
switch (sdlFormat){
case AUDIO_U8: return Unsigned8;
case AUDIO_S16SYS: return Signed16;
#if SDL_VERSION_ATLEAST(1, 3, 0)
case AUDIO_F32MSB: return Float32;
case AUDIO_F32LSB: return Float32;
#endif
}
std::ostringstream out;
out << "Don't know how to deal with SDL format " << sdlFormat << std::endl;
throw MusicException(__FILE__, __LINE__, out.str());
/*
if (bigEndian()){
switch (Sound::Info.format){
case AUDIO_S16MSB: return Signed16;
}
return Signed16;
} else {
switch (Sound::Info.format){
case AUDIO_S16LSB: return Signed16;
}
return Signed16;
}
*/
}
MusicRenderer::MusicRenderer():
convert(formatType(AUDIO_S16SYS), Sound::Info.channels, Sound::Info.frequency,
formatType(Sound::Info.format), Sound::Info.channels, Sound::Info.frequency){
create(Sound::Info.frequency, Sound::Info.channels);
}
MusicRenderer::MusicRenderer(int frequency, int channels):
convert(formatType(AUDIO_S16SYS), channels, frequency,
formatType(Sound::Info.format), Sound::Info.channels, Sound::Info.frequency){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
// Global::debug(1) << "Convert between " << format << ", " << channels << ", " << frequency << " to " << Sound::Info.format << ", " << Sound::Info.channels << ", " << Sound::Info.frequency << std::endl;
/*
SDL_BuildAudioCVT(&convert, format, channels, frequency,
Sound::Info.format, Sound::Info.channels,
Sound::Info.frequency);
*/
int size = convert.convertedLength(BUFFER_SIZE);
data = new Uint8[size < BUFFER_SIZE ? BUFFER_SIZE : size];
position = 0;
converted = 0;
}
/*
static int sampleSize(){
int size = 1;
switch (Sound::Info.format){
case AUDIO_U8:
case AUDIO_S8: size = 1; break;
case AUDIO_U16LSB:
case AUDIO_S16LSB:
case AUDIO_U16MSB:
case AUDIO_S16MSB: size = 2; break;
#if SDL_VERSION_ATLEAST(1, 3, 0)
case AUDIO_S32LSB:
case AUDIO_S32MSB:
case AUDIO_F32LSB:
case AUDIO_F32MSB: size = 2; break;
#endif
default: size = 2; break;
}
return size * Sound::Info.channels;
}
*/
void MusicRenderer::fill(MusicPlayer * player){
position = 0;
/* read samples in dual-channel, 16-bit, signed form */
// TimeDifference time;
// time.startTime();
player->render(data, BUFFER_SIZE / 4);
// time.endTime();
// Global::debug(0) << time.printTime("Render time") << std::endl;
converted = convert.convert(data, BUFFER_SIZE);
}
void MusicRenderer::read(MusicPlayer * player, Uint8 * stream, int bytes){
// Global::debug(0) << "Need " << bytes << " bytes. Have " << (converted - position) << std::endl;
while (bytes > 0){
int length = bytes;
if (length + position >= converted){
length = converted - position;
}
/*
if (length % 4 != 0){
length -= length % 4;
if (length == 0){
fill(player);
continue;
}
}
*/
// Global::debug(0) << "Copy " << length << " bytes" << std::endl;
/* data contains samples in the same format as the output */
memcpy(stream, data + position, length);
stream += length;
position += length;
bytes -= length;
if (position >= converted){
fill(player);
}
}
}
void MusicRenderer::mixer(void * arg, Uint8 * stream, int bytes){
MusicPlayer * player = (MusicPlayer*) arg;
player->getRenderer()->read(player, stream, bytes);
}
void MusicRenderer::play(MusicPlayer & player){
Mix_HookMusic(mixer, &player);
}
void MusicRenderer::pause(){
Mix_HookMusic(NULL, NULL);
}
void MusicRenderer::poll(MusicPlayer & player){
}
MusicRenderer::~MusicRenderer(){
Mix_HookMusic(NULL, NULL);
delete[] data;
}
#elif USE_ALLEGRO
int BUFFER_SIZE = 1 << 11;
static int ALLEGRO_MONO = 0;
static int ALLEGRO_STEREO = 1;
MusicRenderer::MusicRenderer(){
create(Sound::Info.frequency, 2);
}
MusicRenderer::MusicRenderer(int frequency, int channels){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
int configuration = ALLEGRO_STEREO;
if (channels == 1){
configuration = ALLEGRO_MONO;
}
stream = play_audio_stream(BUFFER_SIZE, 16, configuration, frequency, 255, 128);
if (!stream){
throw MusicException(__FILE__, __LINE__, "Could not create Allegro stream");
}
if (stream->len != BUFFER_SIZE){
throw MusicException(__FILE__, __LINE__, "Buffer size mismatch");
}
voice_set_priority(stream->voice, 255);
}
void MusicRenderer::play(MusicPlayer & player){
voice_start(stream->voice);
}
void MusicRenderer::pause(){
voice_stop(stream->voice);
}
void MusicRenderer::poll(MusicPlayer & player){
short * buffer = (short*) get_audio_stream_buffer(stream);
if (buffer){
player.render(buffer, BUFFER_SIZE);
/* allegro wants unsigned data but gme produces signed so to convert
* signed samples to unsigned samples we have to raise each value
* by half the maximum value of a short (0xffff+1)/2 = 0x8000
*/
for (int i = 0; i < BUFFER_SIZE * 2; i++){
buffer[i] += 0x8000;
}
free_audio_stream_buffer(stream);
}
}
MusicRenderer::~MusicRenderer(){
stop_audio_stream(stream);
}
#endif /* USE_ALLEGRO */
}
diff --git a/src/sound/music.cpp b/src/sound/music.cpp
index d231311f..6b194cb4 100644
--- a/src/sound/music.cpp
+++ b/src/sound/music.cpp
@@ -1,470 +1,470 @@
-#include "music.h"
+#include "r-tech1/sound/music.h"
#include <string>
#include <iostream>
#include <algorithm>
// #include "defs.h"
-#include "util/configuration.h"
-#include "../thread.h"
-#include "../funcs.h"
-#include "../file-system.h"
-#include "music-player.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/thread.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/sound/music-player.h"
using namespace std;
static Music * instance = NULL;
static double volume = 1.0;
// static bool muted = false;
static Util::Thread::Id musicThread;
static Util::Thread::Lock musicMutex;
static bool alive = true;
static void * playMusic( void * );
#define LOCK Util::Thread::acquireLock(&musicMutex);
#define UNLOCK Util::Thread::releaseLock(&musicMutex);
/*
#undef LOCK
#undef UNLOCK
#define LOCK
#define UNLOCK
*/
static void * bogus_thread( void * x){
return NULL;
}
Music::Music(bool on):
playing(false),
enabled(on),
fading(0),
musicPlayer(NULL),
currentSong(""){
if (instance != NULL){
cerr << "Trying to instantiate music object twice!" << endl;
return;
}
volume = (double) Configuration::getMusicVolume() / 100.0;
instance = this;
Global::debug(0) << "Supported music extensions " << supportedExtensions() << std::endl;
Util::Thread::initializeLock(&musicMutex);
Global::debug(1) << "Creating music thread" << endl;
if (on){
Util::Thread::createThread(&musicThread, NULL, (Util::Thread::ThreadFunction) playMusic, (void *)instance);
} else {
/* FIXME: just don't create a thread at all.. */
Util::Thread::createThread(&musicThread, NULL, (Util::Thread::ThreadFunction) bogus_thread, NULL);
}
}
/*
static bool isAlive(){
bool f = false;
synchronized{
f = alive;
}
return f;
}
*/
static void * playMusic( void * _music ){
Music * music = (Music *) _music;
Global::debug(1) << "Playing music" << endl;
/*
unsigned int tick = 0;
unsigned int counter;
*/
bool playing = true;
while (playing){
LOCK;{
playing = alive;
if (music != NULL){
music->doPlay();
}
}
UNLOCK;
Util::rest(10);
// Util::YIELD();
// pthread_yield();
}
// cout << "Done with music thread" << endl;
return NULL;
}
double Music::getVolume(){
double vol = 0;
LOCK;{
vol = volume;
}
UNLOCK;
return vol;
}
void Music::doPlay(){
if (this->playing){
double f = fading / 500.0;
switch (fading){
case -1: {
if (volume + f < 0){
fading = 0;
volume = 0;
} else {
volume += f;
this->_setVolume(volume);
}
break;
}
case 1: {
if (volume + f > 1.0){
fading = 0;
volume = 1.0;
} else {
volume += f;
this->_setVolume(volume);
}
break;
}
}
if (musicPlayer != NULL){
musicPlayer->poll();
}
}
}
/*
Music::Music( const char * song ):
volume( 1.0 ),
muted( false ),
player( NULL ),
music_file( NULL ){
loadSong( song );
}
Music::Music( const string & song ):
volume( 1.0 ),
muted( false ),
player( NULL ),
music_file( NULL ){
loadSong( song );
}
*/
void Music::fadeIn(double vol){
LOCK;{
// volume = vol;
instance->_fadeIn();
}
UNLOCK;
}
void Music::fadeOut( double vol ){
LOCK;{
// volume = vol;
instance->_fadeOut();
}
UNLOCK;
}
/* FIXME */
void Music::_fadeIn(){
// fading = 1;
}
void Music::_fadeOut(){
// fading = -1;
}
bool Music::doLoadSong(string song){
bool loaded = false;
LOCK;{
if (instance != NULL){
loaded = instance->internal_loadSong(song);
}
}
UNLOCK;
return loaded;
// muted = false;
}
/* remove an element from a vector at index 'pos' and return it */
template< class Tx_ >
static Tx_ removeVectorElement( vector< Tx_ > & toRemove, int pos ){
int count = 0;
typename vector< Tx_ >::iterator it;
for ( it = toRemove.begin(); it != toRemove.end() && count < pos; count++, it++ );
if ( it == toRemove.end() ){
/* this isnt right, but whatever */
return toRemove.front();
}
Tx_ removed = toRemove[pos];
toRemove.erase(it);
return removed;
}
void Music::loadSong(vector<Filesystem::AbsolutePath> songs){
std::random_shuffle(songs.begin(), songs.end());
for (vector<Filesystem::AbsolutePath>::iterator it = songs.begin(); it != songs.end(); it++){
Global::debug(1) << "Trying to load song " << (*it).path() << endl;
if (doLoadSong((*it).path())){
break;
}
}
}
bool Music::loadSong(const string & song){
return doLoadSong(song);
}
void Music::_play(){
if (playing == false && musicPlayer != NULL){
musicPlayer->play();
playing = true;
}
}
void Music::play(){
LOCK;{
instance->_play();
}
UNLOCK;
}
void Music::_pause(){
playing = false;
if (musicPlayer != NULL){
musicPlayer->pause();
}
}
void Music::pause(){
LOCK;{
instance->_pause();
}
UNLOCK;
}
void Music::soften(){
LOCK;{
instance->_soften();
}
UNLOCK;
}
void Music::_soften(){
if (volume > 0.1){
volume -= 0.1;
} else {
volume = 0.0;
}
_setVolume(volume);
}
void Music::louden(){
LOCK;{
instance->_louden();
}
UNLOCK;
}
void Music::_louden(){
if ( volume < 0.9 ){
volume += 0.1;
} else {
volume = 1.0;
}
_setVolume(volume);
}
void Music::mute(){
setVolume(0);
}
void Music::setVolume( double vol ){
LOCK;{
volume = vol;
if ( volume > 1.0 ){
volume = 1.0;
}
if ( volume < 0 ){
volume = 0;
}
instance->_setVolume( volume );
}
UNLOCK;
}
void Music::_setVolume(double vol){
if (musicPlayer != NULL){
musicPlayer->setVolume(vol);
}
}
Music::~Music(){
LOCK;{
alive = false;
playing = false;
}
UNLOCK;
Global::debug(1) << "Waiting for music thread to die" << endl;
Util::Thread::joinThread(musicThread);
LOCK;{
musicPlayer = NULL;
}
UNLOCK;
}
static string getExtension(string path){
if (path.rfind('.') != string::npos){
return Util::lowerCaseAll(path.substr(path.rfind('.') + 1));
}
return "";
}
/* true if the file extension is something DUMB will probably recognize */
static bool isDumbFile(string path){
string extension = getExtension(path);
return extension == "mod" ||
extension == "s3m" ||
extension == "it" ||
extension == "xm";
}
static bool isGMEFile(string path){
string extension = getExtension(path);
return extension == "nsf" ||
extension == "spc" ||
extension == "gym";
}
static bool isOggFile(string path){
string extension = getExtension(path);
return extension == "ogg";
}
static bool isMp3File(string path){
string extension = getExtension(path);
return extension == "mp3";
}
/* returns a string that lists all the extensions we can play */
string Music::supportedExtensions(){
ostringstream out;
vector<string> all;
all.push_back("xm (extended module)");
all.push_back("s3m (scream tracker 3)");
all.push_back("mod (module)");
all.push_back("it (impulse tracker)");
all.push_back("nsf (nintendo sound file / famicom)");
all.push_back("spc (super nintendo / super famicom)");
all.push_back("gym (sega genesis / mega drive)");
#if defined(HAVE_MP3_MPG123) || defined(HAVE_MP3_MAD)
all.push_back("mp3 (Mpg Layer 3)");
#endif
#ifdef HAVE_OGG
all.push_back("ogg (Ogg Vorbis)");
#endif
bool first = true;
for (vector<string>::iterator it = all.begin(); it != all.end(); it++){
if (!first){
out << ", ";
} else {
first = false;
}
out << *it;
}
return out.str();
}
bool Music::internal_loadSong(string path){
if (!enabled){
return false;
}
// Check current song and/or set it
if (currentSong.compare(path)==0){
return true;
} else {
currentSong = path;
}
Global::debug(0) << "Trying to load '" << path << "'" << endl;
/*
if (musicPlayer != NULL){
Global::debug(0) << "Destroy music player" << std::endl;
delete musicPlayer;
musicPlayer = NULL;
}
*/
try {
if (isDumbFile(path)){
musicPlayer = new Util::DumbPlayer(Filesystem::AbsolutePath(path));
musicPlayer->play();
playing = true;
} else if (isGMEFile(path)){
musicPlayer = new Util::GMEPlayer(path);
musicPlayer->play();
playing = true;
#ifdef HAVE_OGG
} else if (isOggFile(path)){
musicPlayer = new Util::OggPlayer(Filesystem::AbsolutePath(path));
musicPlayer->play();
playing = true;
#endif
#if defined(HAVE_MP3_MPG123) || defined(HAVE_MP3_MAD)
} else if (isMp3File(path)){
/* Utilize SDL mixer to handle mp3 */
musicPlayer = new Util::Mp3Player(Filesystem::AbsolutePath(path));
musicPlayer->play();
playing = true;
#endif
} else {
return false;
}
if (musicPlayer != NULL){
musicPlayer->setVolume(volume);
}
} catch (const Exception::Base & ex){
Global::debug(0) << "Could not open music file '" << path << "' because " << ex.getTrace() << endl;
//! FIXME Change from Base exception in the future
return false;
}
return true;
}
void Music::changeSong(){
// pause();
fadeIn(0.3);
loadSong(Storage::instance().getFiles(Storage::instance().find(Filesystem::RelativePath("music/")), "*"));
play();
}
#undef LOCK
#undef UNLOCK
diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp
index 4beaf71d..3dfa4e64 100644
--- a/src/sound/sound.cpp
+++ b/src/sound/sound.cpp
@@ -1,62 +1,56 @@
#include <stdlib.h>
-#include "sound.h"
+#include "r-tech1/sound/sound.h"
-#ifdef USE_ALLEGRO
-#include "allegro/sound.cpp"
-#endif
-#ifdef USE_SDL
-#include "sdl/sound.cpp"
-#endif
#ifdef USE_ALLEGRO5
#include "allegro5/sound.cpp"
#endif
-#include "../configuration.h"
-#include "../file-system.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/file-system.h"
Sound::SoundInfo Sound::Info;
Sound::Sound( const Sound & copy ):
own( NULL ){
own = copy.own;
if ( own ){
*own += 1;
}
data = copy.data;
}
Sound::Sound(Storage::File & file):
own(NULL){
int length = file.getSize();
char * data = new char[length];
file.readLine(data, length);
try{
loadFromMemory(data, length);
delete[] data;
} catch (const LoadException & fail){
delete[] data;
throw;
}
}
Sound & Sound::operator=( const Sound & rhs ){
if ( own ){
destroy();
}
own = rhs.own;
if ( own ){
*own += 1;
}
data = rhs.data;
return *this;
}
double Sound::scale(double in){
return in * Configuration::getSoundVolume() / 100.0;
}
Sound::~Sound(){
destroy();
}
diff --git a/src/system/allegro5/init.cpp b/src/system/allegro5/init.cpp
index 20db3987..42baf524 100644
--- a/src/system/allegro5/init.cpp
+++ b/src/system/allegro5/init.cpp
@@ -1,28 +1,28 @@
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
-#include "../init.h"
-#include "util/debug.h"
+#include "r-tech1/system/init.h"
+#include "r-tech1/debug.h"
namespace System{
void initSystem(const Global::InitConditions & conditions, Global::stream_type & out){
out << "Allegro5 initialize " << (al_init() ? "Ok" : "Failed") << std::endl;
uint32_t version = al_get_allegro_version();
int major = version >> 24;
int minor = (version >> 16) & 255;
int revision = (version >> 8) & 255;
int release = version & 255;
out << "Allegro5 version " << major << "." << minor << "." << revision << "." << release << std::endl;
out << "Init image: " << (al_init_image_addon() ? "Ok" : "Failed") << std::endl;
out << "Init primitives " << (al_init_primitives_addon() ? "Ok" : "Failed") << std::endl;
out << "Init keyboard " << (al_install_keyboard() ? "Ok" : "Failed") << std::endl;
out << "Init joystick " << (al_install_joystick() ? "Ok" : "Failed") << std::endl;
al_set_app_name("Paintown");
}
}
#endif
diff --git a/src/system/allegro5/timer.cpp b/src/system/allegro5/timer.cpp
index bb79ec94..4d4d4127 100644
--- a/src/system/allegro5/timer.cpp
+++ b/src/system/allegro5/timer.cpp
@@ -1,72 +1,72 @@
-#include "system/timer.h"
-#include "util/init.h"
+#include "r-tech1/system/timer.h"
+#include "r-tech1/init.h"
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
using std::vector;
namespace System{
struct TimerInfo{
TimerInfo(void (*x)(), ALLEGRO_TIMER * y):
tick(x), timer(y){}
void (*tick)();
ALLEGRO_TIMER * timer;
};
static void * do_timer(void * info){
TimerInfo * timerInfo = (TimerInfo*) info;
ALLEGRO_EVENT_SOURCE * source = al_get_timer_event_source(timerInfo->timer);
ALLEGRO_EVENT_QUEUE * queue = al_create_event_queue();
al_register_event_source(queue, source);
while (run_timer_guard.get()){
ALLEGRO_EVENT event;
/* Wait a maximum of 50ms in case we need to restart the timers */
if (al_wait_for_event_timed(queue, &event, 0.05)){
timerInfo->tick();
}
}
al_destroy_event_queue(queue);
al_destroy_timer(timerInfo->timer);
delete timerInfo;
return NULL;
}
static Util::Thread::Id start_timer(void (*func)(), int frequency){
ALLEGRO_TIMER * timer = al_create_timer(ALLEGRO_BPS_TO_SECS(frequency));
if (timer == NULL){
Global::debug(0) << "Could not create timer" << std::endl;
}
al_start_timer(timer);
TimerInfo * info = new TimerInfo(func, timer);
Util::Thread::Id thread;
Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) do_timer, (void*) info);
return thread;
}
static void inc_speed_counter(){
/* probably put input polling here, InputManager::poll(). no, don't do that.
* polling is done in the standardLoop now.
*/
Global::speed_counter4 += 1;
}
/* if you need to count seconds for some reason.. */
static void inc_second_counter() {
Global::second_counter += 1;
}
void startTimers(){
run_timer_guard.set(true);
running_timers.push_back(start_timer(inc_speed_counter, Global::TICS_PER_SECOND));
running_timers.push_back(start_timer(inc_second_counter, 1));
}
}
#endif
diff --git a/src/system/timer.cpp b/src/system/timer.cpp
index 93150acf..f8aadb33 100644
--- a/src/system/timer.cpp
+++ b/src/system/timer.cpp
@@ -1,21 +1,21 @@
-#include "timer.h"
+#include "r-tech1/system/timer.h"
using std::vector;
namespace System{
volatile bool run_timer;
Util::Thread::Lock run_timer_lock;
Util::ThreadBoolean run_timer_guard(run_timer, run_timer_lock);
std::vector<Util::Thread::Id> running_timers;
void closeTimers(){
run_timer_guard.set(false);
for (vector<Util::Thread::Id>::iterator it = running_timers.begin(); it != running_timers.end(); it++){
Util::Thread::Id timer = *it;
Util::Thread::joinThread(timer);
}
running_timers.clear();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:27 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70500
Default Alt Text
(215 KB)

Event Timeline