Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
95 KB
Referenced Files
None
Subscribers
None
diff --git a/SConscript b/SConscript
index b03fe09b..0e04c090 100644
--- a/SConscript
+++ b/SConscript
@@ -1,132 +1,140 @@
import os
-import scons.utils
-import scons.checks
-import scons.env
+import sys
+
+Import('root')
+
+#print "Rtech1 sys path", Dir('.').rel_path(Dir("#%s" % root))
+#print Dir('.').abspath
+#print Dir(Dir('.').rel_path(Dir("#r-tech1"))).abspath
+sys.path.append(Dir('.').rel_path(Dir("#%s" % root)))
+
+import scons_rtech1.utils
+import scons_rtech1.checks
Import('env')
build_type = 'release'
-if scons.utils.useAndroid():
+if scons_rtech1.utils.useAndroid():
build_type = 'armeabi-v7a'
-if scons.utils.useAndroidX64():
+if scons_rtech1.utils.useAndroidX64():
build_type = 'android-x64'
-config = env.Configure(custom_tests = {'CheckAllegro5': scons.checks.checkAllegro5(scons.checks.debug()),
- 'CheckFreetype': scons.checks.checkFreetype,
- 'ConfigChecks': scons.checks.configChecks})
+config = env.Configure(custom_tests = {'CheckAllegro5': scons_rtech1.checks.checkAllegro5(scons_rtech1.checks.debug()),
+ 'CheckFreetype': scons_rtech1.checks.checkFreetype,
+ 'ConfigChecks': scons_rtech1.checks.configChecks})
-if scons.utils.useAndroidX64():
+if scons_rtech1.utils.useAndroidX64():
env['HAVE_ALLEGRO5'] = True
env.Append(CPPDEFINES = ['USE_ALLEGRO5'])
else:
config.CheckAllegro5()
config.CheckFreetype()
config.ConfigChecks()
env = config.Finish()
if not env['HAVE_ALLEGRO5']:
Exit(1)
-if scons.checks.debug():
+if scons_rtech1.checks.debug():
env.Append(CXXFLAGS = ['-g3','-ggdb', '-Werror'])
-build_dir = 'build/%s' % build_type if not scons.checks.debug() else 'build/debug'
+build_dir = 'build/%s' % build_type if not scons_rtech1.checks.debug() else 'build/debug'
options = {'networking': False,
'allegro5': True
}
def getLibName():
- if scons.utils.useAndroid():
+ if scons_rtech1.utils.useAndroid():
return 'lib/r-tech1-arm'
- if scons.checks.debug():
+ if scons_rtech1.checks.debug():
return 'lib/r-tech1-debug'
return 'lib/r-tech1'
libname = getLibName()
env.VariantDir(build_dir, 'src')
-libs = env.SConscript('src/SConscript', variant_dir=build_dir, exports=['env', 'options'])
+libs = env.SConscript('src/SConscript', variant_dir=build_dir, exports=['env', 'options', 'root'])
rtech1 = env.StaticLibrary(libname, libs)
Alias('rtech1', rtech1)
tests_build_dir = os.path.join(build_dir, 'tests')
unit_tests = []
-if not scons.utils.useAndroid():
- unit_tests = SConscript('tests/SConscript', variant_dir = tests_build_dir, exports = ['env', 'rtech1'], duplicate=0)
+if not scons_rtech1.utils.useAndroid() and False:
+ unit_tests = SConscript('tests/SConscript', variant_dir = tests_build_dir, exports = ['env', 'rtech1', 'root'], duplicate=0)
env.Depends(unit_tests, rtech1)
if os.access(env.installPrefix, os.W_OK):
# Install target and configuration
env.Install('{0}/lib'.format(env.installPrefix), rtech1)
header_prefix = '{0}/include/r-tech1'.format(env.installPrefix)
include_dir = 'include/r-tech1'
for root, dirs, files in os.walk(include_dir):
for file in files:
# print "Install %s, %s" % (header_prefix + root[len('include/r-tech1'):], os.path.join(root, file))
# Install to <header location>/<local subdirectory>. The root contains the full
# include/r-tech1/subdirectory, so we chop off the leading include/r-tech1
env.Install(header_prefix + root[len(include_dir):], os.path.join(root, file))
env.Install(os.path.join(header_prefix, 'lz4'), 'src/libs/lz4/lz4.h')
# Construct dependency cflags and libraries for pc script
def createList(content, modifier):
deps = ''
for item in content:
deps += '-{0}{1} '.format(modifier, item) if 'r-tech1' not in item else ''
return deps
pcflags = createList(env['CPPPATH'], 'I')
pclibs = createList(env['LIBS'], 'l')
pclibpaths = createList(env['LIBPATH'], 'L')
# PC script
replacelist = {
- '%lib%': 'r-tech1' if not scons.checks.debug() else 'r-tech1-debug',
+ '%lib%': 'r-tech1' if not scons_rtech1.checks.debug() else 'r-tech1-debug',
'%prefix%': env.installPrefix,
'%rtech1_version%': '1',
'%flags%': pcflags,
'%libs%': pclibs,
'%libpaths%': pclibpaths
}
def script(name):
pc_install = '{0}/lib/pkgconfig/{1}.pc'.format(env.installPrefix, name)
pc_copied = Command(build_dir + '/temp.pc.in', 'misc/r-tech1.pc.in'.format(name), Copy('$TARGET', '$SOURCE'))
pc_script = env.Substfile(build_dir + '/temp.pc.in', SUBST_DICT = replacelist)
env.Depends(pc_script, pc_copied)
pc_mod = Command(build_dir + '/{0}.pc'.format(name), build_dir + '/temp.pc', Copy('$TARGET', '$SOURCE'))
env.Depends(pc_mod, pc_script)
env.InstallAs(pc_install, pc_mod)
return pc_mod, pc_install
- pc_mod, pc_install = script('r-tech1') if not scons.checks.debug() else script('r-tech1-debug')
+ pc_mod, pc_install = script('r-tech1') if not checks.debug() else script('r-tech1-debug')
# Install
env.Alias('install', [env.installPrefix, pc_install])
env.Depends([env.installPrefix, pc_mod], rtech1)
# Uninstall target
env.Command("uninstall", None, Delete(FindInstalledFiles()))
else:
def needsudo(target, source, env):
print 'No write priveleges to {0}, run target [{1}] as sudo'.format(env.installPrefix, target[0])
env.Command('install', None, needsudo)
env.Depends('install', ['rtech1', 'tests'])
env.Command('uninstall', None, needsudo)
env.Depends('uninstall', ['rtech1', 'tests'])
-env.Default(rtech1)
+# env.Default(rtech1)
env.Alias('tests', unit_tests)
for test in unit_tests:
orig = str(test).translate(None,'[]\'')
to = orig.replace('{0}/tests/'.format(build_dir), '')
#print orig, to
copy = Command('bin/{0}'.format(to), orig, Copy('$TARGET', '$SOURCE'))
env.Depends(copy, test)
env.Alias('tests', copy)
Return('rtech1')
diff --git a/SConstruct b/SConstruct
index e2803630..69c5bd52 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,20 +1,22 @@
import os
-import scons.utils
-import scons.checks
-import scons.env
+import scons_rtech1.utils
+import scons_rtech1.checks
+import scons_rtech1.env
-SetOption('num_jobs', scons.utils.detectCPUs())
+SetOption('num_jobs', scons_rtech1.utils.detectCPUs())
+# FIXME: use Dir('.').rel_path(Dir('#"))
includedir = '{0}/include'.format(os.getcwd())
env = Environment(ENV = os.environ, CPPPATH=includedir, tools=['textfile', 'default'])
-if scons.utils.useAndroid():
+if scons_rtech1.utils.useAndroid():
env = scons.env.android(env)
-if scons.utils.useAndroidX64():
+if scons_rtech1.utils.useAndroidX64():
env = scons.env.androidx64(env)
-if not scons.utils.isVerbose():
- env = scons.utils.less_verbose(env)
+if not scons_rtech1.utils.isVerbose():
+ env = scons_rtech1.utils.less_verbose(env)
-SConscript('SConscript', exports = ['env'])
+root = '.'
+SConscript('SConscript', exports = ['env', 'root'])
diff --git a/scons/__init__.py b/scons_rtech1/__init__.py
similarity index 100%
rename from scons/__init__.py
rename to scons_rtech1/__init__.py
diff --git a/scons/checks.py b/scons_rtech1/checks.py
similarity index 100%
rename from scons/checks.py
rename to scons_rtech1/checks.py
diff --git a/scons/env.py b/scons_rtech1/env.py
similarity index 100%
rename from scons/env.py
rename to scons_rtech1/env.py
diff --git a/scons/helpers.py b/scons_rtech1/helpers.py
similarity index 85%
rename from scons/helpers.py
rename to scons_rtech1/helpers.py
index 25f0a6af..b3ce49e6 100644
--- a/scons/helpers.py
+++ b/scons_rtech1/helpers.py
@@ -1,39 +1,43 @@
+import SCons
+
def read_cmake_list(name):
"""
Read a cmake files list and return a dictionary with each cmake variable
matched to a list of filenames.
This makes it easy to add/remove files, as only the cmake list needs to be
modified and scons will automatically pick up the changes.
"""
lists = {}
current = []
reading = False
for line in open(name):
if line.startswith("set("):
current = []
name = line[4:].strip()
lists[name] = current
reading = True
else:
if reading:
# Stop reading files once we hit a line like 'file.cpp)'
if line.strip("\t\r\n").endswith(")"):
reading = False
path = line.strip("( )\t\r\n")
if path:
current.append(path)
return lists
-def findFile(name):
- return findDirectory(name)
+def findFile(root, name):
+ path = SCons.Script.File(name, SCons.Script.Dir(".").rel_path(SCons.Script.Dir("#%s" % root)))
+ return path.abspath
+ #return findDirectory(name)
def findDirectory(name):
import os.path
where = '.'
# just try 5 directories
for i in xrange(0, 6):
if os.path.exists("%s/%s" % (where, name)):
return "%s/%s" % (where, name)
where = os.path.join(where, '..')
raise Exception("Could not find the %s directory" % name)
diff --git a/scons/utils.py b/scons_rtech1/utils.py
similarity index 99%
rename from scons/utils.py
rename to scons_rtech1/utils.py
index 7bc48d8a..30a5c59f 100644
--- a/scons/utils.py
+++ b/scons_rtech1/utils.py
@@ -1,300 +1,301 @@
from SCons.Script import ARGUMENTS
import os
def noColors():
try:
return int(ARGUMENTS['colors']) == 0
except KeyError:
return False
def xterm_color(string, color):
colors = {'none': "0",
'black': "0;30",
'red': "0;31",
'green': "0;32",
'brown': "0;33",
'blue': "0;34",
'purple': "0;35",
'cyan': "0;36",
'light-gray': "0;37",
'dark-gray': "1:30",
'light-red': "1;31",
'light-green': "1;32",
'yellow': "1;33",
'light-blue': "1;34",
'light-purple': "1;35",
'light-cyan': "1;36",
'white': "1;37"}
return "\033[%sm%s\033[0m" % (colors[color], string)
def isPlatform(platform):
import sys
return platform in sys.platform
def isWindows():
return isPlatform("win32")
def isLinux():
return isPlatform("linux")
def isOSX104():
import platform
return isPlatform("darwin") and platform.processor() == 'powerpc'
# Assume 10.6 and up
def isOSX():
return isPlatform("darwin") and not isOSX104()
# todo: figure out when we are on an xterm
def isXterm():
# assume linux and osx are ok
return not isWindows()
def colorize(string, color):
if noColors():
return string
if isXterm():
return xterm_color(string, color)
return string
def colorResult(what):
if what != 0:
return colorize('yes', 'light-green')
else:
return colorize('no', 'light-red')
def peg_to_cpp(target, source, env):
import sys
sys.path.append("src/mugen/parser")
sys.path.append(".")
import peg, re, cpp_generator
name = source[0].name
parser = peg.make_peg_parser(re.sub('\..*', '', name))
fout = open(target[0].path, 'w')
fout.write(cpp_generator.generate(parser(source[0].path)))
fout.write('\n')
fout.close()
# Build a cpp file from a peg definition
def pegBuilder(environment):
from SCons.Builder import Builder
from SCons.Action import Action
return Builder(action = Action(peg_to_cpp, environment['PEG_MAKE']),
suffix = '.cpp',
src_suffix = '.peg')
def readExec(program):
import os
try:
return os.popen(program).readline().replace("\n",'')
except OSError:
return ""
# Try to execute a script that will produce some compiler flags but fail
# gracefully if the script dies or can't be found
def safeParseConfig(environment, config):
# redirects stderr, not super safe
def version1():
import sys
out = open('fail.log', 'w')
old_stderr = sys.stderr
try:
sys.stderr = out
environment.ParseConfig(config)
out.close()
sys.stderr = old_stderr
except Exception, e:
out.close()
sys.stderr = old_stderr
raise e
# use the subprocess module to pass the output of stdout directly
# to mergeflags and trash stderr
# Not done yet!! This requires python 2.4
def version2():
import subprocess
process = subprocess.Popen(config.split(' '), stdout = subprocess.PIPE)
# p = subprocess.Popen(["ruby", "-e", code], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
out = p.stdout.readline().strip()
environment.MergeFlags(out)
version1()
# Create a function that pulls out some key from the shell environment
def makeUseEnvironment(key, default):
def use():
import os
try:
return int(os.environ[key]) == 1
except KeyError:
return default
return use
def makeUseArgument(key, default):
def use():
try:
return int(ARGUMENTS[key]) == 1
except KeyError:
return default
return use
useGch = makeUseArgument('gch', True)
usePrx = makeUseEnvironment('prx', False)
isVerbose = makeUseArgument('verbose', False)
useIntel = makeUseEnvironment('intel', False)
useMinpspw = makeUseEnvironment('minpspw', False)
useAndroid = makeUseEnvironment('android', False)
useAndroidX86 = makeUseEnvironment('androidx86', False)
useAndroidX64 = makeUseEnvironment('androidx64', False)
useIos = makeUseEnvironment('ios', False)
usePs3 = makeUseEnvironment('ps3', False)
useNDS = makeUseEnvironment('nds', False)
useDingoo = makeUseEnvironment('dingoo', False)
useXenon = makeUseEnvironment('xenon', False)
usePandora = makeUseEnvironment('pandora', False)
useWii = makeUseEnvironment('wii', False)
useLLVM = makeUseEnvironment('llvm', False)
useNacl = makeUseEnvironment('nacl', False)
useMpg123 = makeUseEnvironment('mpg123', False)
useMad = makeUseEnvironment('mad', False)
useGCW = makeUseEnvironment('gcw', False)
nativeCompile = makeUseEnvironment('native', False)
enableProfiled = makeUseEnvironment('PROFILE', False)
showTiming = makeUseEnvironment('timing', False)
useAllegro4 = makeUseEnvironment('allegro4', False)
useWii = makeUseEnvironment('wii', False)
def useAllegro():
def byEnv():
try:
return os.environ['ALLEGRO'] == '1'
except KeyError:
return False
def byArgument():
try:
return int(ARGUMENTS['allegro']) == 1
except KeyError:
return False
return byEnv() or byArgument()
def useAllegro5():
def byEnv():
try:
return os.environ['ALLEGRO5'] == '1'
except KeyError:
return False
def byArgument():
try:
return int(ARGUMENTS['allegro5']) == 1
except KeyError:
return False
# FIXME: hack to specify android here
return byEnv() or byArgument() or useAndroid() or useAndroidX86()
def useSDL():
+ print "[rtech1] Allegro ", useAllegro(), " Allegro5", useAllegro5()
return not useAllegro() and not useAllegro5()
# Replace standard tool invocations with nice colored text
def lessVerbose(env):
link_color = 'light-red'
ar_color = 'yellow'
ranlib_color = 'light-purple'
peg_color = 'light-cyan'
env['CCCOMSTR'] = "%s %s" % (colorize('Compiling c file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['SHCCCOMSTR'] = "%s %s" % (colorize('Compiling c file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['CXXCOMSTR'] = "%s %s" % (colorize('Compiling c++ file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['SHCXXCOMSTR'] = "%s %s" % (colorize('Compiling c++ file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['LINKCOMSTR'] = "%s %s" % (colorize('Linking', link_color), colorize('$TARGET', 'light-blue'))
env['SHLINKCOMSTR'] = "%s %s" % (colorize('Linking', link_color), colorize('$TARGET', 'light-blue'))
env['ARCOMSTR'] = "%s %s" % (colorize('Building library', ar_color), colorize('$TARGET', 'light-blue'))
env['RANLIBCOMSTR'] = "%s %s" % (colorize('Indexing library', ranlib_color), colorize('$TARGET', 'light-blue'))
env['PEG_MAKE'] = "%s %s" % (colorize('Creating peg parser', peg_color), colorize('$TARGET', 'light-blue'))
return env
def configure_backend(environment, backends, custom_tests):
config = environment.Configure(custom_tests = custom_tests)
if not config.CheckCompiler():
config.Finish()
raise Exception("No c++ compiler found. Install gcc or clang")
class OkBackend(Exception):
pass
class NoBackend(Exception):
pass
try:
for backend in backends:
if backend == 'SDL' and config.CheckSDL():
environment.Append(CPPDEFINES = ['USE_SDL'])
environment['PAINTOWN_BACKEND'] = 'sdl'
environment.Append(PAINTOWN_PLATFORM = ['sdl'])
raise OkBackend()
if backend == 'Allegro4' and config.CheckAllegro4():
environment.Append(CPPDEFINES = ['USE_ALLEGRO'])
environment['PAINTOWN_BACKEND'] = 'allegro4'
environment.Append(PAINTOWN_PLATFORM = ['allegro4'])
raise OkBackend()
if backend == 'Allegro5' and config.CheckAllegro5():
environment.Append(CPPDEFINES = ['USE_ALLEGRO5'])
environment['PAINTOWN_BACKEND'] = 'allegro5'
environment.Append(PAINTOWN_PLATFORM = ['allegro5'])
raise OkBackend()
config.Finish()
raise NoBackend()
except OkBackend:
pass
return config.Finish()
def checkCompiler(context):
context.Message("Checking for a compiler (%s) ... " % context.env['CXX'])
ok = context.TryCompile("""
int main(int argc, char ** argv){
return 0;
}
""", ".cpp")
context.Result(colorResult(ok))
return ok
def detectCPUs():
import os
"""
Detects the number of CPUs on a system. Cribbed from pp.
"""
# Linux, Unix and MacOS:
if hasattr(os, "sysconf"):
if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
# Linux & Unix:
ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
if isinstance(ncpus, int) and ncpus > 0:
return ncpus
else: # OSX:
return int(os.popen2("sysctl -n hw.ncpu")[1].read())
# Windows:
if "NUMBER_OF_PROCESSORS" in os.environ:
ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]);
if ncpus > 0:
return ncpus
return 1 # Default
def less_verbose(env):
link_color = 'light-red'
ar_color = 'yellow'
ranlib_color = 'light-purple'
peg_color = 'light-cyan'
env['CCCOMSTR'] = "%s %s" % (colorize('Compiling c file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['SHCCCOMSTR'] = "%s %s" % (colorize('Compiling c file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['CXXCOMSTR'] = "%s %s" % (colorize('Compiling c++ file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['SHCXXCOMSTR'] = "%s %s" % (colorize('Compiling c++ file', 'light-green'), colorize('$SOURCE', 'light-blue'))
env['LINKCOMSTR'] = "%s %s" % (colorize('Linking', link_color), colorize('$TARGET', 'light-blue'))
env['SHLINKCOMSTR'] = "%s %s" % (colorize('Linking', link_color), colorize('$TARGET', 'light-blue'))
env['ARCOMSTR'] = "%s %s" % (colorize('Building library', ar_color), colorize('$TARGET', 'light-blue'))
env['RANLIBCOMSTR'] = "%s %s" % (colorize('Indexing library', ranlib_color), colorize('$TARGET', 'light-blue'))
env['PEG_MAKE'] = "%s %s" % (colorize('Creating peg parser', peg_color), colorize('$TARGET', 'light-blue'))
return env
diff --git a/src/SConscript b/src/SConscript
index f6bac376..24500af4 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -1,61 +1,72 @@
-Import('env', 'options')
+Import('env', 'options', 'root')
-from scons import helpers
+#import sys
+#sys.path.append(Dir('..').rel_path(Dir("#r-tech1")))
+#print sys.path
+#import scons_rtech1.helpers
+
+import imp
+
+helpers_source = File("scons_rtech1/helpers.py", Dir(".").rel_path(Dir("#%s" % root)))
+helpers = imp.load_source("scons_rtech1.helpers", helpers_source.abspath)
+# from scons import helpers
import os.path
def tryKey(hashx, key, default):
try:
return hashx[key]
except KeyError:
return default
def useNetwork(options):
return tryKey(options, 'networking', False)
def utilLibrary(env):
- modules = helpers.read_cmake_list(helpers.findFile('src/CMakeLists.txt'))
+ modules = helpers.read_cmake_list(helpers.findFile(root, 'src/CMakeLists.txt'))
source = []
for module in modules:
source.append(env.Object(modules[module]))
return source
def minizipLibrary(env):
return env.SConscript('libs/zip/SConscript', exports = ['env'])
def gmeLibrary(env):
use = env
return SConscript('libs/gme/SConscript', exports = ['use'])
def lzmaLibrary7z(env):
use = env
- return SConscript('libs/7z/SConscript', exports = ['use'])
+ return SConscript('libs/7z/SConscript', exports = ['use', 'root'])
def sflLibrary(env):
use = env
return SConscript('libs/sfl/SConscript', exports = ['use'])
def pcreLibrary(env):
pcreEnv = env.Clone()
env = pcreEnv
return env.SConscript('libs/pcre/SConstruct', exports = ['env'])
def dumbLibrary(env):
dumbEnv = env.Clone()
env = dumbEnv
return env.SConscript('libs/dumb/SConscript', exports = ['env'])
def hawknlLibrary(env):
hawkEnv = env.Clone()
env = hawkEnv
# if isOSX():
# env.Append(CPPDEFINES = 'MACOSX')
return env.SConscript('libs/hawknl/SConscript', exports = ['env'])
+env.Append(CPPPATH = Dir('src', Dir(Dir('.').rel_path(Dir('#%s' % root)))).abspath)
+
all = [utilLibrary(env), minizipLibrary(env), gmeLibrary(env), lzmaLibrary7z(env), sflLibrary(env), pcreLibrary(env), dumbLibrary(env)]
if useNetwork(options):
all.append(hawknlLibrary(env))
Return('all')
diff --git a/src/graphics/bitmap.cpp b/src/graphics/bitmap.cpp
index 78e66265..5a089359 100644
--- a/src/graphics/bitmap.cpp
+++ b/src/graphics/bitmap.cpp
@@ -1,581 +1,581 @@
#include "r-tech1/funcs.h"
#include "r-tech1/graphics/bitmap.h"
#include "r-tech1/file-system.h"
#include <string>
#include <stdio.h>
#include <math.h>
namespace Graphics{
static Bitmap * Screen = NULL;
/* bitmaps that should always be resized to the dimensions of the screen */
static std::vector<Bitmap*> needResize;
Util::Parameter<Bitmap*> screenParameter;
Util::Parameter<Util::ReferenceCount<ShaderManager> > shaderManager;
ShaderManager::ShaderManager(){
}
ShaderManager::~ShaderManager(){
}
Util::ReferenceCount<Shader> ShaderManager::getShader(const std::string & name, Util::ReferenceCount<Shader> (*create)()){
std::map<std::string, Util::ReferenceCount<Shader> >::iterator it = shaders.find(name);
if (it == shaders.end()){
shaders[name] = create();
it = shaders.find(name);
}
return it->second;
}
/* implementation independant definitions can go here */
/*
int SCALE_X = 0;
int SCALE_Y = 0;
*/
/*
const int Bitmap::MODE_TRANS = 0;
const int Bitmap::MODE_SOLID = 1;
*/
const int SPRITE_NO_FLIP = 0;
const int SPRITE_V_FLIP = 1;
const int SPRITE_H_FLIP = 2;
const int SPRITE_NORMAL = 1;
const int SPRITE_LIT = 2;
const int SPRITE_TRANS = 3;
static inline int max(int a, int b){
return a > b ? a : b;
}
INTERNAL_COLOR Color::defaultColor(){
return makeColor(0, 0, 0).color;
}
void initializeExtraStuff();
Bitmap::Bitmap(Storage::File & file):
mustResize(false),
error(false),
bit8MaskColor(makeColor(0, 0, 0)){
int length = file.getSize();
if (length == -1){
throw BitmapException(__FILE__, __LINE__, std::string("Could not read from file"));
}
char * data = new char[length];
try{
file.readLine(data, length);
loadFromMemory(data, length);
delete[] data;
} catch (const BitmapException & fail){
delete[] data;
throw;
} catch (...){
delete[] data;
throw;
}
}
QualityFilter qualityFilterName(const std::string & type){
if (type == "xbr"){
return XbrFilter;
}
if (type == "hqx"){
return HqxFilter;
}
return NoFilter;
}
Bitmap::~Bitmap(){
if (mustResize){
for (std::vector<Bitmap*>::iterator it = needResize.begin(); it != needResize.end(); it++){
Bitmap * who = *it;
if (who == this){
needResize.erase(it);
break;
}
}
}
}
static Bitmap makeTemporaryBitmap(Bitmap *& temporary, int w, int h){
if (temporary == NULL){
temporary = new Bitmap(w, h);
} else if (temporary->getWidth() < w || temporary->getHeight() < h){
int mw = max(temporary->getWidth(), w);
int mh = max(temporary->getHeight(), h);
// printf("Create temporary bitmap %d %d\n", mw, mh);
delete temporary;
temporary = new Bitmap(mw, mh);
}
if (temporary == NULL){
printf("*bug* temporary bitmap is null\n");
}
return Bitmap(*temporary, 0, 0, w, h);
}
/*
Bitmap Bitmap::temporaryBitmap(int w, int h){
return makeTemporaryBitmap(temporary_bitmap, w, h);
}
Bitmap Bitmap::temporaryBitmap2(int w, int h){
return makeTemporaryBitmap(temporary_bitmap2, w, h);
}
*/
void Bitmap::cleanupTemporaryBitmaps(){
}
Bitmap & Bitmap::operator=(const Bitmap & copy){
path = copy.getPath();
this->width = copy.getWidth();
this->height = copy.getHeight();
setData(copy.getData());
return *this;
}
double Bitmap::getScale(){
/* the game is pretty much hard coded to run at 320 scaled upto 640
* and then scaled to whatever the user wants, but as long as
* 320 and 640 remain this number will be 2.
* maybe calculate this at some point
*/
return 2;
/*
if (Scaler != NULL && Buffer != NULL){
double x1 = Scaler->getWidth();
double x2 = Buffer->getWidth();
return x2 / x1;
}
return 1;
*/
}
bool Bitmap::isEmpty() const {
return getWidth() == 0 || getHeight() == 0;
}
/* taken from the color addon from allegro 4.9 */
static void al_color_cmyk_to_rgb(float cyan, float magenta, float yellow, float key, float *red, float *green, float *blue){
float max = 1 - key;
*red = max - cyan * max;
*green = max - magenta * max;
*blue = max - yellow * max;
}
void Bitmap::cymkToRGB(int c, int y, int m, int k, int * r, int * g, int * b){
float fc = (float)c / 255.0;
float fy = (float)y / 255.0;
float fm = (float)m / 255.0;
float fk = (float)k / 255.0;
float fr, fg, fb;
al_color_cmyk_to_rgb(fc, fm, fy, fk, &fr, &fg, &fb);
*r = (int)(fr * 255.0);
*g = (int)(fg * 255.0);
*b = (int)(fb * 255.0);
}
void Bitmap::updateOnResize(){
if (!mustResize){
mustResize = true;
needResize.push_back(this);
}
}
void Bitmap::updateSize(const int width, const int height){
if (getWidth() == width && getHeight() == height){
return;
}
Bitmap created(width, height);
*this = created;
}
/* resize the internal bitmap. not guaranteed to destroy the internal bitmap */
void Bitmap::resize(const int width, const int height){
/* if internal bitmap is already the proper size, do nothing */
if (getWidth() == width && getHeight() == height){
return;
}
Bitmap created(width, height);
Stretch(created);
*this = created;
}
/* decrement bitmap reference counter and free memory if counter hits 0 */
#if 0
void Bitmap::releaseInternalBitmap(){
const int MAGIC_DEBUG = 0xa5a5a5;
if (own != NULL){
if (*own == MAGIC_DEBUG){
printf("[bitmap] Trying to delete an already deleted reference counter %p\n", own);
}
(*own) -= 1;
if ( *own == 0 ){
*own = MAGIC_DEBUG;
delete own;
destroyPrivateData();
own = NULL;
}
}
}
#endif
void Bitmap::BlitToScreen() const {
// this->Blit( *Bitmap::Screen );
this->BlitToScreen(0, 0);
}
void Bitmap::load( const std::string & str ){
// releaseInternalBitmap();
internalLoadFile( str.c_str() );
}
Bitmap Bitmap::scaleBy(const double widthRatio, const double heightRatio) const {
return scaleTo(getWidth() * widthRatio, getHeight() * heightRatio);
}
void Bitmap::border( int min, int max, Color color ) const {
int w = getWidth();
int h = getHeight();
for (int i = min; i < max; i++){
rectangle(i, i, w - 1 - i, h - 1 - i, color);
}
}
void Bitmap::drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const {
drawHFlip(x, y, startWidth, startHeight, width, height, NULL, where);
}
void Bitmap::drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const {
Bitmap sub(*this, getWidth() - width, getHeight() - height, getWidth() - startWidth, getHeight() - startHeight);
sub.drawHFlip(x + startWidth, y + startHeight, filter, where);
}
void Bitmap::drawRotateCenter(const int x, const int y, const int angle, const Bitmap & where){
drawRotate(x - getWidth() / 2, y - getHeight() / 2, angle, where);
}
void Bitmap::drawCenter(const int x, const int y, const Bitmap & where) const {
draw(x - getWidth() / 2, y - getHeight() / 2, where);
}
void Bitmap::drawStretched(const Bitmap & who) const {
drawStretched(0, 0, who.getWidth(), who.getHeight(), who);
}
void Bitmap::draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const {
draw(x, y, startWidth, startHeight, width, height, NULL, where);
/*
Bitmap sub(*this, startWidth, startHeight, width, height);
sub.draw(x + startWidth, y + startHeight, where);
*/
}
void Bitmap::draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const {
Bitmap sub(*this, startWidth, startHeight, width, height);
sub.draw(x + startWidth, y + startHeight, filter, where);
}
void Bitmap::horizontalLine( const int x1, const int y, const int x2, const Graphics::Color color ) const{
this->hLine(x1, y, x2, color);
}
void Bitmap::equilateralTriangle(int x, int y, int angle, int size, Color color) const {
double radians = Util::radians(angle);
int x1 = x + size / 2 * cos(radians + 2 * Util::pi / 3);
int y1 = y + size / 2 * sin(radians + 2 * Util::pi / 3);
int x2 = x + size / 2 * cos(radians - 2 * Util::pi / 3);
int y2 = y + size / 2 * sin(radians - 2 * Util::pi / 3);
int x3 = x + size / 2 * cos(radians);
int y3 = y + size / 2 * sin(radians);
triangle(x1, y1, x2, y2, x3, y3, color);
}
Bitmap Bitmap::greyScale(){
Bitmap grey(getWidth(), getHeight());
for (int x = 0; x < getWidth(); x++){
for (int y = 0; y < getHeight(); y++){
Color pixel = getPixel(x, y);
int val = (int)((0.299*getRed(pixel) + 0.587*getGreen(pixel) + 0.114*getBlue(pixel) + 0.5) + 16);
if (val > 255){
val = 255;
}
grey.putPixel(x, y, makeColor(val, val, val));
}
}
return grey;
}
bool Bitmap::inRange(int x, int y) const {
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
getClipRect(x1, y1, x2, y2);
return (x >= x1 && x <= x2 &&
y >= y1 && y <= y2);
}
void Bitmap::drawMask( const int _x, const int _y, const Bitmap & where ){
Color mask = MaskColor();
for (int x = 0; x < getWidth(); x++){
for (int y = 0; y < getHeight(); y++){
if (getPixel(x,y) == mask){
where.putPixel(x+_x, y+_y, mask);
}
}
}
}
void Bitmap::set8BitMaskColor(const Color & color){
bit8MaskColor = color;
}
Color Bitmap::get8BitMaskColor(){
return bit8MaskColor;
}
void Bitmap::setFakeGraphicsMode(int width, int height){
initializeExtraStuff();
Screen = new Bitmap(width, height);
}
void Bitmap::Blit( const std::string & xpath ) const {
Bitmap duh(xpath);
duh.Blit(*this);
}
void Bitmap::Blit(const Bitmap & where) const {
this->Blit(0, 0, where);
}
void Bitmap::Blit(const int x, const int y, const Bitmap & where) const {
Blit(0, 0, x, y, where);
}
void Bitmap::Blit(const int mx, const int my, const int wx, const int wy, const Bitmap & where) const {
Blit(mx, my, getWidth(), getHeight(), wx, wy, where);
}
void Bitmap::BlitFromScreen(const int x, const int y) const {
Screen->Blit(x, y, getWidth(), getHeight(), 0, 0, *this);
}
//! min (borrowed from allegro)
static inline int Min(int x, int y){ return (((x) < (y)) ? (x) : (y)); }
//! max (borrowed from allegro)
static inline int Max(int x, int y){ return (((x) > (y)) ? (x) : (y)); }
//! mid (borrowed from allegro)
static inline int Mid(int x,int y,int z){ return (Max((x), Min((y), (z)))); }
int Bitmap::getScreenWidth(){
if (Screen != 0){
return Screen->getWidth();
}
return 0;
}
int Bitmap::getScreenHeight(){
if (Screen != 0){
return Screen->getHeight();
}
return 0;
}
void Bitmap::clear() const {
fill(makeColor(0, 0, 0));
}
void Bitmap::copy(const Bitmap & him){
resize(him.getWidth(), him.getHeight());
him.Blit(*this);
}
void Bitmap::Stretch( const Bitmap & where ) const {
if (getWidth() == where.getWidth() && getHeight() == where.getHeight()){
Blit(where);
} else {
Stretch(where, 0, 0, getWidth(), getHeight(), 0, 0, where.getWidth(), where.getHeight());
}
}
void Bitmap::StretchHqx(const Bitmap & where) const {
if (getWidth() == where.getWidth() && getHeight() == where.getHeight()){
Blit(where);
} else {
StretchHqx(where, 0, 0, getWidth(), getHeight(), 0, 0, where.getWidth(), where.getHeight());
}
}
void Bitmap::StretchXbr(const Bitmap & where) const {
if (getWidth() == where.getWidth() && getHeight() == where.getHeight()){
Blit(where);
} else {
StretchXbr(where, 0, 0, getWidth(), getHeight(), 0, 0, where.getWidth(), where.getHeight());
}
}
Bitmap Bitmap::aspectRatio(int aspectWidth, int aspectHeight) const {
double width = getWidth();
double height = getHeight();
double ratio = (double) aspectWidth / (double) aspectHeight;
width = (double) height * ratio;
if (width > getWidth()){
width = getWidth();
height = width / ratio;
}
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
return Bitmap(*this, x, y, (int) width, (int) height);
}
Color darken(Color color, double factor ){
int r = (int)((double)getRed(color) / factor);
int g = (int)((double)getGreen(color) / factor);
int b = (int)((double)getBlue(color) / factor);
return makeColor(r, g, b);
}
LitBitmap::LitBitmap(const Bitmap & b):
Bitmap(b){
int x1, y1, x2, y2;
b.getClipRect(x1, y1, x2, y2);
setClipRect(x1, y1, x2, y2);
}
LitBitmap::LitBitmap():
Bitmap(){
}
LitBitmap::~LitBitmap(){
}
LitBitmap Bitmap::lit() const {
return LitBitmap(*this);
}
TranslucentBitmap Bitmap::translucent() const {
return TranslucentBitmap(*this);
}
TranslucentBitmap Bitmap::translucent(int red, int green, int blue, int alpha) const {
transBlender(red, green, blue, alpha);
return TranslucentBitmap(*this);
}
TranslucentBitmap::TranslucentBitmap(const Bitmap & b):
Bitmap(b){
int x1, y1, x2, y2;
b.getClipRect(x1, y1, x2, y2);
setClipRect(x1, y1, x2, y2);
}
TranslucentBitmap::TranslucentBitmap():
Bitmap(){
}
TranslucentBitmap::~TranslucentBitmap(){
}
void TranslucentBitmap::fill(Color color) const {
Bitmap::applyTrans(color);
}
int StretchedBitmap::getWidth() const {
return width;
}
int StretchedBitmap::getHeight() const {
return height;
}
double StretchedBitmap::getScaleWidth() const {
return (double) where.getWidth() / (double) getWidth();
}
double StretchedBitmap::getScaleHeight() const {
return (double) where.getHeight() / (double) getHeight();
}
BlendPoint::BlendPoint(const Color & color, int length):
color(color),
length(length){
}
void blend_palette(Color * pal, int mp, const Color & startColor, const Color & endColor){
/*
ASSERT(pal);
ASSERT(mp != 0);
*/
int sc_r = Graphics::getRed(startColor);
int sc_g = Graphics::getGreen(startColor);
int sc_b = Graphics::getBlue(startColor);
int ec_r = Graphics::getRed(endColor);
int ec_g = Graphics::getGreen(endColor);
int ec_b = Graphics::getBlue(endColor);
for ( int q = 0; q < mp; q++ ) {
float j = (float)( q + 1 ) / (float)( mp );
int f_r = (int)( 0.5 + (float)( sc_r ) + (float)( ec_r-sc_r ) * j );
int f_g = (int)( 0.5 + (float)( sc_g ) + (float)( ec_g-sc_g ) * j );
int f_b = (int)( 0.5 + (float)( sc_b ) + (float)( ec_b-sc_b ) * j );
pal[q] = Graphics::makeColor( f_r, f_g, f_b );
}
}
std::vector<Color> blend_palette(const std::vector<BlendPoint> & in){
std::vector<Color> out;
int here = 0;
for (int i = 1; i < in.size(); i++){
const BlendPoint & start = in[here];
const BlendPoint & end = in[i];
Color * save = new Color[start.length];
blend_palette(save, start.length, start.color, end.color);
for (int use = 0; use < start.length; use++){
out.push_back(save[use]);
}
delete[] save;
here = i;
}
return out;
}
}
#ifdef USE_ALLEGRO
#include "allegro/bitmap.cpp"
#endif
#ifdef USE_SDL
#include "sdl/bitmap.cpp"
#endif
#ifdef USE_ALLEGRO5
-#include "allegro5/bitmap.cpp"
+#include "graphics/allegro5/bitmap.cpp"
#endif
diff --git a/src/input/linux_joystick.cpp b/src/input/linux_joystick.cpp
index 94c979b9..4e40dadd 100644
--- a/src/input/linux_joystick.cpp
+++ b/src/input/linux_joystick.cpp
@@ -1,390 +1,390 @@
#ifdef LINUX
/* based on
* jstest.c Version 1.2
*
* Copyright (c) 1996-1999 Vojtech Pavlik
*
* Sponsored by SuSE
*/
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <sstream>
#include <linux/input.h>
#include <linux/joystick.h>
-#include "linux_joystick.h"
+#include "r-tech1/input/linux_joystick.h"
#include "r-tech1/debug.h"
using namespace std;
static const char *axis_names[ABS_MAX + 1] = {
"X", "Y", "Z", "Rx", "Ry", "Rz", "Throttle", "Rudder",
"Wheel", "Gas", "Brake", "?", "?", "?", "?", "?",
"Hat0X", "Hat0Y", "Hat1X", "Hat1Y", "Hat2X", "Hat2Y", "Hat3X", "Hat3Y",
"?", "?", "?", "?", "?", "?", "?",
};
static const char *button_names[KEY_MAX - BTN_MISC + 1] = {
"Btn0", "Btn1", "Btn2", "Btn3", "Btn4", "Btn5", "Btn6", "Btn7", "Btn8", "Btn9", "?", "?", "?", "?", "?", "?",
"LeftBtn", "RightBtn", "MiddleBtn", "SideBtn", "ExtraBtn", "ForwardBtn", "BackBtn", "TaskBtn", "?", "?", "?", "?", "?", "?", "?", "?",
"Trigger", "ThumbBtn", "ThumbBtn2", "TopBtn", "TopBtn2", "PinkieBtn", "BaseBtn", "BaseBtn2", "BaseBtn3", "BaseBtn4", "BaseBtn5", "BaseBtn6", "BtnDead",
"BtnA", "BtnB", "BtnC", "BtnX", "BtnY", "BtnZ", "BtnTL", "BtnTR", "BtnTL2", "BtnTR2", "BtnSelect", "BtnStart", "BtnMode", "BtnThumbL", "BtnThumbR", "?",
"?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
"WheelBtn", "Gear up",
};
/* tries to open one /dev/input/jsX and return an open file descriptor */
static int read_joystick(){
for (int num = 0; num < 100; num++){
ostringstream name;
name << "/dev/input/js" << num;
string raw = name.str();
int fd = open(raw.c_str(), O_RDONLY);
if (fd >= 0){
return fd;
}
}
return -1;
}
LinuxJoystick::LinuxJoystick():
button(0),
axis(0){
file = read_joystick();
if (file == -1){
Global::debug(0) << "Could not open joystick" << endl;
} else {
Global::debug(1) << "Opened joystick " << endl;
/* grab useful info */
ioctl(file, JSIOCGVERSION, &version);
ioctl(file, JSIOCGAXES, &axes);
ioctl(file, JSIOCGBUTTONS, &buttons);
ioctl(file, JSIOCGNAME(NAME_LENGTH), name);
ioctl(file, JSIOCGAXMAP, axmap);
ioctl(file, JSIOCGBTNMAP, btnmap);
/* put joystick in nonblocking mode */
fcntl(file, F_SETFL, O_NONBLOCK);
axis = new int[axes];
memset(axis, 0, sizeof(int) * axes);
button = new char[buttons];
memset(button, 0, sizeof(char) * buttons);
Global::debug(1) << "Joystick axis: " << (int)axes << " buttons: " << (int)buttons << endl;
}
}
LinuxJoystick::~LinuxJoystick(){
delete[] axis;
delete[] button;
if (file != -1){
close(file);
}
}
void LinuxJoystick::poll(){
struct js_event js;
if (file == -1){
return;
}
/* from an email by Vojtech Pavlik:
* "if you #include <linux/joystick.h>, the struct is defined in such a way
* that gcc doesn't add padding."
*/
int bytes = read(file, &js, sizeof(struct js_event));
if (bytes == sizeof(struct js_event)){
Global::debug(4) << "Event: type " << (int)js.type << " time " << (int)js.time << " number " << (int)js.number << " value " << (int)js.value << endl;
if (errno != EAGAIN) {
perror("joystick: error reading");
return;
}
switch (js.type & ~JS_EVENT_INIT) {
case JS_EVENT_BUTTON:
button[js.number] = js.value;
break;
case JS_EVENT_AXIS:
axis[js.number] = js.value;
break;
}
}
}
/*
JoystickInput LinuxJoystick::readAll(){
JoystickInput input;
if (file == -1){
return input;
}
if (axes > 0){
if (axis[0] < 0){
input.left = true;
}
if (axis[0] > 0){
input.right = true;
}
if (axes > 1){
if (axis[1] < 0){
input.up = true;
}
if (axis[1] > 0){
input.down = true;
}
}
}
if (buttons > 0 && button[0]){
input.button1 = true;
}
if (buttons > 1 && button[1]){
input.button2 = true;
}
if (buttons > 2 && button[2]){
input.button3 = true;
}
if (buttons > 3 && button[3]){
input.button4 = true;
}
Global::debug(1) << "joystick input up " << input.up
<< " down " << input.down
<< " left " << input.left
<< " right " << input.right
<< " button1 " << input.button1
<< " button2 " << input.button2
<< " button3 " << input.button3
<< " button4 " << input.button4
<< endl;
return input;
}
*/
#if 0
int main (int argc, char **argv)
{
int fd, i;
unsigned char axes = 2;
unsigned char buttons = 2;
int version = 0x000800;
char name[NAME_LENGTH] = "Unknown";
uint16_t btnmap[KEY_MAX - BTN_MISC + 1];
uint8_t axmap[ABS_MAX + 1];
if (argc < 2 || argc > 3 || !strcmp("--help", argv[1])) {
puts("");
puts("Usage: jstest [<mode>] <device>");
puts("");
puts("Modes:");
puts(" --normal One-line mode showing immediate status");
puts(" --old Same as --normal, using 0.x interface");
puts(" --event Prints events as they come in");
puts(" --nonblock Same as --event, in nonblocking mode");
puts(" --select Same as --event, using select() call");
puts("");
return 1;
}
if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) {
perror("jstest");
return 1;
}
ioctl(fd, JSIOCGVERSION, &version);
ioctl(fd, JSIOCGAXES, &axes);
ioctl(fd, JSIOCGBUTTONS, &buttons);
ioctl(fd, JSIOCGNAME(NAME_LENGTH), name);
ioctl(fd, JSIOCGAXMAP, axmap);
ioctl(fd, JSIOCGBTNMAP, btnmap);
printf("Driver version is %d.%d.%d.\n",
version >> 16, (version >> 8) & 0xff, version & 0xff);
printf("Joystick (%s) has %d axes (", name, axes);
for (i = 0; i < axes; i++)
printf("%s%s", i > 0 ? ", " : "", axis_names[axmap[i]]);
puts(")");
printf("and %d buttons (", buttons);
for (i = 0; i < buttons; i++)
printf("%s%s", i > 0 ? ", " : "", button_names[btnmap[i] - BTN_MISC]);
puts(").");
printf("Testing ... (interrupt to exit)\n");
/*
* Old (0.x) interface.
*/
if ((argc == 2 && version < 0x010000) || !strcmp("--old", argv[1])) {
struct JS_DATA_TYPE js;
while (1) {
if (read(fd, &js, JS_RETURN) != JS_RETURN) {
perror("\njstest: error reading");
return 1;
}
printf("Axes: X:%3d Y:%3d Buttons: A:%s B:%s\r",
js.x, js.y, (js.buttons & 1) ? "on " : "off", (js.buttons & 2) ? "on " : "off");
fflush(stdout);
usleep(10000);
}
}
/*
* Event interface, single line readout.
*/
if (argc == 2 || !strcmp("--normal", argv[1])) {
int *axis;
char *button;
int i;
struct js_event js;
axis = calloc(axes, sizeof(int));
button = calloc(buttons, sizeof(char));
while (1) {
if (read(fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
perror("\njstest: error reading");
return 1;
}
switch(js.type & ~JS_EVENT_INIT) {
case JS_EVENT_BUTTON:
button[js.number] = js.value;
break;
case JS_EVENT_AXIS:
axis[js.number] = js.value;
break;
}
printf("\r");
if (axes) {
printf("Axes: ");
for (i = 0; i < axes; i++)
printf("%2d:%6d ", i, axis[i]);
}
if (buttons) {
printf("Buttons: ");
for (i = 0; i < buttons; i++)
printf("%2d:%s ", i, button[i] ? "on " : "off");
}
fflush(stdout);
}
}
/*
* Event interface, events being printed.
*/
if (!strcmp("--event", argv[1])) {
struct js_event js;
while (1) {
if (read(fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
perror("\njstest: error reading");
return 1;
}
printf("Event: type %d, time %d, number %d, value %d\n",
js.type, js.time, js.number, js.value);
fflush(stdout);
}
}
/*
* Reading in nonblocking mode.
*/
if (!strcmp("--nonblock", argv[1])) {
struct js_event js;
fcntl(fd, F_SETFL, O_NONBLOCK);
while (1) {
while (read(fd, &js, sizeof(struct js_event)) == sizeof(struct js_event)) {
printf("Event: type %d, time %d, number %d, value %d\n",
js.type, js.time, js.number, js.value);
}
if (errno != EAGAIN) {
perror("\njstest: error reading");
return 1;
}
usleep(10000);
}
}
/*
* Using select() on joystick fd.
*/
if (!strcmp("--select", argv[1])) {
struct js_event js;
struct timeval tv;
fd_set set;
tv.tv_sec = 1;
tv.tv_usec = 0;
while (1) {
FD_ZERO(&set);
FD_SET(fd, &set);
if (select(fd+1, &set, NULL, NULL, &tv)) {
if (read(fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
perror("\njstest: error reading");
return 1;
}
printf("Event: type %d, time %d, number %d, value %d\n",
js.type, js.time, js.number, js.value);
}
}
}
printf("jstest: unknown mode: %s\n", argv[1]);
return -1;
}
#endif
#endif
diff --git a/src/libs/7z/SConscript b/src/libs/7z/SConscript
index ff311af6..3b06b43d 100644
--- a/src/libs/7z/SConscript
+++ b/src/libs/7z/SConscript
@@ -1,19 +1,22 @@
-Import('use')
+Import('use', 'root')
#source = Split("""
#7zAlloc.c 7zBuf.c 7zBuf2.c 7zCrc.c 7zCrcOpt.c 7zDec.c 7zIn.c CpuArch.c LzmaDec.c Lzma2Dec.c Bra.c Bra86.c Bcj2.c 7zFile.c 7zStream.c
#""")
# Ppmd7.c
# Ppmd7Dec.c
-from scons import helpers
+import imp
+# from scons import helpers
+helpers_source = File("scons_rtech1/helpers.py", Dir(".").rel_path(Dir("#%s" % root)))
+helpers = imp.load_source("scons_rtech1.helpers", helpers_source.abspath)
import os.path
-modules = helpers.read_cmake_list(helpers.findFile('src/libs/7z/CMakeLists.txt'))
+modules = helpers.read_cmake_list(helpers.findFile(root, 'src/libs/7z/CMakeLists.txt'))
source = []
for module in modules:
#source.append(modules[module])
source.append(use.Object(modules[module]))
Return('source')
diff --git a/src/libs/dumb/SConscript b/src/libs/dumb/SConscript
index f47c4fb7..790e3459 100644
--- a/src/libs/dumb/SConscript
+++ b/src/libs/dumb/SConscript
@@ -1,76 +1,76 @@
import os
Import( 'env' )
# env = Environment( ENV = os.environ )
source = Split("""
it/itorder.c
it/xmeffect.c
it/itrender.c
it/itread2.c
it/itunload.c
it/loadmod.c
it/loads3m.c
it/loadxm2.c
it/itload2.c
it/readmod2.c
it/reads3m2.c
it/loadmod2.c
it/loadxm.c
it/loads3m2.c
it/itload.c
it/itmisc.c
it/itread.c
it/readxm.c
it/readmod.c
it/reads3m.c
it/readxm2.c
core/makeduh.c
core/unload.c
core/loadduh.c
core/rawsig.c
core/rendduh.c
core/rendsig.c
core/duhlen.c
core/duhtag.c
core/atexit.c
core/readduh.c
core/register.c
core/dumbfile.c
helpers/sampbuf.c
helpers/stdfile.c
helpers/clickrem.c
helpers/silence.c
helpers/memfile.c
helpers/resample.c
allegro/alplay.c
""");
unused = Split("""
allegro/datit.c
allegro/datxm.c
allegro/datduh.c
allegro/datitq.c
allegro/datmod.c
allegro/dats3m.c
allegro/datxmq.c
allegro/datmodq.c
allegro/dats3mq.c
allegro/datunld.c
allegro/packfile.c
""")
# helpers/resample.inc
# helpers/resamp2.inc
# helpers/resamp3.inc
env.Prepend(CPPPATH = ['include','include/internal'])
# env.Append( CCFLAGS = ['-Wall','-W','-Wwrite-strings','-Wstrict-prototypes','-Wmissing-declarations', '-O2', '-ffast-math', '-fomit-frame-pointer', '-Wno-missing-declarations'] )
-env.Append( CCFLAGS = ['-Wall','-W','-Wwrite-strings','-Wstrict-prototypes','-Wmissing-declarations', '-ffast-math', '-Wno-missing-declarations'] )
+env.Append(CCFLAGS = ['-Wall','-W','-Wwrite-strings','-Wstrict-prototypes','-Wmissing-declarations', '-ffast-math', '-Wno-missing-declarations'] )
-env.Append( CPPDEFINES = 'DUMB_DECLARE_DEPRECATED' )
+env.Append(CPPDEFINES = 'DUMB_DECLARE_DEPRECATED')
x = []
for s in map( lambda x: 'src/%s' % x, source ):
x.append(env.Object(s))
Return( 'x' )
diff --git a/src/sound/music-player.cpp b/src/sound/music-player.cpp
index d502ad7f..7d533560 100644
--- a/src/sound/music-player.cpp
+++ b/src/sound/music-player.cpp
@@ -1,1363 +1,1363 @@
#include "r-tech1/sound/music-renderer.h"
#include "r-tech1/sound/music-player.h"
#include "r-tech1/debug.h"
#include <iostream>
#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 "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/sound.cpp b/src/sound/sound.cpp
index 3dfa4e64..1139484a 100644
--- a/src/sound/sound.cpp
+++ b/src/sound/sound.cpp
@@ -1,56 +1,56 @@
#include <stdlib.h>
#include "r-tech1/sound/sound.h"
#ifdef USE_ALLEGRO5
-#include "allegro5/sound.cpp"
+#include "sound/allegro5/sound.cpp"
#endif
#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();
}

File Metadata

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

Event Timeline