EAPI=2
-inherit autotools eutils games
+inherit eutils games
DESCRIPTION="Alien-smashing action game"
HOMEPAGE="http://www.dogcows.com/yoink/"
-SRC_URI="http://www.dogcows.com/yoink/${P}.tar.bz2
+SRC_URI="http://www.dogcows.com/yoink/chrome/site/${P}.tar.bz2
http://eng.utah.edu/~mcgarvey/yoink/${P}.tar.bz2"
LICENSE="BSD-2 BSD LGPL-2.1 ZLIB"
SLOT="0"
KEYWORDS="amd64 x86"
-IUSE="debug double-precision gtk qt4 threads"
+IUSE="debug double-precision gtk hotload qt4 threads"
RDEPEND="dev-lang/lua
media-libs/libpng
media-libs/libvorbis
media-libs/openal
virtual/glu
- virtual/opengl"
+ virtual/opengl
+ gtk? ( x11-libs/gtk+:2 )
+ qt4? ( !gtk? ( x11-libs/qt-core:4 ) )"
DEPEND="${RDEPEND}
dev-libs/boost
dev-util/pkgconfig"
-src_prepare() {
- sed -i -e "/apps/d" -e "/pixmap/d" data/Makefile.am || die "sed failed"
- sed -i -e "/man/d" Makefile.am || die "sed failed"
-
- eautoreconf
-}
-
src_configure() {
egamesconf \
--disable-dependency-tracking \
$(use_enable debug) \
$(use_enable double-precision) \
+ $(use_enable hotload) \
$(use_enable threads) \
$(use_with gtk) \
$(use_with qt4)
}
src_install() {
- emake DESTDIR="${D}" install || die "emake install failed"
+ emake DESTDIR="${D}" install_man=no install || die "emake failed"
dodoc AUTHORS COPYING README TODO
doman doc/yoink.6
doicon data/yoink.png
--enable-clock_gettime use a very accurate timing function
--enable-debug compile in assertion checks and other debug helps
--enable-double-precision use larger floating-point numbers
- --enable-hotloading watch assets and automatically reload them
+ --enable-hotload automatically reload modified game assets
--enable-threads use threads for concurrency where appropriate
--with-gtk use the gtk2 toolkit (overrides --with-qt4)
config.USE_CLOCK_GETTIME = get_feature("clock_gettime")
config.USE_DOUBLE_PRECISION = get_feature("double-precision")
-config.USE_HOTLOADING = get_feature("hotloading")
+config.USE_HOTLOADING = get_feature("hotload")
config.USE_THREADS = get_feature("threads")
-config.PROFILING_ENABLED = get_feature("profile") and add_cflag("-pg")
-
-if get_package("gtk") then
- -- TODO
+if get_feature("profile") then
+ config.PROFILING_ENABLED = true
+ add_cflag("-pg")
+ LDFLAGS = LDFLAGS .. "-pg"
end
-if get_package("qt4") then
- -- TODO
-end
+if get_package("gtk") then config.USE_GTK = true end
+if get_package("qt4") then config.USE_QT4 = true end
--
texrep 1 1
crease 30.000000
numvert 34
-23 1 -7
-23 0 -7
-12 0 -7
-12 1 -7
-29 1 -7
-29 0 -7
-33 0 -7
-33 1 -7
-22 0 -7
-21 0 -7
-20 0 -7
-19 0 -7
-18 0 -7
-17 0 -7
-16 0 -7
-15 0 -7
-14 0 -7
-13 0 -7
-22 1 -7
-21 1 -7
-20 1 -7
-19 1 -7
-18 1 -7
-17 1 -7
-16 1 -7
-15 1 -7
-14 1 -7
-13 1 -7
-30 1 -7
-31 1 -7
-32 1 -7
-30 0 -7
-31 0 -7
-32 0 -7
+23 1 -3
+23 0 -3
+12 0 -3
+12 1 -3
+29 1 -3
+29 0 -3
+33 0 -3
+33 1 -3
+22 0 -3
+21 0 -3
+20 0 -3
+19 0 -3
+18 0 -3
+17 0 -3
+16 0 -3
+15 0 -3
+14 0 -3
+13 0 -3
+22 1 -3
+21 1 -3
+20 1 -3
+19 1 -3
+18 1 -3
+17 1 -3
+16 1 -3
+15 1 -3
+14 1 -3
+13 1 -3
+30 1 -3
+31 1 -3
+32 1 -3
+30 0 -3
+31 0 -3
+32 0 -3
numsurf 15
SURF 0x00
mat 1
texrep 1 1
crease 30.000000
numvert 74
-18 0 -6
18 0 -2
+18 0 2
+15 0 2
15 0 -2
-15 0 -6
+18 3 2
+15 3 2
18 3 -2
15 3 -2
-18 3 -6
-15 3 -6
+18 1 2
+18 2 2
+15 1 2
+15 2 2
18 1 -2
18 2 -2
15 1 -2
15 2 -2
-18 1 -6
-18 2 -6
-15 1 -6
-15 2 -6
-17 0 -2
-16 0 -2
-17 3 -2
-16 3 -2
-16 1 -2
-17 1 -2
-16 2 -2
-17 2 -2
-18 0 -5
-18 0 -4
-18 0 -3
-18 3 -3
-18 3 -4
-18 3 -5
-18 1 -3
-18 1 -4
-18 1 -5
-18 2 -3
-18 2 -4
-18 2 -5
-15 0 -3
-15 0 -4
-15 0 -5
-15 3 -3
-15 3 -4
-15 3 -5
-15 1 -3
-15 1 -4
-15 1 -5
-15 2 -3
-15 2 -4
-15 2 -5
-15 5.499999 -4.000002
-18 5.499999 -4.000002
-16 5.499999 -4.000002
-17 5.499999 -4.000002
-15 4 -5
-15 4 -4
-15 4 -3
-18 4 -5
-18 4 -4
-18 4 -3
-18 5 -4
-18 2.8 -1.8
-15 2.8 -1.8
-15 5 -4
-17 2.8 -1.8
-16 2.8 -1.8
-18 4.266666 -3.266667
-18 3.533333 -2.533333
-17 5 -4
-16 5 -4
-15 3.533333 -2.533334
-15 4.266666 -3.266667
-16 3.533333 -2.533334
-17 3.533333 -2.533333
-16 4.266666 -3.266667
-17 4.266666 -3.266667
+17 0 2
+16 0 2
+17 3 2
+16 3 2
+16 1 2
+17 1 2
+16 2 2
+17 2 2
+18 0 -1
+18 0 0
+18 0 1
+18 3 1
+18 3 0
+18 3 -1
+18 1 1
+18 1 0
+18 1 -1
+18 2 1
+18 2 0
+18 2 -1
+15 0 1
+15 0 0
+15 0 -1
+15 3 1
+15 3 0
+15 3 -1
+15 1 1
+15 1 0
+15 1 -1
+15 2 1
+15 2 0
+15 2 -1
+15 5.499999 -2e-06
+18 5.499999 -2e-06
+16 5.499999 -2e-06
+17 5.499999 -2e-06
+15 4 -1
+15 4 0
+15 4 1
+18 4 -1
+18 4 0
+18 4 1
+18 5 0
+18 2.8 2.2
+15 2.8 2.2
+15 5 0
+17 2.8 2.2
+16 2.8 2.2
+18 4.266666 0.733333
+18 3.533333 1.466667
+17 5 0
+16 5 0
+15 3.533333 1.466666
+15 4.266666 0.733333
+16 3.533333 1.466666
+17 3.533333 1.466667
+16 4.266666 0.733333
+17 4.266666 0.733333
numsurf 57
SURF 0x00
mat 2
SURF 0x00
mat 2
refs 3
-5 0.375 0.75
-54 0.5 0.5
-39 0.375 0.5
+5 0.499525219202 0.500041484833
+54 0.374525249004 0.750041484833
+39 0.374525249004 0.500041425228
SURF 0x00
mat 2
refs 3
mat 2
refs 3
56 0.25 0.5
-58 0.124999992549 0.5
-57 0.25 0.75
+58 0.25 0.75
+57 0.125 0.5
SURF 0x00
mat 2
refs 3
-55 0.375 0.75
-58 0.5 0.5
+55 0.5 0.5
+58 0.375 0.75
56 0.375 0.5
SURF 0x00
mat 2
refs 3
-6 0.375 0.75
-55 0.5 0.5
+6 0.5 0.5
+55 0.375 0.75
29 0.375 0.5
SURF 0x00
mat 2
L-Lawn
crease 30.000000
numvert 11
+6 0 2
+2 0 4
+2 0 2
+14 0 2
+5 0 -3
+15 0 -3
6 0 -2
-2 0 0
-2 0 -2
14 0 -2
-5 0 -7
-15 0 -7
-6 0 -6
-14 0 -6
-5 0 -2
-15 0 0
-5 0 0
+5 0 2
+15 0 4
+5 0 4
numsurf 6
SURF 0x30
mat 3
texrep 1 1
crease 30.000000
numvert 182
-12 0 -7
-5 0 -7
-5 8 -7
-12 8 -7
-3 8 -7
-12 0 -13
-12 0 -12
-12 0 -11
-12 0 -10
+12 0 -3
+5 0 -3
+5 8 -3
+12 8 -3
+3 8 -3
12 0 -9
12 0 -8
+12 0 -7
+12 0 -6
+12 0 -5
+12 0 -4
+12 8 -4
+12 8 -5
+12 8 -6
+12 8 -7
12 8 -8
12 8 -9
-12 8 -10
-12 8 -11
-12 8 -12
-12 8 -13
-3 8 -13
-3 8 -12
-3 8 -11
-3 8 -10
3 8 -9
3 8 -8
-5 1 -7
-5 2 -7
-5 3 -7
-5 4 -7
-5 5 -7
-5 6 -7
-5 7 -7
-12 1 -7
-12 2 -7
-12 3 -7
-12 4 -7
-12 5 -7
-12 6 -7
-12 7 -7
-12 1 -13
-12 2 -13
-12 3 -13
-12 4 -13
-12 5 -13
-12 6 -13
-12 7 -13
-12 7 -12
-12 6 -12
-12 5 -12
-12 4 -12
-12 3 -12
-12 2 -12
-12 1 -12
-12 7 -11
-12 6 -11
-12 5 -11
-12 4 -11
-12 3 -11
-12 2 -11
-12 1 -11
-12 1 -10
-12 2 -10
-12 3 -10
-12 4 -10
-12 5 -10
-12 6 -10
-12 7 -10
-12 7 -9
-12 6 -9
-12 5 -9
-12 4 -9
-12 3 -9
-12 2 -9
+3 8 -7
+3 8 -6
+3 8 -5
+3 8 -4
+5 1 -3
+5 2 -3
+5 3 -3
+5 4 -3
+5 5 -3
+5 6 -3
+5 7 -3
+12 1 -3
+12 2 -3
+12 3 -3
+12 4 -3
+12 5 -3
+12 6 -3
+12 7 -3
12 1 -9
+12 2 -9
+12 3 -9
+12 4 -9
+12 5 -9
+12 6 -9
+12 7 -9
12 7 -8
12 6 -8
12 5 -8
12 3 -8
12 2 -8
12 1 -8
-11 0 -7
-10 0 -7
-9 0 -7
-8 0 -7
-7 0 -7
-6 0 -7
-6 1 -7
-7 1 -7
-8 1 -7
-9 1 -7
-10 1 -7
-11 1 -7
-6 2 -7
-7 2 -7
-8 2 -7
-9 2 -7
-10 2 -7
-11 2 -7
-6 3 -7
-7 3 -7
-8 3 -7
-9 3 -7
-10 3 -7
-11 3 -7
-6 4 -7
-7 4 -7
-8 4 -7
-9 4 -7
-10 4 -7
-11 4 -7
-6 5 -7
-7 5 -7
-8 5 -7
-9 5 -7
-10 5 -7
-11 5 -7
-6 6 -7
-7 6 -7
-8 6 -7
-9 6 -7
-10 6 -7
-11 6 -7
-6 7 -7
-7 7 -7
-8 7 -7
-9 7 -7
-10 7 -7
-11 7 -7
-11 8 -13
-10 8 -13
-9 8 -13
-8 8 -13
-7 8 -13
-6 8 -13
-5 8 -13
-4 8 -13
-11 8 -12
-10 8 -12
-9 8 -12
-8 8 -12
-7 8 -12
-6 8 -12
-5 8 -12
-4 8 -12
-11 8 -11
-10 8 -11
-9 8 -11
-8 8 -11
-7 8 -11
-6 8 -11
-5 8 -11
-4 8 -11
-11 8 -10
-10 8 -10
-9 8 -10
-8 8 -10
-7 8 -10
-6 8 -10
-5 8 -10
-4 8 -10
+12 7 -7
+12 6 -7
+12 5 -7
+12 4 -7
+12 3 -7
+12 2 -7
+12 1 -7
+12 1 -6
+12 2 -6
+12 3 -6
+12 4 -6
+12 5 -6
+12 6 -6
+12 7 -6
+12 7 -5
+12 6 -5
+12 5 -5
+12 4 -5
+12 3 -5
+12 2 -5
+12 1 -5
+12 7 -4
+12 6 -4
+12 5 -4
+12 4 -4
+12 3 -4
+12 2 -4
+12 1 -4
+11 0 -3
+10 0 -3
+9 0 -3
+8 0 -3
+7 0 -3
+6 0 -3
+6 1 -3
+7 1 -3
+8 1 -3
+9 1 -3
+10 1 -3
+11 1 -3
+6 2 -3
+7 2 -3
+8 2 -3
+9 2 -3
+10 2 -3
+11 2 -3
+6 3 -3
+7 3 -3
+8 3 -3
+9 3 -3
+10 3 -3
+11 3 -3
+6 4 -3
+7 4 -3
+8 4 -3
+9 4 -3
+10 4 -3
+11 4 -3
+6 5 -3
+7 5 -3
+8 5 -3
+9 5 -3
+10 5 -3
+11 5 -3
+6 6 -3
+7 6 -3
+8 6 -3
+9 6 -3
+10 6 -3
+11 6 -3
+6 7 -3
+7 7 -3
+8 7 -3
+9 7 -3
+10 7 -3
+11 7 -3
11 8 -9
10 8 -9
9 8 -9
6 8 -8
5 8 -8
4 8 -8
-4 8 -7
11 8 -7
10 8 -7
9 8 -7
8 8 -7
7 8 -7
6 8 -7
+5 8 -7
+4 8 -7
+11 8 -6
+10 8 -6
+9 8 -6
+8 8 -6
+7 8 -6
+6 8 -6
+5 8 -6
+4 8 -6
+11 8 -5
+10 8 -5
+9 8 -5
+8 8 -5
+7 8 -5
+6 8 -5
+5 8 -5
+4 8 -5
+11 8 -4
+10 8 -4
+9 8 -4
+8 8 -4
+7 8 -4
+6 8 -4
+5 8 -4
+4 8 -4
+4 8 -3
+11 8 -3
+10 8 -3
+9 8 -3
+8 8 -3
+7 8 -3
+6 8 -3
numsurf 158
SURF 0x00
mat 4
texrep 1 1
crease 30.000000
numvert 45
-14 0 -6
14 0 -2
+14 0 2
+6 0 2
6 0 -2
-6 0 -6
+13 0 2
+12 0 2
+11 0 2
+10 0 2
+9 0 2
+8 0 2
+7 0 2
13 0 -2
12 0 -2
11 0 -2
9 0 -2
8 0 -2
7 0 -2
-13 0 -6
-12 0 -6
-11 0 -6
-10 0 -6
-9 0 -6
-8 0 -6
-7 0 -6
-14 0 -5
-14 0 -4
-14 0 -3
-6 0 -3
-6 0 -4
-6 0 -5
-13 0 -5
-13 0 -4
-13 0 -3
-12 0 -5
-12 0 -4
-12 0 -3
-11 0 -5
-11 0 -4
-11 0 -3
-10 0 -5
-10 0 -4
-10 0 -3
-9 0 -3
-9 0 -4
-9 0 -5
-8 0 -3
-8 0 -4
-8 0 -5
-7 0 -3
-7 0 -4
-7 0 -5
+14 0 -1
+14 0 0
+14 0 1
+6 0 1
+6 0 0
+6 0 -1
+13 0 -1
+13 0 0
+13 0 1
+12 0 -1
+12 0 0
+12 0 1
+11 0 -1
+11 0 0
+11 0 1
+10 0 -1
+10 0 0
+10 0 1
+9 0 1
+9 0 0
+9 0 -1
+8 0 1
+8 0 0
+8 0 -1
+7 0 1
+7 0 0
+7 0 -1
numsurf 32
SURF 0x00
mat 1
texrep 1 1
crease 30.000000
numvert 201
-5 0 -7
-5 0 -2
-0 0 -2
-0 15 -7
-0 15 -2
-5 15 -2
-5 15 -7
-0 15 -6
-0 15 -5
-0 15 -4
+5 0 -3
+5 0 2
+0 0 2
0 15 -3
+0 15 2
+5 15 2
5 15 -3
-5 15 -4
-5 15 -5
-5 15 -6
-5 0 -6
-5 0 -5
-5 0 -4
-5 0 -3
-1 15 -7
-2 15 -7
-3 15 -7
-4 15 -7
-1 15 -2
-2 15 -2
-3 15 -2
-4 15 -2
-1 0 -2
-2 0 -2
-3 0 -2
-4 0 -2
-1 15 -6
-2 15 -6
-3 15 -6
-4 15 -6
-1 15 -5
-2 15 -5
-3 15 -5
-4 15 -5
-1 15 -4
-2 15 -4
-3 15 -4
-4 15 -4
+0 15 -2
+0 15 -1
+0 15 0
+0 15 1
+5 15 1
+5 15 0
+5 15 -1
+5 15 -2
+5 0 -2
+5 0 -1
+5 0 0
+5 0 1
1 15 -3
2 15 -3
3 15 -3
4 15 -3
-0 14 -2
-0 13 -2
-0 12 -2
-0 11 -2
-0 10 -2
-0 9 -2
-0 8 -2
-0 7 -2
-0 6 -2
-0 5 -2
-0 4 -2
-0 3 -2
-0 2 -2
-0 1 -2
-5 14 -7
-5 13 -7
-5 12 -7
-5 11 -7
-5 10 -7
-5 9 -7
-5 8 -7
-5 7 -7
-5 6 -7
-5 5 -7
-5 4 -7
-5 3 -7
-5 2 -7
-5 1 -7
-5 14 -2
-5 13 -2
-5 12 -2
-5 11 -2
-5 10 -2
-5 9 -2
-5 8 -2
-5 7 -2
-5 6 -2
-5 5 -2
-5 4 -2
-5 3 -2
-5 2 -2
-5 1 -2
-5 14 -6
-5 13 -6
-5 12 -6
-5 11 -6
-5 10 -6
-5 9 -6
-5 8 -6
-5 7 -6
-5 6 -6
-5 5 -6
-5 4 -6
-5 3 -6
-5 2 -6
-5 1 -6
-5 14 -5
-5 13 -5
-5 12 -5
-5 11 -5
-5 10 -5
-5 9 -5
-5 8 -5
-5 7 -5
-5 6 -5
-5 5 -5
-5 4 -5
-5 3 -5
-5 2 -5
-5 1 -5
-5 14 -4
-5 13 -4
-5 12 -4
-5 11 -4
-5 10 -4
-5 9 -4
-5 8 -4
-5 7 -4
-5 6 -4
-5 5 -4
-5 4 -4
-5 3 -4
-5 2 -4
-5 1 -4
+1 15 2
+2 15 2
+3 15 2
+4 15 2
+1 0 2
+2 0 2
+3 0 2
+4 0 2
+1 15 -2
+2 15 -2
+3 15 -2
+4 15 -2
+1 15 -1
+2 15 -1
+3 15 -1
+4 15 -1
+1 15 0
+2 15 0
+3 15 0
+4 15 0
+1 15 1
+2 15 1
+3 15 1
+4 15 1
+0 14 2
+0 13 2
+0 12 2
+0 11 2
+0 10 2
+0 9 2
+0 8 2
+0 7 2
+0 6 2
+0 5 2
+0 4 2
+0 3 2
+0 2 2
+0 1 2
5 14 -3
5 13 -3
5 12 -3
5 3 -3
5 2 -3
5 1 -3
-4 1 -2
-4 2 -2
-4 3 -2
-4 4 -2
-4 5 -2
-4 6 -2
-4 7 -2
-4 8 -2
-4 9 -2
-4 10 -2
-4 11 -2
-4 12 -2
-4 13 -2
-4 14 -2
-3 14 -2
-3 13 -2
-3 12 -2
-3 11 -2
-3 10 -2
-3 9 -2
-3 8 -2
-3 7 -2
-3 6 -2
-3 5 -2
-3 4 -2
-3 3 -2
-3 2 -2
-3 1 -2
-2 1 -2
-2 2 -2
-2 3 -2
-2 4 -2
-2 5 -2
-2 6 -2
-2 7 -2
-2 8 -2
-2 9 -2
-2 10 -2
-2 11 -2
-2 12 -2
-2 13 -2
-2 14 -2
-1 1 -2
-1 2 -2
-1 3 -2
-1 4 -2
-1 5 -2
-1 6 -2
-1 7 -2
-1 8 -2
-1 9 -2
-1 10 -2
-1 11 -2
-1 12 -2
-1 13 -2
-1 14 -2
-numsurf 181
-SURF 0x00
-mat 4
-refs 4
-1 -1.49011611938e-08 1.0
-0 0.0 0.75
-16 0.25 0.75
-17 0.25 1.0
-SURF 0x00
-mat 4
-refs 3
-16 -1.49011611938e-08 1.0
-0 0.0 0.75
-15 0.25 0.75
-SURF 0x00
-mat 4
-refs 3
-17 -1.49011611938e-08 1.0
-18 0.0 0.75
-1 0.25 0.75
-SURF 0x00
-mat 4
-refs 4
-29 -1.49011611938e-08 1.0
-28 0.0 0.75
-2 0.25 0.75
-1 0.25 1.0
-SURF 0x00
-mat 4
-refs 3
-30 -1.49011611938e-08 1.0
-29 0.0 0.75
-1 0.25 0.75
-SURF 0x00
-mat 4
-refs 3
-28 -1.49011611938e-08 1.0
-27 0.0 0.75
-2 0.25 0.75
+5 14 2
+5 13 2
+5 12 2
+5 11 2
+5 10 2
+5 9 2
+5 8 2
+5 7 2
+5 6 2
+5 5 2
+5 4 2
+5 3 2
+5 2 2
+5 1 2
+5 14 -2
+5 13 -2
+5 12 -2
+5 11 -2
+5 10 -2
+5 9 -2
+5 8 -2
+5 7 -2
+5 6 -2
+5 5 -2
+5 4 -2
+5 3 -2
+5 2 -2
+5 1 -2
+5 14 -1
+5 13 -1
+5 12 -1
+5 11 -1
+5 10 -1
+5 9 -1
+5 8 -1
+5 7 -1
+5 6 -1
+5 5 -1
+5 4 -1
+5 3 -1
+5 2 -1
+5 1 -1
+5 14 0
+5 13 0
+5 12 0
+5 11 0
+5 10 0
+5 9 0
+5 8 0
+5 7 0
+5 6 0
+5 5 0
+5 4 0
+5 3 0
+5 2 0
+5 1 0
+5 14 1
+5 13 1
+5 12 1
+5 11 1
+5 10 1
+5 9 1
+5 8 1
+5 7 1
+5 6 1
+5 5 1
+5 4 1
+5 3 1
+5 2 1
+5 1 1
+4 1 2
+4 2 2
+4 3 2
+4 4 2
+4 5 2
+4 6 2
+4 7 2
+4 8 2
+4 9 2
+4 10 2
+4 11 2
+4 12 2
+4 13 2
+4 14 2
+3 14 2
+3 13 2
+3 12 2
+3 11 2
+3 10 2
+3 9 2
+3 8 2
+3 7 2
+3 6 2
+3 5 2
+3 4 2
+3 3 2
+3 2 2
+3 1 2
+2 1 2
+2 2 2
+2 3 2
+2 4 2
+2 5 2
+2 6 2
+2 7 2
+2 8 2
+2 9 2
+2 10 2
+2 11 2
+2 12 2
+2 13 2
+2 14 2
+1 1 2
+1 2 2
+1 3 2
+1 4 2
+1 5 2
+1 6 2
+1 7 2
+1 8 2
+1 9 2
+1 10 2
+1 11 2
+1 12 2
+1 13 2
+1 14 2
+numsurf 175
SURF 0x00
mat 4
refs 4
texrep 1 1
crease 30.000000
numvert 4
-12.7 3 -6.46203
-12.7 0 -6.46203
-15.7 0 -6.46203
-15.7 3 -6.46203
+12.7 3 -2.46203
+12.7 0 -2.46203
+15.7 0 -2.46203
+15.7 3 -2.46203
numsurf 1
SURF 0x00
mat 5
texrep 1 1
crease 30.000000
numvert 48
+14 0.5 2
14 0.5 -2
-14 0.5 -6
-6 0.5 -6
6 0.5 -2
-14 0 -6
-6 0 -6
+6 0.5 2
14 0 -2
6 0 -2
+14 0 2
+6 0 2
+13 0.5 2
+12 0.5 2
+11 0.5 2
+10 0.5 2
+9 0.5 2
+8 0.5 2
+7 0.5 2
13 0.5 -2
12 0.5 -2
11 0.5 -2
9 0.5 -2
8 0.5 -2
7 0.5 -2
-13 0.5 -6
-12 0.5 -6
-11 0.5 -6
-10 0.5 -6
-9 0.5 -6
-8 0.5 -6
-7 0.5 -6
+13 0 2
+12 0 2
+11 0 2
+10 0 2
+9 0 2
+8 0 2
+7 0 2
13 0 -2
12 0 -2
11 0 -2
9 0 -2
8 0 -2
7 0 -2
-13 0 -6
-12 0 -6
-11 0 -6
-10 0 -6
-9 0 -6
-8 0 -6
-7 0 -6
-14 0.5 -3
-14 0.5 -4
-14 0.5 -5
-6 0.5 -5
-6 0.5 -4
-6 0.5 -3
-14 0 -5
-14 0 -4
-14 0 -3
-6 0 -5
-6 0 -4
-6 0 -3
+14 0.5 1
+14 0.5 0
+14 0.5 -1
+6 0.5 -1
+6 0.5 0
+6 0.5 1
+14 0 -1
+14 0 0
+14 0 1
+6 0 -1
+6 0 0
+6 0 1
numsurf 24
SURF 0x30
mat 1
texrep 1 1
crease 30.000000
numvert 90
-28 0 -10
-28 0 -7
-24 0 -7
-24 0 -10
-28 4 -7
-24 4 -7
-28 4 -10
-24 4 -10
-26 6 -7
-26 6 -10
-26 6.5 -7
-26 6.5 -10
-28 0 -9
-28 0 -8
-24 0 -8
-24 0 -9
-28 4 -8
-28 4 -9
-24 4 -8
-24 4 -9
-26 6 -8
-26 6 -9
-26 6.5 -8
-26 6.5 -9
-28 1 -7
-28 2 -7
-28 3 -7
-24 1 -7
-24 2 -7
-24 3 -7
-28 1 -10
-28 2 -10
-28 3 -10
-24 1 -10
-24 2 -10
-24 3 -10
-28 1 -8
-28 2 -8
-28 3 -8
-28 3 -9
-28 2 -9
-28 1 -9
-24 1 -9
-24 2 -9
-24 3 -9
-24 1 -8
-24 2 -8
-24 3 -8
-27 0 -7
-26 0 -7
-25 0 -7
-27 4 -7
-26 4 -7
-25 4 -7
-25 1 -7
-26 1 -7
-27 1 -7
-27 2 -7
-26 2 -7
-25 2 -7
-25 3 -7
-26 3 -7
-27 3 -7
-25 5 -7
-27 5 -7
-26 5 -7
-23.878679 3.87868 -7
-23.878679 3.87868 -10
-28.121321 3.87868 -7
-28.121321 3.87868 -10
-24.585787 4.585787 -7
-25.292892 5.292893 -7
-25.292892 5.292893 -10
-24.585787 4.585787 -10
-23.878679 3.87868 -8
-23.878679 3.87868 -9
-24.585787 4.585787 -8
-25.292892 5.292893 -8
-24.585787 4.585787 -9
-25.292892 5.292893 -9
-27.414213 4.585786 -10
-26.707108 5.292893 -10
-28.121321 3.87868 -8
-28.121321 3.87868 -9
-27.414213 4.585787 -7
-26.707108 5.292893 -7
-26.707108 5.292893 -8
-27.414213 4.585786 -8
-26.707108 5.292893 -9
-27.414213 4.585786 -9
+28 0 -6
+28 0 -3
+24 0 -3
+24 0 -6
+28 4 -3
+24 4 -3
+28 4 -6
+24 4 -6
+26 6 -3
+26 6 -6
+26 6.5 -3
+26 6.5 -6
+28 0 -5
+28 0 -4
+24 0 -4
+24 0 -5
+28 4 -4
+28 4 -5
+24 4 -4
+24 4 -5
+26 6 -4
+26 6 -5
+26 6.5 -4
+26 6.5 -5
+28 1 -3
+28 2 -3
+28 3 -3
+24 1 -3
+24 2 -3
+24 3 -3
+28 1 -6
+28 2 -6
+28 3 -6
+24 1 -6
+24 2 -6
+24 3 -6
+28 1 -4
+28 2 -4
+28 3 -4
+28 3 -5
+28 2 -5
+28 1 -5
+24 1 -5
+24 2 -5
+24 3 -5
+24 1 -4
+24 2 -4
+24 3 -4
+27 0 -3
+26 0 -3
+25 0 -3
+27 4 -3
+26 4 -3
+25 4 -3
+25 1 -3
+26 1 -3
+27 1 -3
+27 2 -3
+26 2 -3
+25 2 -3
+25 3 -3
+26 3 -3
+27 3 -3
+25 5 -3
+27 5 -3
+26 5 -3
+23.878679 3.87868 -3
+23.878679 3.87868 -6
+28.121321 3.87868 -3
+28.121321 3.87868 -6
+24.585787 4.585787 -3
+25.292892 5.292893 -3
+25.292892 5.292893 -6
+24.585787 4.585787 -6
+23.878679 3.87868 -4
+23.878679 3.87868 -5
+24.585787 4.585787 -4
+25.292892 5.292893 -4
+24.585787 4.585787 -5
+25.292892 5.292893 -5
+27.414213 4.585786 -6
+26.707108 5.292893 -6
+28.121321 3.87868 -4
+28.121321 3.87868 -5
+27.414213 4.585787 -3
+26.707108 5.292893 -3
+26.707108 5.292893 -4
+27.414213 4.585786 -4
+26.707108 5.292893 -5
+27.414213 4.585786 -5
numsurf 67
SURF 0x20
mat 2
SURF 0x00
mat 2
refs 3
-8 0.5 0.5
+8 0.375 0.75
65 0.375 0.5
-64 0.375 0.75
+64 0.5 0.5
SURF 0x00
mat 2
refs 4
mat 2
refs 4
52 0.375 0.5
-65 0.25 0.5
+65 0.375 0.75
63 0.25 0.75
-53 0.375 0.75
+53 0.25 0.5
SURF 0x00
mat 2
refs 3
-4 0.375 0.75
-64 0.5 0.5
+4 0.5 0.5
+64 0.375 0.75
51 0.375 0.5
SURF 0x00
mat 2
M-Lawn
crease 30.000000
numvert 24
-31 0 -2
-31 0 0
-15 0 0
+31 0 2
+31 0 4
+15 0 4
+15 0 2
+23 0 -3
+23 0 -2
15 0 -2
-23 0 -7
-23 0 -6
-15 0 -6
-15 0 -7
-18 0 -6
-18 0 -5
-19 0 -5
-19 0 -6
-19 0 -4
-19 0 -2
+15 0 -3
18 0 -2
-18 0 -4
-28 0 -5
-28 0 -3
-24 0 -3
-24 0 -5
-33 0 -7
-33 0 -6
-29 0 -6
-29 0 -7
+18 0 -1
+19 0 -1
+19 0 -2
+19 0 0
+19 0 2
+18 0 2
+18 0 0
+28 0 -1
+28 0 1
+24 0 1
+24 0 -1
+33 0 -3
+33 0 -2
+29 0 -2
+29 0 -3
numsurf 6
SURF 0x00
mat 3
texrep 1 1
crease 30.000000
numvert 168
-38 0 -9
-38 0 -3
+38 0 -5
+38 0 1
+33 0 1
+33 0 -5
+33 0 0
+33 0 -1
+33 0 -2
33 0 -3
-33 0 -9
33 0 -4
-33 0 -5
-33 0 -6
-33 0 -7
-33 0 -8
-33 1 -3
-33 2 -3
-33 3 -3
-33 4 -3
-33 5 -3
+33 1 1
+33 2 1
+33 3 1
+33 4 1
+33 5 1
+33 6 1
+38 1 -5
+38 2 -5
+38 3 -5
+38 4 -5
+38 5 -5
+38 6 -5
+38 1 1
+38 2 1
+38 3 1
+38 4 1
+38 5 1
+38 6 1
+33 6 -5
+33 5 -5
+33 4 -5
+33 3 -5
+33 2 -5
+33 1 -5
+33 6 0
+33 5 0
+33 4 0
+33 3 0
+33 2 0
+33 1 0
+33 6 -1
+33 5 -1
+33 4 -1
+33 3 -1
+33 2 -1
+33 1 -1
+33 6 -2
+33 5 -2
+33 4 -2
+33 3 -2
+33 2 -2
+33 1 -2
33 6 -3
-38 1 -9
-38 2 -9
-38 3 -9
-38 4 -9
-38 5 -9
-38 6 -9
-38 1 -3
-38 2 -3
-38 3 -3
-38 4 -3
-38 5 -3
-38 6 -3
-33 6 -9
-33 5 -9
-33 4 -9
-33 3 -9
-33 2 -9
-33 1 -9
+33 5 -3
+33 4 -3
+33 3 -3
+33 2 -3
+33 1 -3
33 6 -4
33 5 -4
33 4 -4
33 3 -4
33 2 -4
33 1 -4
-33 6 -5
-33 5 -5
-33 4 -5
-33 3 -5
-33 2 -5
-33 1 -5
-33 6 -6
-33 5 -6
-33 4 -6
-33 3 -6
-33 2 -6
-33 1 -6
-33 6 -7
-33 5 -7
-33 4 -7
-33 3 -7
-33 2 -7
-33 1 -7
-33 6 -8
-33 5 -8
-33 4 -8
-33 3 -8
-33 2 -8
-33 1 -8
-37 0 -3
-36 0 -3
-35 0 -3
-34 0 -3
-34 1 -3
-35 1 -3
-36 1 -3
-37 1 -3
-34 2 -3
-35 2 -3
-36 2 -3
-37 2 -3
-37 3 -3
-36 3 -3
-35 3 -3
-34 3 -3
-34 4 -3
-35 4 -3
-36 4 -3
-37 4 -3
-34 5 -3
-35 5 -3
-36 5 -3
-37 5 -3
-37 6 -3
-36 6 -3
-35 6 -3
-34 6 -3
-38 0 -8
-38 0 -7
-38 0 -6
-38 0 -5
+37 0 1
+36 0 1
+35 0 1
+34 0 1
+34 1 1
+35 1 1
+36 1 1
+37 1 1
+34 2 1
+35 2 1
+36 2 1
+37 2 1
+37 3 1
+36 3 1
+35 3 1
+34 3 1
+34 4 1
+35 4 1
+36 4 1
+37 4 1
+34 5 1
+35 5 1
+36 5 1
+37 5 1
+37 6 1
+36 6 1
+35 6 1
+34 6 1
38 0 -4
+38 0 -3
+38 0 -2
+38 0 -1
+38 0 0
+38 1 0
+38 1 -1
+38 1 -2
+38 1 -3
38 1 -4
-38 1 -5
-38 1 -6
-38 1 -7
-38 1 -8
+38 2 0
+38 2 -1
+38 2 -2
+38 2 -3
38 2 -4
-38 2 -5
-38 2 -6
-38 2 -7
-38 2 -8
+38 3 0
+38 3 -1
+38 3 -2
+38 3 -3
38 3 -4
-38 3 -5
-38 3 -6
-38 3 -7
-38 3 -8
-38 4 -8
-38 4 -7
-38 4 -6
-38 4 -5
38 4 -4
-38 5 -8
-38 5 -7
-38 5 -6
-38 5 -5
+38 4 -3
+38 4 -2
+38 4 -1
+38 4 0
38 5 -4
+38 5 -3
+38 5 -2
+38 5 -1
+38 5 0
+38 6 0
+38 6 -1
+38 6 -2
+38 6 -3
38 6 -4
-38 6 -5
-38 6 -6
-38 6 -7
-38 6 -8
-33 7 -9
-34 7 -9
-35 7 -9
-36 7 -9
-37 7 -9
-38 7 -9
-38 7 -8
-38 7 -7
-38 7 -6
+33 7 -5
+34 7 -5
+35 7 -5
+36 7 -5
+37 7 -5
38 7 -5
38 7 -4
38 7 -3
+38 7 -2
+38 7 -1
+38 7 0
+38 7 1
+33 7 1
+34 7 1
+35 7 1
+36 7 1
+37 7 1
+33 7 -4
33 7 -3
-34 7 -3
-35 7 -3
+33 7 -2
+33 7 -1
+33 7 0
36 7 -3
37 7 -3
-33 7 -8
-33 7 -7
-33 7 -6
-33 7 -5
-33 7 -4
-36 7 -7
-37 7 -7
-37 7 -8
-36 7 -8
-35 7 -7
-35 7 -8
-34 7 -7
-34 7 -8
-36 7 -6
-37 7 -6
-35 7 -6
-34 7 -6
-36 7 -5
-37 7 -5
-35 7 -5
-34 7 -5
-36 7 -4
37 7 -4
+36 7 -4
+35 7 -3
35 7 -4
+34 7 -3
34 7 -4
+36 7 -2
+37 7 -2
+35 7 -2
+34 7 -2
+36 7 -1
+37 7 -1
+35 7 -1
+34 7 -1
+36 7 0
+37 7 0
+35 7 0
+34 7 0
numsurf 149
SURF 0x00
mat 4
texrep 1 1
crease 30.000000
numvert 87
+33 0 4
+33 0 3
+33 0 2
+33 0 1
33 0 0
33 0 -1
33 0 -2
-33 0 -3
-33 0 -4
-33 0 -5
-33 0 -6
-18 0 -4
-18 0 -5
-31 0 0
+18 0 0
+18 0 -1
+31 0 4
+32 0 4
+29 0 -3
+28 0 -3
+27 0 -3
+26 0 -3
+25 0 -3
+24 0 -3
+23 0 -3
+32 0 3
+31 0 3
+19 0 2
+20 0 2
+21 0 2
+22 0 2
+23 0 2
+24 0 2
+25 0 2
+26 0 2
+27 0 2
+28 0 2
+29 0 2
+30 0 2
+31 0 2
+32 0 2
+32 0 1
+31 0 1
+30 0 1
+29 0 1
+28 0 1
+27 0 1
+26 0 1
+25 0 1
+24 0 1
+23 0 1
+22 0 1
+21 0 1
+20 0 1
+19 0 1
32 0 0
-29 0 -7
-28 0 -7
-27 0 -7
-26 0 -7
-25 0 -7
-24 0 -7
-23 0 -7
+31 0 0
+30 0 0
+29 0 0
+28 0 0
+24 0 0
+23 0 0
+22 0 0
+21 0 0
+20 0 0
+19 0 0
32 0 -1
31 0 -1
+30 0 -1
+29 0 -1
+28 0 -1
+27 0 -1
+26 0 -1
+25 0 -1
+24 0 -1
+23 0 -1
+22 0 -1
+21 0 -1
+20 0 -1
+19 0 -1
19 0 -2
20 0 -2
21 0 -2
30 0 -2
31 0 -2
32 0 -2
-32 0 -3
-31 0 -3
-30 0 -3
-29 0 -3
-28 0 -3
-27 0 -3
-26 0 -3
-25 0 -3
-24 0 -3
-23 0 -3
-22 0 -3
-21 0 -3
-20 0 -3
-19 0 -3
-32 0 -4
-31 0 -4
-30 0 -4
-29 0 -4
-28 0 -4
-24 0 -4
-23 0 -4
-22 0 -4
-21 0 -4
-20 0 -4
-19 0 -4
-32 0 -5
-31 0 -5
-30 0 -5
-29 0 -5
-28 0 -5
-27 0 -5
-26 0 -5
-25 0 -5
-24 0 -5
-23 0 -5
-22 0 -5
-21 0 -5
-20 0 -5
-19 0 -5
-19 0 -6
-20 0 -6
-21 0 -6
-22 0 -6
-23 0 -6
-24 0 -6
-25 0 -6
-26 0 -6
-27 0 -6
-28 0 -6
-29 0 -6
-30 0 -6
-31 0 -6
-32 0 -6
numsurf 59
SURF 0x10
mat 1
texrep 1 1
crease 30.000000
numvert 16
-27 3 -4.5
-27 0 -4.5
-24 0 -4.5
-24 3 -4.5
-24 3 -4.5
-24 0 -4.5
-27 0 -4.5
-27 3 -4.5
-28.299999 3 -3.46203
-28.299999 0 -3.46203
-25.299999 0 -3.46203
-25.299999 3 -3.46203
-25.299999 3 -3.46203
-25.299999 0 -3.46203
-28.299999 0 -3.46203
-28.299999 3 -3.46203
+27 3 -0.5
+27 0 -0.5
+24 0 -0.5
+24 3 -0.5
+24 3 -0.5
+24 0 -0.5
+27 0 -0.5
+27 3 -0.5
+28.299999 3 0.53797
+28.299999 0 0.53797
+25.299999 0 0.53797
+25.299999 3 0.53797
+25.299999 3 0.53797
+25.299999 0 0.53797
+28.299999 0 0.53797
+28.299999 3 0.53797
numsurf 4
SURF 0x00
mat 5
texrep 1 1
crease 30.000000
numvert 88
-24 0.5 -4
-28 0.5 -4
-24 0.5 -5
-25 0.5 -5
-26 0.5 -5
-27 0.5 -5
-28 0.5 -5
-24 0.5 -3
-25 0.5 -3
-26 0.5 -3
-27 0.5 -3
-28 0.5 -3
-24 0 -5
-25 0 -5
-26 0 -5
-27 0 -5
-28 0 -5
-24 0 -4
-28 0 -4
-24 0 -3
-25 0 -3
-26 0 -3
-27 0 -3
-28 0 -3
-23 0.5 -7
-29 0.5 -7
-19 0.5 -3
-31 0.5 -1
-31 0.5 0
-33 0.5 -6
-32 0.5 -6
-31 0.5 -6
-30 0.5 -6
-29 0.5 -6
-23 0.5 -6
-22 0.5 -6
-21 0.5 -6
-20 0.5 -6
-19 0.5 -6
-19 0.5 -5
-18 0.5 -5
-19 0.5 -4
-18 0.5 -4
+24 0.5 0
+28 0.5 0
+24 0.5 -1
+25 0.5 -1
+26 0.5 -1
+27 0.5 -1
+28 0.5 -1
+24 0.5 1
+25 0.5 1
+26 0.5 1
+27 0.5 1
+28 0.5 1
+24 0 -1
+25 0 -1
+26 0 -1
+27 0 -1
+28 0 -1
+24 0 0
+28 0 0
+24 0 1
+25 0 1
+26 0 1
+27 0 1
+28 0 1
+23 0.5 -3
+29 0.5 -3
+19 0.5 1
+31 0.5 3
+31 0.5 4
+33 0.5 -2
+32 0.5 -2
31 0.5 -2
30 0.5 -2
29 0.5 -2
-28 0.5 -2
-27 0.5 -2
-26 0.5 -2
-25 0.5 -2
-24 0.5 -2
23 0.5 -2
22 0.5 -2
21 0.5 -2
20 0.5 -2
19 0.5 -2
-32 0 -6
-31 0 -6
-30 0 -6
-29 0 -6
-23 0 -6
-22 0 -6
-21 0 -6
-20 0 -6
-19 0 -6
-19 0 -5
-19 0 -4
-19 0 -3
+19 0.5 -1
+18 0.5 -1
+19 0.5 0
+18 0.5 0
+31 0.5 2
+30 0.5 2
+29 0.5 2
+28 0.5 2
+27 0.5 2
+26 0.5 2
+25 0.5 2
+24 0.5 2
+23 0.5 2
+22 0.5 2
+21 0.5 2
+20 0.5 2
+19 0.5 2
+32 0 -2
31 0 -2
30 0 -2
29 0 -2
-28 0 -2
-27 0 -2
-26 0 -2
-25 0 -2
-24 0 -2
23 0 -2
22 0 -2
21 0 -2
20 0 -2
19 0 -2
-31 0 -1
-23 0 -7
-29 0 -7
-31 0 0
-18 0 -5
-18 0 -4
-33 0 -6
+19 0 -1
+19 0 0
+19 0 1
+31 0 2
+30 0 2
+29 0 2
+28 0 2
+27 0 2
+26 0 2
+25 0 2
+24 0 2
+23 0 2
+22 0 2
+21 0 2
+20 0 2
+19 0 2
+31 0 3
+23 0 -3
+29 0 -3
+31 0 4
+18 0 -1
+18 0 0
+33 0 -2
numsurf 41
SURF 0x30
mat 1
R-Lawn
crease 30.000000
numvert 8
-48 0 -2
-48 0 0
-40 0 0
-40 0 -2
-45 0 -7
-45 0 -6
-39 0 -6
-39 0 -7
+48 0 2
+48 0 4
+40 0 4
+40 0 2
+45 0 -3
+45 0 -2
+39 0 -2
+39 0 -3
numsurf 2
SURF 0x20
mat 3
texrep 1 1
crease 30.000000
numvert 68
-33 0 0
-34 0 0
-35 0 0
-36 0 0
-37 0 0
-38 0 0
-39 0 0
-40 0 0
-38 0 -7
-39 0 -7
+33 0 4
+34 0 4
+35 0 4
+36 0 4
+37 0 4
+38 0 4
+39 0 4
+40 0 4
+38 0 -3
+39 0 -3
+44 0 2
+44 0 1
+44 0 0
+44 0 -1
44 0 -2
-44 0 -3
-44 0 -4
-44 0 -5
-44 0 -6
-33 0 -1
-33 0 -2
-33 0 -3
-34 0 -3
-34 0 -2
-34 0 -1
-35 0 -3
-35 0 -2
-35 0 -1
-36 0 -1
-36 0 -2
-36 0 -3
-37 0 -3
-37 0 -2
-37 0 -1
+33 0 3
+33 0 2
+33 0 1
+34 0 1
+34 0 2
+34 0 3
+35 0 1
+35 0 2
+35 0 3
+36 0 3
+36 0 2
+36 0 1
+37 0 1
+37 0 2
+37 0 3
+38 0 3
+38 0 2
+38 0 1
+38 0 0
38 0 -1
38 0 -2
-38 0 -3
-38 0 -4
-38 0 -5
-38 0 -6
-39 0 -6
-39 0 -5
-39 0 -4
-39 0 -3
39 0 -2
39 0 -1
-40 0 -6
-40 0 -5
-40 0 -4
-40 0 -3
+39 0 0
+39 0 1
+39 0 2
+39 0 3
40 0 -2
40 0 -1
-41 0 -6
-41 0 -5
-41 0 -4
-41 0 -3
+40 0 0
+40 0 1
+40 0 2
+40 0 3
41 0 -2
-42 0 -6
-42 0 -5
-42 0 -4
-42 0 -3
+41 0 -1
+41 0 0
+41 0 1
+41 0 2
42 0 -2
-43 0 -6
-43 0 -5
-43 0 -4
-43 0 -3
+42 0 -1
+42 0 0
+42 0 1
+42 0 2
43 0 -2
+43 0 -1
+43 0 0
+43 0 1
+43 0 2
+45 0 2
+45 0 1
+45 0 0
+45 0 -1
45 0 -2
-45 0 -3
-45 0 -4
-45 0 -5
-45 0 -6
numsurf 48
SURF 0x00
mat 1
texrep 1 1
crease 30.000000
numvert 201
-50 0 -2
-45 0 -2
-45 15 -7
-45 15 -2
-50 15 -2
-45 0 -7
-45 15 -6
-45 15 -5
-45 15 -4
+50 0 2
+45 0 2
45 15 -3
+45 15 2
+50 15 2
45 0 -3
-45 0 -4
-45 0 -5
-45 0 -6
-49 0 -2
-48 0 -2
-47 0 -2
-46 0 -2
-46 15 -2
-47 15 -2
-48 15 -2
-49 15 -2
-45 1 -2
-45 2 -2
-45 3 -2
-45 4 -2
-45 5 -2
-45 6 -2
-45 7 -2
-45 8 -2
-45 9 -2
-45 10 -2
-45 11 -2
-45 12 -2
-45 13 -2
-45 14 -2
-50 1 -2
-50 2 -2
-50 3 -2
-50 4 -2
-50 5 -2
-50 6 -2
-50 7 -2
-50 8 -2
-50 9 -2
-50 10 -2
-50 11 -2
-50 12 -2
-50 13 -2
-50 14 -2
-45 14 -7
-45 13 -7
-45 12 -7
-45 11 -7
-45 10 -7
-45 9 -7
-45 8 -7
-45 7 -7
-45 6 -7
-45 5 -7
-45 4 -7
-45 3 -7
-45 2 -7
-45 1 -7
-45 14 -6
-45 13 -6
-45 12 -6
-45 11 -6
-45 10 -6
-45 9 -6
-45 8 -6
-45 7 -6
-45 6 -6
-45 5 -6
-45 4 -6
-45 3 -6
-45 2 -6
-45 1 -6
-45 14 -5
-45 13 -5
-45 12 -5
-45 11 -5
-45 10 -5
-45 9 -5
-45 8 -5
-45 7 -5
-45 6 -5
-45 5 -5
-45 4 -5
-45 3 -5
-45 2 -5
-45 1 -5
-45 14 -4
-45 13 -4
-45 12 -4
-45 11 -4
-45 10 -4
-45 9 -4
-45 8 -4
-45 7 -4
-45 6 -4
-45 5 -4
-45 4 -4
-45 3 -4
-45 2 -4
-45 1 -4
+45 15 -2
+45 15 -1
+45 15 0
+45 15 1
+45 0 1
+45 0 0
+45 0 -1
+45 0 -2
+49 0 2
+48 0 2
+47 0 2
+46 0 2
+46 15 2
+47 15 2
+48 15 2
+49 15 2
+45 1 2
+45 2 2
+45 3 2
+45 4 2
+45 5 2
+45 6 2
+45 7 2
+45 8 2
+45 9 2
+45 10 2
+45 11 2
+45 12 2
+45 13 2
+45 14 2
+50 1 2
+50 2 2
+50 3 2
+50 4 2
+50 5 2
+50 6 2
+50 7 2
+50 8 2
+50 9 2
+50 10 2
+50 11 2
+50 12 2
+50 13 2
+50 14 2
45 14 -3
45 13 -3
45 12 -3
45 3 -3
45 2 -3
45 1 -3
-49 1 -2
-49 2 -2
-49 3 -2
-49 4 -2
-49 5 -2
-49 6 -2
-49 7 -2
-49 8 -2
-49 9 -2
-49 10 -2
-49 11 -2
-49 12 -2
-49 13 -2
-49 14 -2
-48 1 -2
-48 2 -2
-48 3 -2
-48 4 -2
-48 5 -2
-48 6 -2
-48 7 -2
-48 8 -2
-48 9 -2
-48 10 -2
-48 11 -2
-48 12 -2
-48 13 -2
-48 14 -2
-47 14 -2
-47 13 -2
-47 12 -2
-47 11 -2
-47 10 -2
-47 9 -2
-47 8 -2
-47 7 -2
-47 6 -2
-47 5 -2
-47 4 -2
-47 3 -2
-47 2 -2
-47 1 -2
-46 1 -2
-46 2 -2
-46 3 -2
-46 4 -2
-46 5 -2
-46 6 -2
-46 7 -2
-46 8 -2
-46 9 -2
-46 10 -2
-46 11 -2
-46 12 -2
-46 13 -2
-46 14 -2
+45 14 -2
+45 13 -2
+45 12 -2
+45 11 -2
+45 10 -2
+45 9 -2
+45 8 -2
+45 7 -2
+45 6 -2
+45 5 -2
+45 4 -2
+45 3 -2
+45 2 -2
+45 1 -2
+45 14 -1
+45 13 -1
+45 12 -1
+45 11 -1
+45 10 -1
+45 9 -1
+45 8 -1
+45 7 -1
+45 6 -1
+45 5 -1
+45 4 -1
+45 3 -1
+45 2 -1
+45 1 -1
+45 14 0
+45 13 0
+45 12 0
+45 11 0
+45 10 0
+45 9 0
+45 8 0
+45 7 0
+45 6 0
+45 5 0
+45 4 0
+45 3 0
+45 2 0
+45 1 0
+45 14 1
+45 13 1
+45 12 1
+45 11 1
+45 10 1
+45 9 1
+45 8 1
+45 7 1
+45 6 1
+45 5 1
+45 4 1
+45 3 1
+45 2 1
+45 1 1
+49 1 2
+49 2 2
+49 3 2
+49 4 2
+49 5 2
+49 6 2
+49 7 2
+49 8 2
+49 9 2
+49 10 2
+49 11 2
+49 12 2
+49 13 2
+49 14 2
+48 1 2
+48 2 2
+48 3 2
+48 4 2
+48 5 2
+48 6 2
+48 7 2
+48 8 2
+48 9 2
+48 10 2
+48 11 2
+48 12 2
+48 13 2
+48 14 2
+47 14 2
+47 13 2
+47 12 2
+47 11 2
+47 10 2
+47 9 2
+47 8 2
+47 7 2
+47 6 2
+47 5 2
+47 4 2
+47 3 2
+47 2 2
+47 1 2
+46 1 2
+46 2 2
+46 3 2
+46 4 2
+46 5 2
+46 6 2
+46 7 2
+46 8 2
+46 9 2
+46 10 2
+46 11 2
+46 12 2
+46 13 2
+46 14 2
+46 15 1
+47 15 1
+48 15 1
+49 15 1
+50 15 1
+46 15 0
+47 15 0
+48 15 0
+49 15 0
+50 15 0
+46 15 -1
+47 15 -1
+48 15 -1
+49 15 -1
+50 15 -1
+46 15 -2
+47 15 -2
+48 15 -2
+49 15 -2
+50 15 -2
46 15 -3
47 15 -3
48 15 -3
49 15 -3
50 15 -3
-46 15 -4
-47 15 -4
-48 15 -4
-49 15 -4
-50 15 -4
-46 15 -5
-47 15 -5
-48 15 -5
-49 15 -5
-50 15 -5
-46 15 -6
-47 15 -6
-48 15 -6
-49 15 -6
-50 15 -6
-46 15 -7
-47 15 -7
-48 15 -7
-49 15 -7
-50 15 -7
numsurf 175
SURF 0x00
mat 4
texrep 1 1
crease 30.000000
numvert 12
-40.900002 3 -7.4
-40.900002 0 -7.4
-43.900002 0 -7.4
-43.900002 3 -7.4
-38.800003 3 -6.76203
-38.800003 0 -6.76203
-41.800003 0 -6.76203
-41.800003 3 -6.76203
-45 3 -6.16203
-45 0 -6.16203
-42 0 -6.16203
-42 3 -6.16203
+40.900002 3 -3.4
+40.900002 0 -3.4
+43.900002 0 -3.4
+43.900002 3 -3.4
+38.800003 3 -2.76203
+38.800003 0 -2.76203
+41.800003 0 -2.76203
+41.800003 3 -2.76203
+45 3 -2.16203
+45 0 -2.16203
+42 0 -2.16203
+42 3 -2.16203
numsurf 3
SURF 0x00
mat 5
texrep 1 1
crease 30.000000
numvert 32
-44 0.5 -6
44 0.5 -2
-43 0.5 -6
+44 0.5 2
43 0.5 -2
-42 0.5 -6
+43 0.5 2
42 0.5 -2
-41 0.5 -6
+42 0.5 2
41 0.5 -2
-40 0.5 -6
-40 0.5 0
-40 0.5 -1
+41 0.5 2
40 0.5 -2
-39 0.5 -6
-39 0.5 -7
+40 0.5 4
+40 0.5 3
+40 0.5 2
+39 0.5 -2
+39 0.5 -3
+43 0 2
43 0 -2
-43 0 -6
+42 0 2
42 0 -2
-42 0 -6
+41 0 2
41 0 -2
-41 0 -6
-40 0 -1
+40 0 3
+40 0 2
40 0 -2
-40 0 -6
-39 0 -6
-44 0 -6
+39 0 -2
44 0 -2
-39 0 -7
-40 0 0
+44 0 2
+39 0 -3
+40 0 4
+45 0 2
45 0 -2
-45 0 -6
+45 0.5 2
45 0.5 -2
-45 0.5 -6
numsurf 14
SURF 0x30
mat 1
SetBounds({-5, 0, -6}, {45, 15, 4})
--- Left end tower block
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Front
-
-ResetTransform()
-Translate(-5, 0, 2)
-SetTexture("TowerBlock1")
-DrawTilemap({
- width = 5,
- 2, 2, 2, 2, 2,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 1, 0, 0, 1, 0,
- 4, 4, 4, 4, 4})
-
--- Right side
-
-ResetTransform()
-Rotate(Y, 90)
-Translate(0, 0, 2)
-DrawTilemap({
- width = 5,
- surface = RIGHT,
- 2, 2, 2, 2, 2,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 6,
- 4, 5, 5, 5, 4})
-
--- Top
-
-ResetTransform()
-Rotate(X, 90)
-Translate(-5, 15, -3)
-DrawTilemap({
- width = 5,
- surface = TOP,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3})
-
--- Leftmost background tower block
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Front
-
-if detail > LOW then
- ResetTransform()
- Translate(0, 0, -3)
- DrawTilemap({
- width = 7,
- 2, 2, 2, 2, 2, 2, 2,
- 0, 1, 0, 0, 0, 1, 0,
- 0, 1, 0, 0, 0, 1, 0,
- 0, 1, 0, 0, 6, 1, 0,
- 0, 1, 0, 0, 0, 1, 0,
- 0, 1, 0, 0, 0, 1, 0,
- 0, 1, 0, 0, 0, 1, 0,
- 4, 4, 5, 5, 5, 4, 4})
-
- -- Right side
-
- ResetTransform()
- Rotate(Y, 90)
- Translate(7, 0, -3)
- DrawTilemap({
- width = 6,
- 2, 2, 2, 2, 2, 2,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 4, 4, 4, 4, 4, 4})
-
- -- Top
-
- ResetTransform()
- Rotate(X, 90)
- Translate(-2, 8, -9)
- DrawTilemap({
- width = 9,
- 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3})
-end
-
--- Foreground building with pitched roof
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Left wall
-
-ResetTransform()
-Rotate(Y, -90)
-Translate(10, 0, -2)
-SetTexture("Building")
-DrawTilemap({
- width = 4,
- surface = LEFT,
- -1, 9, 11, -1,
- 9, 10, 12, 11,
- 15, 7, 7, 16,
- 3, 5, 6, 4,
- 3, 6, 5, 4})
-
--- Right wall
-
-ResetTransform()
-Rotate(Y, -90)
-Translate(13, 0, -2)
-DrawTilemap({
- width = 4,
- surface = RIGHT,
- -1, 9, 11, -1,
- 9, 10, 12, 11,
- 15, 7, 7, 16,
- 3, 5, 6, 4,
- 3, 8, 5, 4})
-
--- Front wall
-
-ResetTransform()
-Translate(10, 0, 2)
-DrawTilemap({
- width = 3,
- 15, 7, 16,
- 3, 5, 4,
- 3, 6, 4})
-
--- Pitched roof
-
-ResetTransform()
-Rotate(X, 135)
-Scale(1, 1.5, 1.5)
-Translate(10, 5, 0)
-DrawTilemap({
- width = 3,
- 13, 13, 13,
- 13, 13, 13})
-
--- Finial
-
-ResetTransform()
-Translate(10, 5, -0.00001)
-DrawTilemap({
- width = 3,
- 18, 18, 18})
-
--- Cheaty invisible platform
--- This draws nothing but creates a platform on the roof for walking.
-
-ResetTransform()
-Rotate(X, 90)
-Translate(10, 5, 0)
-DrawTilemap({
- width = 3,
- surface = TOP,
- -1, -1, -1})
-
--- The ground
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Courtyard
-
-ResetTransform()
-Rotate(X, 90)
-Translate(-3, 0, -3)
-SetTexture("Scenery")
-DrawTilemap({
- width = 13,
- surface = TOP,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- -1, -1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- -1, -1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- -1, -1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- -1, -1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})
-
--- Front grass
-
-if detail > MEDIUM then
- ResetTransform()
- Scale(8, 1, 1)
- Translate(1, -0.5, 2)
- DrawTile({
- 2,
- u_scale = 8})
-
- -- Back grass
-
- ResetTransform()
- Scale(8, 1, 1)
- Translate(1, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 8
- })
-
- -- Left grass
-
- ResetTransform()
- Scale(4, 1, 1)
- Rotate(Y, -90)
- Translate(1, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Right grass
-
- ResetTransform()
- Scale(4, 1, 1)
- Rotate(Y, -90)
- Translate(9, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Fence behind house
-
- ResetTransform()
- Scale(11, 1, 1)
- Translate(7, 0, -3)
- DrawTile({
- 4,
- u_scale = 11
- })
-end
-
--- Background building with pitched roof
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Front wall
-
-if detail > LOW then
- ResetTransform()
- Translate(19, 0, -3)
- SetTexture("Building")
- DrawTilemap({
- width = 4,
- -1, 9, 11, -1,
- 9, 10, 12, 11,
- 15, 7, 7, 16,
- 3, 6, 5, 4,
- 3, 5, 6, 4,
- 3, 8, 5, 4})
-
- -- Left wall
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(19, 0, -6)
- DrawTilemap({
- width = 3,
- 15, 1, 16,
- 3, 7, 4,
- 3, 5, 4,
- 3, 0, 4})
-
- -- Right wall
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(23, 0, -6)
- DrawTilemap({
- width = 3,
- 15, 0, 16,
- 3, 7, 4,
- 3, 6, 4,
- 3, 2, 4})
-
- -- Left pitched roof
-
- ResetTransform()
- Rotate(X, 135)
- Scale(1, 1.5, 1.5)
- Rotate(Y, -90)
- Translate(21, 6, -6)
- DrawTilemap({
- width = 3,
- 13, 13, 13,
- 13, 13, 13})
-
- -- Right pitched roof
-
- ResetTransform()
- Rotate(X, -135)
- Scale(1, 1.5, 1.5)
- Rotate(Y, -90)
- Translate(21, 6, -6)
- DrawTilemap({
- width = 3,
- 13, 13, 13,
- 13, 13, 13})
-
- -- Finial
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(21, 6, -6)
- DrawTilemap({
- width = 3,
- 18, 18, 18})
-end
-
--- More ground to the right
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Ground under house
-
-ResetTransform()
-Rotate(X, 90)
-Translate(10, 0, -3)
-SetTexture("Scenery")
-DrawTilemap({
- width = 3,
- surface = TOP,
- 1, 1, 1,
- 1, 1, 1,
- -1, -1, -1,
- -1, -1, -1,
- -1, -1, -1,
- -1, -1, -1,
- 1, 1, 1})
-
--- Left part of center courtyard
-
-ResetTransform()
-Rotate(X, 90)
-Translate(13, 0, -3)
-DrawTilemap({
- width = 8,
- surface = TOP,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1,
- 0, 0, 0, 0, 0, 0, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 0, 0, 0})
-
--- Front grass
-
-if detail > MEDIUM then
- ResetTransform()
- Scale(12, 1, 1)
- Translate(14, -0.5, 2)
- DrawTile({
- 2,
- u_scale = 12
- })
-
- -- Back grass
-
- ResetTransform()
- Scale(4, 1, 1)
- Translate(14, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Front grass next to door
-
- ResetTransform()
- Translate(13, -0.5, 0)
- DrawTile({
- 2,
- u_scale = 1
- })
-
- -- Back grass next to door
-
- ResetTransform()
- Translate(13, -0.5, -1)
- DrawTile({
- 2,
- u_scale = 1
- })
-
- -- Left grass
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(14, -0.5, -2)
- DrawTilemap({
- width = 4,
- 2, -1, 2, 2})
-
- -- Grass left of house
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(18, -0.5, -3)
- DrawTile({
- 2,
- u_scale = 1
- })
-
- -- Grass right of house
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(24, -0.5, -3)
- DrawTile({
- 2,
- u_scale = 1
- })
-
- -- Front grass in center
-
- ResetTransform()
- Scale(4, 1, 1)
- Translate(19, -0.5, 1)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Back grass in center
-
- ResetTransform()
- Scale(4, 1, 1)
- Translate(19, -0.5, -1)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Left grass in center
-
- ResetTransform()
- Scale(2, 1, 1)
- Rotate(Y, -90)
- Translate(19, -0.5, -1)
- DrawTile({
- 2,
- u_scale = 2
- })
-
- -- Right grass in center
-
- ResetTransform()
- Scale(2, 1, 1)
- Rotate(Y, -90)
- Translate(23, -0.5, -1)
- DrawTile({
- 2,
- u_scale = 2
- })
-end
-
--- Right part of center courtyard
-
-ResetTransform()
-Rotate(X, 90)
-Translate(21, 0, -3)
-DrawTilemap({
- width = 7,
- surface = TOP,
- 1, 1, 1, 1, 1, 0, 0,
- 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1})
-
--- Fence to right of back house
-
-if detail > MEDIUM then
- ResetTransform()
- Scale(4, 1, 1)
- Translate(24, 0, -3)
- DrawTile({
- 4,
- u_scale = 4
- })
-
- -- Grass in front of fence
-
- ResetTransform()
- Scale(4, 1, 1)
- Translate(24, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 4
- })
-
- -- Grass to left of tower block
-
- ResetTransform()
- Scale(2, 1, 1)
- Rotate(Y, -90)
- Translate(26, -0.5, 2)
- DrawTile({
- 2,
- u_scale = 2
- })
-
- -- Grass to right of tower block
-
- ResetTransform()
- Scale(2, 1, 1)
- Rotate(Y, -90)
- Translate(35, -0.5, 2)
- DrawTile({
- 2,
- u_scale = 2
- })
-
- -- Next bit of grass
-
- ResetTransform()
- Scale(5, 1, 1)
- Translate(35, -0.5, 2)
- DrawTile({
- 2,
- u_scale = 5
- })
-
- -- Back grass
-
- ResetTransform()
- Scale(6, 1, 1)
- Translate(34, -0.5, -2)
- DrawTile({
- 2,
- u_scale = 6
- })
-
- -- Extra bit of back grass
-
- ResetTransform()
- Rotate(Y, -90)
- Translate(34, -0.5, -3)
- DrawTile({
- 2,
- u_scale = 1
- })
-end
-
--- Ground around tower block
-
-ResetTransform()
-Rotate(X, 90)
-Translate(28, 0, 1)
-DrawTilemap({
- width = 5,
- surface = TOP,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0})
-
--- Rightmost ground
-
-ResetTransform()
-Rotate(X, 90)
-Translate(33, 0, -3)
-DrawTilemap({
- width = 10,
- surface = TOP,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
- 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
- 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
- 0, 0, 0, 0, 0, 0, 0, -1, -1, -1,
- 0, 1, 1, 1, 1, 1, 1, -1, -1, -1})
-
--- Right foreground tower block
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Front
-
-ResetTransform()
-Translate(28, 0, 1)
-SetTexture("TowerBlock1")
-DrawTilemap({
- width = 5,
- 2, 2, 2, 2, 2,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 6,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 0,
- 4, 4, 4, 4, 4})
-
--- Right side
-
-ResetTransform()
-Rotate(Y, 90)
-Translate(33, 0, 1)
-DrawTilemap({
- width = 6,
- surface = RIGHT,
- 2, 2, 2, 2, 2, 2,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 5, 4, 5, 5, 4, 5})
-
--- Left side
-
-ResetTransform()
-Rotate(Y, 90)
-Translate(28, 0, 1)
-DrawTilemap({
- width = 6,
- surface = LEFT,
- 2, 2, 2, 2, 2, 2,
- 0, 1, 6, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 0, 1, 0, 0, 1, 0,
- 5, 4, 5, 5, 4, 5})
-
--- Top
-
-ResetTransform()
-Rotate(X, 90)
-Translate(28, 7, -5)
-DrawTilemap({
- width = 5,
- surface = TOP,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3})
-
--- Right end tower block
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
--- Front
-
-ResetTransform()
-Translate(40, 0, 2)
-DrawTilemap({
- width = 5,
- 2, 2, 2, 2, 2,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 6, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 6, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 0, 1, 0, 0, 1,
- 4, 4, 4, 4, 4})
-
--- Left side
-
-ResetTransform()
-Rotate(Y, 90)
-Translate(40, 0, 2)
-DrawTilemap({
- width = 5,
- surface = LEFT,
- 2, 2, 2, 2, 2,
- 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 6, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 4, 5, 5, 5, 4})
-
--- Top
-
-ResetTransform()
-Rotate(X, 90)
-Translate(40, 15, -3)
-DrawTilemap({
- width = 5,
- surface = TOP,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3})
-
--- Background
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-ResetTransform()
-Translate(-0.3, -0.3, -35)
-Scale(105, 52, 1)
-SetTexture("BackgroundFar")
-DrawTile()
-
-Translate(0, 0, 5)
-SetTexture("BackgroundNear")
-DrawTile({
- blend = detail > LOW and true or false
-})
-
--- Trees
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-SetTexture("Trees")
-
--- Left courtyard
-
-if detail > LOW then
- ResetTransform()
- Scale(3)
- Translate(7.75, -0.1, -2.5)
- DrawTile(1)
-end
-
--- Center courtyard
-
-ResetTransform()
-Scale(3)
-Translate(19, -0.1, -0.5)
-DrawTile(0)
-
-ResetTransform()
-Scale(3)
-Translate(20.25, -0.1, 0.5)
-DrawTile(1)
-
--- Right courtyard
-
-if detail > LOW then
- ResetTransform()
- Scale(3)
- Translate(34, -0.1, -2.75)
- DrawTile(1)
-
- ResetTransform()
- Scale(3)
- Translate(36, -0.1, -3.5)
- DrawTile(0)
-
- ResetTransform()
- Scale(3)
- Translate(37, -0.1, -2.25)
- DrawTile(1)
-end
+--geometry = yoink.mesh("classic.ac")
+--geometry:draw()
+--geometry = yoink.mesh.fromstring([[
+--AC3Db
+--OBJECT poly
+--name "Hello World"
+--...
+--]]
-- Functions:
Event = {}
-function Event:Think()
+do
+ local mysound = yoink.sound("Explosion")
+ local count = 0
+ function Event.Think()
+ if count % 300 == 0 then
+ --mysound:play()
+ end
+ count = count + 1
+ end
+end
+
+
+classic_mesh = yoink.mesh("classic")
+
+--drawme = {}
+
+--world = classic_mesh:object(1)
+--for i = 1, 19 do
+ --local object = world:kid(i)
+ --if object then table.insert(drawme, object) end
+--end
+
+--lawn = classic_mesh:object(1):kid("M-Lawn")
+
+--Event.Draw = function() tower:draw(false) end
+Event.Draw = function()
+ --for i,object in ipairs(drawme) do
+ --object:draw()
+ --end
+ --lawn:draw()
+ classic_mesh:draw()
end
function Event:BadGuyDied(enemy)
#include <moof/manager.hh>
#include <moof/log.hh>
+#include <moof/resource.hh>
#include <moof/script.hh>
#include "Animation.hh"
moof::script script;
std::string path = moof::resource::find_file("animations/"+name, "lua");
- //if (!resource::find(path))
- //{
- //throw std::runtime_error("cannot find resource " + name);
- //}
-
script.import_base_library();
moof::log::import(script);
importAnimationBindings(script);
#include <boost/shared_ptr.hpp>
#include <moof/math.hh>
-#include <moof/resource.hh>
class Animation;
* about anything to whatever drawing context is used to render the frame.
*/
-class Animation : public moof::resource
+class Animation
{
public:
#include <moof/log.hh>
#include <moof/math.hh>
+#include <moof/mesh.hh>
#include <moof/opengl.hh>
#include <moof/settings.hh>
#include <moof/video.hh>
void GameLayer::loadSceneLoader()
{
- state_.script.import_standard_libraries();
+ state_.script.import_safe_standard_libraries();
moof::log::import(state_.script);
+ moof::mesh::import(state_.script, "yoink");
+ moof::sound::import(state_.script, "yoink");
std::string path = moof::resource::find_file("scenes/loader.lua");
if (path.empty())
state_.script.top().get(state_.sceneList);
if (state_.sceneList.size() == 0)
{
- throw std::runtime_error("no variable `scenes' in script loader.");
+ throw std::runtime_error("no variable `scenes' in script loader");
}
}
state_.script.registry().set_field();
}
state_.script.pop();
+
+ table = state_.script.globals().push_field("Event");
+ if (table.is_table())
+ {
+ table.push_field("Draw");
+ state_.script.registry().set_field("Draw");
+ }
+ state_.script.pop();
}
}
GameLayer::GameLayer()
{
- moof::log_info("about to load sound resource...");
- music_.sample("sounds/NightFusionIntro.ogg");
+ music_.sample("NightFusionIntro.ogg");
music_.loop(true);
- music_.enqueue("sounds/NightFusionLoop.ogg");
+ music_.enqueue("NightFusionLoop.ogg");
music_.position(moof::vector3(10.0, 5.0, 0.0));
- mThinkTimer.init(boost::bind(&GameLayer::thinkTimer, this),
- 0.1, moof::timer::repeat);
+ punch_sound_.sample("RobotPunch");
state_.heroine = Heroine::alloc();
state_.heroine->animation.startSequence("FlyDiagonallyUp");
state_.interp.init(0.0, 1.0, 4.0, moof::lerp_scalar::oscillate);
-
- sceneMesh = moof::resource::load("classic.ac");
}
{
bool isMute = false;
settings().get("nomusic", isMute);
- music_.stream();
+ music_.play();
loadSceneLoader();
advanceScene(settings()); // load the first scene
mRay.point = state_.heroine->state().position;
- moof::view::update(t, dt);
-}
-
-void GameLayer::thinkTimer()
-{
state_.script.registry().push_field("Think");
if (state_.script[-1].is_function()) state_.script.call();
- else state_.script.pop();
-}
+ else state_.script.pop();
+ moof::view::update(t, dt);
+}
void GameLayer::rayTimer()
{
state_.camera.upload_to_gl(alpha);
float pos[] = {state_.heroine->state().position[0],
- state_.heroine->state().position[1], 0.0f};
+ state_.heroine->state().position[1], 0.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, pos);
// DRAW THE SCENE
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//state_.scene->draw_if_visible(alpha, state_.camera.frustum());
- sceneMesh->draw(alpha);
+
+ size_t meh = 23;
+ state_.script.push(meh);
+ state_.script.pop();
+
+ state_.script.registry().push_field("Draw");
+ if (state_.script[-1].is_function())
+ {
+ moof::script::status result = state_.script.call();
+ if (result != moof::script::success)
+ {
+ std::string str;
+ state_.script[-1].get(str);
+ throw std::runtime_error("script error: " + str);
+ }
+ }
+ else state_.script.pop();
+
state_.heroine->draw(alpha);
mRay.draw();
#include <boost/shared_ptr.hpp>
#include <moof/math.hh>
-#include <moof/mesh.hh>
#include <moof/sound.hh>
#include <moof/line.hh> // TODO
void loadSceneLoader();
void advanceScene(moof::settings& settings);
- void thinkTimer();
-
void projection();
void projection(moof::scalar width, moof::scalar height);
- GameState state_;
- moof::timer mThinkTimer;
+ mutable GameState state_;
HudP mHud;
- //moof::sound_stream mMusic;
moof::sound punch_sound_;
moof::sound music_;
- moof::mesh_handle sceneMesh;
-
moof::ray2 mRay;
moof::line2 mLine;
moof::circle mCircle;
#include <iostream>
#include <string>
+#if !defined(__WIN32)
+#include <termios.h>
+#else
+int isatty(int dummy) { return 0; }
+#endif
+
#include <stlplus/portability/file_system.hpp>
#include <stlplus/portability/subprocesses.hpp>
#include <moof/opengl.hh>
#include <moof/resource.hh>
#include <moof/settings.hh>
+#include <moof/string.hh>
#include <moof/video.hh>
#include "GameLayer.hh"
moof::view(settings, video)
{
moof::dispatcher& dispatcher = moof::dispatcher::global();
- mNewContextDispatch = dispatcher.add_target("video.newcontext",
- boost::bind(&Main::setupGL));
- setupGL();
+ video_reloaded_ = dispatcher.add_target("video.newcontext",
+ boost::bind(&Main::setup_opengl));
+ setup_opengl();
+
+#if USE_HOTLOADING
+ hotload_timer_.init(boost::bind(&moof::resource::reload_as_needed),
+ SCALAR(0.25),
+ moof::timer::repeat);
+#endif
}
}
-std::string Main::getSearchPath()
+std::string Main::search_paths()
{
// Add search paths; they should be searched in this order:
// 1. YOINK_DATADIR (environment)
return path;
}
-std::string Main::getConfigPath()
+std::string Main::config_paths()
{
// Build the list of config files to search for, in this order:
// 1. YOINK_DATADIR/yoinkrc
}
-void Main::setupGL()
+void Main::setup_opengl()
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
+ //glEnable(GL_CULL_FACE);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_POLYGON_SMOOTH);
+ //glEnable(GL_POINT_SMOOTH);
+ //glEnable(GL_LINE_SMOOTH);
+ //glEnable(GL_POLYGON_SMOOTH);
glShadeModel(GL_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ //glEnable(GL_BLEND);
+ //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0);
//glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
- float light[] = {1.0f, 1.0f, 1.0f, 1.0f};
- glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, light);
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ float amb[] = {0.1f, 0.1f, 0.1f, 1.0f};
+ float dif[] = {0.6f, 0.6f, 0.6f, 1.0f};
+ //glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
- //glMatrixMode(GL_PROJECTION);
- //glLoadIdentity();
- //moof::scalar ratio = moof::core.getVideo()->width() /
- //moof::core.getVideo()->height();
- //gluPerspective(60.0, ratio, 1.0, 250.0);
-
- //glMatrixMode(GL_MODELVIEW);
+ float spec[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
}
-void Main::printUsage()
+void Main::print_usage()
{
std::cout << "Usage: "
<< PACKAGE" [-h|--help] [-i|--info] [OPTION=VALUE]..."
<< "See documentation for more options." << std::endl;
}
-void Main::printInfo(int argc, char* argv[])
+
+void Main::print_info(int argc, char* argv[])
{
+ bool color = (isatty(1) == 1);
+
stlplus::env_vector environment;
std::string assets;
assets.assign(YOINK_DATADIR);
- if (!stlplus::file_readable(assets)) assets += " (no access)";
+ if (!stlplus::file_readable(assets))
+ {
+ assets += " ";
+ if (color) assets += "\033[1;91m";
+ assets += "(no access)";
+ if (color) assets += "\033[0m";
+ }
std::string datadir = environment["YOINK_DATADIR"];
if (!datadir.empty())
{
- if (!stlplus::folder_readable(datadir)) datadir += " (no access)";
+ if (!stlplus::folder_readable(datadir))
+ {
+ datadir += " ";
+ if (color) datadir += "\033[1;91m";
+ datadir += "(no access)";
+ if (color) datadir += "\033[0m";
+ }
}
std::string rc_file = environment["YOINKRC"];
<< " Built: " << COMPILE_TIME << std::endl
<< " Compiler: " << COMPILER_STRING << std::endl
<< " Assets: " << assets << std::endl
- << "Build options: "
-#if !USE_CLOCK_GETTIME
- << "-"
-#endif
- << "clock_gettime "
-#if !DEBUG
- << "-"
+ << "Build options: ";
+
+#if USE_CLOCK_GETTIME
+ print_option("clock_gettime", true);
+#else
+ print_option("clock_gettime", false);
#endif
- << "debug "
-#if !USE_DOUBLE_PRECISION
- << "-"
+#if DEBUG
+ print_option("debug", true);
+#else
+ print_option("debug", false);
#endif
- << "double-precision "
-#if !USE_GTK
- << "-"
+#if USE_GTK
+ print_option("gtk", true);
+#else
+ print_option("gtk", false);
#endif
- << "gtk "
-#if !USE_HOTLOADING
- << "-"
+#if USE_HOTLOADING
+ print_option("hotload", true);
+#else
+ print_option("hotload", false);
#endif
- << "hotloading "
-#if !PROFILING_ENABLED
- << "-"
+#if PROFILING_ENABLED
+ print_option("profile", true);
+#else
+ print_option("profile", false);
#endif
- << "profile "
-#if !USE_QT4
- << "-"
+#if USE_QT4
+ print_option("qt4", true);
+#else
+ print_option("qt4", false);
#endif
- << "qt4 "
-#if !USE_THREADS
- << "-"
+#if USE_THREADS
+ print_option("threads", true);
+#else
+ print_option("threads", false);
#endif
- << "threads" << std::endl
- << " YOINKRC: " << rc_file << std::endl
+ std::cout << std::endl;
+ std::cout << " YOINKRC: " << rc_file << std::endl
<< "YOINK_DATADIR: " << datadir << std::endl;
}
+void Main::print_option(const std::string& option, bool enabled)
+{
+ if (isatty(1) == 1)
+ {
+ if (enabled) std::cout << "\033[1;94m";
+ else std::cout << "\033[1m";
+ }
+ if (!enabled) std::cout << "-";
+ std::cout << option;
+ if (isatty(1) == 1) std::cout << "\033[0m";
+ std::cout << " ";
+}
+
void hello()
{
+ if (isatty(1) == 1) std::cout << "\033[94m";
std::cout << std::endl << PACKAGE_STRING << std::endl
<< "Compiled " << __TIME__ " " __DATE__ << std::endl
<< "Send patches and bug reports to <"
- PACKAGE_BUGREPORT << ">." << std::endl << std::endl;
+ PACKAGE_BUGREPORT << ">." << std::endl << moof::log::endl;
}
void goodbye()
{
- std::cout << std::endl << "Goodbye..." << std::endl << std::endl;
+ if (isatty(1) == 1) std::cout << "\033[94m";
+ std::cout << std::endl << "Goodbye." << std::endl << moof::log::endl;
}
{
moof::backend backend;
- // FIXME: This is temporary.
- moof::timer reloadTimer(boost::bind(&moof::resource::reload_as_needed),
- SCALAR(2.0),
- moof::timer::repeat);
-
if (argc > 1)
{
std::string arg(argv[1]);
if (arg == "-h" || arg == "--help")
{
- Main::printUsage();
+ Main::print_usage();
return 0;
}
else if (arg == "-i" || arg == "--info")
{
- Main::printInfo(argc, argv);
+ Main::print_info(argc, argv);
return 0;
}
}
hello();
atexit(goodbye);
- moof::resource::add_search_paths(Main::getSearchPath());
+ moof::resource::set_search_paths(Main::search_paths());
- moof::settings settings(argc, argv, Main::getConfigPath());
+ moof::settings settings(argc, argv, Main::config_paths());
enum moof::log::level logLevel = moof::log::info;
settings.get("loglevel", logLevel);
catch (const std::exception& e)
{
moof::modal_dialog dialog(moof::modal_dialog::error,
- PACKAGE_STRING, "Unhandled Exception",
+ PACKAGE_STRING, "unhandled exception",
e.what());
-
dialog.run();
- return 1;
}
+ catch (const char* e)
+ {
+ moof::modal_dialog dialog(moof::modal_dialog::error,
+ PACKAGE_STRING, "unhandled exception",
+ e);
+ dialog.run();
+ }
+
+ return 1;
}
#include <moof/dispatcher.hh>
#include <moof/math.hh>
+#include <moof/timer.hh>
#include <moof/view.hh>
void draw(moof::scalar alpha) const;
bool handle_event(const moof::event& event);
- static std::string getSearchPath();
- static std::string getConfigPath();
+ static std::string search_paths();
+ static std::string config_paths();
- static void printUsage();
- static void printInfo(int argc, char* argv[]);
+ static void print_usage();
+ static void print_info(int argc, char* argv[]);
private:
/**
* Set OpenGL to a state we can know and depend on.
*/
- static void setupGL();
+ static void setup_opengl();
- moof::dispatcher::handle mNewContextDispatch;
+ static void print_option(const std::string& option, bool enabled);
+
+ moof::dispatcher::handle video_reloaded_;
+ moof::timer hotload_timer_;
};
#include <moof/log.hh>
#include <moof/manager.hh>
#include <moof/math.hh>
+#include <moof/resource.hh>
#include <moof/script.hh>
#include <moof/settings.hh>
#include <moof/sprite.hh>
};
Quad(const moof::vector3* vertices[4],
- const std::string& texture,
+ const moof::image_handle& texture,
int tileIndex) :
mTilemap(texture, tileIndex),
mBlending(false),
moof::matrix4 mTransform;
- std::string mTexture;
+ moof::image_handle mTexture;
std::list< boost::shared_ptr<impl::Quad> > mObjects;
std::list<moof::line2> mLines;
static int loadBox(moof::script& script, moof::aabb3& aabb)
{
- script[1].require_table();
- script[2].require_table();
+ script[1].require_table("point");
+ script[2].require_table("point");
script[1].push_field(1).get(aabb.min[0]);
script[1].push_field(2).get(aabb.min[1]);
int setBounds(moof::script& script)
{
- int ret = loadBox(script, mBounds);
- return ret;
+ return loadBox(script, mBounds);
}
int resetTransform(moof::script& script)
int rotate(moof::script& script)
{
- size_t index = 0;
- script[1].require_number().get(index);
+ size_t index = 0;
+ moof::scalar value;
- moof::scalar value;
+ script[1].require_number().get(index);
script[2].require_number().get(value);
moof::matrix_rotate_about_world_axis(mTransform, index,
int setTexture(moof::script& script)
{
- script[1].require_string().get(mTexture);
+ std::string texture_name;
+ script[1].require_string().get(texture_name);
+ mTexture = moof::resource::load(texture_name, "png");
return 0;
}
#include <moof/cullable.hh>
#include <moof/drawable.hh>
-#include <moof/resource.hh>
#include <moof/script.hh>
class Scene;
typedef boost::shared_ptr<Scene> SceneP;
-class Scene : public moof::cullable, public moof::drawable, public moof::resource
+class Scene : public moof::cullable, public moof::drawable
{
class impl;
boost::shared_ptr<impl> impl_;
* Get the axis-aligned bounding box surrounding the entity.
* \return The AABB.
*/
- const moof::aabb<3>& aabb() const
+ const moof::aabb3& aabb() const
{
return aabb_;
}
/** Get the bounding sphere surrounding the entity.
* \return The sphere.
*/
- const moof::sphere<3>& sphere() const
+ const moof::sphere3& sphere() const
{
return sphere_;
}
protected:
- moof::aabb<3> aabb_;
- moof::sphere<3> sphere_;
+ moof::aabb3 aabb_;
+ moof::sphere3 sphere_;
};
namespace moof {
+MOOF_REGISTER_RESOURCE(image, png, textures);
+
//static int power_of_two(int input)
//{
//int value = 1;
}
-class image_resource_loader
-{
-public:
-
- image_resource_loader()
- {
- resource::register_type<image>("png", "textures");
- }
-
- ~image_resource_loader()
- {
- resource::unregister_type("png");
- }
-};
-
-static image_resource_loader loader;
-
-
} // namespace moof
#include <fstream>
+#if !defined(__WIN32)
+#include <termios.h>
+#else
+int isatty(int dummy) { return 0; }
+#endif
+
+
#include "log.hh"
#include "script.hh"
}
-std::ostream& log(std::clog);
+log::log(enum level level) :
+ level_(level)
+{
+ if (isatty(1) == 0)
+ switch (level)
+ {
+ case log::error: prefix_ = " error: "; break;
+ case log::warning: prefix_ = "warning: "; break;
+ case log::info: prefix_ = " info: "; break;
+ case log::none: break;
+ }
+ else
+ switch (level)
+ {
+ case log::error: prefix_ = "\033[101m error: "; break;
+ case log::warning: prefix_ = "\033[103mwarning: "; break;
+ case log::info: prefix_ = " info: "; break;
+ case log::none: break;
+ }
+}
+
+std::ostream& operator << (class log& log, log::endl_ endl)
+{
+ if (log::global_level_ < log.level_) return null_log;
+ if (isatty(1) == 0) return moof::log << std::endl;
+ else return moof::log << "\033[0m" << std::endl;
+}
+
+std::ostream& operator << (std::ostream& stream, log::endl_ endl)
+{
+ if (isatty(1) == 0) return stream << std::endl;
+ else return stream << "\033[0m" << std::endl;
+}
+
+
+std::ostream& log(std::cout);
static std::ofstream null_log_;
std::ostream& null_log(null_log_);
-class log log_error( log::error, " error: ");
-class log log_warning(log::warning, "warning: ");
-class log log_info( log::info, " info: ");
+class log log_error( log::error);
+class log log_warning(log::warning);
+class log log_info( log::info);
static int log_script(script& script, enum log::level level)
#include <cstdlib> // exit
#include <iostream>
+#include <string>
namespace moof {
* \param level The log level.
* \param prefix The string printed before each log message.
*/
- log(enum level level, const char* prefix) :
- level_(level),
- prefix_(prefix) /* only pass literal strings */ {}
+ log(enum level level);
+
+
+ /**
+ * Output this to end a line. This is equivalent to std::endl except
+ * this will also reset terminal format attributes.
+ */
+ static struct endl_
+ {
+ } endl;
template <class A>
void operator () (const A& a)
{
- *this << a << std::endl;
+ *this << a << endl;
}
template <class A, class B>
void operator () (const A& a, const B& b)
{
- *this << a << " " << b << std::endl;
+ *this << a << " " << b << endl;
}
template <class A, class B, class C>
void operator () (const A& a, const B& b, const C& c)
{
- *this << a << " " << b << " " << c << std::endl;
+ *this << a << " " << b << " " << c << endl;
}
template <class A, class B, class C, class D>
void operator () (const A& a, const B& b, const C& c, const D& d)
{
- *this << a << " " << b << " " << c << " " << d << std::endl;
+ *this << a << " " << b << " " << c << " " << d << endl;
}
template <class A, class B, class C, class D, class E>
<< b << " "
<< c << " "
<< d << " "
- << e << std::endl;
+ << e << endl;
}
private:
template <class T> friend std::ostream& operator << (log&, const T&);
+ friend std::ostream& operator << (log&, endl_);
static enum level global_level_;
enum level level_;
- const char* prefix_;
+ std::string prefix_;
};
return moof::log << log.prefix_ << item;
}
+std::ostream& operator << (class log& log, log::endl_ endl);
+std::ostream& operator << (std::ostream& stream, log::endl_ endl);
+
} // namespace moof
#include "mesh.hh"
#include "opengl.hh"
+// TODO: this file needs to be cleaned up
+
#define AC3D_FORMAT_VERSION (0x0b)
#define ZLIB_BUF_SIZE (262114)
namespace moof {
+MOOF_REGISTER_RESOURCE(mesh, ac, models);
+
+
static std::string read_string(std::istream& stream)
{
std::string str;
return triplet;
}
-
-template <int D>
-inline vector< scalar, fixed<D> > read_triplet(std::istream& stream)
+inline vector3 read_triplet(std::istream& stream)
{
- vector< scalar, fixed<D> > triplet;
+ vector3 triplet;
stream >> triplet[0] >> triplet[1] >> triplet[2];
return triplet;
}
+inline vector4 read_color(std::istream& stream)
+{
+ vector4 color;
+ stream >> color[0] >> color[1] >> color[2];
+ color[3] = SCALAR(1.0);
+ return color;
+}
+
void mesh::import(std::istream& stream)
{
materials_.push_back(material(read_string(stream)));
stream >> atom;
- materials_.back().diffuse = read_triplet<4>(stream);
+ materials_.back().diffuse = read_color(stream);
stream >> atom;
- materials_.back().ambient = read_triplet<3>(stream);
+ materials_.back().ambient = read_color(stream);
stream >> atom;
- materials_.back().emissive = read_triplet<3>(stream);
+ materials_.back().emissive = read_color(stream);
stream >> atom;
- materials_.back().specular = read_triplet<3>(stream);
+ materials_.back().specular = read_color(stream);
stream >> atom >> materials_.back().shininess;
- stream >> atom >> materials_.back().diffuse[3]; // transparency
- materials_.back().diffuse[3] = 1.0; // FIXME: temporary
-
- log_info("read material", materials_.back().name,
- materials_.back().diffuse);
+ stream >> atom >> materials_.back().diffuse[3];
+ materials_.back().diffuse[3] = SCALAR(1.0) -
+ materials_.back().diffuse[3];
}
else if (atom == "OBJECT")
{
throw std::runtime_error("unexpected object type " + atom);
}
- object_ptr newObj = object::alloc();
+ object_ptr newObj = object::alloc(*this);
if (obj)
{
}
else if (atom == "name")
{
- if (obj) obj->name = read_string(stream);
+ if (obj)
+ {
+ obj->name = read_string(stream);
+ object_ptr parent = obj->parent.lock();
+ if (parent) parent->kids_byname.insert(std::make_pair(obj->name, obj));
+ }
else throw std::runtime_error("unexpected atom: " + atom);
}
else if (atom == "data")
int numvert = 0;
stream >> numvert;
- log_warning("adding verts", numvert);
-
for (int i = 0; i < numvert; ++i)
{
- obj->verts.push_back(read_triplet<3>(stream));
- log_error("vert", obj->verts.back());
+ obj->verts.push_back(read_triplet(stream));
}
}
else if (atom == "numsurf")
stream >> atom;
if (atom != "SURF") throw std::runtime_error("uh oh");
- int flags = read_hex(stream);
- log_info(flags);
+ read_hex(stream);
int material = 0;
stream >> atom;
if ((int)obj->faces.size() <= material)
{
- log_info("inserting face...");
- //obj->faces.insert(obj->faces.begin() + material,
- //material_group());
obj->faces.resize(material + 1);
- log_info("inserted face", material, obj->faces.size());
}
-
material_group& face = obj->faces[material];
- int vert;
+ unsigned vert;
stream >> vert;
vector2 uv = read_pair(stream);
+ if (vert < face.triangles_uv.size())
+ {
+ if (uv != face.triangles_uv[vert])
+ {
+ obj->verts.push_back(obj->verts[vert]);
+ face.triangles_uv.resize(obj->verts.size());
+ vert = obj->verts.size() - 1;
+ }
+ }
+ else face.triangles_uv.resize(vert + 1);
+ face.triangles_uv[vert] = uv;
face.triangles.push_back(vert);
- face.triangles_uv.push_back(uv);
- unsigned first = face.triangles.back();
- vector2 first_uv = face.triangles_uv.back();
+ unsigned first = vert;
stream >> vert;
uv = read_pair(stream);
+ if (vert < face.triangles_uv.size())
+ {
+ if (uv != face.triangles_uv[vert])
+ {
+ obj->verts.push_back(obj->verts[vert]);
+ face.triangles_uv.resize(obj->verts.size());
+ vert = obj->verts.size() - 1;
+ }
+ }
+ else face.triangles_uv.resize(vert + 1);
+ face.triangles_uv[vert] = uv;
face.triangles.push_back(vert);
- face.triangles_uv.push_back(uv);
stream >> vert;
uv = read_pair(stream);
+ if (vert < face.triangles_uv.size())
+ {
+ if (uv != face.triangles_uv[vert])
+ {
+ obj->verts.push_back(obj->verts[vert]);
+ face.triangles_uv.resize(obj->verts.size());
+ vert = obj->verts.size() - 1;
+ }
+ }
+ else face.triangles_uv.resize(vert + 1);
+ face.triangles_uv[vert] = uv;
face.triangles.push_back(vert);
- face.triangles_uv.push_back(uv);
- unsigned last = face.triangles.back();
- vector2 last_uv = face.triangles_uv.back();
+ unsigned last = vert;
for (int j = 3; j < numrefs; ++j)
{
- // first
face.triangles.push_back(first);
- face.triangles_uv.push_back(first_uv);
-
- // last
face.triangles.push_back(last);
- face.triangles_uv.push_back(last_uv);
stream >> vert;
uv = read_pair(stream);
+ if (vert < face.triangles_uv.size())
+ {
+ if (uv != face.triangles_uv[vert])
+ {
+ obj->verts.push_back(obj->verts[vert]);
+ face.triangles_uv.resize(obj->verts.size());
+ vert = obj->verts.size() - 1;
+ }
+ }
+ else face.triangles_uv.resize(vert + 1);
+ face.triangles_uv[vert] = uv;
face.triangles.push_back(vert);
- face.triangles_uv.push_back(uv);
last = face.triangles.back();
- last_uv = face.triangles_uv.back();
}
}
}
else if (atom == "kids")
{
- for (int i = kids.size(); i > 0; --i)
- {
- if (--kids.top() <= 0)
- {
- ASSERT(obj && "should be an object");
- obj = obj->parent;
- kids.pop();
- }
- else break;
- }
+ //while (0 < kids.size())
+ //{
+ //if (--kids.top() <= 0)
+ //{
+ //ASSERT(obj && "should be an object");
+ //obj = obj->parent;
+ //kids.pop();
+ //}
+ //else break;
+ //}
int numkids = 0;
stream >> numkids;
- if (numkids > 0) kids.push(numkids);
-
- if (kids.size() > 0)
+ if (0 < numkids) kids.push(numkids);
+ else
{
- log_info("KIDS", kids.top(), "|", kids.size());
+ if (0 < kids.size() && 0 < --kids.top()) kids.pop();
+ obj = obj->parent.lock();
}
}
else
}
}
while (stream);
+
+ std::vector<object_ptr>::iterator meh;
+ for (meh = objects_.begin(); meh != objects_.end(); ++meh)
+ {
+ object_ptr cow = *meh;
+ log_info("OBJ: -", cow->name, cow->kids.size());
+
+ std::vector<object_ptr>::iterator foo;
+ for (foo = cow->kids.begin(); foo != cow->kids.end(); ++foo)
+ {
+ log_info("OBJ: -", (*foo)->name, (*foo)->kids.size());
+ }
+ }
}
+//unsigned mesh::read_vertex_line(std::istream& stream)
+//{
+ //unsigned vert;
+ //stream >> vert;
+ //vector2 uv = read_pair(stream);
+ //if (vert < face.triangles_uv.size())
+ //{
+ //if (uv != face.triangles_uv[vert])
+ //{
+ //obj->verts.push_back(obj->verts[vert]);
+ //face.triangles_uv.resize(obj->verts.size());
+ //vert = obj->verts.size() - 1;
+ //}
+ //}
+ //else face.triangles_uv.resize(vert + 1);
+ //face.triangles_uv[vert] = uv;
+ //face.triangles.push_back(vert);
+//}
+
+
mesh::mesh(const std::string& path)
{
void mesh::draw(scalar alpha) const
{
- //glEnableClientState(GL_VERTEX_ARRAY);
- //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-
std::vector<object_ptr>::const_iterator it;
for (it = objects_.begin(); it != objects_.end(); ++it)
{
- (*it)->draw(*this, alpha);
+ (*it)->draw(alpha);
}
+
+ // TODO: disable vertex array?
}
void mesh::set_material(const material& material) const
{
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material.diffuse.data());
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material.ambient.data());
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material.specular.data());
- glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material.emissive.data());
- glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.shininess);
- //glColor(material.diffuse);
+ glColor(material.diffuse);
+ glMaterial(GL_FRONT, GL_DIFFUSE, material.diffuse);
+ glMaterial(GL_FRONT, GL_AMBIENT, material.ambient);
+ glMaterial(GL_FRONT, GL_SPECULAR, material.specular);
+ glMaterial(GL_FRONT, GL_EMISSION, material.emissive);
+ glMaterial(GL_FRONT, GL_SHININESS, material.shininess);
}
-void mesh::object::draw(const mesh& mesh, scalar alpha) const
+void mesh::object::draw(scalar alpha, bool recurse) const
{
- //log_info("cool", verts.size());
- //{
- //image::reset_binding();
- //std::vector<vector3>::const_iterator it;
- //glBegin(GL_LINE_STRIP);
- //for (it = verts.begin(); it != verts.end(); ++it)
- //{
- //glVertex(*it);
- //}
- //glEnd();
- //}
-
- //glPolygonMode(GL_BACK, GL_LINE);
- //glVertexPointer(3, GL_SCALAR, 0, verts[0].data());
- if (texture) texture->bind();
- else image::reset_binding();
+ glVertexPointer(verts);
+
+ if (texture)
+ {
+ texture->bind();
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ else
+ {
+ image::reset_binding();
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
for (size_t i = 0; i < faces.size(); ++i)
{
const material_group& face = faces[i];
+ if (face.triangles.size() == 0) continue;
+
mesh.set_material(i);
- //it->draw(alpha);
- //std::vector<unsigned>::const_iterator jt;
- int count = face.triangles.size();
- for (int j = 0; j < count; j += 3)
- {
- glBegin(GL_TRIANGLES);
- glTexCoord(face.triangles_uv[j]);
- glVertex(verts[face.triangles[j]]);
- glTexCoord(face.triangles_uv[j+1]);
- glVertex(verts[face.triangles[j+1]]);
- glTexCoord(face.triangles_uv[j+2]);
- glVertex(verts[face.triangles[j+2]]);
- glEnd();
- }
- }
- std::vector<object_ptr>::const_iterator jt;
- for (jt = kids.begin(); jt != kids.end(); ++jt)
- {
- (*jt)->draw(mesh, alpha);
+ if (texture) glTexCoordPointer(face.triangles_uv);
+ glDrawElements(GL_TRIANGLES, face.triangles);
}
-}
-void mesh::material_group::draw(scalar alpha) const
-{
- // TODO: setup material
-
- /*
- if (triangles.size() > 0)
+ if (recurse)
{
- //log_info("drawing triangles:", triangles.size()/3);
- glTexCoordPointer(2, GL_SCALAR, 0, triangles_uv[0].data());
- glDrawElements(GL_TRIANGLES,
- triangles.size(), GL_UNSIGNED_INT,
- &triangles[0]);
+ std::vector<object_ptr>::const_iterator jt;
+ for (jt = kids.begin(); jt != kids.end(); ++jt)
+ {
+ (*jt)->draw(alpha);
+ }
}
- */
}
-class mesh_resource_loader
-{
-public:
+//class mesh_resource_loader
+//{
+//public:
- mesh_resource_loader()
- {
- resource::register_type<mesh>("ac", "models");
- }
+ //mesh_resource_loader()
+ //{
+ //resource::register_type<mesh>("ac", "models");
+ //}
- ~mesh_resource_loader()
- {
- resource::unregister_type("ac");
- }
-};
+ //~mesh_resource_loader()
+ //{
+ //resource::unregister_type("ac");
+ //}
+//};
-static mesh_resource_loader loader;
+//static mesh_resource_loader loader;
} // namespace moof
*/
#include <iostream>
+#include <map>
+#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
-#include <moof/drawable.hh>
+#include <moof/entity.hh>
#include <moof/image.hh>
#include <moof/math.hh>
#include <moof/resource.hh>
namespace moof {
-class mesh : public boost::noncopyable, public drawable
+class script;
+
+
+class mesh : public boost::noncopyable, public entity
{
public:
std::string name;
vector4 diffuse;
- vector3 ambient;
- vector3 emissive;
- vector3 specular;
+ vector4 ambient;
+ vector4 emissive;
+ vector4 specular;
scalar shininess;
};
void set_material(int index) const;
void set_material(const material& material) const;
- struct material_group : public drawable
+ struct material_group
{
- material_group() {}
-
- void draw(scalar alpha = SCALAR(0.0)) const;
-
-
std::vector<unsigned> triangles;
std::vector<vector2> triangles_uv;
};
class object;
typedef boost::shared_ptr<object> object_ptr;
+ typedef boost::weak_ptr<object> object_weakptr;
struct object
{
- object() :
+ object(const mesh& m) :
+ mesh(m),
texrep(SCALAR(1.0), SCALAR(1.0)) {}
- static object_ptr alloc()
+ static object_ptr alloc(const mesh& m)
{
- return object_ptr(new object);
+ return object_ptr(new object(m));
}
+ void draw(scalar alpha = SCALAR(0.0), bool recurse = true) const;
- void draw(const mesh& mesh, scalar alpha = SCALAR(0.0)) const;
+ const moof::mesh& mesh;
std::string name;
std::string data;
std::vector<material_group> faces;
std::vector<object_ptr> kids;
- object_ptr parent;
+ std::map<std::string,object_ptr> kids_byname;
+ object_weakptr parent;
};
+ object_ptr operator [] (unsigned index) const
+ {
+ return objects_[index];
+ }
+
+
+ /**
+ * Import script bindings for the mesh class.
+ * \param The script.
+ * \param The name of the namespace to import to.
+ */
+ static void import(script& script, const std::string& nspace = "");
+
+
private:
void import(std::istream& stream);
--- /dev/null
+
+/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+**] All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+#include "log.hh"
+#include "mesh.hh"
+#include "script.hh"
+
+
+namespace moof {
+
+
+static int mesh_new(script& script)
+{
+ script::slot name = script[2].require_string("mesh name");
+
+ std::string str;
+ name.get(str);
+
+ mesh_handle mesh = resource::load(str, "ac");
+ if (!mesh) name.raise("unable to load mesh from file");
+
+ script.push(mesh);
+ return 1;
+}
+
+static int mesh_draw(script& script)
+{
+ mesh_handle* mesh;
+ script[1].require_object<mesh_handle>("mesh").get(mesh);
+
+ scalar alpha;
+ if (script[2].get(alpha)) (*mesh)->draw(alpha);
+ else (*mesh)->draw();
+
+ return 0;
+}
+
+static int mesh_index(script& script)
+{
+ mesh_handle* mesh;
+ script[1].require_object<mesh_handle>("mesh").get(mesh);
+
+ unsigned index;
+ script[2].require_number("index").get(index);
+ --index;
+
+ script.push((**mesh)[index]);
+ script::slot e = script[-1].push_environment();
+ e.set_field("mesh", *mesh);
+ e.pop();
+ return 1;
+}
+
+
+static int object_new(script& script)
+{
+ return script.raise("cannot construct a mesh object without a mesh");
+}
+
+static int object_draw(script& script)
+{
+ mesh::object_ptr* object;
+ script[1].require_object<mesh::object_ptr>("mesh object").get(object);
+
+ scalar alpha;
+ bool recurse;
+ if (script[2].get(alpha))
+ {
+ if (script[3].get(recurse)) (*object)->draw(alpha, recurse);
+ else (*object)->draw(alpha);
+ }
+ else
+ {
+ if (script[2].get(recurse)) (*object)->draw(SCALAR(0.0), recurse);
+ else (*object)->draw();
+ }
+
+ return 0;
+}
+
+static int object_index(script& script)
+{
+ mesh::object_ptr* object;
+ script[1].require_object<mesh::object_ptr>("mesh object").get(object);
+
+ if (script[2].is_number())
+ {
+ unsigned index;
+ script[2].get(index);
+ --index;
+ script.push((*object)->kids[index]);
+ }
+ else if (script[2].is_string())
+ {
+ std::string name;
+ script[2].get(name);
+ script.push((*object)->kids_byname[name]);
+ }
+ else
+ {
+ script[2].raise_type_error("index or name");
+ }
+ return 1;
+}
+
+
+void mesh::import(script& script, const std::string& nspace)
+{
+ script.check_stack(8);
+
+ script::slot parent = script.push_table(nspace);
+ script::slot meta = script.push_class<mesh_handle>(mesh_new);
+
+ meta.set_field("draw", mesh_draw);
+ meta.set_field("object", mesh_index);
+
+ script::slot object_meta = script.push_class<mesh::object_ptr>(object_new);
+ object_meta.set_field("draw", object_draw);
+ object_meta.set_field("kid", object_index);
+ meta.set_field("__object");
+
+ parent.set_field("mesh");
+ parent.pop();
+}
+
+
+} // namespace moof
+
"%s", text2.c_str());
gtk_window_set_title(GTK_WINDOW(dialog), title.c_str());
- std::string icon_path(PACKAGE".png");
- if (resource::find(icon_path))
+ std::string icon_path = resource::find_file(PACKAGE".png");
+ if (!icon_path.empty())
{
GdkPixbuf* iconPixbuf = gdk_pixbuf_new_from_file(icon_path.c_str(),
NULL);
dialog.setInformativeText(text2.c_str());
dialog.setStandardButtons(QMessageBox::Close);
- std::string icon_path(PACKAGE".png");
- if (resource::find(icon_path))
+ std::string icon_path = resource::find_file(PACKAGE".png");
+ if (!icon_path.empty())
{
QIcon icon(icon_path.c_str());
dialog.setWindowIcon(icon);
#include "config.h"
+#include <vector>
+
#include <SDL/SDL_opengl.h>
#include <moof/math.hh>
OPENGL_GENERIC_FUNC(void, Rect, V4);
+inline void glMaterial(GLenum face, GLenum pname, moof::scalar s)
+{
+ glMaterialf(face, pname, float(s));
+}
+
+inline void glMaterial(GLenum face, GLenum pname, const moof::vector4& v)
+{
+#if USE_DOUBLE_PRECISION
+ float f[] = {v[0], v[1], v[2], v[3]};
+ glMaterialfv(face, pname, f);
+#else
+ glMaterialfv(face, pname, v.data());
+#endif
+}
+
+inline void glVertexPointer(const std::vector<moof::vector3>& v)
+{
+ glVertexPointer(3, GL_SCALAR, 0, v[0].data());
+}
+inline void glTexCoordPointer(const std::vector<moof::vector2>& v)
+{
+ glTexCoordPointer(2, GL_SCALAR, 0, v[0].data());
+}
+
+inline void glDrawElements(GLenum type, const std::vector<GLuint>& v)
+{
+ glDrawElements(type, v.size(), GL_UNSIGNED_INT, &v[0]);
+}
+
+
#if USE_DOUBLE_PRECISION
inline void glGetScalar(GLenum a, GLscalar* b) { glGetDoublev(a, b); }
#else
#include "config.h"
+#include <queue>
+
#ifdef USE_HOTLOADING
#include <sys/inotify.h>
#include <sys/ioctl.h>
#endif
-#include <queue>
-
#include <boost/algorithm/string.hpp>
#include <boost/weak_ptr.hpp>
#include <stlplus/portability/file_system.hpp>
namespace moof {
-bool resource::call_registry(const std::string& extension,
- loader_ptr& loader,
- registry_action action)
+/*] Filesystem searching
+ *************************************************************************/
+
+static std::vector<std::string> search_paths_;
+
+void resource::set_search_paths(const std::string& paths)
{
- static type_lookup table;
+ boost::split(search_paths_, paths, boost::is_any_of(":"));
+}
- switch (action)
+
+std::string resource::find_file(const std::string& name)
+{
+ std::string ext = stlplus::extension_part(name);
+ std::string prefix;
+ std::string path;
+
+ loader_ptr loader;
+ call_registry(ext, loader, lookup);
+ if (loader) prefix = loader->prefix();
+
+ std::vector<std::string>::iterator it;
+ for (it = search_paths_.begin(); it != search_paths_.end(); ++it)
{
- case set:
+ if (!prefix.empty())
{
- if (loader) table[extension] = loader;
- else table.erase(extension);
- break;
+ // try it with the prefix first
+ path = stlplus::filespec_to_path(*it, prefix);
+ path = stlplus::filespec_to_path(path, name);
+ log_info("looking for", name, "at", path);
+ if (stlplus::file_exists(path)) return path;
}
- case lookup:
- {
- std::map<std::string,loader_ptr>::iterator it;
- it = table.find(extension);
- if (it != table.end()) loader = (*it).second;
- break;
- }
+ path = stlplus::filespec_to_path(*it, name);
+ log_info("looking for", name, "at", path);
+ if (stlplus::file_exists(path)) return path;
}
- return loader;
+ log_error("cannot find resource file:", name);
+ return std::string();
}
-static std::string search_paths_;
-
-typedef boost::weak_ptr<resource> resource_weakptr;
-static hash<std::string,resource_weakptr,hash_function> resource_table_;
-
-static hash<std::string,std::string,hash_function> prefix_table_;
+std::string resource::find_file(const std::string& name,
+ const std::string& ext)
+{
+ std::string actual_ext = stlplus::extension_part(name);
+ if (actual_ext != ext)
+ {
+ // try the explicit extension first
+ return find_file(stlplus::create_filename(name, ext));
+ }
+ return find_file(name);
+}
-#ifdef USE_HOTLOADING
-static hash<int,std::string,hash_function> monitor_lookup_;
-static int monitor_fd_ = inotify_init1(IN_NONBLOCK);
-#endif
+/*] Resource loading
+ *************************************************************************/
-int resource::reload_as_needed()
+typedef boost::weak_ptr<resource> resource_weakptr;
+static struct rsrc_list
{
- int num_resources = 0;
+ // this table holds weak references to any and all loaded resources
+ hash<std::string,resource_weakptr,hash_function> table;
-#ifdef USE_HOTLOADING
- log_info("hotloading?");
- char bytes[BUF_SIZE];
- int num_bytes;
- if (0 < (num_bytes = read(monitor_fd_, bytes, num_bytes)))
+#ifdef DEBUG
+ // this destructor will let us know if the program exits while
+ // resources are still being held
+ ~rsrc_list()
{
- char* end = bytes + num_bytes;
- char* byte = bytes;
-
- log_warning("num_bytes:", num_bytes);
- log_error("1");
-
- while (byte < end)
+ hash<std::string,resource_weakptr,hash_function>::iterator it;
+ for (it = table.begin(); it != table.end(); ++it)
{
- struct inotify_event* event = (struct inotify_event*)byte;
+ log_warning("leaked resource:", (*it).first);
+ }
+ }
+#endif
+} rsrc_list;
- if (event->mask & IN_IGNORED)
- {
- log_warning("watch", event->wd, "removed");
- }
+#ifdef USE_HOTLOADING
+static struct watch_list
+{
+ // this table associates a watch descriptor with a loaded resource
+ hash<int,resource_weakptr,hash_function> table;
- log_error("2");
- hash<int,std::string,hash_function>::iterator it;
- it = monitor_lookup_.find(event->wd);
- if (it != monitor_lookup_.end())
- {
- log_error("3");
- std::string path = (*it).second;
- monitor_lookup_.erase(it);
- resource::reload(path);
- }
+ int fd; // the inotify file descriptor
- byte += sizeof(*event) + event->len;
+ watch_list() :
+ fd(inotify_init1(IN_NONBLOCK)) {}
- ++num_resources;
- }
+ ~watch_list()
+ {
+ close(fd);
}
-#endif
- return num_resources;
-}
+ int add(resource_ptr rsrc)
+ {
+ int wd = inotify_add_watch(fd, rsrc->path().c_str(),
+ IN_DELETE_SELF | IN_MODIFY);
+ table[wd] = rsrc;
+ return wd;
+ }
+ void remove(int wd)
+ {
+ if (wd != -1) inotify_rm_watch(fd, wd);
+ }
+} watch_list;
+#endif
-resource::~resource()
+resource_ptr resource::load(const std::string& name)
{
-#ifdef USE_HOTLOADING
- inotify_rm_watch(monitor_fd_, wd_);
-#endif
+ std::string ext = stlplus::extension_part(name);
+ return load_with_path(find_file(name, ext), ext);
}
-
resource_ptr resource::load(const std::string& name,
const std::string& ext)
{
- return load_with_path(find_file(name, ext));
-}
-
-resource_ptr resource::load(const std::string& name)
-{
- return load_with_path(find_file(name));
+ return load_with_path(find_file(name, ext), ext);
}
-resource_ptr resource::load_with_path(const std::string& path)
+resource_ptr resource::load_with_path(const std::string& path,
+ const std::string& ext)
{
- std::string extension = stlplus::extension_part(path);
+ if (path.empty()) return resource_ptr();
+ // first try to lookup the resource
hash<std::string,resource_weakptr,hash_function>::iterator it;
- it = resource_table_.find(path);
- if (it != resource_table_.end())
+ it = rsrc_list.table.find(path);
+ if (it != rsrc_list.table.end())
{
- resource_weakptr rsrc = (*it).second;
- resource_ptr locked = rsrc.lock();
- if (locked) return locked;
+ resource_ptr rsrc = (*it).second.lock();
+ if (rsrc) return rsrc;
}
+ // then proceed to use the registered loader to get the resource
loader_ptr loader;
- call_registry(extension, loader, lookup);
+ call_registry(ext, loader, lookup);
if (loader)
{
resource_ptr rsrc(loader->load(path));
- rsrc->set_loader(path, loader);
- resource_table_[path] = rsrc;
-
+ rsrc_list.table[path] = rsrc;
+ rsrc->path_ = path;
+ rsrc->type_ = ext;
#ifdef USE_HOTLOADING
- int wd = inotify_add_watch(monitor_fd_, path.c_str(), IN_MODIFY);
- rsrc->set_watch_descriptor(wd);
- monitor_lookup_[wd] = path;
+ rsrc->wd_ = watch_list.add(rsrc);
#endif
-
- log_info("loaded", rsrc.get());
return rsrc;
}
- log_warning("cannot load resource of unknown type:", path);
+ log_warning("cannot load resource of unregistered type:", path);
return resource_ptr();
}
-resource_ptr resource::reload(std::string& path)
+/*] Hotloading
+ *************************************************************************/
+
+int resource::reload_as_needed()
{
- log_info("reloading...", path);
- hash<std::string,resource_weakptr,hash_function>::iterator it;
- it = resource_table_.find(path);
- if (it != resource_table_.end())
+ int count = 0;
+
+#ifdef USE_HOTLOADING
+ char bytes[BUF_SIZE];
+ int num_bytes;
+ // an inotify file descriptor lets your read inotify_event structures
+ if (0 < (num_bytes = read(watch_list.fd, bytes, sizeof(bytes))))
{
- resource_weakptr rsrc = (*it).second;
- resource_ptr locked = rsrc.lock();
- if (locked)
+ char* end = bytes + num_bytes;
+ char* byte = bytes;
+
+ while (byte < end)
{
- locked->reload();
- return locked;
+ struct inotify_event* event = (struct inotify_event*)byte;
+ byte += sizeof(*event) + event->len;
+
+ hash<int,resource_weakptr,hash_function>::iterator it;
+ it = watch_list.table.find(event->wd);
+ if (it != watch_list.table.end())
+ {
+ resource_ptr rsrc = (*it).second.lock();
+ if (rsrc)
+ {
+ rsrc->reload();
+ ++count;
+
+ if (event->mask & IN_IGNORED)
+ {
+ watch_list.table.erase(event->wd);
+ rsrc->wd_ = watch_list.add(rsrc);
+ }
+ }
+ else
+ {
+ // if we can't lock the resource, it was unloaded so we
+ // don't need to watch it anymore
+ watch_list.table.erase(event->wd);
+ }
+ }
}
}
+#endif
- return load(path);
+ return count;
}
void resource::reload()
{
- log_info("reloaded", path_);
+ loader_ptr loader;
+ call_registry(type_, loader, lookup);
- resource* resource = loader_->load(path_);
- //*this = *resource;
+ resource_ptr resource(loader->load(path_));
resource_ = resource->resource_;
typeinfo_ = resource->typeinfo_;
unloader_ = resource->unloader_;
+}
+resource::~resource()
+{
+ rsrc_list.table.erase(path_);
#ifdef USE_HOTLOADING
- int wd = inotify_add_watch(monitor_fd_, path_.c_str(), IN_MODIFY);
- set_watch_descriptor(wd);
- monitor_lookup_[wd] = path_;
+ watch_list.remove(wd_);
#endif
-
- delete resource;
}
-void resource::add_search_paths(const std::string& paths)
-{
- search_paths_ = paths;
-}
+/*] Resource registration
+ *************************************************************************/
-
-std::string resource::find_file(const std::string& name)
+bool resource::call_registry(const std::string& ext,
+ loader_ptr& loader,
+ registry_action action)
{
- std::vector<std::string> paths;
- boost::split(paths, search_paths_, boost::is_any_of(":"));
-
- std::string ext = stlplus::extension_part(name);
- std::string prefix("hi");
-
- loader_ptr loader;
- call_registry(ext, loader, lookup);
- if (loader) prefix = loader->prefix();
+ static std::map<std::string,loader_ptr> table;
- log_info("find_file:", ext, prefix);
-
- std::vector<std::string>::iterator it;
- for (it = paths.begin(); it != paths.end(); ++it)
+ switch (action)
{
- std::string path = stlplus::create_filespec(*it, name);
- log_info("looking for", name, "at", path);
- if (stlplus::file_exists(path)) return path;
-
- // try it with the prefix added
- if (!prefix.empty())
+ case set:
{
- *it = stlplus::create_filespec(*it, prefix);
- path = stlplus::create_filespec(*it, name);
- log_info("looking for", name, "at", path);
- if (stlplus::file_exists(path)) return path;
+ if (loader) table[ext] = loader;
+ else table.erase(ext);
+ break;
}
- }
-
- log_error("cannot find resource file:", name);
- return std::string();
-}
-
-std::string resource::find_file(const std::string& name,
- const std::string& ext)
-{
- std::string actual_ext = stlplus::extension_part(name);
- if (actual_ext != ext)
- {
- return find_file(stlplus::create_filename(name, ext));
+ case lookup:
+ {
+ std::map<std::string,loader_ptr>::iterator it;
+ it = table.find(ext);
+ if (it != table.end()) loader = (*it).second;
+ break;
+ }
}
- return find_file(name);
+
+ return loader;
}
* Interface for textures, sounds, and other types of resources.
*/
-#include "config.h"
-
#include <map>
#include <stdexcept>
#include <string>
{
public:
- // XXX: this won't be necessary once the existing code is modified to
- // use the resource handles
- resource() {}
-
/**
* Add a directory to search when looking for resource files.
* \param paths A colon-separated list of directory paths.
*/
- static void add_search_paths(const std::string& paths);
+ static void set_search_paths(const std::string& paths);
/**
- * Get the path to a resource of a given name.
- * \param path The name of the resource to find. Upon successful
- * return, this is changed to an absolute path to the resource.
- * \return True if a path to a resource was found, false otherwise.
+ * Get the path to a resource of a given name. This uses the search
+ * path(s) and resources prefixes to locate resource files.
+ * \param name The name or partial path of the resource to find.
+ * \return The full path of the resource.
*/
static std::string find_file(const std::string& name);
+ /**
+ * Get the path to a resource of a given name and explicit type. This
+ * uses the search path(s) and resources prefixes to locate resource
+ * files.
+ * \param name The name or partial path of the resource to find.
+ * \param ext The extension is appended to the name if the same
+ * extension is not already a part of name.
+ * \return The full path of the resource.
+ */
static std::string find_file(const std::string& name,
const std::string& ext);
* Unregister the type associated with a file extension. Resources of
* this type will no longer be loadable, although resources which are
* already loaded will remain loaded.
- * \param extension The file extension
+ * \param extension The file extension.
*/
static void unregister_type(const std::string& extension)
{
}
+ /**
+ * Find and load a resource by name or path.
+ * \param name The name or partial path of the resource. This should
+ * include the extension so that the correct loader can be chosen.
+ * \return The resource.
+ */
static resource_ptr load(const std::string& name);
+
+ /**
+ * Find and load a resource by name or path.
+ * \param name The name or partial path of the resource. This should
+ * include the extension so that the correct loader can be chosen.
+ * \param
+ * \return The resource.
+ */
static resource_ptr load(const std::string& name,
const std::string& ext);
- static resource_ptr reload(std::string& path);
-
/**
- * Construct a resource container.
- * \param ptr A pointer to the underlying resource data.
+ * Reload the resource data. This will cause the resource file to be
+ * reread, and the underlying resource data will change.
*/
- template <class T>
- explicit resource(T* ptr) :
- resource_(ptr),
- typeinfo_(const_cast<std::type_info*>(&typeid(T))),
- unloader_(new specific_unloader<T>(ptr)) {}
+ void reload();
/**
- * Deconstruct a resource container.
+ * Get the path of file from which this resource was loaded.
+ * \return The path.
*/
- virtual ~resource();
-
+ std::string path() const
+ {
+ return path_;
+ }
/**
- * Reload the resource data. This will cause the resource file to be
- * reread, and the underlying resource data will change.
+ * Reloads some resources which have been modified on disk since they
+ * were loaded. Hotloading must have been enabled at compile-time.
+ * \return The number of resources reloaded.
*/
- void reload();
+ static int reload_as_needed();
/**
/**
- * Reloads some resources which have been modified on disk since they
- * were loaded. Hotloading must have been enabled at compile-time.
- * \return The number of resources reloaded.
+ * Deconstruct a resource container.
*/
- static int reload_as_needed();
+ virtual ~resource();
private:
- static resource_ptr load_with_path(const std::string& path);
+ template <class T>
+ explicit resource(T* ptr) :
+ resource_(ptr),
+ typeinfo_(const_cast<std::type_info*>(&typeid(T))),
+ unloader_(new specific_unloader<T>(ptr)),
+ wd_(-1) {}
+
+ static resource_ptr load_with_path(const std::string& path,
+ const std::string& extension);
+
class loader
{
public:
- //loader() {}
loader(const std::string& prefix) :
prefix_(prefix) {}
{
public:
- //specific_loader() {}
specific_loader(const std::string& prefix) :
loader(prefix) {}
virtual resource* load(const std::string& path)
{
- log_info("loading resource of type ", typeid(T).name());
return new resource(new T(path));
}
};
virtual ~specific_unloader()
{
- log_info("unloading resource of type ", typeid(T).name());
delete object_;
}
};
- void set_loader(const std::string& path, loader_ptr loader)
- {
- path_ = path;
- loader_ = loader;
- }
-
-
- void* resource_;
- std::type_info* typeinfo_;
- unloader_ptr unloader_;
-
- std::string path_;
- loader_ptr loader_;
-
- typedef std::map<std::string,loader_ptr> type_lookup;
- //typedef boost::shared_ptr<type_lookup> type_lookup_ptr;
- //static type_lookup_ptr type_lookup_;
- //static type_lookup type_lookup_;
-
enum registry_action
{
lookup,
loader_ptr& loader,
registry_action action);
-#ifdef USE_HOTLOADING
- int wd_;
- void set_watch_descriptor(int wd)
- {
- wd_ = wd;
- }
-#endif
+ void* resource_;
+ std::type_info* typeinfo_;
+ unloader_ptr unloader_;
+ int wd_;
+ std::string path_;
+ std::string type_;
};
resource_(resource::load(name, ext)) {}
-
/**
* Get whether or not the handle is dereferenceable to the type of this
* handle. A resource handle is dereferenceable if it is not a null
};
+/**
+ * This macro easily registers types to act as resources. It should be
+ * used in a module file in global scope.
+ * \param TYPE The type (class), qualified as needed for the scope.
+ * \param EXT The file extension the resource uses.
+ * \param PREFIX The path prefix where a resource of this type could be.
+ */
+#define MOOF_REGISTER_RESOURCE(TYPE, EXT, PREFIX) \
+namespace { \
+ struct EXT { \
+ EXT() { moof::resource::register_type<TYPE>(#EXT, #PREFIX); } \
+ ~EXT() { moof::resource::unregister_type(#EXT); } \
+ }; \
+ static EXT EXT; \
+}
+
+
} // namespace moof
#endif // _MOOF_RESOURCE_HH_
/**
* \file script.hh
- * A thin wrapper over Lua. This is not meant as a complicated binding
+ * A thin wrapper over Lua 5.1. This is not meant as a complicated binding
* package between C++ and Lua. It is not meant to obscure the division
* between C++ and Lua but rather to clarify it and make it more
* manageable. It does not hide the concept of the Lua stack, but rather
* providing a cleaner, more consistent API.
*/
+#include <cstring>
#include <iostream>
-#include <list>
#include <map>
+#include <stdexcept>
#include <string>
+#include <sstream>
+#include <utility>
#include <vector>
#include <boost/bind.hpp>
public:
typedef boost::function<int(script&)> function;
+ typedef int (*cfunction)(script&);
enum status
{
globals_index = LUA_GLOBALSINDEX
};
+
+ template <class T>
+ static int object_finalizer(script& script)
+ {
+ reinterpret_cast<T*>(script[1].get_data())->~T();
+ return 0;
+ }
+
+
/**
* This is the most prominent abstraction on top of the standard Lua
* API. A slot object represents a value on the stack. More
* value of which will change as things are pushed onto and popped from
* the stack).
*/
-
struct slot
{
/**
* You have direct access to the index of the value on the stack
* being represented.
*/
-
int index;
thread = LUA_TTHREAD
};
+ static std::string type_name(type type)
+ {
+ switch (type)
+ {
+ case none: return "none";
+ case nil: return "nil";
+ case boolean: return "boolean";
+ case light_data:
+ case data: return "userdata";
+ case number: return "number";
+ case string: return "string";
+ case table: return "table";
+ case function: return "function";
+ case thread: return "thread";
+ }
+ return "?";
+ }
+
slot(const class script& s, int i = 0) :
index(i),
- script_(const_cast<class script&>(s)) {}
-
- /**
- * A copied value presently points to the same value, except the
- * real index is used. That means that if a value that refers to a
- * frame referenced from the top of the stack will have its
- * normalized index copied into the new value object.
- */
-
- //slot(const slot& copy) :
- //index(copy.positiveIndex()),
- //script_(copy.script_) {}
+ script_(const_cast<class script*>(&s)) {}
// check the type of the value
bool is_boolean() const
- { return (bool)lua_isboolean(script_.state_, index); }
+ { return (bool)lua_isboolean(script_->state_, index); }
bool is_imported_function() const
- { return (bool)lua_iscfunction(script_.state_, index); }
+ { return (bool)lua_iscfunction(script_->state_, index); }
bool is_function() const
- { return (bool)lua_isfunction(script_.state_, index); }
+ { return (bool)lua_isfunction(script_->state_, index); }
bool is_nil() const
- { return (bool)lua_isnil(script_.state_, index); }
+ { return (bool)lua_isnil(script_->state_, index); }
bool is_none() const
- { return (bool)lua_isnone(script_.state_, index); }
+ { return (bool)lua_isnone(script_->state_, index); }
bool is_none_or_nil() const
- { return (bool)lua_isnoneornil(script_.state_, index); }
+ { return (bool)lua_isnoneornil(script_->state_, index); }
bool is_number() const
- { return (bool)lua_isnumber(script_.state_, index); }
+ { return (bool)lua_isnumber(script_->state_, index); }
bool is_string() const
- { return (bool)lua_isstring(script_.state_, index); }
+ { return (bool)lua_isstring(script_->state_, index); }
bool is_table() const
- { return (bool)lua_istable(script_.state_, index); }
+ { return (bool)lua_istable(script_->state_, index); }
bool is_thread() const
- { return (bool)lua_isthread(script_.state_, index); }
+ { return (bool)lua_isthread(script_->state_, index); }
bool is_data() const
- { return (bool)lua_isuserdata(script_.state_, index); }
+ { return (bool)lua_isuserdata(script_->state_, index); }
bool is_light_data() const
- { return (bool)lua_islightuserdata(script_.state_, index); }
+ { return (bool)lua_islightuserdata(script_->state_, index); }
/**
* Check the value and throw an error if its the wrong type.
- * There's a little caveat: This method never returns because it
- * does a long jump. Consequently, constructed C++ objects which
- * exist on the stack between the current frame and some lua
- * function will not be destructed. That's not a problem for
- * objects that only exist on the stack, but any objects that
- * allocate memory on the heap (such as containers or strings) will
- * leak. Therefore, you should only call this method after
- * cleaning up such objects. The best thing to do for defining
- * functions is to simply check all the parameters at the get-go
- * before any C++ objects are even constructed.
*/
-
- void require_type(type t) const
+ const slot& require_type(type t) const
{
- if (t != type())
- {
- luaL_typerror(script_.state_, index,
- lua_typename(script_.state_, t));
- }
+ if (t != type()) raise_type_error(type_name(t));
+ return *this;
}
- void raise(const char* error)
+ const slot& require_boolean(const std::string& what = "boolean") const
{
- luaL_argerror(script_.state_, index, error);
+ if (!is_boolean()) raise_type_error(what);
+ return *this;
}
-
-
- slot& require_boolean()
+ const slot& require_number(const std::string& what = "number") const
{
- if (!is_boolean())
- {
- luaL_typerror(script_.state_, index, "boolean");
- }
+ if (!is_number()) raise_type_error(what);
return *this;
}
- slot& require_number()
+ const slot& require_string(const std::string& what = "string") const
{
- if (!is_number())
- {
- luaL_typerror(script_.state_, index, "number");
- }
+ if (!is_string()) raise_type_error(what);
return *this;
}
- slot& require_string()
+ const slot& require_table(const std::string& what = "table") const
{
- if (!is_string())
- {
- luaL_typerror(script_.state_, index, "string");
- }
+ if (!is_table()) raise_type_error(what);
return *this;
}
- slot& require_table()
+ const slot& require_function(const std::string& what = "function") const
{
- if (!is_table())
- {
- luaL_typerror(script_.state_, index, "table");
- }
+ if (!is_function()) raise_type_error(what);
return *this;
}
- slot& require_function()
+ const slot& require_data(const std::string& what = "userdata") const
{
- if (!is_function())
- {
- luaL_typerror(script_.state_, index, "function");
- }
+ if (!is_data()) raise_type_error(what);
return *this;
}
- slot& require_data()
+ const slot& require_nil(const std::string& what = "nil") const
{
- if (!is_data())
- {
- luaL_typerror(script_.state_, index, "data");
- }
+ if (!is_nil()) raise_type_error(what);
return *this;
}
- slot& require_nil()
+ const slot& require_thread(const std::string& what = "thread") const
{
- if (!is_nil())
- {
- luaL_typerror(script_.state_, index, "nil");
- }
+ if (!is_thread()) raise_type_error(what);
return *this;
}
- slot& require_thread()
+
+ template <class T>
+ const slot& require_object(const std::string& what = typeid(T).name()) const
{
- if (!is_thread())
+ if (!is_data()) raise_type_error(what);
+
+ slot metatable = push_metatable();
+ if (!metatable.is_table())
{
- luaL_typerror(script_.state_, index, "thread");
+ metatable.pop();
+ raise_type_error(what);
}
+
+ slot type = metatable.push_field("__cxxtype");
+ std::type_info* typeinfo;
+ if (!type.get(typeinfo))
+ {
+ metatable.pop();
+ raise_type_error(what);
+ }
+
+ metatable.pop();
+ if (*typeinfo != typeid(T)) raise_type_error(what);
return *this;
}
/**
* Get the type of the value.
*/
-
enum type type() const
{
- return (enum type)lua_type(script_.state_, index);
+ return (enum type)lua_type(script_->state_, index);
}
/**
* Get the name of the type of the value as a string.
*/
-
std::string type_name() const
{
- return std::string(luaL_typename(script_.state_, index));
+ if (is_none()) return "none";
+ else if (is_data() && !is_light_data())
+ {
+ slot metatable = push_metatable();
+ if (!metatable.is_table())
+ {
+ metatable.pop();
+ return "userdata";
+ }
+
+ slot type = metatable.push_field("__cxxtype");
+ std::type_info* typeinfo;
+ if (!type.get(typeinfo))
+ {
+ metatable.pop();
+ return "userdata";
+ }
+
+ metatable.pop();
+ return typeinfo->name();
+ }
+ return luaL_typename(script_->state_, index);
}
* Get the length of the value according to the definition given by
* Lua.
*/
+ size_t size() const
+ {
+ return lua_objlen(script_->state_, index);
+ }
size_t length() const
{
- return lua_objlen(script_.state_, index);
+ return size();
}
- int positiveIndex() const
+ int positive_index() const
{
- if (index < 0) return index + lua_gettop(script_.state_) + 1;
+ if (index < 0) return index + lua_gettop(script_->state_) + 1;
else return index;
}
* Get a pointer value (for userdata, tables, threads, and
* functions).
*/
-
const void* id() const
{
- return lua_topointer(script_.state_, index);
+ return lua_topointer(script_->state_, index);
}
bool is_identical(const slot& rhs) const
{
- return &script_ == &(rhs.script_) && index == rhs.index;
+ return script_ == rhs.script_ && index == rhs.index;
}
operator bool () const
bool operator == (const slot& rhs) const
{
- return (bool)lua_equal(script_.state_, index, rhs.index);
- }
- bool operator != (const slot& rhs) const
- {
- return !(*this == rhs);
+ return (bool)lua_equal(script_->state_, index, rhs.index);
}
bool operator < (const slot& rhs) const
{
- return (bool)lua_lessthan(script_.state_, index, rhs.index);
- }
- bool operator <= (const slot& rhs) const
- {
- return *this < rhs || *this == rhs;
- }
- bool operator > (const slot& rhs) const
- {
- return !(*this <= rhs);
- }
- bool operator >= (const slot& rhs) const
- {
- return !(*this < rhs);
+ return (bool)lua_lessthan(script_->state_, index, rhs.index);
}
/**
* Convert the underlying value to a C++ type.
*/
-
template <class T>
bool get(T& value) const
{
if (is_number())
{
- value = (T)lua_tointeger(script_.state_, index);
+ value = (T)lua_tointeger(script_->state_, index);
return true;
}
return false;
{
if (is_number())
{
- value = (float)lua_tonumber(script_.state_, index);
+ value = (float)lua_tonumber(script_->state_, index);
return true;
}
return false;
{
if (is_number())
{
- value = (double)lua_tonumber(script_.state_, index);
+ value = (double)lua_tonumber(script_->state_, index);
return true;
}
return false;
{
if (is_boolean())
{
- value = (bool)lua_toboolean(script_.state_, index);
+ value = (bool)lua_toboolean(script_->state_, index);
return true;
}
return false;
{
if (is_string())
{
- value = lua_tolstring(script_.state_, index, &size);
+ value = lua_tolstring(script_->state_, index, &size);
return true;
}
return false;
return false;
}
- bool get(void*& value) const
+ template <class T>
+ bool get(T*& value) const
{
if (is_data())
{
- value = lua_touserdata(script_.state_, index);
+ value = reinterpret_cast<T*>(lua_touserdata(script_->state_, index));
return true;
}
return false;
}
+ void* get_data() const
+ {
+ return lua_touserdata(script_->state_, index);
+ }
template <class T>
bool get(std::vector<T>& array) const
array.clear();
- slot value = script_[-1];
- int realIndex = positiveIndex();
+ slot value = (*script_)[-1];
+ int realIndex = positive_index();
bool done = false;
for (int i = 1; !done; ++i)
{
- lua_rawgeti(script_.state_, realIndex, i);
+ lua_rawgeti(script_->state_, realIndex, i);
T v;
if (value.get(v)) array.push_back(v);
else done = true;
- script_.pop();
+ script_->pop();
}
return true;
dictionary.clear();
- slot key = script_[-2];
- slot value = script_[-1];
- int realIndex = positiveIndex();
+ slot key = (*script_)[-2];
+ slot value = (*script_)[-1];
+ int realIndex = positive_index();
- script_.push_nil();
- while (lua_next(script_.state_, realIndex) != 0)
+ script_->push_nil();
+ while (lua_next(script_->state_, realIndex) != 0)
{
std::string k;
if (!key.is_number() && key.get(k))
T v;
if (value.get(v)) dictionary[k] = v;
}
- script_.pop();
+ script_->pop();
}
- script_.pop();
+ script_->pop();
return true;
}
/**
* Get the value of a field from the table.
*/
-
template <class T, class V>
- bool get(T& value, V field) const
+ bool get(T& value, const V& field) const
{
bool ret = push_field(field).get(value);
- script_.pop();
+ script_->pop();
return ret;
}
template <class T, class V>
- void set_field(T field, V value)
+ void set_field(const T& field, const V& value)
{
- script_.push(field);
- script_.push(value);
+ script_->push(field);
+ script_->push(value);
set_field();
}
void set_field()
{
- lua_settable(script_.state_, index);
+ lua_settable(script_->state_, index);
+ }
+
+
+ void set_field(const std::string& field)
+ {
+ set_field(field.c_str());
+ }
+ void set_field(const char* field)
+ {
+ lua_setfield(script_->state_, index, field);
}
template <class T>
- void set_field(const std::string& field, T value)
+ void set_field(const std::string& field, const T& value)
{
set_field(field.c_str(), value);
}
template <class T>
- void set_field(const char* field, T value)
+ void set_field(const char* field, const T& value)
{
- script_.push(value);
- lua_setfield(script_.state_, index, field);
+ script_->push(value);
+ set_field(field);
}
+ /**
+ * Set the top value to be the metatable of this value.
+ */
+ void set_metatable()
+ {
+ lua_setmetatable(script_->state_, index);
+ }
/**
* This set method, as opposed to the others, sets the value of the
template <class T>
void set(T value)
{
- script_.push(value);
- replace();
+ script_->push(value);
+ set();
}
- void set()
- {
- replace();
- }
-
-
/**
* Replace this value with the value at the top of the stack.
*/
+ void set()
+ {
+ lua_replace(script_->state_, index);
+ }
- void replace()
+ void set_nil()
{
- lua_replace(script_.state_, index);
+ script_->push_nil();
+ set();
}
+
void remove()
{
- lua_remove(script_.state_, index);
+ lua_remove(script_->state_, index);
}
+ /**
+ * Remove this value and everything above it.
+ */
void pop()
{
- // removes this slot, taking with it everything above it
- script_.pop(script_.stack_size() - index + 1);
+ if (index < 0) script_->pop(-index);
+ else script_->pop(script_->stack_size() - index + 1);
}
/**
* Inserts the top-most value on the stack at position index,
* shifting other values as needed.
*/
-
void insert_top_here()
{
- lua_insert(script_.state_, index);
+ lua_insert(script_->state_, index);
}
/**
* Copy the value and push the copy to the stack.
*/
-
slot push_copy() const
{
- lua_pushvalue(script_.state_, index);
- return script_.top();
+ lua_pushvalue(script_->state_, index);
+ return script_->top();
}
slot push_metatable() const
{
- lua_getmetatable(script_.state_, index);
- return script_.top();
+ lua_getmetatable(script_->state_, index);
+ return script_->top();
}
slot push_environment() const
{
- lua_getfenv(script_.state_, index);
- return script_.top();
+ lua_getfenv(script_->state_, index);
+ return script_->top();
}
slot push_field() const
{
- lua_gettable(script_.state_, index);
- return script_.top();
+ lua_gettable(script_->state_, index);
+ return script_->top();
}
template <class T>
slot push_field(T index) const
{
- script_.push(index);
+ script_->push(index);
return push_field();
}
}
slot push_field(const char* name) const
{
- lua_getfield(script_.state_, index, name);
- return script_.top();
+ lua_getfield(script_->state_, index, name);
+ return script_->top();
}
class script& script()
{
- return script_;
+ return *script_;
}
const class script& script() const
{
- return script_;
+ return *script_;
+ }
+
+
+ /**
+ * Throw an exception with a message formatted to communicate a
+ * type mismatch with the argument represented by this slot.
+ */
+ int raise_type_error(const std::string& expected) const
+ {
+ lua_Debug ar;
+ lua_getstack(script_->state_, 0, &ar);
+ lua_getinfo(script_->state_, "n", &ar);
+ const char* func = ar.name ? ar.name : "unknown function";
+
+ std::ostringstream stream;
+ stream << "bad argument " << index << " to '" << func
+ << "' (" << expected << " expected, got "
+ << type_name() << ")";
+
+ throw std::invalid_argument(stream.str());
+ return 0;
+ }
+
+ /**
+ * Throw a generic error concerning this particular slot.
+ */
+ int raise(const std::string& message) const
+ {
+ lua_Debug ar;
+ lua_getstack(script_->state_, 0, &ar);
+ lua_getinfo(script_->state_, "n", &ar);
+ const char* func = ar.name ? ar.name : "unknown function";
+
+ std::ostringstream stream;
+ stream << "bad argument " << index << " to '" << func
+ << "' (" << message << ")";
+
+ throw std::invalid_argument(stream.str());
+ return 0;
}
private:
- class script& script_;
+ mutable class script* script_;
};
{
if (state_) destroy();
state_ = luaL_newstate();
- registry().set_field("Script_hh_Object", (void*)this);
}
luaL_openlibs(state_);
}
+ void import_safe_standard_libraries()
+ {
+ import_base_library();
+ import_string_library();
+ import_table_library();
+ import_math_library();
+ import_os_library();
+ import_debug_library();
+
+ slot g = globals();
+
+ push_nil(); g.set_field("dofile");
+ push_nil(); g.set_field("loadfile");
+ push_nil(); g.set_field("require");
+ push_nil(); g.set_field("io");
+ push_nil(); g.set_field("package");
+ slot os = g.push_field("os");
+ push_nil(); os.set_field("execute");
+ push_nil(); os.set_field("exit");
+ push_nil(); os.set_field("getenv");
+ push_nil(); os.set_field("remove");
+ push_nil(); os.set_field("rename");
+ push_nil(); os.set_field("tmpname");
+ pop();
+ }
+
void import_base_library()
{
- lua_pushcfunction(state_, luaopen_base);
+ push(luaopen_base);
push(LUA_COLIBNAME);
call(1, 0);
}
void import_package_library()
{
- lua_pushcfunction(state_, luaopen_package);
+ push(luaopen_package);
push(LUA_LOADLIBNAME);
call(1, 0);
}
void import_string_library()
{
- lua_pushcfunction(state_, luaopen_string);
+ push(luaopen_string);
push(LUA_STRLIBNAME);
call(1, 0);
}
void import_table_library()
{
- lua_pushcfunction(state_, luaopen_table);
+ push(luaopen_table);
push(LUA_TABLIBNAME);
call(1, 0);
}
void import_math_library()
{
- lua_pushcfunction(state_, luaopen_math);
+ push(luaopen_math);
push(LUA_MATHLIBNAME);
call(1, 0);
}
void import_io_library()
{
- lua_pushcfunction(state_, luaopen_io);
+ push(luaopen_io);
push(LUA_IOLIBNAME);
call(1, 0);
}
void import_os_library()
{
- lua_pushcfunction(state_, luaopen_os);
+ push(luaopen_os);
push(LUA_OSLIBNAME);
call(1, 0);
}
void import_debug_library()
{
- lua_pushcfunction(state_, luaopen_debug);
+ push(luaopen_debug);
push(LUA_DBLIBNAME);
call(1, 0);
}
}
- /**
+ /*
* Thread-handling methods.
*/
return script(state_);
}
- void push_thread()
+ slot push_thread()
{
lua_pushthread(state_);
+ return top();
}
status resume(int nargs)
return status(lua_resume(state_, nargs));
}
- status getStatus() const
+ status thread_status() const
{
return status(lua_status(state_));
}
bool is_main_thread() const
{
- return is_main_thread_;
+ bool is_main = lua_pushthread(state_);
+ lua_pop(state_, 1);
+ return is_main;
}
/**
- * Throw an error with the value at the top of the stack. This method
- * never returns because it does a long jump. Consequently,
- * constructed C++ objects which exist on the stack between the
- * current frame and some lua function will not be destructed. That's
- * not a problem for objects that only exist on the stack, but any
- * objects that allocate memory on the heap (such as containers or
- * strings) will leak. Therefore, you should only call this method
- * after cleaning up such objects.
+ * Throw an error with the value at the top of the stack. If this is
+ * called from an imported function, the error will be caught and
+ * returned on the stack when the execution aborts.
*/
+ int raise()
+ {
+ throw std::runtime_error("");
+ return 0;
+ }
- void raise()
+ /**
+ * Throw an error with a given message describing the problem. If this
+ * is called from an imported function, the error will be caught and
+ * returned on the stack when the execution aborts.
+ */
+ int raise(const std::string& message)
{
- lua_error(state_);
+ throw std::runtime_error(message);
+ return 0;
}
- /**
+ /*
* Get significant values.
*/
* enough to hold whatever you want to push on it. This is usually
* only an issue if you're pushing stuff in a loop.
*/
- bool checkStack(int extra)
+ bool check_stack(int extra)
{
return (bool)lua_checkstack(state_, extra);
}
}
- /**
+ /*
* Push some values onto the stack.
*/
- template <class T>
- slot push(T value)
+
+ slot push(char value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(unsigned char value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(short value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(unsigned short value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(int value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(unsigned int value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(long value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(unsigned long value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(long long value)
+ {
+ lua_pushinteger(state_, lua_Integer(value));
+ return top();
+ }
+ slot push(unsigned long long value)
{
lua_pushinteger(state_, lua_Integer(value));
return top();
slot push(float value)
{
- lua_pushnumber(state_, (lua_Number)value);
+ lua_pushnumber(state_, lua_Number(value));
return top();
}
slot push(double value)
{
- lua_pushnumber(state_, (lua_Number)value);
+ lua_pushnumber(state_, lua_Number(value));
return top();
}
slot push(const function& function)
{
- functions_.push_back(function);
- lua_pushlightuserdata(state_, (void*)&functions_.back());
- lua_pushcclosure(state_, dispatch_call, 1);
+ push<script::function>(function);
+ push_pointer(this);
+ push(call_functor, 2);
return top();
}
-
- slot push(void* data)
+ slot push(cfunction function)
{
- lua_pushlightuserdata(state_, data);
+ push_pointer(function);
+ push_pointer(this);
+ push(call_function, 2);
return top();
}
+ template <class T>
+ slot push(const T& object)
+ {
+ void* storage;
+ slot copy = push_data(storage, sizeof(T));
+ new(storage) T(object);
+
+ push_class_metatable<T>();
+ copy.set_metatable();
+ return copy;
+ }
+
+ template <class T>
+ slot push_class(const function& ctor)
+ {
+ slot metatable = push_class_metatable<T>();
+
+ slot constructor = push_table();
+ push(ctor);
+ constructor.set_field("__call");
+ metatable.set_metatable();
+
+ return metatable;
+ }
+ template <class T>
+ slot push_class(cfunction ctor)
+ {
+ slot metatable = push_class_metatable<T>();
+
+ slot constructor = push_table();
+ push(ctor);
+ constructor.set_field("__call");
+ metatable.set_metatable();
+
+ return metatable;
+ }
+
slot push_nil()
{
lua_pushnil(state_);
return top();
}
- slot push_new_data(void*& data, size_t size)
+ slot push_data(void*& data, size_t size)
{
data = lua_newuserdata(state_, size);
return top();
}
- slot push_new_table(int narr = 0, int nrec = 0)
+ template <class T>
+ slot push_pointer(const T* ptr)
+ {
+ lua_pushlightuserdata(state_, const_cast<void*>((const void*)ptr));
+ return top();
+ }
+ slot push_pointer(cfunction function)
+ {
+ return push_pointer((void*)function);
+ }
+
+ slot push_table(const std::string& name, int narr = 0, int nrec = 0)
+ {
+ if (name.empty()) return globals().push_field("_G");
+
+ slot table = globals().push_field(name);
+ if (table.is_table()) return table;
+
+ pop();
+ push_table(narr, nrec);
+ globals().set_field(name);
+
+ return globals().push_field(name);
+ }
+ slot push_table(int narr = 0, int nrec = 0)
{
lua_createtable(state_, narr, nrec);
return top();
}
+ slot push_metatable(const std::string& type, bool& is_new)
+ {
+ is_new = luaL_newmetatable(state_, type.c_str());
+ return top();
+ }
+ slot push_metatable(const std::string& type)
+ {
+ luaL_newmetatable(state_, type.c_str());
+ return top();
+ }
+
+ template <class T>
+ slot push_type()
+ {
+ return push_pointer(&typeid(T));
+ }
+
/**
* Call a function on the stack. The correct procedure is to push a
* will pop them off upon return, leaving up to nresults return values
* (default is any number of return values, depending on the callee).
*/
-
status call(int nargs = 0, int nresults = LUA_MULTRET)
{
return status(lua_pcall(state_, nargs, nresults, 0));
/**
* Pops n values from the top of the stack.
*/
-
void pop(int n = 1)
{
lua_pop(state_, n);
/**
* Index into the stack to get a slot.
*/
-
slot operator [] (int index) const
{
return slot(*this, index);
}
- /**
+ /*
* Control over the garbage collection process.
*/
- void collect_all()
+ void collect_garbage()
{
lua_gc(state_, LUA_GCCOLLECT, 0);
}
+ void collect_garbage(int step)
+ {
+ lua_gc(state_, LUA_GCSTEP, step);
+ }
- void stop_collector()
+ void disable_garbage_collector()
{
lua_gc(state_, LUA_GCSTOP, 0);
}
-
- void restart_collector()
+ void enable_garbage_collector()
{
lua_gc(state_, LUA_GCRESTART, 0);
}
- int memory_used() const
+ float memory_used() const
{
// in kilobytes
- return lua_gc(state_, LUA_GCCOUNT, 0);
+ return lua_gc(state_, LUA_GCCOUNT, 0) +
+ lua_gc(state_, LUA_GCCOUNTB, 0) / 1024.0f;
}
- void collect(int step)
- {
- lua_gc(state_, LUA_GCSTEP, step);
- }
-
- void tune_collector(int pause, int step)
+ void tune_garbage_collector(int pause, int step = 200)
{
lua_gc(state_, LUA_GCSETPAUSE, pause);
lua_gc(state_, LUA_GCSETSTEPMUL, step);
private:
script(lua_State* state) :
- state_(lua_newthread(state)),
- is_main_thread_(false) {}
+ state_(lua_newthread(state)) {}
+
+ slot push(lua_CFunction function, int upvalues = 0)
+ {
+ lua_pushcclosure(state_, function, upvalues);
+ return top();
+ }
+
+ template <class T>
+ slot push_class_metatable()
+ {
+ bool is_new;
+ slot metatable = push_metatable(typeid(T).name(), is_new);
+ if (is_new)
+ {
+ metatable.push_copy(); // class behavior
+ metatable.set_field("__index");
+
+ push_type<T>();
+ metatable.set_field("__cxxtype"); // type_info
+
+ push(object_finalizer_<T>);
+ metatable.set_field("__gc"); // finalizer
+
+ //push(object_tostring_<T>);
+ //metatable.set_field("__tostring"); // tostring
+ }
+ return metatable;
+ }
+
+ template <class T>
+ static int object_tostring_(lua_State* state)
+ {
+ std::ostringstream stream;
+ stream << *reinterpret_cast<T*>(lua_touserdata(state, 1));
+ lua_pushlstring(state, stream.str().c_str(), stream.str().length());
+ return 1;
+ }
+
+ template <class T>
+ static int object_finalizer_(lua_State* state)
+ {
+ reinterpret_cast<T*>(lua_touserdata(state, 1))->~T();
+ return 0;
+ }
- static int dispatch_call(lua_State* state)
+ static int call_functor(lua_State* state)
{
- const function* function = (const script::function*)lua_touserdata(state,
+ function* function = (script::function*)lua_touserdata(state,
lua_upvalueindex(1));
- lua_getfield(state, LUA_REGISTRYINDEX, "Script_hh_Object");
- script* script = (moof::script*)lua_touserdata(state, -1);
- lua_pop(state, 1);
+ script* script = (moof::script*)lua_touserdata(state,
+ lua_upvalueindex(2));
- return (*function)(*script);
+ try
+ {
+ return (*function)(*script);
+ }
+ catch (const std::exception& e)
+ {
+ if (0 < std::strlen(e.what()))
+ {
+ luaL_where(state, 1);
+ lua_pushstring(state, e.what());
+ lua_concat(state, 2);
+ }
+ return lua_error(state);
+ }
+ catch (const char* e)
+ {
+ luaL_where(state, 1);
+ lua_pushstring(state, e);
+ lua_concat(state, 2);
+ return lua_error(state);
+ }
+ catch (...)
+ {
+ return lua_error(state);
+ }
+ }
+
+
+ static int call_function(lua_State* state)
+ {
+ cfunction function = (cfunction)lua_touserdata(state,
+ lua_upvalueindex(1));
+
+ script* script = (moof::script*)lua_touserdata(state,
+ lua_upvalueindex(2));
+
+ try
+ {
+ return function(*script);
+ }
+ catch (const std::exception& e)
+ {
+ if (0 < std::strlen(e.what()))
+ {
+ luaL_where(state, 1);
+ lua_pushstring(state, e.what());
+ lua_concat(state, 2);
+ }
+ return lua_error(state);
+ }
+ catch (const char* e)
+ {
+ luaL_where(state, 1);
+ lua_pushstring(state, e);
+ lua_concat(state, 2);
+ return lua_error(state);
+ }
+ catch (...)
+ {
+ return lua_error(state);
+ }
}
+
void destroy()
{
- if (is_main_thread_) lua_close(state_);
+ if (is_main_thread()) lua_close(state_);
}
+
lua_State* state_;
- bool is_main_thread_;
- std::list<function> functions_;
};
+using namespace std::rel_ops;
+
+/**
+ * Output a script value to a stream.
+ */
inline std::ostream& operator << (std::ostream& stream,
const script::slot& slot)
{
#include <deque>
#include <list>
#include <stdexcept>
-#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/cstdint.hpp>
#include "hash.hh"
#include "log.hh"
-#include "manager.hh"
#include "sound.hh"
#include "resource.hh"
#include "timer.hh"
#ifndef BUF_SIZE
-#define BUF_SIZE (4096)
+#define BUF_SIZE (4096 * 64)
#endif
-#define NUM_BUFFERS (8)
+#define NUM_BUFFERS (4)
namespace moof {
+/*] Sound backend
+ *************************************************************************/
+
class sound_backend
{
public:
class sound_resource;
typedef resource_handle<sound_resource> sound_handle;
-
-class sound_resource_loader
-{
-public:
-
- sound_resource_loader()
- {
- resource::register_type<sound_resource>("ogg", "sounds");
- }
-
- ~sound_resource_loader()
- {
- resource::unregister_type("ogg");
- }
-};
-
-static sound_resource_loader loader;
-
+MOOF_REGISTER_RESOURCE(sound_resource, ogg, sounds);
-// SOUND BUFFER
+/*] Sound buffer
+ *************************************************************************/
class buffer
{
-// SOUND RESOURCE
+/*] Sound resource
+ *************************************************************************/
class sound_resource : public boost::noncopyable
{
};
+/*] Sound class
+ *************************************************************************/
class sound::impl
{
if (!stream_timer_.is_valid())
{
stream_timer_.init(boost::bind(&impl::stream_update, this, _1, _2),
- 0.01, timer::repeat);
+ SCALAR(0.5), timer::repeat);
}
alSourcePlay(source_);
void sound::play()
-{
- // pass through
- impl_->play();
-}
-
-void sound::stream()
{
// pass through
impl_->stream();
{
if (is_playing()) pause();
else play();
- // TODO: what about streaming sources?
}
bool sound::is_playing() const
namespace moof {
+class script;
+
+
class sound
{
public:
void enqueue(const std::string& name);
void play();
- void stream();
void stop();
void pause();
void rewind();
static void listener_orientation(const vector3& forward,
const vector3& up);
+ static void import(script& script, const std::string& nspace = "");
private:
--- /dev/null
+
+/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+**] All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+#include "script.hh"
+#include "sound.hh"
+
+
+namespace moof {
+
+
+static int sound_new(script& script)
+{
+ script::slot name = script[2].require_string("sound name");
+
+ std::string str;
+ name.get(str);
+
+ script.push(sound(str));
+ return 1;
+}
+
+static int sound_enqueue(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+
+ std::string name;
+ script[2].require_string("sound name").get(name);
+
+ sound->enqueue(name);
+ return 0;
+}
+
+static int sound_play(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ sound->play();
+ return 0;
+}
+
+static int sound_stop(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ sound->stop();
+ return 0;
+}
+
+static int sound_pause(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ sound->pause();
+ return 0;
+}
+
+static int sound_rewind(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ sound->rewind();
+ return 0;
+}
+
+static int sound_toggle(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ sound->toggle();
+ return 0;
+}
+
+static int sound_is_playing(script& script)
+{
+ sound* sound;
+ script[1].require_object<moof::sound>("sound").get(sound);
+ script.push(sound->is_playing());
+ return 1;
+}
+
+
+void sound::import(script& script, const std::string& nspace)
+{
+ script.check_stack(4);
+
+ script::slot parent = script.push_table(nspace);
+ script::slot meta = script.push_class<sound>(sound_new);
+
+ meta.set_field("enqueue", sound_enqueue);
+ meta.set_field("play", sound_play);
+ meta.set_field("stop", sound_stop);
+ meta.set_field("pause", sound_pause);
+ meta.set_field("rewind", sound_rewind);
+ meta.set_field("toggle", sound_toggle);
+ meta.set_field("is_playing", sound_is_playing);
+
+ parent.set_field("sound");
+ parent.pop();
+}
+
+
+} // namespace moof
+
#include <stdexcept>
+#include <boost/shared_array.hpp>
+
#include "ConvertUTF.h"
+#include "script.hh"
#include "string.hh"
namespace moof {
-// TODO this code is ugly
-
wstring multi_to_wide(const string& multi)
{
- size_t length = multi.length();
+ typedef boost::shared_array<wchar_t> buffer;
if (sizeof(wchar_t) == 2)
{
- wchar_t* wide = new wchar_t[length + 1];
-
- const UTF8* srcStart = reinterpret_cast<const UTF8*>(multi.c_str());
- const UTF8* srcEnd = srcStart + length;
- UTF16* targetStart = reinterpret_cast<UTF16*>(wide);
- UTF16* targetEnd = targetStart + length+1;
+ size_t length = multi.length();
+ buffer wide(new wchar_t[length + 1]);
+ const UTF8* src1 = (const UTF8*)multi.c_str();
+ const UTF8* src2 = src1 + length;
+ UTF16* dst1 = (UTF16*)wide.get();
+ UTF16* dst2 = dst1 + length+1;
- ConversionResult res = ConvertUTF8toUTF16(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
+ if (ConvertUTF8toUTF16(&src1, src2,
+ &dst1, dst2, lenientConversion) != conversionOK)
{
- delete[] wide;
- throw std::runtime_error("bad conversion from multi to wide characters");
+ throw std::runtime_error("bad string conversion");
}
- *targetStart = 0;
- wstring convertedStr(wide);
- delete[] wide;
-
- return convertedStr;
+ *dst1 = 0;
+ wstring str(wide.get());
+ return str;
}
else if (sizeof(wchar_t) == 4)
{
- wchar_t* wide = new wchar_t[length];
-
- const UTF8* srcStart = reinterpret_cast<const UTF8*>(multi.c_str());
- const UTF8* srcEnd = srcStart + length;
- UTF32* targetStart = reinterpret_cast<UTF32*>(wide);
- UTF32* targetEnd = targetStart + length;
+ size_t length = multi.length();
+ buffer wide(new wchar_t[length + 1]);
+ const UTF8* src1 = (const UTF8*)multi.c_str();
+ const UTF8* src2 = src1 + length;
+ UTF32* dst1 = (UTF32*)wide.get();
+ UTF32* dst2 = dst1 + length+1;
- ConversionResult res = ConvertUTF8toUTF32(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
+ if (ConvertUTF8toUTF32(&src1, src2,
+ &dst1, dst2, lenientConversion) != conversionOK)
{
- delete[] wide;
- throw std::runtime_error("bad conversion from multi to wide characters");
+ throw std::runtime_error("bad string conversion");
}
- *targetStart = 0;
- wstring convertedStr(wide);
- delete[] wide;
-
- return convertedStr;
+ *dst1 = 0;
+ wstring str(wide.get());
+ return str;
}
else
{
throw std::runtime_error("unknown size of wide characters");
}
- return L"";
}
string wide_to_multi(const wstring& wide)
{
- size_t length = wide.length();
+ typedef boost::shared_array<char> buffer;
if (sizeof(wchar_t) == 2)
{
- size_t multiLength = 3 * length + 1;
- char* multi = new char[multiLength];
-
- const UTF16* srcStart = reinterpret_cast<const UTF16*>(wide.c_str());
- const UTF16* srcEnd = srcStart + length;
- UTF8* targetStart = reinterpret_cast<UTF8*>(multi);
- UTF8* targetEnd = targetStart + multiLength;
+ size_t length = wide.length();
+ size_t multi_length = 3 * length + 1;
+ buffer multi(new char[multi_length]);
+ const UTF16* src1 = (const UTF16*)wide.c_str();
+ const UTF16* src2 = src1 + length;
+ UTF8* dst1 = (UTF8*)multi.get();
+ UTF8* dst2 = dst1 + multi_length;
- ConversionResult res = ConvertUTF16toUTF8(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
+ if (ConvertUTF16toUTF8(&src1, src2,
+ &dst1, dst2, lenientConversion) != conversionOK)
{
- delete[] multi;
- throw std::runtime_error("bad conversion from wide to multi-characters");
+ throw std::runtime_error("bad string conversion");
}
- *targetStart = 0;
- string convertedStr(multi);
- delete[] multi;
-
- return convertedStr;
+ *dst1 = 0;
+ string str(multi.get());
+ return str;
}
else if (sizeof(wchar_t) == 4)
{
- size_t multiLength = 4 * length + 1;
- char* multi = new char[multiLength];
+ size_t length = wide.length();
+ size_t multi_length = 4 * length + 1;
+ buffer multi(new char[multi_length]);
+ const UTF32* src1 = (const UTF32*)wide.c_str();
+ const UTF32* src2 = src1 + length;
+ UTF8* dst1 = (UTF8*)multi.get();
+ UTF8* dst2 = dst1 + multi_length;
- const UTF32* srcStart = reinterpret_cast<const UTF32*>(wide.c_str());
- const UTF32* srcEnd = srcStart + length;
- UTF8* targetStart = reinterpret_cast<UTF8*>(multi);
- UTF8* targetEnd = targetStart + multiLength;
-
- ConversionResult res = ConvertUTF32toUTF8(&srcStart, srcEnd,
- &targetStart, targetEnd, lenientConversion);
- if (res != conversionOK)
+ if (ConvertUTF32toUTF8(&src1, src2,
+ &dst1, dst2, lenientConversion) != conversionOK)
{
- delete[] multi;
- throw std::runtime_error("bad conversion from wide to multi-characters");
+ throw std::runtime_error("bad string conversion");
}
- *targetStart = 0;
- string convertedStr(multi);
- delete[] multi;
-
- return convertedStr;
+ *dst1 = 0;
+ string str(multi.get());
+ return str;
}
else
{
throw std::runtime_error("unknown size of wide characters");
}
- return "";
+}
+
+
+static script& regex_script()
+{
+ static script script;
+ static bool init = true;
+ if (init)
+ {
+ script.import_string_library();
+ script.globals().push_field("string").push_field("match");
+ script.globals().set_field("match");
+ script.top().push_field("gmatch");
+ script.globals().set_field("gmatch");
+ script.top().push_field("gsub");
+ script.globals().set_field("gsub");
+ script.push_nil();
+ script.globals().set_field("string");
+ script.pop();
+ init = false;
+ }
+ return script;
+}
+
+
+regex::regex(const string& pattern)
+{
+ regex::pattern(pattern);
+}
+
+regex::regex(const string& pattern, const string& source)
+{
+ regex::pattern(pattern);
+ match(source);
+}
+
+regex::~regex()
+{
+ script& script = regex_script();
+
+ script.push_pointer(this);
+ script.push_nil();
+ script.globals().set_field();
+ script.push_pointer(this);
+ script.push_nil();
+ script.registry().set_field();
+}
+
+
+string regex::pattern() const
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot saved = script.registry().push_field();
+
+ string pattern;
+ saved.get(pattern);
+
+ saved.pop();
+ return pattern;
+}
+
+void regex::pattern(const string& pattern)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script.push(pattern);
+ script.registry().set_field();
+}
+
+
+void regex::match(const string& source)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+
+ script.globals().push_field("gmatch");
+ script.push(source);
+ script.push_pointer(this);
+ script.registry().push_field();
+ script.call(2, 1);
+
+ script.globals().set_field();
+}
+
+bool regex::get(string& match)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call(0, 1);
+ bool result = value.get(match);
+ script.pop();
+ return result;
+}
+
+bool regex::get(std::vector<string>& captures)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call();
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+
+bool regex::match(string& match,
+ const string& pattern,
+ const string& source,
+ int position)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // Lua indices count from one.
+ script.push(position);
+ script.call(3, 1);
+
+ bool result = value.get(match);
+ script.clear_stack();
+ return result;
+}
+
+bool regex::match(std::vector<string>& captures,
+ const string& pattern,
+ const string& source,
+ int position)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // Lua indices count from one.
+ script.push(position);
+ script.call(3);
+
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+
+int regex::sub(string& substitution,
+ const string& pattern,
+ const string& source,
+ const string& replacement)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("gsub");
+ script.push(source);
+ script.push(pattern);
+ script.push(replacement);
+ script.call(3, 2);
+
+ value.get(substitution);
+
+ ++value.index;
+ int count = 0;
+ value.get(count);
+
+ script.clear_stack();
+ return count;
}
/**
* \file string.hh
- * Functions related to string manipulations.
+ * Functions and classes related to string manipulation.
*/
#include <string>
+#include <boost/noncopyable.hpp>
+
namespace moof {
string wide_to_multi(const wstring& wide);
-} // namespace moof
+/**
+ * Class exposing the pattern-matching and substitution methods used in
+ * Lua.
+ */
+class regex : public boost::noncopyable
+{
+public:
+
+ /**
+ * Construct a regex object.
+ */
+ regex() {}
+
+ /**
+ * Construct a regex object with a pattern.
+ * \param pattern The pattern.
+ */
+ regex(const string& pattern);
+
+ /**
+ * Construct a regex object with a pattern and source to match.
+ * \param pattern The pattern.
+ * \param source The source string.
+ */
+ regex(const string& pattern, const string& source);
+
+ /**
+ * Deconstruct the regex.
+ */
+ ~regex();
+
+
+ /**
+ * Get the regex pattern.
+ */
+ string pattern() const;
+
+ /**
+ * Set the regex pattern.
+ */
+ void pattern(const string& pattern);
+
+
+ /**
+ * Match a string against the pattern iteratively.
+ * \param source The source string.
+ */
+ void match(const string& source);
+
+ /**
+ * Get the next match. If the pattern contains captures, this version
+ * will only get the first capture.
+ * \param match Reference to a string to be assigned the match.
+ * \return True if there was a match to get, false otherwise.
+ */
+ bool get(string& match);
+
+ /**
+ * Get the next match. Use this version if the pattern contains more
+ * than one capture to get all of the captures.
+ * \param captures Reference to a vector of strings to hold the result.
+ * \return True if there was a match to get, false otherwise.
+ */
+ bool get(std::vector<string>& captures);
+
+
+ /**
+ * Match a string against a pattern all at one time.
+ * \param pattern The pattern.
+ * \param source The source string.
+ * \param position The index of the first character of source to match.
+ * \return The match.
+ */
+ static string match(const string& pattern,
+ const string& source,
+ int position = 0)
+ {
+ string match;
+ regex::match(match, pattern, source, position);
+ return match;
+ }
+
+ /**
+ * Match a string against a pattern all at one time.
+ * \param match A reference to a string to be assigned the match.
+ * \param pattern The pattern.
+ * \param source The source string.
+ * \param position The index of the first character of source to match.
+ * \return True if a match was made, false otherwise.
+ */
+ static bool match(string& match,
+ const string& pattern,
+ const string& source,
+ int position = 0);
+
+ /**
+ * Match a string against a pattern all at one time. If the pattern
+ * contains captures, the resulting vector will contain all of the
+ * captures.
+ * \param captures A reference to a vector of strings to contain the
+ * result.
+ * \param pattern The pattern.
+ * \param source The source string.
+ * \param position The index of the first character of source to match.
+ * \return True if a match was made, false otherwise.
+ */
+ static bool match(std::vector<string>& captures,
+ const string& pattern,
+ const string& source,
+ int position = 0);
+
+
+ /**
+ * Substitute a string using a pattern and replacement string.
+ * \param pattern The pattern.
+ * \param source The source string.
+ * \param replacement The replacement string; may also contain
+ * references to captures.
+ * \return The string with any substitutions made.
+ */
+ static string sub(const string& pattern,
+ const string& source,
+ const string& replacement)
+ {
+ string substitution;
+ regex::sub(substitution, pattern, source, replacement);
+ return substitution;
+ }
+
+ /**
+ * Substitute a string using a pattern and replacement string.
+ * \param substitution A reference to a string to contain the result.
+ * \param pattern The pattern.
+ * \param source The source string.
+ * \param replacement The replacement string; may also contain
+ * references to captures.
+ * \return The number of substitutions made.
+ */
+ static int sub(string& substitution,
+ const string& pattern,
+ const string& source,
+ const string& replacement);
+};
+
+} // namespace moof
#endif // _MOOF_STRINGTOOLS_HH_
}
-void timer::fire_expired_timers()
-{
- fire_expired_timers(ticks());
-}
-
void timer::fire_expired_timers(scalar t)
{
if (next_expiration_ > t) return;
ASSERT(result == 0 && "cannot access clock");
return scalar(ts.tv_sec - reference_) +
- scalar(ts.tv_nsec) / 1000000000.0;
+ scalar(ts.tv_nsec) * SCALAR(0.000000001);
}
void timer::sleep(scalar seconds, mode mode)
if (mode == absolute) seconds -= ticks();
ts.tv_sec = time_t(seconds);
- ts.tv_nsec = long((seconds - scalar(ts.tv_sec)) * 1000000000.0);
+ ts.tv_nsec = long((seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0));
do
{
scalar timer::ticks()
{
Uint32 ms = SDL_GetTicks();
- return scalar(ms / 1000) + scalar(ms % 1000) / 1000.0;
+ return scalar(ms / 1000) + scalar(ms % 1000) * SCALAR(0.001);
}
void timer::sleep(scalar seconds, mode mode)
{
if (mode == absolute) seconds -= ticks();
- SDL_Delay(Uint32(clamp(int(seconds * 1000.0), 0, 1000)));
+ SDL_Delay(Uint32(clamp(Uint32(seconds * SCALAR(1000.0)), 0, 1000)));
}
#endif // USE_CLOCK_GETTIME
* Fire any timers which are not yet invalidated but have an expiration
* time in the past.
*/
- static void fire_expired_timers();
+ static void fire_expired_timers()
+ {
+ fire_expired_timers(ticks());
+ }
/**
* Fire any timers which are not yet invalidated but have an expiration