Force consistent line endings.

I'd suggest enabling the EolExtension:
this way we won't go back and forth here.
This commit is contained in:
Jason Felds
2011-03-16 15:51:54 -04:00
parent e27b454306
commit 7c4044a2fc
75 changed files with 24426 additions and 24404 deletions
+22
View File
@@ -0,0 +1,22 @@
[repository]
native = CRLF
[patterns]
**.cpp = CRLF
**.h = CRLF
**.txt = CRLF
**.lua = CRLF
**.sln = CRLF
**.ini = CRLF
**.redir = CRLF
**.sm = CRLF
**.ssc = CRLF
**.vcproj = CRLF
**.xsl = CRLF
**.xml = CRLF
**.jpg = BIN
**.png = BIN
**.jpeg = BIN
**.ogg = BIN
**.sh = LF
Makefile = LF
+3 -3
View File
@@ -1,4 +1,4 @@
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2;diffuse, Var "Color1";);
GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0);
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2;diffuse, Var "Color1";);
GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0);
};
+3 -3
View File
@@ -1,4 +1,4 @@
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2);
GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0);
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2);
GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0);
};
+3 -3
View File
@@ -1,4 +1,4 @@
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2);
GainFocusCommand=cmd(finishtweening;diffuse,color("#FFFFA0");accelerate,0.6;diffusealpha,0);
return Def.Quad {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2);
GainFocusCommand=cmd(finishtweening;diffuse,color("#FFFFA0");accelerate,0.6;diffusealpha,0);
};
+186 -186
View File
@@ -1,187 +1,187 @@
BMS Format Specification(Remake version.)
Written in June 28th 2003.
original document written by Urao Yane.
edited by U(uhangel4u@yahoo.co.jp)
"BMS" means a Be-Music Source file. A file which has BMS suffix is regarded as the BMS file.
This file format was produced by Urao Yane and NBK in 1998.and It revised sometime.
And I adopted this file format to BM98, Delight Delight Reduplication, MixWaver, nazoBMPlay and so on.
Now,anyone can use this format freely.
BM98 Drink Edition
http://www5c.biglobe.ne.jp/~kbs/bm98/ (Japanese)
Delight Delight Reduplicaton
http://nickle.hey.to/ (Japanese)
MixWaver
http://hello.to/mixwaver/ (Korean)
nazoBMPlay
http://www.nothing.sh/nazobmplay/ (Japanese)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Command Line>
The line begining at '#' is the command line. All the rest are ignored (use for comments).
And this BMS file is compiled at runtime , so you can order any lines freely.
And there is no difference in the command line between using a capital letter or not.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Header>
#PLAYER [1-4]
#PLAYER 1
This data is for Single Play.
#PLAYER 2
This data is for Two Players.
#PLAYER 3
This data is for Double Play.
#PLAYER 4
This data is for Two Players.(Players will plays same sequence)
#GENRE xxxxxxxx
Definition of Genre.
#TITLE xxxxxxxx
Definition of Title.
#ARTIST xxxxxxxx
Definition of Artist.
#BPM xxx
Definition of BPM.(Beats Per Minite) at the top of music. default : 130 value type : double.
#MIDIFILE xxxxxxx.mid
Background music by MIDI.but,It's not recommend.
#PLAYLEVEL x
Information of Game Level for player.
#RANK [0-3]
judgement level.
x = 0 :very hard, 1: hard, 2: normal, 3: easy default : 2
#VOLWAV xxx
relative volume control (percentage)
#TOTAL xxx
increments of Groove Gauge
ex.
#TOTAL 120
It means when all sequence was played over great, Groove Gauge's value is 120%
#WAVxx yyyyyyyy.wav(or .mp3)
definition of Wave Data. xx : 01 to FZ(01-09-0A-0Z-10-1Z...) , yyyyyyyy.wav : wave file name
When use mp3 files,you need mp3 CODEC.
e.g.
#WAV01 HOUSE01.WAV // assign HOUSE01.WAV to 01 wav
#WAV02 HOUSE02.WAV // assign HOUSE02.WAV to 02 wav
#WAVFZ HOUSE03.mp3 // assign HOUSE03.mp3 to FZ wav
#BMPxx yyyyyyyy.bmp(or gif,jpg,png)
definition of Bitmap file. xx : 01 to FF(Hex) , yyyyyyyy.bmp : bitmap file name
Bitmap size must be 256 * 256.(max color 65536)
If you use "gif or jpg or png", with Susie Plug-in.
gif : ifgif.spi jpg : ifjpg.spi png : ifpng.spi
About Susie Plug-ins : http://www.digitalpad.co.jp/~takechin/
e.g.
#BMP01 HOUSE01.BMP // assign HOUSE01.BMP to 01 bitmap
#BMP02 HOUSE02.BMP // assign HOUSE02.BMP to 02 bitmap
#BMPEE HOUSE03.PNG // assign HOUSE03.PNG to EE bitmap
#StageFile xxxx.bmp(or gif,jpg,png)
Show assigned Picture when loading bitmaps,wavs and compiling bms.
#BPMxx yyy
Use to change BPM(Beats Per Minite). xx : 01 to ff(Hex)
But ,the bitmap defined by #BMP00 is something special.
This bitmap shows when a player do a poor play.
#STOPxx yyy
Use to stop sequence. xx : 01 to ff(Hex)
yyy : a quarter note = 48
an eighth note = 24
a whole note = 192
note / n = 192/n
#CDDA xx
Audio cds Track No.
#BackBMP xxxx.bmp(or gif,jpg,png)
Set BackGround Picture.(size:640*480)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// a sample of random loading function
#random 2 // create a random number (1 or 2)
#if 1 // if the number was equal to 1 then...
#00111:31313131 // this is effective...
#endif
#if 2 // if the number was equal to 2 then...
#00113:32003232 // this is effective
#endif
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Channel Messages>
#aaabb:cccccccc
aaa: track number (from 000 to 999)
bb : channel number where you want to send message.(from 00 to FF)
cccccccc : <message>
<a brief Channel Number>
01 : BGM(background music by WAVE)
02 : shortening note.
03 : changing a Tempo[1-255]
04 : BGA(background animation)
06 : changing Poor-bitmap
07 : BGA Layer.
08 : Extended BPM(Use assigned of #BPMxx)
09 : Stop the sequence(Use assigned of #STOPxx)
11 to 19 : Object Channel of 1 player side
21 to 29 : Object Channel of 2 player side
31 to 39 : Can't show Object Channel of 1 player side
41 to 49 : Can't show Object Channel of 2 player side
51 to 59 : Long note Object Channel of 1 player side
61 to 69 : Long note Object Channel of 2 player side
<Example>
#00211:03030303
This means 4 objects at the left of 1 player side in 002 track.
This object is assigned to wave No.03 which was defined by #WAV03 xxxx.wav.
And this 4 objects are arranged evenly in this track.
Please try the following patterns.
#00211:0303030303
#00211:0303000303
#00211:010101
#00211:00020202
P.S.
#00202:0.5 : Track2 have Half length.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
This document and this format is free!
I hope the day will come when my BMS format will use all over the world.
BMS Format Specification(Remake version.)
Written in June 28th 2003.
original document written by Urao Yane.
edited by U(uhangel4u@yahoo.co.jp)
"BMS" means a Be-Music Source file. A file which has BMS suffix is regarded as the BMS file.
This file format was produced by Urao Yane and NBK in 1998.and It revised sometime.
And I adopted this file format to BM98, Delight Delight Reduplication, MixWaver, nazoBMPlay and so on.
Now,anyone can use this format freely.
BM98 Drink Edition
http://www5c.biglobe.ne.jp/~kbs/bm98/ (Japanese)
Delight Delight Reduplicaton
http://nickle.hey.to/ (Japanese)
MixWaver
http://hello.to/mixwaver/ (Korean)
nazoBMPlay
http://www.nothing.sh/nazobmplay/ (Japanese)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Command Line>
The line begining at '#' is the command line. All the rest are ignored (use for comments).
And this BMS file is compiled at runtime , so you can order any lines freely.
And there is no difference in the command line between using a capital letter or not.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Header>
#PLAYER [1-4]
#PLAYER 1
This data is for Single Play.
#PLAYER 2
This data is for Two Players.
#PLAYER 3
This data is for Double Play.
#PLAYER 4
This data is for Two Players.(Players will plays same sequence)
#GENRE xxxxxxxx
Definition of Genre.
#TITLE xxxxxxxx
Definition of Title.
#ARTIST xxxxxxxx
Definition of Artist.
#BPM xxx
Definition of BPM.(Beats Per Minite) at the top of music. default : 130 value type : double.
#MIDIFILE xxxxxxx.mid
Background music by MIDI.but,It's not recommend.
#PLAYLEVEL x
Information of Game Level for player.
#RANK [0-3]
judgement level.
x = 0 :very hard, 1: hard, 2: normal, 3: easy default : 2
#VOLWAV xxx
relative volume control (percentage)
#TOTAL xxx
increments of Groove Gauge
ex.
#TOTAL 120
It means when all sequence was played over great, Groove Gauge's value is 120%
#WAVxx yyyyyyyy.wav(or .mp3)
definition of Wave Data. xx : 01 to FZ(01-09-0A-0Z-10-1Z...) , yyyyyyyy.wav : wave file name
When use mp3 files,you need mp3 CODEC.
e.g.
#WAV01 HOUSE01.WAV // assign HOUSE01.WAV to 01 wav
#WAV02 HOUSE02.WAV // assign HOUSE02.WAV to 02 wav
#WAVFZ HOUSE03.mp3 // assign HOUSE03.mp3 to FZ wav
#BMPxx yyyyyyyy.bmp(or gif,jpg,png)
definition of Bitmap file. xx : 01 to FF(Hex) , yyyyyyyy.bmp : bitmap file name
Bitmap size must be 256 * 256.(max color 65536)
If you use "gif or jpg or png", with Susie Plug-in.
gif : ifgif.spi jpg : ifjpg.spi png : ifpng.spi
About Susie Plug-ins : http://www.digitalpad.co.jp/~takechin/
e.g.
#BMP01 HOUSE01.BMP // assign HOUSE01.BMP to 01 bitmap
#BMP02 HOUSE02.BMP // assign HOUSE02.BMP to 02 bitmap
#BMPEE HOUSE03.PNG // assign HOUSE03.PNG to EE bitmap
#StageFile xxxx.bmp(or gif,jpg,png)
Show assigned Picture when loading bitmaps,wavs and compiling bms.
#BPMxx yyy
Use to change BPM(Beats Per Minite). xx : 01 to ff(Hex)
But ,the bitmap defined by #BMP00 is something special.
This bitmap shows when a player do a poor play.
#STOPxx yyy
Use to stop sequence. xx : 01 to ff(Hex)
yyy : a quarter note = 48
an eighth note = 24
a whole note = 192
note / n = 192/n
#CDDA xx
Audio cds Track No.
#BackBMP xxxx.bmp(or gif,jpg,png)
Set BackGround Picture.(size:640*480)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// a sample of random loading function
#random 2 // create a random number (1 or 2)
#if 1 // if the number was equal to 1 then...
#00111:31313131 // this is effective...
#endif
#if 2 // if the number was equal to 2 then...
#00113:32003232 // this is effective
#endif
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<Channel Messages>
#aaabb:cccccccc
aaa: track number (from 000 to 999)
bb : channel number where you want to send message.(from 00 to FF)
cccccccc : <message>
<a brief Channel Number>
01 : BGM(background music by WAVE)
02 : shortening note.
03 : changing a Tempo[1-255]
04 : BGA(background animation)
06 : changing Poor-bitmap
07 : BGA Layer.
08 : Extended BPM(Use assigned of #BPMxx)
09 : Stop the sequence(Use assigned of #STOPxx)
11 to 19 : Object Channel of 1 player side
21 to 29 : Object Channel of 2 player side
31 to 39 : Can't show Object Channel of 1 player side
41 to 49 : Can't show Object Channel of 2 player side
51 to 59 : Long note Object Channel of 1 player side
61 to 69 : Long note Object Channel of 2 player side
<Example>
#00211:03030303
This means 4 objects at the left of 1 player side in 002 track.
This object is assigned to wave No.03 which was defined by #WAV03 xxxx.wav.
And this 4 objects are arranged evenly in this track.
Please try the following patterns.
#00211:0303030303
#00211:0303000303
#00211:010101
#00211:00020202
P.S.
#00202:0.5 : Track2 have Half length.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
This document and this format is free!
I hope the day will come when my BMS format will use all over the world.
Urao Yane

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

+157 -157
View File
@@ -1,157 +1,157 @@
Documentation on the KSF Format
-------------------------------
The KSF format is designed for representing steps for 5 panel diagonal
dancing games, such as Pump It Up. It was originally used in the Kick It Up
simulator, but can also be parsed by other programs. However, this seems
to be the only actual format description available.
The intention of this document is not to encourage creation of KSF files.
I believe the format to be broken, and provide this reference only for
people wishing to implement legacy file readers. Any new 5 panel dancing
patterns should use a well-defined format such as .dance or .sm.
Directory Layout
----------------
KSF filenames are case-insensitive.
A KSF directory contains the following files:
- At least one file matching *.KSF, containing the step data.
- A file named SONG.MP3, SONG.WAV, or SONG.OGG.
- A file named INTRO.MP3, INTRO.WAV, or INTRO.OGG, containing a sound clip,
used to preview the song in song selectors.
- Disc.bmp, a 300x200 image used in song selectors.
- Back.bmp or Title.bmp, a 640x480 image used as a background during the song.
KSF directories may not have a special naming format, but some simulators
will use the directory name to get the artist and title name, if it's not
available in the KSF files themseleves. The format is "Title",
"Title - Artist", or "Title - Artist - Difficulty". Difficulty can be
ignored here, as it can be gotten from the KSF filename. Using the path
name to determine the metadata for the song should only be used if it's
not available in #TITLE.
Concievably other audio or image formats could be used. None have been
seen in the wild.
KSF Filenames
-------------
KSF filenames describe the game type and difficulty. Each file holds the
data for only one level of difficulty. There are two possible forms of
the name: *<gametype>*.ksf, or *<difficulty>_<playernumber>*.ksf.
The first type is used for double mode, and half-double mode. Double.ksf
contains the steps for "Double" mode, where one player uses both paths.
Stepmania supports Halfdouble.ksf, which ignores the outer 4 panels.
The latter type is used for single ("unison", which is not the same
as Dance Dance Revolution's Unison mode in early mixes) steps, where both
players have the same steps, and couple steps, where players have different
ones. If the player number is 1, they are single steps; if it's 2, they're
couple steps. Difficulty is a difficulty name.
KSF Headers
-----------
The basic KSF format is similar to DWI, SM, and MSD. Metadata is given
in the format of:
#TAGNAME:VALUE;
The exception being the #STEPS tag, which has a newline between the ":"
and the first line of steps, and ends in "2222222222222" on a line by
itself instead of ";".
KSF files seem to use CRLF (Windows-style) line termination. The vast
majority of KSF files are in CP942/KSC 5601 encoding, but some are
in EUC-KR. If ASCII alternatives are needed for these encodings, the
path name must be checked as above.
Common headers in KSF files are as follows:
#TITLE: The artist and title of the song, and sometimes the difficulty.
These are separated by " - "s, so the format is either "Title",
"Artist - Title", or "Artist - Title - Difficulty". Information missing
from this line can be filled in via path or file names.
#BPM: The BPM of the song. This is analogous to the BPM value for every other
dance format.
#STARTTIME: The time into the song to offset events, in centiseconds. This
is the opposite of .dance's gap and .sm's offset, and the same as .dwi's
gap (although they use different units).
#TICKCOUNT: Each step line specifies 1/TICKCOUNT beats. That is, if
TICKCOUNT is 1, each line is the equivalent of a 'q' in .dance. If it's
2, each line is the same as a normal length note in DWI (an 'e' in .dance).
#STEP: Until a line of "2222222222222" is encountered, each line after this
one represents a set of steps.
Step Lines
----------
Each line in the step section represents one "line" of steps, like SM
or .dance. Each line is 13 digits long; in single (unison) modes, only the
first 5 are used; in couple and double, the first 10 are used.
The order of the steps is Down Left, Up Left, Center, Up Right, Down Right.
The second player's (or second pad in double) steps are the same order,
but in positions 6-10 instead of 1-5.
A 0 in a position indicates no step. A 1 indicates a regular step. A 4
indicates a hold, for as long as a 4 is found in that column. The hold
ends on the beat of the last 4, not on the first 0.
Some files have been seen with repeated '1's in this manner as well;
it is unknown if any dance simulator supports this use of KSF, and since
a perfectly good non-ambiguous means of representing holds is available,
its use is not recommended.
A 2 (or a line of 13 2s) indicates the end of the step pattern.
BPM Changes
-----------
BPM changes are handled by header values; they are specified by a pair
of values #BPMx and #BUNKIx, where x is an integer. An example is:
#BPM:146.10;
#BPM2:180.20;
#BPM3:195.00;
#TICKCOUNT:2;
#STARTTIME:0;
#BUNKI:4200;
#BUNKI2:10000;
BPMn+1 starts at the time specified in centiseconds by BUNKIn (where n
is omitted if it is 1). In the above, 42 seconds (4200 centiseconds)
into the song, the BPM changes from its initial 146.1 to 180.2, and
then 100 seconds into the song, from 180.2 to 195.
BUNKIs can be a decimal value.
Syntax Exceptions
-----------------
Unlike DWI files, KSF files seem to have few exceptions or violations of
their syntax in the files seen in the wild. This may be because the format
is so mind-numbingly stupid.
Still Unknown
-------------
Some files contain a #STARTTIMEx (like #BPMx or #BUNKIx).
KSF step lines are 13 digits wide; only 10 digits appear to specify steps,
but the last 3 are not always 0. They probably represent something.
Author
------
This document was written by Joe Wreschnig <piman@debian.org>. It is
released into the public domain.
Changes
-------
2003.08.15
- Initial check in / release.
Acknowledgements
----------------
This document is based primarily off of extensive work done by Matt Reppert.
The Stepmania KSF loader source code (src/NotesLoaderKSF.cpp) also proved
useful in verifying some information.
Documentation on the KSF Format
-------------------------------
The KSF format is designed for representing steps for 5 panel diagonal
dancing games, such as Pump It Up. It was originally used in the Kick It Up
simulator, but can also be parsed by other programs. However, this seems
to be the only actual format description available.
The intention of this document is not to encourage creation of KSF files.
I believe the format to be broken, and provide this reference only for
people wishing to implement legacy file readers. Any new 5 panel dancing
patterns should use a well-defined format such as .dance or .sm.
Directory Layout
----------------
KSF filenames are case-insensitive.
A KSF directory contains the following files:
- At least one file matching *.KSF, containing the step data.
- A file named SONG.MP3, SONG.WAV, or SONG.OGG.
- A file named INTRO.MP3, INTRO.WAV, or INTRO.OGG, containing a sound clip,
used to preview the song in song selectors.
- Disc.bmp, a 300x200 image used in song selectors.
- Back.bmp or Title.bmp, a 640x480 image used as a background during the song.
KSF directories may not have a special naming format, but some simulators
will use the directory name to get the artist and title name, if it's not
available in the KSF files themseleves. The format is "Title",
"Title - Artist", or "Title - Artist - Difficulty". Difficulty can be
ignored here, as it can be gotten from the KSF filename. Using the path
name to determine the metadata for the song should only be used if it's
not available in #TITLE.
Concievably other audio or image formats could be used. None have been
seen in the wild.
KSF Filenames
-------------
KSF filenames describe the game type and difficulty. Each file holds the
data for only one level of difficulty. There are two possible forms of
the name: *<gametype>*.ksf, or *<difficulty>_<playernumber>*.ksf.
The first type is used for double mode, and half-double mode. Double.ksf
contains the steps for "Double" mode, where one player uses both paths.
Stepmania supports Halfdouble.ksf, which ignores the outer 4 panels.
The latter type is used for single ("unison", which is not the same
as Dance Dance Revolution's Unison mode in early mixes) steps, where both
players have the same steps, and couple steps, where players have different
ones. If the player number is 1, they are single steps; if it's 2, they're
couple steps. Difficulty is a difficulty name.
KSF Headers
-----------
The basic KSF format is similar to DWI, SM, and MSD. Metadata is given
in the format of:
#TAGNAME:VALUE;
The exception being the #STEPS tag, which has a newline between the ":"
and the first line of steps, and ends in "2222222222222" on a line by
itself instead of ";".
KSF files seem to use CRLF (Windows-style) line termination. The vast
majority of KSF files are in CP942/KSC 5601 encoding, but some are
in EUC-KR. If ASCII alternatives are needed for these encodings, the
path name must be checked as above.
Common headers in KSF files are as follows:
#TITLE: The artist and title of the song, and sometimes the difficulty.
These are separated by " - "s, so the format is either "Title",
"Artist - Title", or "Artist - Title - Difficulty". Information missing
from this line can be filled in via path or file names.
#BPM: The BPM of the song. This is analogous to the BPM value for every other
dance format.
#STARTTIME: The time into the song to offset events, in centiseconds. This
is the opposite of .dance's gap and .sm's offset, and the same as .dwi's
gap (although they use different units).
#TICKCOUNT: Each step line specifies 1/TICKCOUNT beats. That is, if
TICKCOUNT is 1, each line is the equivalent of a 'q' in .dance. If it's
2, each line is the same as a normal length note in DWI (an 'e' in .dance).
#STEP: Until a line of "2222222222222" is encountered, each line after this
one represents a set of steps.
Step Lines
----------
Each line in the step section represents one "line" of steps, like SM
or .dance. Each line is 13 digits long; in single (unison) modes, only the
first 5 are used; in couple and double, the first 10 are used.
The order of the steps is Down Left, Up Left, Center, Up Right, Down Right.
The second player's (or second pad in double) steps are the same order,
but in positions 6-10 instead of 1-5.
A 0 in a position indicates no step. A 1 indicates a regular step. A 4
indicates a hold, for as long as a 4 is found in that column. The hold
ends on the beat of the last 4, not on the first 0.
Some files have been seen with repeated '1's in this manner as well;
it is unknown if any dance simulator supports this use of KSF, and since
a perfectly good non-ambiguous means of representing holds is available,
its use is not recommended.
A 2 (or a line of 13 2s) indicates the end of the step pattern.
BPM Changes
-----------
BPM changes are handled by header values; they are specified by a pair
of values #BPMx and #BUNKIx, where x is an integer. An example is:
#BPM:146.10;
#BPM2:180.20;
#BPM3:195.00;
#TICKCOUNT:2;
#STARTTIME:0;
#BUNKI:4200;
#BUNKI2:10000;
BPMn+1 starts at the time specified in centiseconds by BUNKIn (where n
is omitted if it is 1). In the above, 42 seconds (4200 centiseconds)
into the song, the BPM changes from its initial 146.1 to 180.2, and
then 100 seconds into the song, from 180.2 to 195.
BUNKIs can be a decimal value.
Syntax Exceptions
-----------------
Unlike DWI files, KSF files seem to have few exceptions or violations of
their syntax in the files seen in the wild. This may be because the format
is so mind-numbingly stupid.
Still Unknown
-------------
Some files contain a #STARTTIMEx (like #BPMx or #BUNKIx).
KSF step lines are 13 digits wide; only 10 digits appear to specify steps,
but the last 3 are not always 0. They probably represent something.
Author
------
This document was written by Joe Wreschnig <piman@debian.org>. It is
released into the public domain.
Changes
-------
2003.08.15
- Initial check in / release.
Acknowledgements
----------------
This document is based primarily off of extensive work done by Matt Reppert.
The Stepmania KSF loader source code (src/NotesLoaderKSF.cpp) also proved
useful in verifying some information.
+337 -337
View File
@@ -1,337 +1,337 @@
The "Dance" Format
------------------
The goals of this format are easy parsability, easy human readability,
brevity, and disambiguity.
Generic Information
-------------------
All strings are case-sensitive. Filenames are case-sensitive. The
directory separator is '/' regardless of the platform. All text
is encoded in UTF-8. Byte-order marking is not allowed.
Enhanced Backus-Naur Form (ENBF) Specification
----------------------------------------------
This is purely the grammar. A semantic explanation is below.
Although this is given as a CFG specification, .dance is designed to be
parsed by a table-based DFA (as in pydance's fileparsers.py)
Primitives:
<String> ::= a sequence of characters
<Float> ::= 0.0 to Inf, decimal value
<NegInt> ::= 0 | -1 | -2 | -3 ...
<PosInt> ::= 0 | 1 | 2 | 3 ...
Almost primitives:
<Whitespace> ::= (" " | "\t")+
<Newline> ::= "\n" | "\r\n" | "\r"
<LongString> ::= <String> (<Whitespace> <String>)*
<EndToken> ::= "end" <Newline>
<Int> ::= <NegInt> | <PosInt>
<Comment> ::= [("#" <LongString>) | <Whitespace>] <Newline>
Basic Structure:
<File> ::= <Metadata> [<TextSection>+] <StepSection>+
Metadata Storage:
<Metadata> ::= (<Comment> | <MetadataLine>)+ <EndToken>
<MetadataLine> ::= (<Filename> | <Title> | <Subtitle> | <Artist> | <Mix> |
<BPM> | <Offset> | <BG> | <Banner> | <Preview> |
<Checksum> | <StartAt> | <EndAt> | <Author> | <CDTitle> |
<RevisionDate> | <Valid> | <Movie>) <Newline>
<Filename> ::= "filename" <Whitespace> <LongString>
<Title> ::= "title" <Whitespace> <LongString>
<Subtitle> ::= "subtitle" <Whitespace> <LongString>
<Artist> ::= "artist" <Whitespace> <LongString>
<Mix> ::= "mix" <Whitespace> <LongString>
<BPM> ::= "bpm" <Whitespace> <Float>
<BPMDisplay> :: "bpmdisplay" ((<Whitespace> <Float>)+ | "*")
<Gap> ::= "gap" <Whitespace> <Int>
<StartAt> ::= "startat" <Whitespace> <Float>
<EndAt> ::= "endat" <Whitespace> <Float>
<BG> ::= "background" <Whitespace> <LongString>
<Banner> ::= "banner" <Whitespace> <LongString>
<Banner> ::= "cdtitle" <Whitespace> <LongString>
<Preview> :: "preview" <Whitespace> <Float> <Whitespace> <Float>
<Checksum> ::= "md5sum" <Whitespace> <String>
<Author> ::= "author" <Whitespace> <LongString>
<Movie> ::= "movie" <Whitespace> <LongString>
<RevisionDate> ::= "revision" <Whitespace> <LongString>
<Valid> ::= "valid" <Whitespace> 1 | 0
Text Sections:
<TextSection> ::= [<Description>] [<Lyrics>]
<Lyrics> ::= "LYRICS" <Newline> (<LyricLine>)+ <EndToken>
<LyricLine> ::= <Float> <Whitespace> <PosInt> <Whitespace> <LongString> <Newline>
<Description> ::= "DESCRIPTION" <Newline> (<LongString> <Newline>)+ <EndToken>
Step Sections:
<StepSection> ::= <GameMode> <Difficulty> <Sequence>+ <EndToken>
<GameMode> ::= <String> <Newline>
<Difficulty> ::= <String> <Whitespace> <PosInt> <Newline>
<Sequence> ::= (<Comment> | <Buttons> | <Command>) <Newline>
Note Sequences:
<Buttons> ::= <NoteType> (<Whitespace> <ButtonPresses>)+
<NoteType> ::= "u" | "n" | "x" | "t" | "f" | "s" | "w" | "e" | "q" | "h" | "o"
<ButtonPresses> ::= (0 | 1 | 3 | 5 | 7)+
Song Commands:
<Command> ::= <ChangeBPM> | <Ready> | <Wait> | <Stop> | <Delay> | <Lyric>
<ChangeBPM> ::= "B" <Whitespace> <Float>
<Ready> ::= "R"
<Wait> ::= "W" <Whitespace> <Float>
<Stop> ::= "S" <Whitespace> <Float>
<Delay> ::= "D" <Whitespace> <Float>
<Lyric> ::= "L" <Whitespace> <Float> <Whitespace> <PosInt> <Whitespace>
<LongString>
Informal & Semantic Description
-------------------------------
The dance format is basically the step format, but generalized, smaller,
and more readable. A script to convert .step files to .dance files is
forthcoming.
A simple file might look like:
filename asong.ogg
title A Song
subtitle Crazy Mix
artist Someone
# This is a comment
end
DESCRIPTION
This is an example song.
It's pretty uninteresting.
end
SINGLE
BASIC 0
q 1010
# This is another comment.
q 0101
q 3030
q 1010
end
Metadata Section:
The metadata section of the song is the first section, and contains
important data about the file. An explanation of the keys follow:
'filename': The filename of the audio file to play.
'title': The name of the song. This should not include "Foo Mix".
'subtitle': "Foo Mix", "Crazy Version", whatever. Default none.
'artist': The name of the artist(s) and any remixers.
'bpm': The beats per minute of the song.
'gap': The millisecond offset into the song at which the arrows should
start. If the first beat is 0.3 seconds into the song, for example,
this should be -300. This can be negative. Default 0.
'bpmdisplay': A whitespace-separated list of floats, which will be
cycled through on the song selector's BPM display. If
not present this defaults to the BPM if the song. If "*",
the BPM is displayed as constantly changing.
'background': A background image (to display while the song is playing).
Default none.
'banner': A banner for the song (to display in the song select). Default none.
'cdtitle': A small (64x40) image to use as a CD title. Default none. This
path should either be relative to a special CD title directory,
or to the directory the file is in.
'preview': An offset to seconds to start a song preview at, and a length to
play the preview. Default 45.0 and 10.0.
'startat', 'endat': Start and end the music at these positions in seconds.
offset and the steps are then relative to the startat
position. Default 0.0 and the length of the song.
'md5sum': If present, the MD5 checksum of the 'filename' file. If it's
present and the file doesn't match, a warning can be issued.
'author': The person who wrote this file. Default none.
'revision': The date of the last revision of this file, in YYYY.MM.DD format.
Defaults to "1970.01.01".
'movie': The filename of a background movie; defaults to none.
'valid': If not true, this song should be not selected using in random play
modes (e.g., it's not finished, hasn't been timed, etc). Default 1.
The 'filename', 'title', 'artist', and 'bpm' keys are mandatory.
Note that songs in this format will *NOT* have any files autodetected. If
you want them to be found, explicitly state them in the file.
The metadata section, like all sections, must end with "end" on a line
by itself.
Text Sections:
There are two "text" sections in dance files; these are essentially
extended metadata sections.
The DESCRIPTION section contains a description of the song. The format
roughly follows the DPKG description format: All lines of text start
with a space. Whitespace, including newlines, is ignored. A period ('.')
on a line by itself (with a space before it!) is to be interpreted as a
paragraph separator. An 'end' token on a single line, with no space before
it, ends the description.
The LYRICS section contains lyric timing information. The format
of each line is, an integer, a float, and then a string. The integer
specifies the lyric "channel"; lyrics in the same channel should overwrite
each other, appear in the same place on the screen, etc. The float is the
time into the song during which the lyric should appear, irrespective
of the 'gap' value.
Step Sections:
The meat of the file is in the step sections, which actually describe
the game-related stuff. A step section is started as soon as an unknown
section token is encounter (i.e. currently not LYRICS or DESCRIPTION).
This first token is then taken as the "game mode". The two tokens on the
next line are the difficulty name and rating number.
Then, until the "end" token, there are lines describing the steps. These
may be either a command, or a set of buttons to press. The "base" is 'q',
the quarter note, which represents one beat in the song.
o Whole note (4 on-beat arrows)
h 1/2 note
q 1/4 note
e 1/8 note
w 1/12 note
s 1/16 note
f 1/24 note
t 1/32 note
u 1/48 note
x 1/64 note
n 1/192 note
After the note comes a string of buttons. All these strings should be
the same length across game modes. Example strings might "1001" or "0030".
0 No button at this time
1 A regular press at this time
3 This button must be pressed here and held down until a 1 is encounted
5 A secret step at this time.
7 A secret step and hold at this time.
(Note - With bitwise &,
num & 1 => pressed here,
num & 2 => hold here,
num & 4 => this is a secret note.
This correspondance is not necesarily guaranateed to be true for all
future additions to the .dance format, but will be maintained if possible.)
Possible commands are:
B <Float> Change the BPM of the song to this number at this point.
R "Ready? Go!" graphics/sound, if any.
W <Float> Wait this many seconds before the next event.
S <Float> Stop scrolling for this many seconds before the next event.
D <Float> The same as a sequence of 0 note strings for this many beats.
L <PosInt> <LongString> Display some lyrics at this point.
Failing Gracefully
------------------
Often, your parsers may come across tokens they don't know; maybe because
someone made an invalid file, or because the parser doesn't support all
of this format (or an old version of this format). If this is a section
token, this isn't a big problem; jump to the next end token and keep
going. Metadata tokens are equally easy to skip.
Tokens in steps are more complicated. In general, you should treat
them as comments, treat unknown note types as 0s, and hope for the
best.
Bad files shouldn't make your parser crash. It should return an error to
the program, which behaves accordingly.
Future Extensions
-----------------
If this format is found to be inadaquate, the following extensions
may be added:
New metadata keys. This would be a new line in the metadata section.
It is unlikely such a line would be mandatory, since current songs
work fine without them.
New note types and commands. These would be new lowercase or uppercase
single characters in the song section.
Standard Game Modes
-------------------
SINGLE - Normal single player with up, down, left, and right, or versus
mode, if no VERSUS is found.
VERSUS - Two players, both with the same steps.
COUPLE - Two players with different steps.
DOUBLE - Doubles, one player on both pads.
5PANEL - Diagonal directions, and the center, for one player.
5VERSUS, 5COUPLE, 5DOUBLE - Similar to the 4 panel relationships.
6PANEL, 6VERSUS, 6DOUBLE, 6COUPLE: Up left, up right, up, down, left,
and right.
8PANEL, etc: All directions except center.
9PANEL, etc: All directions including center.
3PANEL, etc: Up left, down, and up right.
Changes:
--------
2004.03.01
- Version 1.2, released with pydance 1.0.
- Add 9 panel game mode.
2004.01.16
- Include comments in the example.
2003.12.23
- 3 panel modes.
- bpmdisplay metadata key.
2003.12.22
- 'cdtitle' metadata line.
2003.08.15
- Specify note types more exactly.
- Fix the broken DESCRIPTION in the example.
- Remove obsolete notes about the pydance implementation.
- Add more game modes to the list (especially of note is VERSUS).
2003.07.30
- Fix example of 'gap' attribute (-300 instead of 300).
- Fix nonsensical hold arrow example.
2003.06.29
- Fix a typo ("::" => "::=").
2003.06.27
- Add EBNF for COUPLE-style modes (spaces in Buttons)
2003.06.26
- Add a missing newline to LyricLine.
- Add (currently unexplained) BACKGROUNDS section.
2003.06.03
- Version 1.1
- Add 192nd notes with 'n', 48th with 'u'.
2003.06.01
- Version 1.0
- No more I command.
2003.05.23:
- Started changes.
- v1.0 draft preparation.
- Need to explain the I command.
The "Dance" Format
------------------
The goals of this format are easy parsability, easy human readability,
brevity, and disambiguity.
Generic Information
-------------------
All strings are case-sensitive. Filenames are case-sensitive. The
directory separator is '/' regardless of the platform. All text
is encoded in UTF-8. Byte-order marking is not allowed.
Enhanced Backus-Naur Form (ENBF) Specification
----------------------------------------------
This is purely the grammar. A semantic explanation is below.
Although this is given as a CFG specification, .dance is designed to be
parsed by a table-based DFA (as in pydance's fileparsers.py)
Primitives:
<String> ::= a sequence of characters
<Float> ::= 0.0 to Inf, decimal value
<NegInt> ::= 0 | -1 | -2 | -3 ...
<PosInt> ::= 0 | 1 | 2 | 3 ...
Almost primitives:
<Whitespace> ::= (" " | "\t")+
<Newline> ::= "\n" | "\r\n" | "\r"
<LongString> ::= <String> (<Whitespace> <String>)*
<EndToken> ::= "end" <Newline>
<Int> ::= <NegInt> | <PosInt>
<Comment> ::= [("#" <LongString>) | <Whitespace>] <Newline>
Basic Structure:
<File> ::= <Metadata> [<TextSection>+] <StepSection>+
Metadata Storage:
<Metadata> ::= (<Comment> | <MetadataLine>)+ <EndToken>
<MetadataLine> ::= (<Filename> | <Title> | <Subtitle> | <Artist> | <Mix> |
<BPM> | <Offset> | <BG> | <Banner> | <Preview> |
<Checksum> | <StartAt> | <EndAt> | <Author> | <CDTitle> |
<RevisionDate> | <Valid> | <Movie>) <Newline>
<Filename> ::= "filename" <Whitespace> <LongString>
<Title> ::= "title" <Whitespace> <LongString>
<Subtitle> ::= "subtitle" <Whitespace> <LongString>
<Artist> ::= "artist" <Whitespace> <LongString>
<Mix> ::= "mix" <Whitespace> <LongString>
<BPM> ::= "bpm" <Whitespace> <Float>
<BPMDisplay> :: "bpmdisplay" ((<Whitespace> <Float>)+ | "*")
<Gap> ::= "gap" <Whitespace> <Int>
<StartAt> ::= "startat" <Whitespace> <Float>
<EndAt> ::= "endat" <Whitespace> <Float>
<BG> ::= "background" <Whitespace> <LongString>
<Banner> ::= "banner" <Whitespace> <LongString>
<Banner> ::= "cdtitle" <Whitespace> <LongString>
<Preview> :: "preview" <Whitespace> <Float> <Whitespace> <Float>
<Checksum> ::= "md5sum" <Whitespace> <String>
<Author> ::= "author" <Whitespace> <LongString>
<Movie> ::= "movie" <Whitespace> <LongString>
<RevisionDate> ::= "revision" <Whitespace> <LongString>
<Valid> ::= "valid" <Whitespace> 1 | 0
Text Sections:
<TextSection> ::= [<Description>] [<Lyrics>]
<Lyrics> ::= "LYRICS" <Newline> (<LyricLine>)+ <EndToken>
<LyricLine> ::= <Float> <Whitespace> <PosInt> <Whitespace> <LongString> <Newline>
<Description> ::= "DESCRIPTION" <Newline> (<LongString> <Newline>)+ <EndToken>
Step Sections:
<StepSection> ::= <GameMode> <Difficulty> <Sequence>+ <EndToken>
<GameMode> ::= <String> <Newline>
<Difficulty> ::= <String> <Whitespace> <PosInt> <Newline>
<Sequence> ::= (<Comment> | <Buttons> | <Command>) <Newline>
Note Sequences:
<Buttons> ::= <NoteType> (<Whitespace> <ButtonPresses>)+
<NoteType> ::= "u" | "n" | "x" | "t" | "f" | "s" | "w" | "e" | "q" | "h" | "o"
<ButtonPresses> ::= (0 | 1 | 3 | 5 | 7)+
Song Commands:
<Command> ::= <ChangeBPM> | <Ready> | <Wait> | <Stop> | <Delay> | <Lyric>
<ChangeBPM> ::= "B" <Whitespace> <Float>
<Ready> ::= "R"
<Wait> ::= "W" <Whitespace> <Float>
<Stop> ::= "S" <Whitespace> <Float>
<Delay> ::= "D" <Whitespace> <Float>
<Lyric> ::= "L" <Whitespace> <Float> <Whitespace> <PosInt> <Whitespace>
<LongString>
Informal & Semantic Description
-------------------------------
The dance format is basically the step format, but generalized, smaller,
and more readable. A script to convert .step files to .dance files is
forthcoming.
A simple file might look like:
filename asong.ogg
title A Song
subtitle Crazy Mix
artist Someone
# This is a comment
end
DESCRIPTION
This is an example song.
It's pretty uninteresting.
end
SINGLE
BASIC 0
q 1010
# This is another comment.
q 0101
q 3030
q 1010
end
Metadata Section:
The metadata section of the song is the first section, and contains
important data about the file. An explanation of the keys follow:
'filename': The filename of the audio file to play.
'title': The name of the song. This should not include "Foo Mix".
'subtitle': "Foo Mix", "Crazy Version", whatever. Default none.
'artist': The name of the artist(s) and any remixers.
'bpm': The beats per minute of the song.
'gap': The millisecond offset into the song at which the arrows should
start. If the first beat is 0.3 seconds into the song, for example,
this should be -300. This can be negative. Default 0.
'bpmdisplay': A whitespace-separated list of floats, which will be
cycled through on the song selector's BPM display. If
not present this defaults to the BPM if the song. If "*",
the BPM is displayed as constantly changing.
'background': A background image (to display while the song is playing).
Default none.
'banner': A banner for the song (to display in the song select). Default none.
'cdtitle': A small (64x40) image to use as a CD title. Default none. This
path should either be relative to a special CD title directory,
or to the directory the file is in.
'preview': An offset to seconds to start a song preview at, and a length to
play the preview. Default 45.0 and 10.0.
'startat', 'endat': Start and end the music at these positions in seconds.
offset and the steps are then relative to the startat
position. Default 0.0 and the length of the song.
'md5sum': If present, the MD5 checksum of the 'filename' file. If it's
present and the file doesn't match, a warning can be issued.
'author': The person who wrote this file. Default none.
'revision': The date of the last revision of this file, in YYYY.MM.DD format.
Defaults to "1970.01.01".
'movie': The filename of a background movie; defaults to none.
'valid': If not true, this song should be not selected using in random play
modes (e.g., it's not finished, hasn't been timed, etc). Default 1.
The 'filename', 'title', 'artist', and 'bpm' keys are mandatory.
Note that songs in this format will *NOT* have any files autodetected. If
you want them to be found, explicitly state them in the file.
The metadata section, like all sections, must end with "end" on a line
by itself.
Text Sections:
There are two "text" sections in dance files; these are essentially
extended metadata sections.
The DESCRIPTION section contains a description of the song. The format
roughly follows the DPKG description format: All lines of text start
with a space. Whitespace, including newlines, is ignored. A period ('.')
on a line by itself (with a space before it!) is to be interpreted as a
paragraph separator. An 'end' token on a single line, with no space before
it, ends the description.
The LYRICS section contains lyric timing information. The format
of each line is, an integer, a float, and then a string. The integer
specifies the lyric "channel"; lyrics in the same channel should overwrite
each other, appear in the same place on the screen, etc. The float is the
time into the song during which the lyric should appear, irrespective
of the 'gap' value.
Step Sections:
The meat of the file is in the step sections, which actually describe
the game-related stuff. A step section is started as soon as an unknown
section token is encounter (i.e. currently not LYRICS or DESCRIPTION).
This first token is then taken as the "game mode". The two tokens on the
next line are the difficulty name and rating number.
Then, until the "end" token, there are lines describing the steps. These
may be either a command, or a set of buttons to press. The "base" is 'q',
the quarter note, which represents one beat in the song.
o Whole note (4 on-beat arrows)
h 1/2 note
q 1/4 note
e 1/8 note
w 1/12 note
s 1/16 note
f 1/24 note
t 1/32 note
u 1/48 note
x 1/64 note
n 1/192 note
After the note comes a string of buttons. All these strings should be
the same length across game modes. Example strings might "1001" or "0030".
0 No button at this time
1 A regular press at this time
3 This button must be pressed here and held down until a 1 is encounted
5 A secret step at this time.
7 A secret step and hold at this time.
(Note - With bitwise &,
num & 1 => pressed here,
num & 2 => hold here,
num & 4 => this is a secret note.
This correspondance is not necesarily guaranateed to be true for all
future additions to the .dance format, but will be maintained if possible.)
Possible commands are:
B <Float> Change the BPM of the song to this number at this point.
R "Ready? Go!" graphics/sound, if any.
W <Float> Wait this many seconds before the next event.
S <Float> Stop scrolling for this many seconds before the next event.
D <Float> The same as a sequence of 0 note strings for this many beats.
L <PosInt> <LongString> Display some lyrics at this point.
Failing Gracefully
------------------
Often, your parsers may come across tokens they don't know; maybe because
someone made an invalid file, or because the parser doesn't support all
of this format (or an old version of this format). If this is a section
token, this isn't a big problem; jump to the next end token and keep
going. Metadata tokens are equally easy to skip.
Tokens in steps are more complicated. In general, you should treat
them as comments, treat unknown note types as 0s, and hope for the
best.
Bad files shouldn't make your parser crash. It should return an error to
the program, which behaves accordingly.
Future Extensions
-----------------
If this format is found to be inadaquate, the following extensions
may be added:
New metadata keys. This would be a new line in the metadata section.
It is unlikely such a line would be mandatory, since current songs
work fine without them.
New note types and commands. These would be new lowercase or uppercase
single characters in the song section.
Standard Game Modes
-------------------
SINGLE - Normal single player with up, down, left, and right, or versus
mode, if no VERSUS is found.
VERSUS - Two players, both with the same steps.
COUPLE - Two players with different steps.
DOUBLE - Doubles, one player on both pads.
5PANEL - Diagonal directions, and the center, for one player.
5VERSUS, 5COUPLE, 5DOUBLE - Similar to the 4 panel relationships.
6PANEL, 6VERSUS, 6DOUBLE, 6COUPLE: Up left, up right, up, down, left,
and right.
8PANEL, etc: All directions except center.
9PANEL, etc: All directions including center.
3PANEL, etc: Up left, down, and up right.
Changes:
--------
2004.03.01
- Version 1.2, released with pydance 1.0.
- Add 9 panel game mode.
2004.01.16
- Include comments in the example.
2003.12.23
- 3 panel modes.
- bpmdisplay metadata key.
2003.12.22
- 'cdtitle' metadata line.
2003.08.15
- Specify note types more exactly.
- Fix the broken DESCRIPTION in the example.
- Remove obsolete notes about the pydance implementation.
- Add more game modes to the list (especially of note is VERSUS).
2003.07.30
- Fix example of 'gap' attribute (-300 instead of 300).
- Fix nonsensical hold arrow example.
2003.06.29
- Fix a typo ("::" => "::=").
2003.06.27
- Add EBNF for COUPLE-style modes (spaces in Buttons)
2003.06.26
- Add a missing newline to LyricLine.
- Add (currently unexplained) BACKGROUNDS section.
2003.06.03
- Version 1.1
- Add 192nd notes with 'n', 48th with 'u'.
2003.06.01
- Version 1.0
- No more I command.
2003.05.23:
- Started changes.
- v1.0 draft preparation.
- Need to explain the I command.
+88 -88
View File
@@ -1,88 +1,88 @@
ThemePrefs, v0.7
----------------
ThemePrefs is a system for handling theme-specific preferences in a standard,
efficient, and predictable way. All you do, basically, is declare a table of
preferences and options and use GetThemePref(name) to get your preference
values as needed. This system will handle all disk I/O as well.
Additionally, it can work in combination with ThemePrefsRows to generate
OptionsRows for all preferences, saving you (most of) the trouble with
integrating it into your theme. More on that later.
The prefs are written, using IniFile, into Save/ThemePrefs.ini, written under
the section corresponding to your theme name (if ThemeInfo exists, it will
use the Name field listed there; otherwise, it will use the folder name).
----------------------
Section 1: Declaration
----------------------
To declare preferences for your theme to use, make a table with named
tables in it; its name is used for the preference, and the tables hold
the options for that preference. All you need to know for now is that
Default is required; for more options, check ThemePrefsRows.
After the table is declared, pass it to the function ThemePrefs.InitAll().
(If you're planning not to use any OptionsRows at all, you can just use
ThemePrefs.Init() to save some processing time, but seriously give the
ThemePrefsRows system a look before you disregard it.)
[code]
local Prefs =
{
BoolPref = { Default = false },
IntPref = { Default = 3 },
}
ThemePrefs.InitAll( Prefs )
[/code]
If your theme is "default", this will generate a ThemePrefs.ini like so:
[default]
BoolPref=false
IntPref=3
----------------
Section 2: Usage
----------------
You can access the value with ThemePrefs.Get(name) or GetThemePref(name):
both calls work identically. The return type will be based on whatever you set
it to, but the subsystem will always try number, then bool, then string, in
that order. Use true and false for bools, not 1 and 0.
For example, if you wanted to branch something in the metrics based on
the value of BoolPref (which is a boolean), you could use the following:
NextScreen=GetThemePref('BoolPref') and "ScreenTrue" or "ScreenFalse"
If you want to set a preference value for some reason, you can use either
ThemePrefs.Set(name, value) or SetThemePref(name, value), but the point of
this API is to simplify and standardize prefs handling, so you really should
not need it. (Use ThemePrefsRows instead.)
-----------------------
Section 3: Localization
-----------------------
ThemePrefs has two strings that can be localized, to be placed under
[ThemePrefs] in the appropriate language INI.
IniFileMissing - displayed when IniFile.lua is not found, which means
ThemePrefs cannot be loaded from or written to disk
UnknownPreference - displayed when an attempt is made to read or write
a preference that does not exist in the system. Uses %s for the
name of the unknown preference.
---------------------
Section 4: Disclaimer
---------------------
Though this is working fine so far, it is still experimental! If you run
into problems, or have suggestions, comments, questions, etc., please talk
to "vyhd" in #sm-ssc on irc.badnik.net, as it's his code to maintain; he
hates subjecting other people to his code (and occasionally vice versa),
but will gladly address concerns that come up.
ThemePrefs, v0.7
----------------
ThemePrefs is a system for handling theme-specific preferences in a standard,
efficient, and predictable way. All you do, basically, is declare a table of
preferences and options and use GetThemePref(name) to get your preference
values as needed. This system will handle all disk I/O as well.
Additionally, it can work in combination with ThemePrefsRows to generate
OptionsRows for all preferences, saving you (most of) the trouble with
integrating it into your theme. More on that later.
The prefs are written, using IniFile, into Save/ThemePrefs.ini, written under
the section corresponding to your theme name (if ThemeInfo exists, it will
use the Name field listed there; otherwise, it will use the folder name).
----------------------
Section 1: Declaration
----------------------
To declare preferences for your theme to use, make a table with named
tables in it; its name is used for the preference, and the tables hold
the options for that preference. All you need to know for now is that
Default is required; for more options, check ThemePrefsRows.
After the table is declared, pass it to the function ThemePrefs.InitAll().
(If you're planning not to use any OptionsRows at all, you can just use
ThemePrefs.Init() to save some processing time, but seriously give the
ThemePrefsRows system a look before you disregard it.)
[code]
local Prefs =
{
BoolPref = { Default = false },
IntPref = { Default = 3 },
}
ThemePrefs.InitAll( Prefs )
[/code]
If your theme is "default", this will generate a ThemePrefs.ini like so:
[default]
BoolPref=false
IntPref=3
----------------
Section 2: Usage
----------------
You can access the value with ThemePrefs.Get(name) or GetThemePref(name):
both calls work identically. The return type will be based on whatever you set
it to, but the subsystem will always try number, then bool, then string, in
that order. Use true and false for bools, not 1 and 0.
For example, if you wanted to branch something in the metrics based on
the value of BoolPref (which is a boolean), you could use the following:
NextScreen=GetThemePref('BoolPref') and "ScreenTrue" or "ScreenFalse"
If you want to set a preference value for some reason, you can use either
ThemePrefs.Set(name, value) or SetThemePref(name, value), but the point of
this API is to simplify and standardize prefs handling, so you really should
not need it. (Use ThemePrefsRows instead.)
-----------------------
Section 3: Localization
-----------------------
ThemePrefs has two strings that can be localized, to be placed under
[ThemePrefs] in the appropriate language INI.
IniFileMissing - displayed when IniFile.lua is not found, which means
ThemePrefs cannot be loaded from or written to disk
UnknownPreference - displayed when an attempt is made to read or write
a preference that does not exist in the system. Uses %s for the
name of the unknown preference.
---------------------
Section 4: Disclaimer
---------------------
Though this is working fine so far, it is still experimental! If you run
into problems, or have suggestions, comments, questions, etc., please talk
to "vyhd" in #sm-ssc on irc.badnik.net, as it's his code to maintain; he
hates subjecting other people to his code (and occasionally vice versa),
but will gladly address concerns that come up.
+145 -145
View File
@@ -1,145 +1,145 @@
ThemePrefsRows, v0.5
--------------------
ThemePrefsRows is an optional system that works with ThemePrefs to generate
Lua-based OptionsRows for every preference used in the system. All you do is
declare a table of preferences and pass it to ThemePrefs.InitAll(), which will
also initialize ThemePrefs. Note that you do need to add an entry for each
preference in [OptionTitles] and [OptionExplanations] to give the row its name
and describe what it does; I hope to find a (clean) way to do it from Lua.
----------------------
Section 1: Declaration
----------------------
Declaring preferences is the same basic concept as ThemePrefs; see that doc
for the basics. So I'll go into the stuff that's important to this API.
As mentioned in ThemePrefs, the table contains options. The possible options
and their types are outlaid here. (The pref's type is defined by Default.)
Default: whatever the value is set to by default. For sanity's sake, you
should have this in your Choices table.
Choices (table): an indexed array containing all the possible OptionsRow
choices. If you're using a Values table, the array values should be
strings. If not, you can use any type that can cast to a string.
Values (table): indexed array of the pref's type containing the value used when
the Choices entry with the same index is chosen in the row. If that
confused you, don't worry: it'll make more sense in the example.
This is optional, if your pref type can cast to strings.
Params (table): optional modifications to the OptionsRow. I'll cover this in
more detail in a later section. You probably won't need it.
To make this clearer, have an example of a valid prefs table:
[code]
local prefs =
{
BoolPref =
{
Default = false,
Choices = { "On", "Off" },
Values = { true, false },
},
IntPref =
{
Default = 3,
Choices = { 1, 2, 3, 4, 5 },
Params = { SelectType = "ShowOneInRow" }
}
}
ThemePrefs.InitAll( prefs )
[/code]
So when "On" is selected, BoolPref will be set to true, and selecting "Off"
will set it false. Simple enough, yeah? This will scale to any type you like.
Enumerations, strings, whatever.
-----------------
Section 2: Params
-----------------
We did promise a more in-depth look at Params, so here it is.
The following arguments and values are currently accepted for Params:
LayoutType (string): "ShowAllInRow" (default), "ShowOneInRow".
ExportOnChange (bool): currently disabled in the source, but available to
set in case it's enabled later. If true, the Save function (which
handles actually setting the preference) is called whenever a value
is changed rather than when the screen changes.
EnabledForPlayers (function): has 'self' as an argument, returns a table of
PlayerNumbers who are allowed to select stuff. Not important yet.
ReloadRowMessages (table): contains an indexed array of strings. Whenever
any of the messages in this table are broadcast, the Load function
(which loads the list of possible options and sets the selected
value/s) is called again.
LoadSelections (function): takes self, list, pn, overrides the default
function. This is advanced usage, so you should probably know
what you're doing to use it. Probably unnecessary.
SaveSelections (function): takes self, list, pn, and overrides the default
function. This is advanced as well, for the same reasons. Fortunately,
you probably won't need it.
----------------
Section 3: Usage
----------------
To get the OptionsRow for the preference you want, use ThemePrefRow(name)
or ThemePrefsRows.GetRow(name); they're the same function. You'd use this
as, for example in the metrics:
Line1="lua,ThemePrefRow('BoolPref')"
Unfortunately, you do need to do some more work with the Language INIs too.
For each declared preference, you need an entry under [OptionTitles] for its
title and an entry under [OptionExplanations] for its description. The key for
both is the name of the preference. With the above example, that'd be e.g.
[OptionTitles]
(...)
BoolPref=BoolPref
IntPref=IntPref
[OptionExplanations]
(...)
BoolPref=Toggles a simple boolean preference between true and false.
IntPref=Sets an integer value between 1 and 5.
-----------------------
Section 4: Localization
-----------------------
ThemePrefsRows has three themable strings:
NoDefaultInValues - if the default value isn't actually in choices or values,
this is displayed. Takes %s for the affected preference's name.
TypeMismatch - if the default type and a value type mismatch, this is shown.
Takes %s, %d, and %s for the default's type, the index of the
mismatching value, and the value's type respectively.
ChoicesSizeMismatch - if the Choices and Values arrays have different
lengths, this is displayed. Takes %d and %d for the size of
Choices and Values, respectively.
---------------------
Section 5: Disclaimer
---------------------
This isn't as tested as I'd like. For this version, it remains experimental.
Quite experimental. If you run into problems, please let me know so I can
fix them.
Please direct all questions, comments, complaints, bug reports, etc. to "vyhd"
in #sm-ssc on irc.badnik.net or whatever other form of communication you like.
ThemePrefsRows, v0.5
--------------------
ThemePrefsRows is an optional system that works with ThemePrefs to generate
Lua-based OptionsRows for every preference used in the system. All you do is
declare a table of preferences and pass it to ThemePrefs.InitAll(), which will
also initialize ThemePrefs. Note that you do need to add an entry for each
preference in [OptionTitles] and [OptionExplanations] to give the row its name
and describe what it does; I hope to find a (clean) way to do it from Lua.
----------------------
Section 1: Declaration
----------------------
Declaring preferences is the same basic concept as ThemePrefs; see that doc
for the basics. So I'll go into the stuff that's important to this API.
As mentioned in ThemePrefs, the table contains options. The possible options
and their types are outlaid here. (The pref's type is defined by Default.)
Default: whatever the value is set to by default. For sanity's sake, you
should have this in your Choices table.
Choices (table): an indexed array containing all the possible OptionsRow
choices. If you're using a Values table, the array values should be
strings. If not, you can use any type that can cast to a string.
Values (table): indexed array of the pref's type containing the value used when
the Choices entry with the same index is chosen in the row. If that
confused you, don't worry: it'll make more sense in the example.
This is optional, if your pref type can cast to strings.
Params (table): optional modifications to the OptionsRow. I'll cover this in
more detail in a later section. You probably won't need it.
To make this clearer, have an example of a valid prefs table:
[code]
local prefs =
{
BoolPref =
{
Default = false,
Choices = { "On", "Off" },
Values = { true, false },
},
IntPref =
{
Default = 3,
Choices = { 1, 2, 3, 4, 5 },
Params = { SelectType = "ShowOneInRow" }
}
}
ThemePrefs.InitAll( prefs )
[/code]
So when "On" is selected, BoolPref will be set to true, and selecting "Off"
will set it false. Simple enough, yeah? This will scale to any type you like.
Enumerations, strings, whatever.
-----------------
Section 2: Params
-----------------
We did promise a more in-depth look at Params, so here it is.
The following arguments and values are currently accepted for Params:
LayoutType (string): "ShowAllInRow" (default), "ShowOneInRow".
ExportOnChange (bool): currently disabled in the source, but available to
set in case it's enabled later. If true, the Save function (which
handles actually setting the preference) is called whenever a value
is changed rather than when the screen changes.
EnabledForPlayers (function): has 'self' as an argument, returns a table of
PlayerNumbers who are allowed to select stuff. Not important yet.
ReloadRowMessages (table): contains an indexed array of strings. Whenever
any of the messages in this table are broadcast, the Load function
(which loads the list of possible options and sets the selected
value/s) is called again.
LoadSelections (function): takes self, list, pn, overrides the default
function. This is advanced usage, so you should probably know
what you're doing to use it. Probably unnecessary.
SaveSelections (function): takes self, list, pn, and overrides the default
function. This is advanced as well, for the same reasons. Fortunately,
you probably won't need it.
----------------
Section 3: Usage
----------------
To get the OptionsRow for the preference you want, use ThemePrefRow(name)
or ThemePrefsRows.GetRow(name); they're the same function. You'd use this
as, for example in the metrics:
Line1="lua,ThemePrefRow('BoolPref')"
Unfortunately, you do need to do some more work with the Language INIs too.
For each declared preference, you need an entry under [OptionTitles] for its
title and an entry under [OptionExplanations] for its description. The key for
both is the name of the preference. With the above example, that'd be e.g.
[OptionTitles]
(...)
BoolPref=BoolPref
IntPref=IntPref
[OptionExplanations]
(...)
BoolPref=Toggles a simple boolean preference between true and false.
IntPref=Sets an integer value between 1 and 5.
-----------------------
Section 4: Localization
-----------------------
ThemePrefsRows has three themable strings:
NoDefaultInValues - if the default value isn't actually in choices or values,
this is displayed. Takes %s for the affected preference's name.
TypeMismatch - if the default type and a value type mismatch, this is shown.
Takes %s, %d, and %s for the default's type, the index of the
mismatching value, and the value's type respectively.
ChoicesSizeMismatch - if the Choices and Values arrays have different
lengths, this is displayed. Takes %d and %d for the size of
Choices and Values, respectively.
---------------------
Section 5: Disclaimer
---------------------
This isn't as tested as I'd like. For this version, it remains experimental.
Quite experimental. If you run into problems, please let me know so I can
fix them.
Please direct all questions, comments, complaints, bug reports, etc. to "vyhd"
in #sm-ssc on irc.badnik.net or whatever other form of communication you like.
+19 -19
View File
@@ -1,19 +1,19 @@
local t = Def.ActorFrame {
Def.Sprite {
Texture="_receptor";
Frame0000=0;
Delay0000=1;
InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand');
NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
};
Def.Sprite {
Texture="_rflash";
Frame0000=0;
Delay0000=1;
InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand');
PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand');
LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand');
NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
};
};
return t;
local t = Def.ActorFrame {
Def.Sprite {
Texture="_receptor";
Frame0000=0;
Delay0000=1;
InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand');
NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
};
Def.Sprite {
Texture="_rflash";
Frame0000=0;
Delay0000=1;
InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand');
PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand');
LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand');
NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
};
};
return t;
+5 -5
View File
@@ -1,5 +1,5 @@
return Def.Sprite {
Texture=NOTESKIN:GetPath( '_space', 'tap note' );
-- probably don't need this line
Frames = Sprite.LinearFrames( 1, 1 );
};
return Def.Sprite {
Texture=NOTESKIN:GetPath( '_space', 'tap note' );
-- probably don't need this line
Frames = Sprite.LinearFrames( 1, 1 );
};
+19 -19
View File
@@ -1,19 +1,19 @@
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"scroller.ini"
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"_grey (no mipmaps).png"
""
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"scroller.ini"
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"_grey (no mipmaps).png"
""
+316 -316
View File
@@ -1,316 +1,316 @@
// MilkShape 3D ASCII
Frames: 30
Frame: 1
Meshes: 2
"scroll" 0 0
17
0 28.576029 12.295176 2.879607 0.114769 0.235221 -1
0 22.456854 18.468002 2.879607 0.103466 0.102288 -1
0 0.000001 -0.000001 2.879607 0.061984 0.500000 -1
0 31.867174 4.250518 2.879607 0.120849 0.408464 -1
0 31.829239 -4.441243 2.879607 0.120779 0.595643 -1
0 28.467997 -12.456865 2.879607 0.114570 0.768261 -1
0 22.295166 -18.576036 2.879607 0.103167 0.900038 -1
0 14.250505 -21.867176 2.879607 0.088308 0.970913 -1
0 -14.441256 -21.829237 2.879607 0.035309 0.970096 -1
0 -22.456873 -18.467987 2.879607 0.020503 0.897711 -1
0 -28.576046 -12.295153 2.879607 0.009200 0.764778 -1
0 -31.867182 -4.250491 2.879607 0.003120 0.591535 -1
0 -31.829235 4.441269 2.879607 0.003190 0.404357 -1
0 -28.467979 12.456886 2.879607 0.009399 0.231739 -1
0 -22.295141 18.576052 2.879607 0.020802 0.099962 -1
0 -14.250477 21.867180 2.879607 0.035661 0.029087 -1
0 14.441284 21.829229 2.879607 0.088660 0.029904 -1
1
0.000000 0.000000 1.000000
16
0 0 1 2 0 0 0 1
0 2 3 0 0 0 0 1
0 2 4 3 0 0 0 1
0 2 5 4 0 0 0 1
0 2 6 5 0 0 0 1
0 2 7 6 0 0 0 1
0 2 8 7 0 0 0 1
0 2 9 8 0 0 0 1
0 2 10 9 0 0 0 1
0 2 11 10 0 0 0 1
0 2 12 11 0 0 0 1
0 2 13 12 0 0 0 1
0 2 14 13 0 0 0 1
0 2 15 14 0 0 0 1
0 2 16 15 0 0 0 1
0 2 1 16 0 0 0 1
"frame" 1 1
65
1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1
1 27.639259 11.675143 3.321190 0.856463 0.427477 -1
1 21.828669 17.536682 3.321190 0.801575 0.296586 -1
1 30.764435 4.036170 3.321190 0.857082 0.569410 -1
1 30.728415 -4.217276 3.321190 0.803338 0.700776 -1
1 27.536673 -11.828679 3.321190 0.703414 0.801575 -1
1 21.675133 -17.639269 3.321190 0.572522 0.856463 -1
1 14.036156 -20.764439 3.321190 0.430590 0.857082 -1
1 -14.217289 -20.728411 3.321190 0.299224 0.803338 -1
1 -21.828686 -17.536667 3.321190 0.198425 0.703414 -1
1 -27.639275 -11.675121 3.321190 0.143537 0.572522 -1
1 -30.764442 -4.036143 3.321190 0.142919 0.430589 -1
1 -30.728407 4.217301 3.321190 0.196662 0.299224 -1
1 -27.536659 11.828699 3.321190 0.296586 0.198425 -1
1 -21.675112 17.639282 3.321190 0.427478 0.143538 -1
1 -14.036130 20.764444 3.321190 0.569411 0.142919 -1
1 14.217316 20.728405 3.321190 0.700777 0.196662 -1
1 23.683174 20.286118 3.156490 0.848857 0.264694 -1
1 30.404764 13.505603 3.156490 0.912349 0.416107 -1
1 34.019917 4.668982 3.156490 0.913065 0.580292 -1
1 33.978256 -4.878449 3.156490 0.850896 0.732254 -1
1 30.286112 -13.683181 3.156490 0.735306 0.848857 -1
1 23.505600 -20.404768 3.156490 0.583893 0.912349 -1
1 14.668977 -24.019918 3.156490 0.419708 0.913065 -1
1 -14.878452 -23.978252 3.156490 0.267746 0.850896 -1
1 -23.683182 -20.286110 3.156490 0.151143 0.735306 -1
1 -30.404770 -13.505592 3.156490 0.087651 0.583893 -1
1 -34.019920 -4.668968 3.156490 0.086935 0.419708 -1
1 -33.978249 4.878465 3.156490 0.149104 0.267746 -1
1 -30.286102 13.683196 3.156490 0.264694 0.151143 -1
1 -23.505577 20.404779 3.156490 0.416107 0.087651 -1
1 -14.668951 24.019922 3.156490 0.580293 0.086935 -1
1 14.878481 23.978243 3.156490 0.732254 0.149104 -1
1 26.305698 24.174189 -0.301926 0.917477 0.218408 -1
1 25.196014 22.529018 1.012907 0.887427 0.238677 -1
1 32.660770 14.998834 1.012907 0.957940 0.406831 -1
1 34.315567 16.094122 -0.301926 0.993459 0.399605 -1
1 36.675629 5.185213 1.012907 0.958735 0.589169 -1
1 38.623604 5.563864 -0.301926 0.994316 0.596085 -1
1 36.629364 -5.417810 1.012907 0.889693 0.757932 -1
1 38.573959 -5.813441 -0.301926 0.919919 0.777938 -1
1 32.529015 -15.196017 1.012907 0.761323 0.887427 -1
1 34.174187 -16.305698 -0.301926 0.781592 0.917477 -1
1 24.998833 -22.660772 1.012907 0.593169 0.957940 -1
1 26.094122 -24.315565 -0.301926 0.600395 0.993459 -1
1 15.185220 -26.675629 1.012907 0.410831 0.958735 -1
1 15.563870 -28.623604 -0.301926 0.403915 0.994316 -1
1 -15.417803 -26.629364 1.012907 0.242068 0.889693 -1
1 -15.813432 -28.573965 -0.301926 0.222062 0.919919 -1
1 -25.196011 -22.529020 1.012907 0.112573 0.761323 -1
1 -26.305689 -24.174196 -0.301926 0.082523 0.781592 -1
1 -32.660770 -14.998836 1.012907 0.042060 0.593169 -1
1 -34.315559 -16.094126 -0.301926 0.006541 0.600395 -1
1 -36.675629 -5.185212 1.012907 0.041265 0.410831 -1
1 -38.623604 -5.563865 -0.301926 0.005684 0.403915 -1
1 -36.629356 5.417814 1.012907 0.110308 0.242068 -1
1 -38.573959 5.813443 -0.301926 0.080082 0.222062 -1
1 -32.529011 15.196029 1.012907 0.238677 0.112573 -1
1 -34.174187 16.305708 -0.301926 0.218408 0.082523 -1
1 -24.998821 22.660780 1.012907 0.406831 0.042060 -1
1 -26.094109 24.315575 -0.301926 0.399605 0.006541 -1
1 -15.185204 26.675629 1.012907 0.589169 0.041265 -1
1 -15.563847 28.623608 -0.301926 0.596086 0.005684 -1
1 15.417831 26.629356 1.012907 0.757932 0.110308 -1
1 15.813461 28.573956 -0.301926 0.777938 0.080082 -1
65
0.000000 0.000000 1.000000
0.023734 0.018076 0.999555
0.015010 0.025783 0.999555
0.028845 0.007618 0.999555
0.029564 -0.004001 0.999555
0.025783 -0.015010 0.999555
0.018076 -0.023734 0.999555
0.007649 -0.028839 0.999555
-0.003940 -0.029565 0.999555
-0.015010 -0.025783 0.999555
-0.023734 -0.018076 0.999555
-0.028845 -0.007618 0.999555
-0.029565 0.004001 0.999555
-0.025783 0.015010 0.999555
-0.018076 0.023734 0.999555
-0.007649 0.028839 0.999555
0.003940 0.029565 0.999555
0.179817 0.302000 0.936196
0.281699 0.210198 0.936196
0.340695 0.086397 0.936196
0.347824 -0.050559 0.936196
0.302000 -0.179817 0.936196
0.210198 -0.281699 0.936196
0.086772 -0.340640 0.936181
-0.049893 -0.347841 0.936225
-0.179817 -0.301999 0.936196
-0.281699 -0.210198 0.936196
-0.340695 -0.086396 0.936196
-0.347824 0.050559 0.936196
-0.302000 0.179817 0.936196
-0.210198 0.281699 0.936196
-0.086772 0.340641 0.936181
0.049893 0.347841 0.936225
0.338996 0.437135 0.833064
0.330211 0.485536 0.809454
0.490881 0.322210 0.809454
0.480475 0.274131 0.833064
0.576820 0.109832 0.809454
0.548807 0.069395 0.833063
0.574943 -0.119268 0.809454
0.533588 -0.145907 0.833063
0.485536 -0.330211 0.809454
0.437135 -0.338996 0.833064
0.322211 -0.490881 0.809454
0.274132 -0.480475 0.833064
0.110702 -0.576729 0.809400
0.070446 -0.548768 0.833001
-0.118450 -0.575039 0.809506
-0.145397 -0.533702 0.833080
-0.330210 -0.485536 0.809454
-0.338996 -0.437135 0.833064
-0.490881 -0.322211 0.809454
-0.480475 -0.274132 0.833064
-0.576820 -0.109831 0.809454
-0.548807 -0.069395 0.833064
-0.574943 0.119268 0.809454
-0.533587 0.145907 0.833064
-0.485535 0.330210 0.809454
-0.437134 0.338996 0.833064
-0.322210 0.490881 0.809454
-0.274131 0.480475 0.833064
-0.110701 0.576729 0.809400
-0.070446 0.548768 0.833001
0.118450 0.575039 0.809506
0.145397 0.533702 0.833080
112
1 0 1 2 0 1 2 2
1 0 3 1 0 3 1 2
1 0 4 3 0 4 3 2
1 0 5 4 0 5 4 2
1 0 6 5 0 6 5 2
1 0 7 6 0 7 6 2
1 0 8 7 0 8 7 2
1 0 9 8 0 9 8 2
1 0 10 9 0 10 9 2
1 0 11 10 0 11 10 2
1 0 12 11 0 12 11 2
1 0 13 12 0 13 12 2
1 0 14 13 0 14 13 2
1 0 15 14 0 15 14 2
1 0 16 15 0 16 15 2
1 0 2 16 0 2 16 2
1 17 2 1 17 2 1 2
1 17 1 18 17 1 18 2
1 18 1 3 18 1 3 2
1 18 3 19 18 3 19 2
1 19 3 4 19 3 4 2
1 19 4 20 19 4 20 2
1 20 4 5 20 4 5 2
1 20 5 21 20 5 21 2
1 21 5 6 21 5 6 2
1 21 6 22 21 6 22 2
1 22 6 7 22 6 7 2
1 22 7 23 22 7 23 2
1 23 7 8 23 7 8 2
1 23 8 24 23 8 24 2
1 24 8 9 24 8 9 2
1 24 9 25 24 9 25 2
1 25 9 10 25 9 10 2
1 25 10 26 25 10 26 2
1 26 10 11 26 10 11 2
1 26 11 27 26 11 27 2
1 27 11 12 27 11 12 2
1 27 12 28 27 12 28 2
1 28 12 13 28 12 13 2
1 28 13 29 28 13 29 2
1 29 13 14 29 13 14 2
1 29 14 30 29 14 30 2
1 30 14 15 30 14 15 2
1 30 15 31 30 15 31 2
1 31 15 16 31 15 16 2
1 31 16 32 31 16 32 2
1 2 17 32 2 17 32 2
1 2 32 16 2 32 16 2
1 33 34 35 33 34 35 2
1 33 35 36 33 35 36 2
1 34 17 18 34 17 18 2
1 34 18 35 34 18 35 2
1 36 35 37 36 35 37 2
1 36 37 38 36 37 38 2
1 35 18 19 35 18 19 2
1 35 19 37 35 19 37 2
1 38 37 39 38 37 39 2
1 38 39 40 38 39 40 2
1 37 19 20 37 19 20 2
1 37 20 39 37 20 39 2
1 40 39 41 40 39 41 2
1 40 41 42 40 41 42 2
1 39 20 21 39 20 21 2
1 39 21 41 39 21 41 2
1 42 41 43 42 41 43 2
1 42 43 44 42 43 44 2
1 41 21 22 41 21 22 2
1 41 22 43 41 22 43 2
1 44 43 45 44 43 45 2
1 44 45 46 44 45 46 2
1 43 22 23 43 22 23 2
1 43 23 45 43 23 45 2
1 46 45 47 46 45 47 2
1 46 47 48 46 47 48 2
1 45 23 24 45 23 24 2
1 45 24 47 45 24 47 2
1 48 47 49 48 47 49 2
1 48 49 50 48 49 50 2
1 47 24 25 47 24 25 2
1 47 25 49 47 25 49 2
1 50 49 51 50 49 51 2
1 50 51 52 50 51 52 2
1 49 25 26 49 25 26 2
1 49 26 51 49 26 51 2
1 52 51 53 52 51 53 2
1 52 53 54 52 53 54 2
1 51 26 27 51 26 27 2
1 51 27 53 51 27 53 2
1 54 53 55 54 53 55 2
1 54 55 56 54 55 56 2
1 53 27 28 53 27 28 2
1 53 28 55 53 28 55 2
1 56 55 57 56 55 57 2
1 56 57 58 56 57 58 2
1 55 28 29 55 28 29 2
1 55 29 57 55 29 57 2
1 58 57 59 58 57 59 2
1 58 59 60 58 59 60 2
1 57 29 30 57 29 30 2
1 57 30 59 57 30 59 2
1 60 59 61 60 59 61 2
1 60 61 62 60 61 62 2
1 59 30 31 59 30 31 2
1 59 31 61 59 31 61 2
1 62 61 63 62 61 63 2
1 62 63 64 62 63 64 2
1 61 31 32 61 31 32 2
1 61 32 63 61 32 63 2
1 17 34 63 17 34 63 2
1 17 63 32 17 63 32 2
1 34 33 64 34 33 64 2
1 34 64 63 34 64 63 2
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
Bones: 0
GroupComments: 0
MaterialComments: 0
BoneComments: 0
ModelComment: 0
// MilkShape 3D ASCII
Frames: 30
Frame: 1
Meshes: 2
"scroll" 0 0
17
0 28.576029 12.295176 2.879607 0.114769 0.235221 -1
0 22.456854 18.468002 2.879607 0.103466 0.102288 -1
0 0.000001 -0.000001 2.879607 0.061984 0.500000 -1
0 31.867174 4.250518 2.879607 0.120849 0.408464 -1
0 31.829239 -4.441243 2.879607 0.120779 0.595643 -1
0 28.467997 -12.456865 2.879607 0.114570 0.768261 -1
0 22.295166 -18.576036 2.879607 0.103167 0.900038 -1
0 14.250505 -21.867176 2.879607 0.088308 0.970913 -1
0 -14.441256 -21.829237 2.879607 0.035309 0.970096 -1
0 -22.456873 -18.467987 2.879607 0.020503 0.897711 -1
0 -28.576046 -12.295153 2.879607 0.009200 0.764778 -1
0 -31.867182 -4.250491 2.879607 0.003120 0.591535 -1
0 -31.829235 4.441269 2.879607 0.003190 0.404357 -1
0 -28.467979 12.456886 2.879607 0.009399 0.231739 -1
0 -22.295141 18.576052 2.879607 0.020802 0.099962 -1
0 -14.250477 21.867180 2.879607 0.035661 0.029087 -1
0 14.441284 21.829229 2.879607 0.088660 0.029904 -1
1
0.000000 0.000000 1.000000
16
0 0 1 2 0 0 0 1
0 2 3 0 0 0 0 1
0 2 4 3 0 0 0 1
0 2 5 4 0 0 0 1
0 2 6 5 0 0 0 1
0 2 7 6 0 0 0 1
0 2 8 7 0 0 0 1
0 2 9 8 0 0 0 1
0 2 10 9 0 0 0 1
0 2 11 10 0 0 0 1
0 2 12 11 0 0 0 1
0 2 13 12 0 0 0 1
0 2 14 13 0 0 0 1
0 2 15 14 0 0 0 1
0 2 16 15 0 0 0 1
0 2 1 16 0 0 0 1
"frame" 1 1
65
1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1
1 27.639259 11.675143 3.321190 0.856463 0.427477 -1
1 21.828669 17.536682 3.321190 0.801575 0.296586 -1
1 30.764435 4.036170 3.321190 0.857082 0.569410 -1
1 30.728415 -4.217276 3.321190 0.803338 0.700776 -1
1 27.536673 -11.828679 3.321190 0.703414 0.801575 -1
1 21.675133 -17.639269 3.321190 0.572522 0.856463 -1
1 14.036156 -20.764439 3.321190 0.430590 0.857082 -1
1 -14.217289 -20.728411 3.321190 0.299224 0.803338 -1
1 -21.828686 -17.536667 3.321190 0.198425 0.703414 -1
1 -27.639275 -11.675121 3.321190 0.143537 0.572522 -1
1 -30.764442 -4.036143 3.321190 0.142919 0.430589 -1
1 -30.728407 4.217301 3.321190 0.196662 0.299224 -1
1 -27.536659 11.828699 3.321190 0.296586 0.198425 -1
1 -21.675112 17.639282 3.321190 0.427478 0.143538 -1
1 -14.036130 20.764444 3.321190 0.569411 0.142919 -1
1 14.217316 20.728405 3.321190 0.700777 0.196662 -1
1 23.683174 20.286118 3.156490 0.848857 0.264694 -1
1 30.404764 13.505603 3.156490 0.912349 0.416107 -1
1 34.019917 4.668982 3.156490 0.913065 0.580292 -1
1 33.978256 -4.878449 3.156490 0.850896 0.732254 -1
1 30.286112 -13.683181 3.156490 0.735306 0.848857 -1
1 23.505600 -20.404768 3.156490 0.583893 0.912349 -1
1 14.668977 -24.019918 3.156490 0.419708 0.913065 -1
1 -14.878452 -23.978252 3.156490 0.267746 0.850896 -1
1 -23.683182 -20.286110 3.156490 0.151143 0.735306 -1
1 -30.404770 -13.505592 3.156490 0.087651 0.583893 -1
1 -34.019920 -4.668968 3.156490 0.086935 0.419708 -1
1 -33.978249 4.878465 3.156490 0.149104 0.267746 -1
1 -30.286102 13.683196 3.156490 0.264694 0.151143 -1
1 -23.505577 20.404779 3.156490 0.416107 0.087651 -1
1 -14.668951 24.019922 3.156490 0.580293 0.086935 -1
1 14.878481 23.978243 3.156490 0.732254 0.149104 -1
1 26.305698 24.174189 -0.301926 0.917477 0.218408 -1
1 25.196014 22.529018 1.012907 0.887427 0.238677 -1
1 32.660770 14.998834 1.012907 0.957940 0.406831 -1
1 34.315567 16.094122 -0.301926 0.993459 0.399605 -1
1 36.675629 5.185213 1.012907 0.958735 0.589169 -1
1 38.623604 5.563864 -0.301926 0.994316 0.596085 -1
1 36.629364 -5.417810 1.012907 0.889693 0.757932 -1
1 38.573959 -5.813441 -0.301926 0.919919 0.777938 -1
1 32.529015 -15.196017 1.012907 0.761323 0.887427 -1
1 34.174187 -16.305698 -0.301926 0.781592 0.917477 -1
1 24.998833 -22.660772 1.012907 0.593169 0.957940 -1
1 26.094122 -24.315565 -0.301926 0.600395 0.993459 -1
1 15.185220 -26.675629 1.012907 0.410831 0.958735 -1
1 15.563870 -28.623604 -0.301926 0.403915 0.994316 -1
1 -15.417803 -26.629364 1.012907 0.242068 0.889693 -1
1 -15.813432 -28.573965 -0.301926 0.222062 0.919919 -1
1 -25.196011 -22.529020 1.012907 0.112573 0.761323 -1
1 -26.305689 -24.174196 -0.301926 0.082523 0.781592 -1
1 -32.660770 -14.998836 1.012907 0.042060 0.593169 -1
1 -34.315559 -16.094126 -0.301926 0.006541 0.600395 -1
1 -36.675629 -5.185212 1.012907 0.041265 0.410831 -1
1 -38.623604 -5.563865 -0.301926 0.005684 0.403915 -1
1 -36.629356 5.417814 1.012907 0.110308 0.242068 -1
1 -38.573959 5.813443 -0.301926 0.080082 0.222062 -1
1 -32.529011 15.196029 1.012907 0.238677 0.112573 -1
1 -34.174187 16.305708 -0.301926 0.218408 0.082523 -1
1 -24.998821 22.660780 1.012907 0.406831 0.042060 -1
1 -26.094109 24.315575 -0.301926 0.399605 0.006541 -1
1 -15.185204 26.675629 1.012907 0.589169 0.041265 -1
1 -15.563847 28.623608 -0.301926 0.596086 0.005684 -1
1 15.417831 26.629356 1.012907 0.757932 0.110308 -1
1 15.813461 28.573956 -0.301926 0.777938 0.080082 -1
65
0.000000 0.000000 1.000000
0.023734 0.018076 0.999555
0.015010 0.025783 0.999555
0.028845 0.007618 0.999555
0.029564 -0.004001 0.999555
0.025783 -0.015010 0.999555
0.018076 -0.023734 0.999555
0.007649 -0.028839 0.999555
-0.003940 -0.029565 0.999555
-0.015010 -0.025783 0.999555
-0.023734 -0.018076 0.999555
-0.028845 -0.007618 0.999555
-0.029565 0.004001 0.999555
-0.025783 0.015010 0.999555
-0.018076 0.023734 0.999555
-0.007649 0.028839 0.999555
0.003940 0.029565 0.999555
0.179817 0.302000 0.936196
0.281699 0.210198 0.936196
0.340695 0.086397 0.936196
0.347824 -0.050559 0.936196
0.302000 -0.179817 0.936196
0.210198 -0.281699 0.936196
0.086772 -0.340640 0.936181
-0.049893 -0.347841 0.936225
-0.179817 -0.301999 0.936196
-0.281699 -0.210198 0.936196
-0.340695 -0.086396 0.936196
-0.347824 0.050559 0.936196
-0.302000 0.179817 0.936196
-0.210198 0.281699 0.936196
-0.086772 0.340641 0.936181
0.049893 0.347841 0.936225
0.338996 0.437135 0.833064
0.330211 0.485536 0.809454
0.490881 0.322210 0.809454
0.480475 0.274131 0.833064
0.576820 0.109832 0.809454
0.548807 0.069395 0.833063
0.574943 -0.119268 0.809454
0.533588 -0.145907 0.833063
0.485536 -0.330211 0.809454
0.437135 -0.338996 0.833064
0.322211 -0.490881 0.809454
0.274132 -0.480475 0.833064
0.110702 -0.576729 0.809400
0.070446 -0.548768 0.833001
-0.118450 -0.575039 0.809506
-0.145397 -0.533702 0.833080
-0.330210 -0.485536 0.809454
-0.338996 -0.437135 0.833064
-0.490881 -0.322211 0.809454
-0.480475 -0.274132 0.833064
-0.576820 -0.109831 0.809454
-0.548807 -0.069395 0.833064
-0.574943 0.119268 0.809454
-0.533587 0.145907 0.833064
-0.485535 0.330210 0.809454
-0.437134 0.338996 0.833064
-0.322210 0.490881 0.809454
-0.274131 0.480475 0.833064
-0.110701 0.576729 0.809400
-0.070446 0.548768 0.833001
0.118450 0.575039 0.809506
0.145397 0.533702 0.833080
112
1 0 1 2 0 1 2 2
1 0 3 1 0 3 1 2
1 0 4 3 0 4 3 2
1 0 5 4 0 5 4 2
1 0 6 5 0 6 5 2
1 0 7 6 0 7 6 2
1 0 8 7 0 8 7 2
1 0 9 8 0 9 8 2
1 0 10 9 0 10 9 2
1 0 11 10 0 11 10 2
1 0 12 11 0 12 11 2
1 0 13 12 0 13 12 2
1 0 14 13 0 14 13 2
1 0 15 14 0 15 14 2
1 0 16 15 0 16 15 2
1 0 2 16 0 2 16 2
1 17 2 1 17 2 1 2
1 17 1 18 17 1 18 2
1 18 1 3 18 1 3 2
1 18 3 19 18 3 19 2
1 19 3 4 19 3 4 2
1 19 4 20 19 4 20 2
1 20 4 5 20 4 5 2
1 20 5 21 20 5 21 2
1 21 5 6 21 5 6 2
1 21 6 22 21 6 22 2
1 22 6 7 22 6 7 2
1 22 7 23 22 7 23 2
1 23 7 8 23 7 8 2
1 23 8 24 23 8 24 2
1 24 8 9 24 8 9 2
1 24 9 25 24 9 25 2
1 25 9 10 25 9 10 2
1 25 10 26 25 10 26 2
1 26 10 11 26 10 11 2
1 26 11 27 26 11 27 2
1 27 11 12 27 11 12 2
1 27 12 28 27 12 28 2
1 28 12 13 28 12 13 2
1 28 13 29 28 13 29 2
1 29 13 14 29 13 14 2
1 29 14 30 29 14 30 2
1 30 14 15 30 14 15 2
1 30 15 31 30 15 31 2
1 31 15 16 31 15 16 2
1 31 16 32 31 16 32 2
1 2 17 32 2 17 32 2
1 2 32 16 2 32 16 2
1 33 34 35 33 34 35 2
1 33 35 36 33 35 36 2
1 34 17 18 34 17 18 2
1 34 18 35 34 18 35 2
1 36 35 37 36 35 37 2
1 36 37 38 36 37 38 2
1 35 18 19 35 18 19 2
1 35 19 37 35 19 37 2
1 38 37 39 38 37 39 2
1 38 39 40 38 39 40 2
1 37 19 20 37 19 20 2
1 37 20 39 37 20 39 2
1 40 39 41 40 39 41 2
1 40 41 42 40 41 42 2
1 39 20 21 39 20 21 2
1 39 21 41 39 21 41 2
1 42 41 43 42 41 43 2
1 42 43 44 42 43 44 2
1 41 21 22 41 21 22 2
1 41 22 43 41 22 43 2
1 44 43 45 44 43 45 2
1 44 45 46 44 45 46 2
1 43 22 23 43 22 23 2
1 43 23 45 43 23 45 2
1 46 45 47 46 45 47 2
1 46 47 48 46 47 48 2
1 45 23 24 45 23 24 2
1 45 24 47 45 24 47 2
1 48 47 49 48 47 49 2
1 48 49 50 48 49 50 2
1 47 24 25 47 24 25 2
1 47 25 49 47 25 49 2
1 50 49 51 50 49 51 2
1 50 51 52 50 51 52 2
1 49 25 26 49 25 26 2
1 49 26 51 49 26 51 2
1 52 51 53 52 51 53 2
1 52 53 54 52 53 54 2
1 51 26 27 51 26 27 2
1 51 27 53 51 27 53 2
1 54 53 55 54 53 55 2
1 54 55 56 54 55 56 2
1 53 27 28 53 27 28 2
1 53 28 55 53 28 55 2
1 56 55 57 56 55 57 2
1 56 57 58 56 57 58 2
1 55 28 29 55 28 29 2
1 55 29 57 55 29 57 2
1 58 57 59 58 57 59 2
1 58 59 60 58 59 60 2
1 57 29 30 57 29 30 2
1 57 30 59 57 30 59 2
1 60 59 61 60 59 61 2
1 60 61 62 60 61 62 2
1 59 30 31 59 30 31 2
1 59 31 61 59 31 61 2
1 62 61 63 62 61 63 2
1 62 63 64 62 63 64 2
1 61 31 32 61 31 32 2
1 61 32 63 61 32 63 2
1 17 34 63 17 34 63 2
1 17 63 32 17 63 32 2
1 34 33 64 34 33 64 2
1 34 64 63 34 64 63 2
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
Bones: 0
GroupComments: 0
MaterialComments: 0
BoneComments: 0
ModelComment: 0
+316 -316
View File
@@ -1,316 +1,316 @@
// MilkShape 3D ASCII
Frames: 30
Frame: 1
Meshes: 2
"scroll" 0 0
17
0 18.576029 12.295176 2.879607 0.112493 0.233639 -1
0 12.456854 18.468002 2.879607 0.095922 0.099912 -1
0 0.000001 -0.000001 2.879607 0.062189 0.500000 -1
0 21.867174 4.250518 2.879607 0.121405 0.407917 -1
0 21.829239 -4.441243 2.879607 0.121302 0.596214 -1
0 18.467995 -12.456865 2.879607 0.112200 0.769864 -1
0 12.295166 -18.576036 2.879607 0.095484 0.902428 -1
0 4.250505 -21.867176 2.879607 0.073699 0.973727 -1
0 -4.441256 -21.829237 2.879607 0.050162 0.972905 -1
0 -12.456874 -18.467987 2.879607 0.028456 0.900088 -1
0 -18.576044 -12.295153 2.879607 0.011886 0.766360 -1
0 -21.867182 -4.250491 2.879607 0.002973 0.592082 -1
0 -21.829233 4.441269 2.879607 0.003076 0.403785 -1
0 -18.467979 12.456886 2.879607 0.012178 0.230136 -1
0 -12.295140 18.576052 2.879607 0.028894 0.097571 -1
0 -4.250477 21.867180 2.879607 0.050679 0.026273 -1
0 4.441284 21.829229 2.879607 0.074216 0.027095 -1
1
0.000000 0.000000 1.000000
16
0 0 1 2 0 0 0 1
0 2 3 0 0 0 0 1
0 2 4 3 0 0 0 1
0 2 5 4 0 0 0 1
0 2 6 5 0 0 0 1
0 2 7 6 0 0 0 1
0 2 8 7 0 0 0 1
0 2 9 8 0 0 0 1
0 2 10 9 0 0 0 1
0 2 11 10 0 0 0 1
0 2 12 11 0 0 0 1
0 2 13 12 0 0 0 1
0 2 14 13 0 0 0 1
0 2 15 14 0 0 0 1
0 2 16 15 0 0 0 1
0 2 1 16 0 0 0 1
"frame" 1 1
65
1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1
1 17.639259 11.675143 3.321190 0.856463 0.427477 -1
1 11.828669 17.536682 3.321190 0.801575 0.296586 -1
1 20.764435 4.036170 3.321190 0.857082 0.569410 -1
1 20.728415 -4.217276 3.321190 0.803338 0.700776 -1
1 17.536673 -11.828679 3.321190 0.703414 0.801575 -1
1 11.675133 -17.639269 3.321190 0.572522 0.856463 -1
1 4.036156 -20.764439 3.321190 0.430590 0.857082 -1
1 -4.217289 -20.728411 3.321190 0.299224 0.803338 -1
1 -11.828687 -17.536667 3.321190 0.198425 0.703414 -1
1 -17.639275 -11.675121 3.321190 0.143537 0.572522 -1
1 -20.764442 -4.036143 3.321190 0.142919 0.430589 -1
1 -20.728407 4.217301 3.321190 0.196662 0.299224 -1
1 -17.536659 11.828699 3.321190 0.296586 0.198425 -1
1 -11.675112 17.639282 3.321190 0.427478 0.143538 -1
1 -4.036130 20.764444 3.321190 0.569411 0.142919 -1
1 4.217315 20.728405 3.321190 0.700777 0.196662 -1
1 13.683175 20.286118 3.156490 0.848857 0.264694 -1
1 20.404764 13.505603 3.156490 0.912349 0.416107 -1
1 24.019917 4.668982 3.156490 0.913065 0.580292 -1
1 23.978254 -4.878449 3.156490 0.850896 0.732254 -1
1 20.286112 -13.683181 3.156490 0.735306 0.848857 -1
1 13.505599 -20.404768 3.156490 0.583893 0.912349 -1
1 4.668977 -24.019918 3.156490 0.419708 0.913065 -1
1 -4.878453 -23.978252 3.156490 0.267746 0.850896 -1
1 -13.683182 -20.286110 3.156490 0.151143 0.735306 -1
1 -20.404770 -13.505592 3.156490 0.087651 0.583893 -1
1 -24.019920 -4.668968 3.156490 0.086935 0.419708 -1
1 -23.978251 4.878465 3.156490 0.149104 0.267746 -1
1 -20.286102 13.683196 3.156490 0.264694 0.151143 -1
1 -13.505578 20.404779 3.156490 0.416107 0.087651 -1
1 -4.668952 24.019922 3.156490 0.580293 0.086935 -1
1 4.878480 23.978243 3.156490 0.732254 0.149104 -1
1 16.305698 24.174189 -0.301926 0.917477 0.218408 -1
1 15.196015 22.529018 1.012907 0.887427 0.238677 -1
1 22.660770 14.998834 1.012907 0.957940 0.406831 -1
1 24.315565 16.094122 -0.301926 0.993459 0.399605 -1
1 26.675631 5.185213 1.012907 0.958735 0.589169 -1
1 28.623606 5.563864 -0.301926 0.994316 0.596085 -1
1 26.629364 -5.417810 1.012907 0.889693 0.757932 -1
1 28.573961 -5.813441 -0.301926 0.919919 0.777938 -1
1 22.529016 -15.196017 1.012907 0.761323 0.887427 -1
1 24.174189 -16.305698 -0.301926 0.781592 0.917477 -1
1 14.998834 -22.660772 1.012907 0.593169 0.957940 -1
1 16.094122 -24.315565 -0.301926 0.600395 0.993459 -1
1 5.185220 -26.675629 1.012907 0.410831 0.958735 -1
1 5.563870 -28.623604 -0.301926 0.403915 0.994316 -1
1 -5.417803 -26.629364 1.012907 0.242068 0.889693 -1
1 -5.813432 -28.573965 -0.301926 0.222062 0.919919 -1
1 -15.196011 -22.529020 1.012907 0.112573 0.761323 -1
1 -16.305689 -24.174196 -0.301926 0.082523 0.781592 -1
1 -22.660770 -14.998836 1.012907 0.042060 0.593169 -1
1 -24.315561 -16.094126 -0.301926 0.006541 0.600395 -1
1 -26.675631 -5.185212 1.012907 0.041265 0.410831 -1
1 -28.623606 -5.563865 -0.301926 0.005684 0.403915 -1
1 -26.629358 5.417814 1.012907 0.110308 0.242068 -1
1 -28.573961 5.813443 -0.301926 0.080082 0.222062 -1
1 -22.529011 15.196029 1.012907 0.238677 0.112573 -1
1 -24.174185 16.305708 -0.301926 0.218408 0.082523 -1
1 -14.998822 22.660780 1.012907 0.406831 0.042060 -1
1 -16.094109 24.315575 -0.301926 0.399605 0.006541 -1
1 -5.185204 26.675629 1.012907 0.589169 0.041265 -1
1 -5.563847 28.623608 -0.301926 0.596086 0.005684 -1
1 5.417831 26.629356 1.012907 0.757932 0.110308 -1
1 5.813461 28.573956 -0.301926 0.777938 0.080082 -1
65
0.000000 0.000000 1.000000
0.023734 0.018076 0.999555
0.015010 0.025783 0.999555
0.028845 0.007618 0.999555
0.029564 -0.004001 0.999555
0.025783 -0.015010 0.999555
0.018076 -0.023734 0.999555
0.007618 -0.028845 0.999555
-0.004001 -0.029564 0.999555
-0.015010 -0.025783 0.999555
-0.023734 -0.018076 0.999555
-0.028845 -0.007618 0.999555
-0.029564 0.004001 0.999555
-0.025783 0.015010 0.999555
-0.018076 0.023734 0.999555
-0.007618 0.028845 0.999555
0.004001 0.029565 0.999555
0.179817 0.302000 0.936196
0.281699 0.210198 0.936196
0.340695 0.086397 0.936196
0.347824 -0.050559 0.936196
0.301999 -0.179816 0.936196
0.210198 -0.281699 0.936196
0.086396 -0.340695 0.936196
-0.050559 -0.347824 0.936196
-0.179817 -0.301999 0.936196
-0.281699 -0.210198 0.936196
-0.340695 -0.086396 0.936196
-0.347824 0.050559 0.936196
-0.301999 0.179817 0.936196
-0.210198 0.281699 0.936196
-0.086396 0.340695 0.936196
0.050559 0.347824 0.936196
0.338996 0.437135 0.833064
0.330211 0.485536 0.809454
0.490881 0.322211 0.809454
0.480475 0.274132 0.833064
0.576820 0.109832 0.809454
0.548807 0.069395 0.833064
0.574943 -0.119268 0.809454
0.533588 -0.145907 0.833064
0.485536 -0.330211 0.809454
0.437135 -0.338996 0.833064
0.322211 -0.490881 0.809454
0.274132 -0.480475 0.833064
0.109832 -0.576820 0.809454
0.069395 -0.548807 0.833064
-0.119268 -0.574943 0.809454
-0.145907 -0.533588 0.833064
-0.330210 -0.485536 0.809454
-0.338996 -0.437135 0.833064
-0.490881 -0.322211 0.809454
-0.480475 -0.274132 0.833064
-0.576820 -0.109831 0.809454
-0.548807 -0.069395 0.833064
-0.574943 0.119268 0.809454
-0.533587 0.145907 0.833064
-0.485536 0.330211 0.809454
-0.437135 0.338996 0.833064
-0.322210 0.490881 0.809454
-0.274131 0.480475 0.833064
-0.109831 0.576820 0.809454
-0.069394 0.548807 0.833064
0.119268 0.574943 0.809454
0.145907 0.533588 0.833064
112
1 0 1 2 0 1 2 2
1 0 3 1 0 3 1 2
1 0 4 3 0 4 3 2
1 0 5 4 0 5 4 2
1 0 6 5 0 6 5 2
1 0 7 6 0 7 6 2
1 0 8 7 0 8 7 2
1 0 9 8 0 9 8 2
1 0 10 9 0 10 9 2
1 0 11 10 0 11 10 2
1 0 12 11 0 12 11 2
1 0 13 12 0 13 12 2
1 0 14 13 0 14 13 2
1 0 15 14 0 15 14 2
1 0 16 15 0 16 15 2
1 0 2 16 0 2 16 2
1 17 2 1 17 2 1 2
1 17 1 18 17 1 18 2
1 18 1 3 18 1 3 2
1 18 3 19 18 3 19 2
1 19 3 4 19 3 4 2
1 19 4 20 19 4 20 2
1 20 4 5 20 4 5 2
1 20 5 21 20 5 21 2
1 21 5 6 21 5 6 2
1 21 6 22 21 6 22 2
1 22 6 7 22 6 7 2
1 22 7 23 22 7 23 2
1 23 7 8 23 7 8 2
1 23 8 24 23 8 24 2
1 24 8 9 24 8 9 2
1 24 9 25 24 9 25 2
1 25 9 10 25 9 10 2
1 25 10 26 25 10 26 2
1 26 10 11 26 10 11 2
1 26 11 27 26 11 27 2
1 27 11 12 27 11 12 2
1 27 12 28 27 12 28 2
1 28 12 13 28 12 13 2
1 28 13 29 28 13 29 2
1 29 13 14 29 13 14 2
1 29 14 30 29 14 30 2
1 30 14 15 30 14 15 2
1 30 15 31 30 15 31 2
1 31 15 16 31 15 16 2
1 31 16 32 31 16 32 2
1 2 17 32 2 17 32 2
1 2 32 16 2 32 16 2
1 33 34 35 33 34 35 2
1 33 35 36 33 35 36 2
1 34 17 18 34 17 18 2
1 34 18 35 34 18 35 2
1 36 35 37 36 35 37 2
1 36 37 38 36 37 38 2
1 35 18 19 35 18 19 2
1 35 19 37 35 19 37 2
1 38 37 39 38 37 39 2
1 38 39 40 38 39 40 2
1 37 19 20 37 19 20 2
1 37 20 39 37 20 39 2
1 40 39 41 40 39 41 2
1 40 41 42 40 41 42 2
1 39 20 21 39 20 21 2
1 39 21 41 39 21 41 2
1 42 41 43 42 41 43 2
1 42 43 44 42 43 44 2
1 41 21 22 41 21 22 2
1 41 22 43 41 22 43 2
1 44 43 45 44 43 45 2
1 44 45 46 44 45 46 2
1 43 22 23 43 22 23 2
1 43 23 45 43 23 45 2
1 46 45 47 46 45 47 2
1 46 47 48 46 47 48 2
1 45 23 24 45 23 24 2
1 45 24 47 45 24 47 2
1 48 47 49 48 47 49 2
1 48 49 50 48 49 50 2
1 47 24 25 47 24 25 2
1 47 25 49 47 25 49 2
1 50 49 51 50 49 51 2
1 50 51 52 50 51 52 2
1 49 25 26 49 25 26 2
1 49 26 51 49 26 51 2
1 52 51 53 52 51 53 2
1 52 53 54 52 53 54 2
1 51 26 27 51 26 27 2
1 51 27 53 51 27 53 2
1 54 53 55 54 53 55 2
1 54 55 56 54 55 56 2
1 53 27 28 53 27 28 2
1 53 28 55 53 28 55 2
1 56 55 57 56 55 57 2
1 56 57 58 56 57 58 2
1 55 28 29 55 28 29 2
1 55 29 57 55 29 57 2
1 58 57 59 58 57 59 2
1 58 59 60 58 59 60 2
1 57 29 30 57 29 30 2
1 57 30 59 57 30 59 2
1 60 59 61 60 59 61 2
1 60 61 62 60 61 62 2
1 59 30 31 59 30 31 2
1 59 31 61 59 31 61 2
1 62 61 63 62 61 63 2
1 62 63 64 62 63 64 2
1 61 31 32 61 31 32 2
1 61 32 63 61 32 63 2
1 17 34 63 17 34 63 2
1 17 63 32 17 63 32 2
1 34 33 64 34 33 64 2
1 34 64 63 34 64 63 2
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
Bones: 0
GroupComments: 0
MaterialComments: 0
BoneComments: 0
ModelComment: 0
// MilkShape 3D ASCII
Frames: 30
Frame: 1
Meshes: 2
"scroll" 0 0
17
0 18.576029 12.295176 2.879607 0.112493 0.233639 -1
0 12.456854 18.468002 2.879607 0.095922 0.099912 -1
0 0.000001 -0.000001 2.879607 0.062189 0.500000 -1
0 21.867174 4.250518 2.879607 0.121405 0.407917 -1
0 21.829239 -4.441243 2.879607 0.121302 0.596214 -1
0 18.467995 -12.456865 2.879607 0.112200 0.769864 -1
0 12.295166 -18.576036 2.879607 0.095484 0.902428 -1
0 4.250505 -21.867176 2.879607 0.073699 0.973727 -1
0 -4.441256 -21.829237 2.879607 0.050162 0.972905 -1
0 -12.456874 -18.467987 2.879607 0.028456 0.900088 -1
0 -18.576044 -12.295153 2.879607 0.011886 0.766360 -1
0 -21.867182 -4.250491 2.879607 0.002973 0.592082 -1
0 -21.829233 4.441269 2.879607 0.003076 0.403785 -1
0 -18.467979 12.456886 2.879607 0.012178 0.230136 -1
0 -12.295140 18.576052 2.879607 0.028894 0.097571 -1
0 -4.250477 21.867180 2.879607 0.050679 0.026273 -1
0 4.441284 21.829229 2.879607 0.074216 0.027095 -1
1
0.000000 0.000000 1.000000
16
0 0 1 2 0 0 0 1
0 2 3 0 0 0 0 1
0 2 4 3 0 0 0 1
0 2 5 4 0 0 0 1
0 2 6 5 0 0 0 1
0 2 7 6 0 0 0 1
0 2 8 7 0 0 0 1
0 2 9 8 0 0 0 1
0 2 10 9 0 0 0 1
0 2 11 10 0 0 0 1
0 2 12 11 0 0 0 1
0 2 13 12 0 0 0 1
0 2 14 13 0 0 0 1
0 2 15 14 0 0 0 1
0 2 16 15 0 0 0 1
0 2 1 16 0 0 0 1
"frame" 1 1
65
1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1
1 17.639259 11.675143 3.321190 0.856463 0.427477 -1
1 11.828669 17.536682 3.321190 0.801575 0.296586 -1
1 20.764435 4.036170 3.321190 0.857082 0.569410 -1
1 20.728415 -4.217276 3.321190 0.803338 0.700776 -1
1 17.536673 -11.828679 3.321190 0.703414 0.801575 -1
1 11.675133 -17.639269 3.321190 0.572522 0.856463 -1
1 4.036156 -20.764439 3.321190 0.430590 0.857082 -1
1 -4.217289 -20.728411 3.321190 0.299224 0.803338 -1
1 -11.828687 -17.536667 3.321190 0.198425 0.703414 -1
1 -17.639275 -11.675121 3.321190 0.143537 0.572522 -1
1 -20.764442 -4.036143 3.321190 0.142919 0.430589 -1
1 -20.728407 4.217301 3.321190 0.196662 0.299224 -1
1 -17.536659 11.828699 3.321190 0.296586 0.198425 -1
1 -11.675112 17.639282 3.321190 0.427478 0.143538 -1
1 -4.036130 20.764444 3.321190 0.569411 0.142919 -1
1 4.217315 20.728405 3.321190 0.700777 0.196662 -1
1 13.683175 20.286118 3.156490 0.848857 0.264694 -1
1 20.404764 13.505603 3.156490 0.912349 0.416107 -1
1 24.019917 4.668982 3.156490 0.913065 0.580292 -1
1 23.978254 -4.878449 3.156490 0.850896 0.732254 -1
1 20.286112 -13.683181 3.156490 0.735306 0.848857 -1
1 13.505599 -20.404768 3.156490 0.583893 0.912349 -1
1 4.668977 -24.019918 3.156490 0.419708 0.913065 -1
1 -4.878453 -23.978252 3.156490 0.267746 0.850896 -1
1 -13.683182 -20.286110 3.156490 0.151143 0.735306 -1
1 -20.404770 -13.505592 3.156490 0.087651 0.583893 -1
1 -24.019920 -4.668968 3.156490 0.086935 0.419708 -1
1 -23.978251 4.878465 3.156490 0.149104 0.267746 -1
1 -20.286102 13.683196 3.156490 0.264694 0.151143 -1
1 -13.505578 20.404779 3.156490 0.416107 0.087651 -1
1 -4.668952 24.019922 3.156490 0.580293 0.086935 -1
1 4.878480 23.978243 3.156490 0.732254 0.149104 -1
1 16.305698 24.174189 -0.301926 0.917477 0.218408 -1
1 15.196015 22.529018 1.012907 0.887427 0.238677 -1
1 22.660770 14.998834 1.012907 0.957940 0.406831 -1
1 24.315565 16.094122 -0.301926 0.993459 0.399605 -1
1 26.675631 5.185213 1.012907 0.958735 0.589169 -1
1 28.623606 5.563864 -0.301926 0.994316 0.596085 -1
1 26.629364 -5.417810 1.012907 0.889693 0.757932 -1
1 28.573961 -5.813441 -0.301926 0.919919 0.777938 -1
1 22.529016 -15.196017 1.012907 0.761323 0.887427 -1
1 24.174189 -16.305698 -0.301926 0.781592 0.917477 -1
1 14.998834 -22.660772 1.012907 0.593169 0.957940 -1
1 16.094122 -24.315565 -0.301926 0.600395 0.993459 -1
1 5.185220 -26.675629 1.012907 0.410831 0.958735 -1
1 5.563870 -28.623604 -0.301926 0.403915 0.994316 -1
1 -5.417803 -26.629364 1.012907 0.242068 0.889693 -1
1 -5.813432 -28.573965 -0.301926 0.222062 0.919919 -1
1 -15.196011 -22.529020 1.012907 0.112573 0.761323 -1
1 -16.305689 -24.174196 -0.301926 0.082523 0.781592 -1
1 -22.660770 -14.998836 1.012907 0.042060 0.593169 -1
1 -24.315561 -16.094126 -0.301926 0.006541 0.600395 -1
1 -26.675631 -5.185212 1.012907 0.041265 0.410831 -1
1 -28.623606 -5.563865 -0.301926 0.005684 0.403915 -1
1 -26.629358 5.417814 1.012907 0.110308 0.242068 -1
1 -28.573961 5.813443 -0.301926 0.080082 0.222062 -1
1 -22.529011 15.196029 1.012907 0.238677 0.112573 -1
1 -24.174185 16.305708 -0.301926 0.218408 0.082523 -1
1 -14.998822 22.660780 1.012907 0.406831 0.042060 -1
1 -16.094109 24.315575 -0.301926 0.399605 0.006541 -1
1 -5.185204 26.675629 1.012907 0.589169 0.041265 -1
1 -5.563847 28.623608 -0.301926 0.596086 0.005684 -1
1 5.417831 26.629356 1.012907 0.757932 0.110308 -1
1 5.813461 28.573956 -0.301926 0.777938 0.080082 -1
65
0.000000 0.000000 1.000000
0.023734 0.018076 0.999555
0.015010 0.025783 0.999555
0.028845 0.007618 0.999555
0.029564 -0.004001 0.999555
0.025783 -0.015010 0.999555
0.018076 -0.023734 0.999555
0.007618 -0.028845 0.999555
-0.004001 -0.029564 0.999555
-0.015010 -0.025783 0.999555
-0.023734 -0.018076 0.999555
-0.028845 -0.007618 0.999555
-0.029564 0.004001 0.999555
-0.025783 0.015010 0.999555
-0.018076 0.023734 0.999555
-0.007618 0.028845 0.999555
0.004001 0.029565 0.999555
0.179817 0.302000 0.936196
0.281699 0.210198 0.936196
0.340695 0.086397 0.936196
0.347824 -0.050559 0.936196
0.301999 -0.179816 0.936196
0.210198 -0.281699 0.936196
0.086396 -0.340695 0.936196
-0.050559 -0.347824 0.936196
-0.179817 -0.301999 0.936196
-0.281699 -0.210198 0.936196
-0.340695 -0.086396 0.936196
-0.347824 0.050559 0.936196
-0.301999 0.179817 0.936196
-0.210198 0.281699 0.936196
-0.086396 0.340695 0.936196
0.050559 0.347824 0.936196
0.338996 0.437135 0.833064
0.330211 0.485536 0.809454
0.490881 0.322211 0.809454
0.480475 0.274132 0.833064
0.576820 0.109832 0.809454
0.548807 0.069395 0.833064
0.574943 -0.119268 0.809454
0.533588 -0.145907 0.833064
0.485536 -0.330211 0.809454
0.437135 -0.338996 0.833064
0.322211 -0.490881 0.809454
0.274132 -0.480475 0.833064
0.109832 -0.576820 0.809454
0.069395 -0.548807 0.833064
-0.119268 -0.574943 0.809454
-0.145907 -0.533588 0.833064
-0.330210 -0.485536 0.809454
-0.338996 -0.437135 0.833064
-0.490881 -0.322211 0.809454
-0.480475 -0.274132 0.833064
-0.576820 -0.109831 0.809454
-0.548807 -0.069395 0.833064
-0.574943 0.119268 0.809454
-0.533587 0.145907 0.833064
-0.485536 0.330211 0.809454
-0.437135 0.338996 0.833064
-0.322210 0.490881 0.809454
-0.274131 0.480475 0.833064
-0.109831 0.576820 0.809454
-0.069394 0.548807 0.833064
0.119268 0.574943 0.809454
0.145907 0.533588 0.833064
112
1 0 1 2 0 1 2 2
1 0 3 1 0 3 1 2
1 0 4 3 0 4 3 2
1 0 5 4 0 5 4 2
1 0 6 5 0 6 5 2
1 0 7 6 0 7 6 2
1 0 8 7 0 8 7 2
1 0 9 8 0 9 8 2
1 0 10 9 0 10 9 2
1 0 11 10 0 11 10 2
1 0 12 11 0 12 11 2
1 0 13 12 0 13 12 2
1 0 14 13 0 14 13 2
1 0 15 14 0 15 14 2
1 0 16 15 0 16 15 2
1 0 2 16 0 2 16 2
1 17 2 1 17 2 1 2
1 17 1 18 17 1 18 2
1 18 1 3 18 1 3 2
1 18 3 19 18 3 19 2
1 19 3 4 19 3 4 2
1 19 4 20 19 4 20 2
1 20 4 5 20 4 5 2
1 20 5 21 20 5 21 2
1 21 5 6 21 5 6 2
1 21 6 22 21 6 22 2
1 22 6 7 22 6 7 2
1 22 7 23 22 7 23 2
1 23 7 8 23 7 8 2
1 23 8 24 23 8 24 2
1 24 8 9 24 8 9 2
1 24 9 25 24 9 25 2
1 25 9 10 25 9 10 2
1 25 10 26 25 10 26 2
1 26 10 11 26 10 11 2
1 26 11 27 26 11 27 2
1 27 11 12 27 11 12 2
1 27 12 28 27 12 28 2
1 28 12 13 28 12 13 2
1 28 13 29 28 13 29 2
1 29 13 14 29 13 14 2
1 29 14 30 29 14 30 2
1 30 14 15 30 14 15 2
1 30 15 31 30 15 31 2
1 31 15 16 31 15 16 2
1 31 16 32 31 16 32 2
1 2 17 32 2 17 32 2
1 2 32 16 2 32 16 2
1 33 34 35 33 34 35 2
1 33 35 36 33 35 36 2
1 34 17 18 34 17 18 2
1 34 18 35 34 18 35 2
1 36 35 37 36 35 37 2
1 36 37 38 36 37 38 2
1 35 18 19 35 18 19 2
1 35 19 37 35 19 37 2
1 38 37 39 38 37 39 2
1 38 39 40 38 39 40 2
1 37 19 20 37 19 20 2
1 37 20 39 37 20 39 2
1 40 39 41 40 39 41 2
1 40 41 42 40 41 42 2
1 39 20 21 39 20 21 2
1 39 21 41 39 21 41 2
1 42 41 43 42 41 43 2
1 42 43 44 42 43 44 2
1 41 21 22 41 21 22 2
1 41 22 43 41 22 43 2
1 44 43 45 44 43 45 2
1 44 45 46 44 45 46 2
1 43 22 23 43 22 23 2
1 43 23 45 43 23 45 2
1 46 45 47 46 45 47 2
1 46 47 48 46 47 48 2
1 45 23 24 45 23 24 2
1 45 24 47 45 24 47 2
1 48 47 49 48 47 49 2
1 48 49 50 48 49 50 2
1 47 24 25 47 24 25 2
1 47 25 49 47 25 49 2
1 50 49 51 50 49 51 2
1 50 51 52 50 51 52 2
1 49 25 26 49 25 26 2
1 49 26 51 49 26 51 2
1 52 51 53 52 51 53 2
1 52 53 54 52 53 54 2
1 51 26 27 51 26 27 2
1 51 27 53 51 27 53 2
1 54 53 55 54 53 55 2
1 54 55 56 54 55 56 2
1 53 27 28 53 27 28 2
1 53 28 55 53 28 55 2
1 56 55 57 56 55 57 2
1 56 57 58 56 57 58 2
1 55 28 29 55 28 29 2
1 55 29 57 55 29 57 2
1 58 57 59 58 57 59 2
1 58 59 60 58 59 60 2
1 57 29 30 57 29 30 2
1 57 30 59 57 30 59 2
1 60 59 61 60 59 61 2
1 60 61 62 60 61 62 2
1 59 30 31 59 30 31 2
1 59 31 61 59 31 61 2
1 62 61 63 62 61 63 2
1 62 63 64 62 63 64 2
1 61 31 32 61 31 32 2
1 61 32 63 61 32 63 2
1 17 34 63 17 34 63 2
1 17 63 32 17 63 32 2
1 34 33 64 34 33 64 2
1 34 64 63 34 64 63 2
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
""
""
Bones: 0
GroupComments: 0
MaterialComments: 0
BoneComments: 0
ModelComment: 0
+5 -5
View File
@@ -1,5 +1,5 @@
[AnimatedTexture]
TexVelocityY=1
TexOffsetX=0
Frame0000=scroller.png
Delay0000=1.0
[AnimatedTexture]
TexVelocityY=1
TexOffsetX=0
Frame0000=scroller.png
Delay0000=1.0
+19 -19
View File
@@ -1,19 +1,19 @@
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"scroller.ini"
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"_yellow (no mipmaps).png"
""
Materials: 2
"scroll"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"scroller.ini"
""
"frame"
0.000000 0.000000 0.000000 1.000000
0.800000 0.800000 0.800000 1.000000
1.000000 1.000000 1.000000 1.000000
0.000000 0.000000 0.000000 1.000000
0.000000
1.000000
"_yellow (no mipmaps).png"
""
+2 -2
View File
@@ -1,3 +1,3 @@
return NOTESKIN:LoadActor("Center","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0);
return NOTESKIN:LoadActor("Center","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0);
};
+2 -2
View File
@@ -1,3 +1,3 @@
return NOTESKIN:LoadActor("DownLeft","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
return NOTESKIN:LoadActor("DownLeft","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
};
@@ -1,3 +1,3 @@
return NOTESKIN:LoadActor("DownRight","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
return NOTESKIN:LoadActor("DownRight","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
};
+2 -2
View File
@@ -1,3 +1,3 @@
return NOTESKIN:LoadActor("UpLeft","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
return NOTESKIN:LoadActor("UpLeft","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
};
+2 -2
View File
@@ -1,3 +1,3 @@
return NOTESKIN:LoadActor("UpRight","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
return NOTESKIN:LoadActor("UpRight","Tap Note")..{
InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0)
};
@@ -1,299 +1,299 @@
function GetLocalProfiles()
local ret = {};
for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do
local profile=PROFILEMAN:GetLocalProfileFromIndex(p);
local item = Def.ActorFrame {
--[[ Def.Quad {
InitCommand=cmd(zoomto,200,1;y,40/2);
OnCommand=cmd(diffuse,Color('Outline'););
}; --]]
LoadFont("Common Normal") .. {
Text=profile:GetDisplayName();
InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true);
};
LoadFont("Common Normal") .. {
InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true);
BeginCommand=function(self)
local numSongsPlayed = profile:GetNumTotalSongsPlayed();
local s = numSongsPlayed == 1 and "Song" or "Songs";
-- todo: localize
self:settext( numSongsPlayed.." "..s.." Played" );
end;
};
};
table.insert( ret, item );
end;
return ret;
end;
function LoadCard(cColor)
local t = Def.ActorFrame {
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. {
InitCommand=cmd(diffuse,cColor);
};
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") );
};
return t
end
function LoadPlayerStuff(Player)
local ret = {};
local pn = (Player == PLAYER_1) and 1 or 2;
--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. {
Name = 'BigFrame';
}; --]]
local t = Def.ActorFrame {
Name = 'JoinFrame';
LoadCard(Color('Orange'));
--[[ Def.Quad {
InitCommand=cmd(zoomto,200+4,230+4);
OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5"));
};
Def.Quad {
InitCommand=cmd(zoomto,200,230);
OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5);
}; --]]
LoadFont("Common Normal") .. {
Text="Press &START; to join.";
InitCommand=cmd(shadowlength,1);
OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5"));
};
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = 'BigFrame';
LoadCard(PlayerColor(Player));
};
table.insert( ret, t );
--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. {
Name = 'SmallFrame';
}; --]]
t = Def.ActorFrame {
Name = 'SmallFrame';
--[[ Def.Quad {
InitCommand=cmd(zoomto,170+4,32+4);
OnCommand=cmd(shadowlength,1);
}; --]]
InitCommand=cmd(y,-2);
Def.Quad {
InitCommand=cmd(zoomto,200-10,40+2);
OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40);
OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25"));
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40;y,-40/2+20);
OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,1;y,-40/2+1);
OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25"));
};
};
table.insert( ret, t );
t = Def.ActorScroller{
Name = 'Scroller';
NumItemsToDraw=6;
-- InitCommand=cmd(y,-230/2+20;);
OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15);
TransformFunction=function(self, offset, itemIndex, numItems)
local focus = scale(math.abs(offset),0,2,1,0);
self:visible(false);
self:y(math.floor( offset*40 ));
-- self:zoomy( focus );
-- self:z(-math.abs(offset));
-- self:zoom(focus);
end;
children = GetLocalProfiles();
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = "EffectFrame";
--[[ Def.Quad {
InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
};
Def.Quad {
InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
}; --]]
};
table.insert( ret, t );
--[[ t = Def.BitmapText {
OnCommand = cmd(y,160);
Name = 'SelectedProfileText';
Font = "Common Normal";
Text = 'No profile';
}; --]]
t = LoadFont("Common Normal") .. {
Name = 'SelectedProfileText';
--InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player));
InitCommand=cmd(y,160;shadowlength,1;);
};
table.insert( ret, t );
return ret;
end;
function UpdateInternal3(self, Player)
local pn = (Player == PLAYER_1) and 1 or 2;
local frame = self:GetChild(string.format('P%uFrame', pn));
local scroller = frame:GetChild('Scroller');
local seltext = frame:GetChild('SelectedProfileText');
local joinframe = frame:GetChild('JoinFrame');
local smallframe = frame:GetChild('SmallFrame');
local bigframe = frame:GetChild('BigFrame');
if GAMESTATE:IsHumanPlayer(Player) then
frame:visible(true);
if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then
--using profile if any
joinframe:visible(false);
smallframe:visible(true);
bigframe:visible(true);
seltext:visible(true);
scroller:visible(true);
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player);
if ind > 0 then
scroller:SetDestinationItem(ind-1);
seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName());
else
if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then
scroller:SetDestinationItem(0);
self:queuecommand('UpdateInternal2');
else
joinframe:visible(true);
smallframe:visible(false);
bigframe:visible(false);
scroller:visible(false);
seltext:settext('No profile');
end;
end;
else
--using card
smallframe:visible(false);
scroller:visible(false);
seltext:settext('CARD');
SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0);
end;
else
joinframe:visible(true);
scroller:visible(false);
seltext:visible(false);
smallframe:visible(false);
bigframe:visible(false);
end;
end;
local t = Def.ActorFrame {
StorageDevicesChangedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
CodeMessageCommand = function(self, params)
if params.Name == 'Start' or params.Name == 'Center' then
MESSAGEMAN:Broadcast("StartButton");
if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1);
else
SCREENMAN:GetTopScreen():Finish();
end;
end;
if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 1 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 0 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Back' then
if GAMESTATE:GetNumPlayersEnabled()==0 then
SCREENMAN:GetTopScreen():Cancel();
else
MESSAGEMAN:Broadcast("BackButton");
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2);
end;
end;
end;
PlayerJoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
PlayerUnjoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
OnCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
UpdateInternal2Command=function(self)
UpdateInternal3(self, PLAYER_1);
UpdateInternal3(self, PLAYER_2);
end;
children = {
Def.ActorFrame {
Name = 'P1Frame';
InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_1 then
(cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_1);
};
Def.ActorFrame {
Name = 'P2Frame';
InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_2 then
(cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_2);
};
-- sounds
LoadActor( THEME:GetPathS("Common","start") )..{
StartButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","cancel") )..{
BackButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","value") )..{
DirectionButtonMessageCommand=cmd(play);
};
};
};
return t;
function GetLocalProfiles()
local ret = {};
for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do
local profile=PROFILEMAN:GetLocalProfileFromIndex(p);
local item = Def.ActorFrame {
--[[ Def.Quad {
InitCommand=cmd(zoomto,200,1;y,40/2);
OnCommand=cmd(diffuse,Color('Outline'););
}; --]]
LoadFont("Common Normal") .. {
Text=profile:GetDisplayName();
InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true);
};
LoadFont("Common Normal") .. {
InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true);
BeginCommand=function(self)
local numSongsPlayed = profile:GetNumTotalSongsPlayed();
local s = numSongsPlayed == 1 and "Song" or "Songs";
-- todo: localize
self:settext( numSongsPlayed.." "..s.." Played" );
end;
};
};
table.insert( ret, item );
end;
return ret;
end;
function LoadCard(cColor)
local t = Def.ActorFrame {
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. {
InitCommand=cmd(diffuse,cColor);
};
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") );
};
return t
end
function LoadPlayerStuff(Player)
local ret = {};
local pn = (Player == PLAYER_1) and 1 or 2;
--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. {
Name = 'BigFrame';
}; --]]
local t = Def.ActorFrame {
Name = 'JoinFrame';
LoadCard(Color('Orange'));
--[[ Def.Quad {
InitCommand=cmd(zoomto,200+4,230+4);
OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5"));
};
Def.Quad {
InitCommand=cmd(zoomto,200,230);
OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5);
}; --]]
LoadFont("Common Normal") .. {
Text="Press &START; to join.";
InitCommand=cmd(shadowlength,1);
OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5"));
};
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = 'BigFrame';
LoadCard(PlayerColor(Player));
};
table.insert( ret, t );
--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. {
Name = 'SmallFrame';
}; --]]
t = Def.ActorFrame {
Name = 'SmallFrame';
--[[ Def.Quad {
InitCommand=cmd(zoomto,170+4,32+4);
OnCommand=cmd(shadowlength,1);
}; --]]
InitCommand=cmd(y,-2);
Def.Quad {
InitCommand=cmd(zoomto,200-10,40+2);
OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40);
OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25"));
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40;y,-40/2+20);
OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,1;y,-40/2+1);
OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25"));
};
};
table.insert( ret, t );
t = Def.ActorScroller{
Name = 'Scroller';
NumItemsToDraw=6;
-- InitCommand=cmd(y,-230/2+20;);
OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15);
TransformFunction=function(self, offset, itemIndex, numItems)
local focus = scale(math.abs(offset),0,2,1,0);
self:visible(false);
self:y(math.floor( offset*40 ));
-- self:zoomy( focus );
-- self:z(-math.abs(offset));
-- self:zoom(focus);
end;
children = GetLocalProfiles();
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = "EffectFrame";
--[[ Def.Quad {
InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
};
Def.Quad {
InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
}; --]]
};
table.insert( ret, t );
--[[ t = Def.BitmapText {
OnCommand = cmd(y,160);
Name = 'SelectedProfileText';
Font = "Common Normal";
Text = 'No profile';
}; --]]
t = LoadFont("Common Normal") .. {
Name = 'SelectedProfileText';
--InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player));
InitCommand=cmd(y,160;shadowlength,1;);
};
table.insert( ret, t );
return ret;
end;
function UpdateInternal3(self, Player)
local pn = (Player == PLAYER_1) and 1 or 2;
local frame = self:GetChild(string.format('P%uFrame', pn));
local scroller = frame:GetChild('Scroller');
local seltext = frame:GetChild('SelectedProfileText');
local joinframe = frame:GetChild('JoinFrame');
local smallframe = frame:GetChild('SmallFrame');
local bigframe = frame:GetChild('BigFrame');
if GAMESTATE:IsHumanPlayer(Player) then
frame:visible(true);
if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then
--using profile if any
joinframe:visible(false);
smallframe:visible(true);
bigframe:visible(true);
seltext:visible(true);
scroller:visible(true);
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player);
if ind > 0 then
scroller:SetDestinationItem(ind-1);
seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName());
else
if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then
scroller:SetDestinationItem(0);
self:queuecommand('UpdateInternal2');
else
joinframe:visible(true);
smallframe:visible(false);
bigframe:visible(false);
scroller:visible(false);
seltext:settext('No profile');
end;
end;
else
--using card
smallframe:visible(false);
scroller:visible(false);
seltext:settext('CARD');
SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0);
end;
else
joinframe:visible(true);
scroller:visible(false);
seltext:visible(false);
smallframe:visible(false);
bigframe:visible(false);
end;
end;
local t = Def.ActorFrame {
StorageDevicesChangedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
CodeMessageCommand = function(self, params)
if params.Name == 'Start' or params.Name == 'Center' then
MESSAGEMAN:Broadcast("StartButton");
if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1);
else
SCREENMAN:GetTopScreen():Finish();
end;
end;
if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 1 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 0 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Back' then
if GAMESTATE:GetNumPlayersEnabled()==0 then
SCREENMAN:GetTopScreen():Cancel();
else
MESSAGEMAN:Broadcast("BackButton");
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2);
end;
end;
end;
PlayerJoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
PlayerUnjoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
OnCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
UpdateInternal2Command=function(self)
UpdateInternal3(self, PLAYER_1);
UpdateInternal3(self, PLAYER_2);
end;
children = {
Def.ActorFrame {
Name = 'P1Frame';
InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_1 then
(cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_1);
};
Def.ActorFrame {
Name = 'P2Frame';
InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_2 then
(cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_2);
};
-- sounds
LoadActor( THEME:GetPathS("Common","start") )..{
StartButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","cancel") )..{
BackButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","value") )..{
DirectionButtonMessageCommand=cmd(play);
};
};
};
return t;
+8 -8
View File
@@ -1,8 +1,8 @@
# _16px fonts is a "virtual font" that assembles various fonts into a unified
# place. _16px fonts in particular is imported in Common default.ini.
# Also, themes can create new fonts, and overload this file to
# have them pulled in for every 16-pixel font.
# xxx: we don't have 16px japanese or korean fonts
[main]
import=_Thai 16px,_misc 16px,_game chars 16px
# _16px fonts is a "virtual font" that assembles various fonts into a unified
# place. _16px fonts in particular is imported in Common default.ini.
# Also, themes can create new fonts, and overload this file to
# have them pulled in for every 16-pixel font.
# xxx: we don't have 16px japanese or korean fonts
[main]
import=_Thai 16px,_misc 16px,_game chars 16px
+13 -13
View File
@@ -1,13 +1,13 @@
# This "font" just pulls in default characters for a 20-pixel
# font. Other import fonts can be created for other sizes.
# Also, themes can create new fonts, and overload this file to
# have them pulled in for every 20-pixel font.
[main]
# We don't have a 20px Japanese font, so use the 24px one instead;
# pulling in a Kanji font that's a little too big looks fine, but
# pulling in one that's a little too small looks bad.
# The characters in _game chars 16px are actually very large;
# they'll look fine here, too.
import=_japanese 24px,_korean 24px,_game chars 16px,_misc 16px
# This "font" just pulls in default characters for a 20-pixel
# font. Other import fonts can be created for other sizes.
# Also, themes can create new fonts, and overload this file to
# have them pulled in for every 20-pixel font.
[main]
# We don't have a 20px Japanese font, so use the 24px one instead;
# pulling in a Kanji font that's a little too big looks fine, but
# pulling in one that's a little too small looks bad.
# The characters in _game chars 16px are actually very large;
# they'll look fine here, too.
import=_japanese 24px,_korean 24px,_game chars 16px,_misc 16px
@@ -1,3 +1,3 @@
return Def.Quad{
InitCommand=cmd(zoomto,4,22;diffuse,color("#AABBDD"));
return Def.Quad{
InitCommand=cmd(zoomto,4,22;diffuse,color("#AABBDD"));
};
+119 -119
View File
@@ -1,119 +1,119 @@
--[[
IniFile: basically a Lua rewrite of SM's IniFile class that serves as the
basis for the sm-ssc UserPrefs and ThemePrefs configuration systems.
Note that this is a namespace, not a class per se.
--]]
-- TODO: move this into a more general section
-- func takes a key and a value
function foreach_ordered( tbl, func )
local keys = { }
for k,_ in pairs(tbl) do keys[#keys+1] = k end
table.sort( keys )
-- iterate in sorted order
for _,key in ipairs(keys) do func( key, tbl[key]) end
end
-- redeclared here for my sanity's sake
-- TODO: declare these as global variables
local RageFile =
{
READ = 1,
WRITE = 2,
STREAMED = 4,
SLOW_FLUSH = 8
}
-- IniFile namespace
IniFile =
{
StrToKeyVal = function( str )
local _, _, key, value = str:find( "(.+)=(.*)" )
-- key is always a string, but value may be num, bool, or nil.
-- do a few quick checks to see which one it is.
-- if it's a nil, convert it to an empty string and return
if value == nil then value = ""; return key, value; end
-- if it's a number, convert it in place and return
if tonumber(value) ~= nil then value = tonumber(value); return key, value; end
-- not a number, so let's try a boolean value
if value == "true" then value = true;
elseif value == "false" then value = false;
end
return key, value
end,
ReadFile = function( file_path )
Trace( "IniFile.ReadFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.READ) then
Warn( string.format("ReadFile(%s): %s",file_path,file:GetError()) )
file:destroy()
return { } -- return a blank table
end
local tbl = { }
local current = tbl
while not file:AtEOF() do
local str = file:GetLine()
-- is this a section?
local _, _, sec = str:find( "%[(.+)%]" )
-- if so, set focus there; otherwise, try to
-- read a key/value pair (ignore blank lines)
if sec then
-- if this section doesn't exist, create it
tbl[sec] = tbl[sec] and tbl[sec] or { }
current = tbl[sec]
Warn( "Switching section to " .. sec )
else
local k, v = IniFile.StrToKeyVal( str )
if k and v then current[k] = v end
end
end
file:Close()
file:destroy()
return tbl
end,
WriteFile = function( file_path, tbl )
Trace( "IniFile.WriteFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.WRITE) then
Warn( string.format("WriteFile(%s): %s",file_path.file:GetError()) )
file:destroy()
return false
end
-- declare functions so we can write with foreach_ordered
local function put_pair( k, v )
file:PutLine( string.format("%s=%s", k, tostring(v)) )
end
local function put_section( section, pair )
file:PutLine( "[" .. section .. "]" )
foreach_ordered( pair, put_pair )
file:PutLine("") -- put a blank line between sections
end
-- each base key is a section and its value is a
-- table of key-value pairs under that section.
foreach_ordered( tbl, put_section )
file:Close()
file:destroy()
return true
end
};
--[[
IniFile: basically a Lua rewrite of SM's IniFile class that serves as the
basis for the sm-ssc UserPrefs and ThemePrefs configuration systems.
Note that this is a namespace, not a class per se.
--]]
-- TODO: move this into a more general section
-- func takes a key and a value
function foreach_ordered( tbl, func )
local keys = { }
for k,_ in pairs(tbl) do keys[#keys+1] = k end
table.sort( keys )
-- iterate in sorted order
for _,key in ipairs(keys) do func( key, tbl[key]) end
end
-- redeclared here for my sanity's sake
-- TODO: declare these as global variables
local RageFile =
{
READ = 1,
WRITE = 2,
STREAMED = 4,
SLOW_FLUSH = 8
}
-- IniFile namespace
IniFile =
{
StrToKeyVal = function( str )
local _, _, key, value = str:find( "(.+)=(.*)" )
-- key is always a string, but value may be num, bool, or nil.
-- do a few quick checks to see which one it is.
-- if it's a nil, convert it to an empty string and return
if value == nil then value = ""; return key, value; end
-- if it's a number, convert it in place and return
if tonumber(value) ~= nil then value = tonumber(value); return key, value; end
-- not a number, so let's try a boolean value
if value == "true" then value = true;
elseif value == "false" then value = false;
end
return key, value
end,
ReadFile = function( file_path )
Trace( "IniFile.ReadFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.READ) then
Warn( string.format("ReadFile(%s): %s",file_path,file:GetError()) )
file:destroy()
return { } -- return a blank table
end
local tbl = { }
local current = tbl
while not file:AtEOF() do
local str = file:GetLine()
-- is this a section?
local _, _, sec = str:find( "%[(.+)%]" )
-- if so, set focus there; otherwise, try to
-- read a key/value pair (ignore blank lines)
if sec then
-- if this section doesn't exist, create it
tbl[sec] = tbl[sec] and tbl[sec] or { }
current = tbl[sec]
Warn( "Switching section to " .. sec )
else
local k, v = IniFile.StrToKeyVal( str )
if k and v then current[k] = v end
end
end
file:Close()
file:destroy()
return tbl
end,
WriteFile = function( file_path, tbl )
Trace( "IniFile.WriteFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.WRITE) then
Warn( string.format("WriteFile(%s): %s",file_path.file:GetError()) )
file:destroy()
return false
end
-- declare functions so we can write with foreach_ordered
local function put_pair( k, v )
file:PutLine( string.format("%s=%s", k, tostring(v)) )
end
local function put_section( section, pair )
file:PutLine( "[" .. section .. "]" )
foreach_ordered( pair, put_pair )
file:PutLine("") -- put a blank line between sections
end
-- each base key is a section and its value is a
-- table of key-value pairs under that section.
foreach_ordered( tbl, put_section )
file:Close()
file:destroy()
return true
end
};
+141 -141
View File
@@ -1,141 +1,141 @@
--[[
ThemePrefs: handles the underlying structure for ThemePrefs, so any themes
built off of this can simply declare their prefs and default values, and
access them through this system.
v0.7.1: Dec. 28, 2010. Added language support.
v0.7.0: Dec. 15, 2010. Initial version.
vyhd wrote this for sm-ssc. <3 you guys
--]]
-- local function to handle themed error strings
-- (and to ensure we're getting all of them from the same section)
local function GetString( name )
return THEME:GetString( "ThemePrefs", name )
end
function PrintTable( tbl )
Trace( "Printing table" )
for k,v in pairs(tbl) do
Trace( ("[%s] -> %s"):format(tostring(k),tostring(v)) )
end
end
local ThemePrefsPath = "Save/ThemePrefs.ini";
local FallbackTheme = "_fallback";
-- This will be set on load.
local PrefsTable = nil;
-- Gets the name of the current theme using themeInfo
-- if available and the ThemeManager name otherwise.
local function GetThemeName()
return themeInfo and themeInfo.Name or THEME:GetThemeDisplayName()
end
-- Given a preference name, returns the table it's in. Checks the current
-- theme first, then _fallback, then all other sections, in that order.
local function ResolveTable( pref )
-- check the section for this theme
local name = GetThemeName()
local val = PrefsTable[name][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in %s"):format(pref,name) )
return PrefsTable[name]
end
-- not in the current theme; check the fallback if it exists
if PrefsTable[FallbackTheme] then
val = PrefsTable[FallbackTheme][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in fallback"):format(pref) )
return PrefsTable[FallbackTheme]
end
end
-- not there either. check every section.
-- XXX: we should do this less redundantly.
for section, _ in pairs(PrefsTable) do
val = PrefsTable[section][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in section %s"):format(pref,section) )
return PrefsTable[section] end
end
-- not found at all
Trace( ("ResolveTable(%s): pref not found"):format(pref) )
return nil
end
ThemePrefs =
{
NeedsSaved = false,
-- Loads preferences from Save/ThemePrefs.ini, then adds theme
-- preferences (and default values if applicable) to PrefsTable.
-- Only read from disk once, when _fallback calls this; we just
-- need the base set once to add prefs onto.
Init = function( prefs, bLoadFromDisk )
-- If we don't have IniFile, we can't read/write from/to disk
if not IniFile then Warn( GetString("IniFileMissing") ) end
Trace( ("ThemePrefs.Init(prefs, %s)"):format(tostring(bLoadFromDisk)) )
if bLoadFromDisk then
Trace( "ThemePrefs.Init: loading from disk" )
if not ThemePrefs.Load() then return false end
end
Trace( "ThemePrefs.Init: not loading from disk" )
-- create the section if it doesn't exist
local section = GetThemeName()
PrefsTable[section] = PrefsTable[section] and PrefsTable[section] or { }
Trace( "Using section " .. section )
-- if the key doesn't exist, add it with our default value
for k, tbl in pairs(prefs) do
if not PrefsTable[section][k] then
Trace( k .. " doesn't exist, creating" )
PrefsTable[section][k] = tbl.Default
end
end
PrintTable( PrefsTable[section] )
end,
Load = function()
if not IniFile then return false end
PrefsTable = IniFile.ReadFile( ThemePrefsPath )
return true
end,
Save = function()
Trace( "ThemePrefs.Save" )
if not IniFile then return false end
if not NeedsSaved then return end
NeedsSaved = false
IniFile.WriteFile( ThemePrefsPath, PrefsTable )
end,
Get = function( name )
Trace( ("ThemePrefs.Get(%s)"):format(name) )
local tbl = ResolveTable(name)
if tbl then return tbl[name] end
Warn( "Get: "..GetString("UnknownPreference"):format(name) )
return nil
end,
Set = function( name, value )
Trace( ("ThemePrefs.Set(%s, %s)"):format(name, tostring(value)) )
local tbl = ResolveTable(name)
if tbl then tbl[name] = value; NeedsSaved = true; return end
Warn( "Set: "..GetString("UnknownPreference"):format(name) )
end,
};
-- global aliases
GetThemePref = ThemePrefs.Get
SetThemePref = ThemePrefs.Set
--[[
ThemePrefs: handles the underlying structure for ThemePrefs, so any themes
built off of this can simply declare their prefs and default values, and
access them through this system.
v0.7.1: Dec. 28, 2010. Added language support.
v0.7.0: Dec. 15, 2010. Initial version.
vyhd wrote this for sm-ssc. <3 you guys
--]]
-- local function to handle themed error strings
-- (and to ensure we're getting all of them from the same section)
local function GetString( name )
return THEME:GetString( "ThemePrefs", name )
end
function PrintTable( tbl )
Trace( "Printing table" )
for k,v in pairs(tbl) do
Trace( ("[%s] -> %s"):format(tostring(k),tostring(v)) )
end
end
local ThemePrefsPath = "Save/ThemePrefs.ini";
local FallbackTheme = "_fallback";
-- This will be set on load.
local PrefsTable = nil;
-- Gets the name of the current theme using themeInfo
-- if available and the ThemeManager name otherwise.
local function GetThemeName()
return themeInfo and themeInfo.Name or THEME:GetThemeDisplayName()
end
-- Given a preference name, returns the table it's in. Checks the current
-- theme first, then _fallback, then all other sections, in that order.
local function ResolveTable( pref )
-- check the section for this theme
local name = GetThemeName()
local val = PrefsTable[name][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in %s"):format(pref,name) )
return PrefsTable[name]
end
-- not in the current theme; check the fallback if it exists
if PrefsTable[FallbackTheme] then
val = PrefsTable[FallbackTheme][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in fallback"):format(pref) )
return PrefsTable[FallbackTheme]
end
end
-- not there either. check every section.
-- XXX: we should do this less redundantly.
for section, _ in pairs(PrefsTable) do
val = PrefsTable[section][pref]
if val ~= nil then
Trace( ("ResolveTable(%s): found in section %s"):format(pref,section) )
return PrefsTable[section] end
end
-- not found at all
Trace( ("ResolveTable(%s): pref not found"):format(pref) )
return nil
end
ThemePrefs =
{
NeedsSaved = false,
-- Loads preferences from Save/ThemePrefs.ini, then adds theme
-- preferences (and default values if applicable) to PrefsTable.
-- Only read from disk once, when _fallback calls this; we just
-- need the base set once to add prefs onto.
Init = function( prefs, bLoadFromDisk )
-- If we don't have IniFile, we can't read/write from/to disk
if not IniFile then Warn( GetString("IniFileMissing") ) end
Trace( ("ThemePrefs.Init(prefs, %s)"):format(tostring(bLoadFromDisk)) )
if bLoadFromDisk then
Trace( "ThemePrefs.Init: loading from disk" )
if not ThemePrefs.Load() then return false end
end
Trace( "ThemePrefs.Init: not loading from disk" )
-- create the section if it doesn't exist
local section = GetThemeName()
PrefsTable[section] = PrefsTable[section] and PrefsTable[section] or { }
Trace( "Using section " .. section )
-- if the key doesn't exist, add it with our default value
for k, tbl in pairs(prefs) do
if not PrefsTable[section][k] then
Trace( k .. " doesn't exist, creating" )
PrefsTable[section][k] = tbl.Default
end
end
PrintTable( PrefsTable[section] )
end,
Load = function()
if not IniFile then return false end
PrefsTable = IniFile.ReadFile( ThemePrefsPath )
return true
end,
Save = function()
Trace( "ThemePrefs.Save" )
if not IniFile then return false end
if not NeedsSaved then return end
NeedsSaved = false
IniFile.WriteFile( ThemePrefsPath, PrefsTable )
end,
Get = function( name )
Trace( ("ThemePrefs.Get(%s)"):format(name) )
local tbl = ResolveTable(name)
if tbl then return tbl[name] end
Warn( "Get: "..GetString("UnknownPreference"):format(name) )
return nil
end,
Set = function( name, value )
Trace( ("ThemePrefs.Set(%s, %s)"):format(name, tostring(value)) )
local tbl = ResolveTable(name)
if tbl then tbl[name] = value; NeedsSaved = true; return end
Warn( "Set: "..GetString("UnknownPreference"):format(name) )
end,
};
-- global aliases
GetThemePref = ThemePrefs.Get
SetThemePref = ThemePrefs.Set
+164 -164
View File
@@ -1,164 +1,164 @@
--[[
ThemePrefsRows: you give it the choices, values, and params, and it'll
generate the rest; quirky behavior to be outlined below. Documentation
will be provided once this system is stabilized.
v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches.
v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings.
v0.5.0: Dec. 15, 2010. Initial version. Not very well tested.
vyhd wrote this for sm-ssc
--]]
-- unless overridden, these parameters will be used for the OptionsRow
local DefaultParams =
{
LayoutType = "ShowAllInRow",
SelectType = "SelectOne",
OneChoiceForAllPlayers = true,
ExportOnChange = false,
EnabledForPlayers = nil,
ReloadRowMessages = nil,
-- takes a function(self, list, pn);
-- if not used, we use the default
LoadSelections = nil,
SaveSelections = nil,
}
-- local alias to simplify error reporting
local function GetString( name )
return THEME:GetString( "ThemePrefsRows", name )
end
local function DefaultLoad( pref, default, choices, values )
return function(self, list, pn)
local val = ThemePrefs.Get( pref )
-- if our current value is here, set focus to that
for i=1, #choices do
if values[i] == val then list[i] = true return end
end
-- try the default value
for i=1, #choices do
if values[i] == default then list[i] = true return end
end
-- set to the first value and output a warning
Warn( GetString("NoDefaultInValues"):format(pref) )
list[1] = true
end
end
local function DefaultSave( pref, choices, values )
local msg = "ThemePrefChanged"
local params = { Name = pref }
return function(self, list, pn)
for i=1, #choices do
if list[i] then ThemePrefs.Set( pref, values[i] ) break end
MESSAGEMAN:Broadcast( msg, params )
end
end
end
-- This function checks for mismatches between the default value and the
-- values table passed to the ThemePrefRow, e.g. it will return false if
-- you have a boolean default and an integer value. I'm somewhat stricter
-- about types than Lua is because I don't like the unpredictability and
-- complexity of coercing values transparently in a bunch of places.
local function TypesMatch( Values, Default )
local DefaultType = type(Default)
for i, value in ipairs(Values) do
local ValueType = type(value)
if ValueType ~= DefaultType then
Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) )
return false
end
end
return true
end
local function CreateThemePrefRow( pref, tbl )
-- can't make an option handler without options
if not tbl.Choices then return nil end
local Choices = tbl.Choices
local Default = tbl.Default
local Values = tbl.Values and tbl.Values or Choices
local Params = tbl.Params and tbl.Params or { }
-- if the choices aren't strings, make them strings now
for i, str in ipairs(Choices) do
Choices[i] = tostring( Choices[i] )
end
-- check to see that Values and Choices have the same length
if #Choices ~= #Values then
Warn( GetString("ChoicesSizeMismatch") )
return nil
end
-- check to see that everything in Values matches the type of Default
if not TypesMatch( Values, Default ) then return nil end
-- set the name and choices here; we'll do the rest below
local Handler = { Name = pref, Choices = Choices }
-- add all the keys in DefaultParams, get the value from
-- Params if it exists and DefaultParams otherwise
-- (note that we explicitly check for nil, due to bools.)
for k, _ in pairs(DefaultParams) do
Handler[k] = Params[k] ~= nil and Params[k] or DefaultParams[k]
end
-- if we don't have LoadSelections and SaveSelections, make them
if not Handler.LoadSelections then
Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values )
end
if not Handler.SaveSelections then
Handler.SaveSelections = DefaultSave( pref, Choices, Values )
end
return Handler
end
-- All OptionsRows for preferences are stuck in this table, accessible
-- through GetRow('name') in the namespace or ThemePrefRow('name') in
-- the global namespace. (I like to keep pollution to a minimum.)
local Rows = { }
ThemePrefsRows =
{
IsInitted = false,
Init = function( prefs )
for pref, tbl in pairs(prefs) do
Rows[pref] = CreateThemePrefRow( pref, tbl )
end
end,
GetRow = function( pref )
Trace( ("GetRow(%s), type %s"):format(pref, type(Rows[pref])) )
return Rows[pref]
end,
}
-- Global namespace alias
ThemePrefRow = ThemePrefsRows.GetRow
-- UGLY: declare this here, even though it's in the previous namespace,
-- so we can have one call to initialize both systems (ThemePrefsRow is
-- declared after ThemePrefs, so it can't actually be in that file...)
ThemePrefs.InitAll = function( prefs )
Trace( "ThemePrefs.InitAll( prefs )" )
ThemePrefs.Init( prefs, true )
ThemePrefsRows.Init( prefs )
end
--[[
ThemePrefsRows: you give it the choices, values, and params, and it'll
generate the rest; quirky behavior to be outlined below. Documentation
will be provided once this system is stabilized.
v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches.
v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings.
v0.5.0: Dec. 15, 2010. Initial version. Not very well tested.
vyhd wrote this for sm-ssc
--]]
-- unless overridden, these parameters will be used for the OptionsRow
local DefaultParams =
{
LayoutType = "ShowAllInRow",
SelectType = "SelectOne",
OneChoiceForAllPlayers = true,
ExportOnChange = false,
EnabledForPlayers = nil,
ReloadRowMessages = nil,
-- takes a function(self, list, pn);
-- if not used, we use the default
LoadSelections = nil,
SaveSelections = nil,
}
-- local alias to simplify error reporting
local function GetString( name )
return THEME:GetString( "ThemePrefsRows", name )
end
local function DefaultLoad( pref, default, choices, values )
return function(self, list, pn)
local val = ThemePrefs.Get( pref )
-- if our current value is here, set focus to that
for i=1, #choices do
if values[i] == val then list[i] = true return end
end
-- try the default value
for i=1, #choices do
if values[i] == default then list[i] = true return end
end
-- set to the first value and output a warning
Warn( GetString("NoDefaultInValues"):format(pref) )
list[1] = true
end
end
local function DefaultSave( pref, choices, values )
local msg = "ThemePrefChanged"
local params = { Name = pref }
return function(self, list, pn)
for i=1, #choices do
if list[i] then ThemePrefs.Set( pref, values[i] ) break end
MESSAGEMAN:Broadcast( msg, params )
end
end
end
-- This function checks for mismatches between the default value and the
-- values table passed to the ThemePrefRow, e.g. it will return false if
-- you have a boolean default and an integer value. I'm somewhat stricter
-- about types than Lua is because I don't like the unpredictability and
-- complexity of coercing values transparently in a bunch of places.
local function TypesMatch( Values, Default )
local DefaultType = type(Default)
for i, value in ipairs(Values) do
local ValueType = type(value)
if ValueType ~= DefaultType then
Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) )
return false
end
end
return true
end
local function CreateThemePrefRow( pref, tbl )
-- can't make an option handler without options
if not tbl.Choices then return nil end
local Choices = tbl.Choices
local Default = tbl.Default
local Values = tbl.Values and tbl.Values or Choices
local Params = tbl.Params and tbl.Params or { }
-- if the choices aren't strings, make them strings now
for i, str in ipairs(Choices) do
Choices[i] = tostring( Choices[i] )
end
-- check to see that Values and Choices have the same length
if #Choices ~= #Values then
Warn( GetString("ChoicesSizeMismatch") )
return nil
end
-- check to see that everything in Values matches the type of Default
if not TypesMatch( Values, Default ) then return nil end
-- set the name and choices here; we'll do the rest below
local Handler = { Name = pref, Choices = Choices }
-- add all the keys in DefaultParams, get the value from
-- Params if it exists and DefaultParams otherwise
-- (note that we explicitly check for nil, due to bools.)
for k, _ in pairs(DefaultParams) do
Handler[k] = Params[k] ~= nil and Params[k] or DefaultParams[k]
end
-- if we don't have LoadSelections and SaveSelections, make them
if not Handler.LoadSelections then
Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values )
end
if not Handler.SaveSelections then
Handler.SaveSelections = DefaultSave( pref, Choices, Values )
end
return Handler
end
-- All OptionsRows for preferences are stuck in this table, accessible
-- through GetRow('name') in the namespace or ThemePrefRow('name') in
-- the global namespace. (I like to keep pollution to a minimum.)
local Rows = { }
ThemePrefsRows =
{
IsInitted = false,
Init = function( prefs )
for pref, tbl in pairs(prefs) do
Rows[pref] = CreateThemePrefRow( pref, tbl )
end
end,
GetRow = function( pref )
Trace( ("GetRow(%s), type %s"):format(pref, type(Rows[pref])) )
return Rows[pref]
end,
}
-- Global namespace alias
ThemePrefRow = ThemePrefsRows.GetRow
-- UGLY: declare this here, even though it's in the previous namespace,
-- so we can have one call to initialize both systems (ThemePrefsRow is
-- declared after ThemePrefs, so it can't actually be in that file...)
ThemePrefs.InitAll = function( prefs )
Trace( "ThemePrefs.InitAll( prefs )" )
ThemePrefs.Init( prefs, true )
ThemePrefsRows.Init( prefs )
end
@@ -1,299 +1,299 @@
function GetLocalProfiles()
local ret = {};
for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do
local profile=PROFILEMAN:GetLocalProfileFromIndex(p);
local item = Def.ActorFrame {
--[[ Def.Quad {
InitCommand=cmd(zoomto,200,1;y,40/2);
OnCommand=cmd(diffuse,Color('Outline'););
}; --]]
LoadFont("Common Normal") .. {
Text=profile:GetDisplayName();
InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true);
};
LoadFont("Common Normal") .. {
InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true);
BeginCommand=function(self)
local numSongsPlayed = profile:GetNumTotalSongsPlayed();
local s = numSongsPlayed == 1 and "Song" or "Songs";
-- todo: localize
self:settext( numSongsPlayed.." "..s.." Played" );
end;
};
};
table.insert( ret, item );
end;
return ret;
end;
function LoadCard(cColor)
local t = Def.ActorFrame {
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. {
InitCommand=cmd(diffuse,cColor);
};
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") );
};
return t
end
function LoadPlayerStuff(Player)
local ret = {};
local pn = (Player == PLAYER_1) and 1 or 2;
--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. {
Name = 'BigFrame';
}; --]]
local t = Def.ActorFrame {
Name = 'JoinFrame';
LoadCard(Color('Orange'));
--[[ Def.Quad {
InitCommand=cmd(zoomto,200+4,230+4);
OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5"));
};
Def.Quad {
InitCommand=cmd(zoomto,200,230);
OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5);
}; --]]
LoadFont("Common Normal") .. {
Text="Press &START; to join.";
InitCommand=cmd(shadowlength,1);
OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5"));
};
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = 'BigFrame';
LoadCard(PlayerColor(Player));
};
table.insert( ret, t );
--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. {
Name = 'SmallFrame';
}; --]]
t = Def.ActorFrame {
Name = 'SmallFrame';
--[[ Def.Quad {
InitCommand=cmd(zoomto,170+4,32+4);
OnCommand=cmd(shadowlength,1);
}; --]]
InitCommand=cmd(y,-2);
Def.Quad {
InitCommand=cmd(zoomto,200-10,40+2);
OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40);
OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25"));
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40;y,-40/2+20);
OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,1;y,-40/2+1);
OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25"));
};
};
table.insert( ret, t );
t = Def.ActorScroller{
Name = 'Scroller';
NumItemsToDraw=6;
-- InitCommand=cmd(y,-230/2+20;);
OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15);
TransformFunction=function(self, offset, itemIndex, numItems)
local focus = scale(math.abs(offset),0,2,1,0);
self:visible(false);
self:y(math.floor( offset*40 ));
-- self:zoomy( focus );
-- self:z(-math.abs(offset));
-- self:zoom(focus);
end;
children = GetLocalProfiles();
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = "EffectFrame";
--[[ Def.Quad {
InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
};
Def.Quad {
InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
}; --]]
};
table.insert( ret, t );
--[[ t = Def.BitmapText {
OnCommand = cmd(y,160);
Name = 'SelectedProfileText';
Font = "Common Normal";
Text = 'No profile';
}; --]]
t = LoadFont("Common Normal") .. {
Name = 'SelectedProfileText';
--InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player));
InitCommand=cmd(y,160;shadowlength,1;);
};
table.insert( ret, t );
return ret;
end;
function UpdateInternal3(self, Player)
local pn = (Player == PLAYER_1) and 1 or 2;
local frame = self:GetChild(string.format('P%uFrame', pn));
local scroller = frame:GetChild('Scroller');
local seltext = frame:GetChild('SelectedProfileText');
local joinframe = frame:GetChild('JoinFrame');
local smallframe = frame:GetChild('SmallFrame');
local bigframe = frame:GetChild('BigFrame');
if GAMESTATE:IsHumanPlayer(Player) then
frame:visible(true);
if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then
--using profile if any
joinframe:visible(false);
smallframe:visible(true);
bigframe:visible(true);
seltext:visible(true);
scroller:visible(true);
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player);
if ind > 0 then
scroller:SetDestinationItem(ind-1);
seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName());
else
if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then
scroller:SetDestinationItem(0);
self:queuecommand('UpdateInternal2');
else
joinframe:visible(true);
smallframe:visible(false);
bigframe:visible(false);
scroller:visible(false);
seltext:settext('No profile');
end;
end;
else
--using card
smallframe:visible(false);
scroller:visible(false);
seltext:settext('CARD');
SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0);
end;
else
joinframe:visible(true);
scroller:visible(false);
seltext:visible(false);
smallframe:visible(false);
bigframe:visible(false);
end;
end;
local t = Def.ActorFrame {
StorageDevicesChangedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
CodeMessageCommand = function(self, params)
if params.Name == 'Start' or params.Name == 'Center' then
MESSAGEMAN:Broadcast("StartButton");
if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1);
else
SCREENMAN:GetTopScreen():Finish();
end;
end;
if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 1 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 0 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Back' then
if GAMESTATE:GetNumPlayersEnabled()==0 then
SCREENMAN:GetTopScreen():Cancel();
else
MESSAGEMAN:Broadcast("BackButton");
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2);
end;
end;
end;
PlayerJoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
PlayerUnjoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
OnCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
UpdateInternal2Command=function(self)
UpdateInternal3(self, PLAYER_1);
UpdateInternal3(self, PLAYER_2);
end;
children = {
Def.ActorFrame {
Name = 'P1Frame';
InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_1 then
(cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_1);
};
Def.ActorFrame {
Name = 'P2Frame';
InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_2 then
(cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_2);
};
-- sounds
LoadActor( THEME:GetPathS("Common","start") )..{
StartButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","cancel") )..{
BackButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","value") )..{
DirectionButtonMessageCommand=cmd(play);
};
};
};
return t;
function GetLocalProfiles()
local ret = {};
for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do
local profile=PROFILEMAN:GetLocalProfileFromIndex(p);
local item = Def.ActorFrame {
--[[ Def.Quad {
InitCommand=cmd(zoomto,200,1;y,40/2);
OnCommand=cmd(diffuse,Color('Outline'););
}; --]]
LoadFont("Common Normal") .. {
Text=profile:GetDisplayName();
InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true);
};
LoadFont("Common Normal") .. {
InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true);
BeginCommand=function(self)
local numSongsPlayed = profile:GetNumTotalSongsPlayed();
local s = numSongsPlayed == 1 and "Song" or "Songs";
-- todo: localize
self:settext( numSongsPlayed.." "..s.." Played" );
end;
};
};
table.insert( ret, item );
end;
return ret;
end;
function LoadCard(cColor)
local t = Def.ActorFrame {
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. {
InitCommand=cmd(diffuse,cColor);
};
LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") );
};
return t
end
function LoadPlayerStuff(Player)
local ret = {};
local pn = (Player == PLAYER_1) and 1 or 2;
--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. {
Name = 'BigFrame';
}; --]]
local t = Def.ActorFrame {
Name = 'JoinFrame';
LoadCard(Color('Orange'));
--[[ Def.Quad {
InitCommand=cmd(zoomto,200+4,230+4);
OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5"));
};
Def.Quad {
InitCommand=cmd(zoomto,200,230);
OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5);
}; --]]
LoadFont("Common Normal") .. {
Text="Press &START; to join.";
InitCommand=cmd(shadowlength,1);
OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5"));
};
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = 'BigFrame';
LoadCard(PlayerColor(Player));
};
table.insert( ret, t );
--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. {
Name = 'SmallFrame';
}; --]]
t = Def.ActorFrame {
Name = 'SmallFrame';
--[[ Def.Quad {
InitCommand=cmd(zoomto,170+4,32+4);
OnCommand=cmd(shadowlength,1);
}; --]]
InitCommand=cmd(y,-2);
Def.Quad {
InitCommand=cmd(zoomto,200-10,40+2);
OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40);
OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25"));
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,40;y,-40/2+20);
OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35);
};
Def.Quad {
InitCommand=cmd(zoomto,200-10,1;y,-40/2+1);
OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25"));
};
};
table.insert( ret, t );
t = Def.ActorScroller{
Name = 'Scroller';
NumItemsToDraw=6;
-- InitCommand=cmd(y,-230/2+20;);
OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15);
TransformFunction=function(self, offset, itemIndex, numItems)
local focus = scale(math.abs(offset),0,2,1,0);
self:visible(false);
self:y(math.floor( offset*40 ));
-- self:zoomy( focus );
-- self:z(-math.abs(offset));
-- self:zoom(focus);
end;
children = GetLocalProfiles();
};
table.insert( ret, t );
t = Def.ActorFrame {
Name = "EffectFrame";
--[[ Def.Quad {
InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
};
Def.Quad {
InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1);
OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25);
}; --]]
};
table.insert( ret, t );
--[[ t = Def.BitmapText {
OnCommand = cmd(y,160);
Name = 'SelectedProfileText';
Font = "Common Normal";
Text = 'No profile';
}; --]]
t = LoadFont("Common Normal") .. {
Name = 'SelectedProfileText';
--InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player));
InitCommand=cmd(y,160;shadowlength,1;);
};
table.insert( ret, t );
return ret;
end;
function UpdateInternal3(self, Player)
local pn = (Player == PLAYER_1) and 1 or 2;
local frame = self:GetChild(string.format('P%uFrame', pn));
local scroller = frame:GetChild('Scroller');
local seltext = frame:GetChild('SelectedProfileText');
local joinframe = frame:GetChild('JoinFrame');
local smallframe = frame:GetChild('SmallFrame');
local bigframe = frame:GetChild('BigFrame');
if GAMESTATE:IsHumanPlayer(Player) then
frame:visible(true);
if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then
--using profile if any
joinframe:visible(false);
smallframe:visible(true);
bigframe:visible(true);
seltext:visible(true);
scroller:visible(true);
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player);
if ind > 0 then
scroller:SetDestinationItem(ind-1);
seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName());
else
if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then
scroller:SetDestinationItem(0);
self:queuecommand('UpdateInternal2');
else
joinframe:visible(true);
smallframe:visible(false);
bigframe:visible(false);
scroller:visible(false);
seltext:settext('No profile');
end;
end;
else
--using card
smallframe:visible(false);
scroller:visible(false);
seltext:settext('CARD');
SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0);
end;
else
joinframe:visible(true);
scroller:visible(false);
seltext:visible(false);
smallframe:visible(false);
bigframe:visible(false);
end;
end;
local t = Def.ActorFrame {
StorageDevicesChangedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
CodeMessageCommand = function(self, params)
if params.Name == 'Start' or params.Name == 'Center' then
MESSAGEMAN:Broadcast("StartButton");
if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1);
else
SCREENMAN:GetTopScreen():Finish();
end;
end;
if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 1 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then
if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then
local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber);
if ind > 0 then
if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then
MESSAGEMAN:Broadcast("DirectionButton");
self:queuecommand('UpdateInternal2');
end;
end;
end;
end;
if params.Name == 'Back' then
if GAMESTATE:GetNumPlayersEnabled()==0 then
SCREENMAN:GetTopScreen():Cancel();
else
MESSAGEMAN:Broadcast("BackButton");
SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2);
end;
end;
end;
PlayerJoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
PlayerUnjoinedMessageCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
OnCommand=function(self, params)
self:queuecommand('UpdateInternal2');
end;
UpdateInternal2Command=function(self)
UpdateInternal3(self, PLAYER_1);
UpdateInternal3(self, PLAYER_2);
end;
children = {
Def.ActorFrame {
Name = 'P1Frame';
InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_1 then
(cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_1);
};
Def.ActorFrame {
Name = 'P2Frame';
InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y);
OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1);
OffCommand=cmd(bouncebegin,0.35;zoom,0);
PlayerJoinedMessageCommand=function(self,param)
if param.Player == PLAYER_2 then
(cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self);
end;
end;
children = LoadPlayerStuff(PLAYER_2);
};
-- sounds
LoadActor( THEME:GetPathS("Common","start") )..{
StartButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","cancel") )..{
BackButtonMessageCommand=cmd(play);
};
LoadActor( THEME:GetPathS("Common","value") )..{
DirectionButtonMessageCommand=cmd(play);
};
};
};
return t;
@@ -1,12 +1,12 @@
return Def.ActorFrame {
FOV=90;
--[[ LoadActor("shot") .. {
InitCommand=cmd(diffusealpha,0;zoom,2;blend,'BlendMode_Add');
MilestoneCommand=cmd(diffusealpha,0.75;rotationz,0;accelerate,2.5;diffusealpha,0;rotationz,360;zoom,2.5);
}; --]]
--[[ LoadActor("shot") .. {
InitCommand=cmd(diffusealpha,0;zoom,2;zoomx,-2;blend,'BlendMode_Add');
MilestoneCommand=cmd(diffusealpha,0.75;rotationz,-360;x,0;linear,2.5;diffusealpha,0;rotationz,0;zoom,2.5);
}; --]]
LoadActor(THEME:GetPathG("Combo","100Milestone"));
};
return Def.ActorFrame {
FOV=90;
--[[ LoadActor("shot") .. {
InitCommand=cmd(diffusealpha,0;zoom,2;blend,'BlendMode_Add');
MilestoneCommand=cmd(diffusealpha,0.75;rotationz,0;accelerate,2.5;diffusealpha,0;rotationz,360;zoom,2.5);
}; --]]
--[[ LoadActor("shot") .. {
InitCommand=cmd(diffusealpha,0;zoom,2;zoomx,-2;blend,'BlendMode_Add');
MilestoneCommand=cmd(diffusealpha,0.75;rotationz,-360;x,0;linear,2.5;diffusealpha,0;rotationz,0;zoom,2.5);
}; --]]
LoadActor(THEME:GetPathG("Combo","100Milestone"));
};
@@ -1,11 +1,11 @@
local ShowFlashyCombo = GetUserPrefB("UserPrefFlashyCombo")
return Def.ActorFrame {
LoadActor("explosion") .. {
InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo);
MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,90;zoom,1.75;diffusealpha,0);
};
LoadActor("explosion") .. {
InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo);
MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,-90;zoom,2.5;diffusealpha,0);
};
local ShowFlashyCombo = GetUserPrefB("UserPrefFlashyCombo")
return Def.ActorFrame {
LoadActor("explosion") .. {
InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo);
MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,90;zoom,1.75;diffusealpha,0);
};
LoadActor("explosion") .. {
InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo);
MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,-90;zoom,2.5;diffusealpha,0);
};
};
+157 -157
View File
@@ -1,157 +1,157 @@
--Special Scoring types.
local r = {};
local DisabledScoringModes = { 'DDR Extreme', '[SSC] Radar Master' };
--the following metatable makes any missing value in a table 0 instead of nil.
local ZeroIfNotFound = { __index = function() return 0 end; };
-- Retrieve the amount of taps/holds/rolls involved. Used for some formulas.
function GetTotalItems(radars)
return radars:GetValue('RadarCategory_TapsAndHolds')
+ radars:GetValue('RadarCategory_Holds')
+ radars:GetValue('RadarCategory_Rolls');
end;
-- Determine whether marvelous timing is to be considered.
function IsW1Allowed(tapScore)
return tapScore == 'TapNoteScore_W2'
and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never'
or not (GAMESTATE:IsCourseMode() and
PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly'));
end;
-- Get the radar values directly. The individual steps aren't used much.
function GetDirectRadar(player)
return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player);
end;
-----------------------------------------------------------
--DDR 1st Mix and 2nd Mix Scoring
-----------------------------------------------------------
r['DDR 1stMIX'] = function(params, pss)
local dCombo = math.floor((pss:GetCurrentCombo()+1)/4);
local bScore = (dCombo^2+1) * 100;
local multLookup = { ['TapNoteScore_W1']=3, ['TapNoteScore_W2']=3, ['TapNoteScore_W3']=1 };
setmetatable(multLookup, ZeroIfNotFound);
--if score increases above the boundaries of a 32-bit signed
--(about 2.15 billion), it stops increasing. Conveniently,
--1st Mix clamped score as well.
pss:SetScore(clamp(pss:GetScore()+(bScore*multLookup[params.TapNoteScore]),0,999999999));
end;
-----------------------------------------------------------
--DDR 4th Mix/Extra Mix/Konamix/GB3/DDRPC Scoring
-----------------------------------------------------------
r['DDR 4thMIX'] = function(params, pss)
local scoreLookupTable = { ['TapNoteScore_W1']=777, ['TapNoteScore_W2']=777, ['TapNoteScore_W3']=555 };
setmetatable(scoreLookupTable, ZeroIfNotFound);
local comboBonusForThisStep = (pss:GetCurrentCombo()+1)*333;
pss:SetScore(clamp(pss:GetScore()+scoreLookupTable[params.TapNoteScore]+(scoreLookupTable[params.TapNoteScore] and comboBonusForThisStep or 0),0,999999999));
end;
-----------------------------------------------------------
--DDR MAX2/Extreme Scoring
--This scoring system doesn't work and is locked out.
-----------------------------------------------------------
r['DDR Extreme'] = function(params, pss)
local judgmentBase = {
['TapNoteScore_W1'] = 10,
['TapNoteScore_W2'] = 9,
['TapNoteScore_W3'] = 5
};
setmetatable(judgmentBase, ZeroIfNotFound);
local steps = GAMESTATE:GetCurrentSteps(params.Player);
local radarValues = steps:GetRadarValues(params.Player);
local baseScore = (steps:IsAnEdit() and
5 or steps:GetMeter()) * 10000000;
local currentStep = 0; -- TODO: Get current step/hold.
local totalItems = GetTotalItems(radarValues);
local singleStep = (1 + totalItems) * totalItems / 2;
local stepLast = math.floor(baseScore / singleStep) * currentStep;
local judgeScore = 0;
if (params.HoldNoteScore == 'HoldNoteScore_Held') then
judgeScore = judgmentBase['TapNoteScore_W1'];
else
judgeScore = judgmentBase[params.TapNoteScore];
if (IsW1Allowed(params.TapNoteScore)) then
judgeScore = judgmentBase['TapNoteScore_W1'];
end;
end;
local stepScore = judgeScore * stepLast;
pss:SetScore(pss:GetScore() + stepScore);
end;
-----------------------------------------------------------
--DDR SuperNOVA(-esque) scoring
-----------------------------------------------------------
r['DDR SuperNOVA'] = function(params, pss)
local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 };
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues);
local buildScore = (10000000 / totalItems * multLookup[params.TapNoteScore]) + (10000000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0));
pss:SetScore(pss:GetScore() + math.round(buildScore));
end;
-----------------------------------------------------------
--DDR SuperNOVA 2(-esque) scoring
-----------------------------------------------------------
r['DDR SuperNOVA 2'] = function(params, pss)
local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 };
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues);
local buildScore = (100000 / totalItems * multLookup[params.TapNoteScore] - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + (100000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0));
pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10));
end;
-----------------------------------------------------------
--Radar Master (doesn't work in 1.2.1, disabled)
--don't try to "fix it up", either. you *cannot* make it work in 1.2.1.
-----------------------------------------------------------
r['[SSC] Radar Master'] = function(params, pss)
local masterTable = {
['RadarCategory_Stream'] = 0,
['RadarCategory_Voltage'] = 0,
['RadarCategory_Air'] = 0,
['RadarCategory_Freeze'] = 0,
['RadarCategory_Chaos'] = 0
};
local totalRadar = 0;
local finalScore = 0;
for k,v in pairs(masterTable) do
local firstRadar = GetDirectRadar(params.Player):GetValue(k);
if firstRadar == 0 then
masterTable[k] = nil;
else
masterTable[k] = firstRadar;
totalRadar = totalRadar + firstRadar;
end;
end;
--two loops are needed because we need to calculate totalRadar
--to actually calculate any part of the score
for k,v in pairs(masterTable) do
local curPortion = pss:GetRadarActual():GetValue(k) / v;
finalScore = finalScore + curPortion*(500000000*(v/totalRadar));
end;
pss:SetScore(finalScore);
end;
------------------------------------------------------------
--Marvelous Incorporated Grading System (or MIGS for short)
--basically like DP scoring with locked DP values
------------------------------------------------------------
r['MIGS'] = function(params,pss)
local curScore = 0;
local tapScoreTable = { ['TapNoteScore_W1'] = 3, ['TapNoteScore_W2'] = 2, ['TapNoteScore_W3'] = 1, ['TapNoteScore_W5'] = -4, ['TapNoteScore_Miss'] = -8 };
for k,v in pairs(tapScoreTable) do
curScore = curScore + ( pss:GetTapNoteScores(k) * v );
end;
curScore = curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 );
pss:SetScore(clamp(curScore,0,math.huge));
end;
SpecialScoring = {};
setmetatable(SpecialScoring, {
__metatable = { "Letting you change the metatable sort of defeats the purpose." };
__index = function(tbl, key)
for v in ivalues(DisabledScoringModes) do
if key == v then return r['DDR 1stMIX']; end;
end;
return r[key];
end;
}
);
--Special Scoring types.
local r = {};
local DisabledScoringModes = { 'DDR Extreme', '[SSC] Radar Master' };
--the following metatable makes any missing value in a table 0 instead of nil.
local ZeroIfNotFound = { __index = function() return 0 end; };
-- Retrieve the amount of taps/holds/rolls involved. Used for some formulas.
function GetTotalItems(radars)
return radars:GetValue('RadarCategory_TapsAndHolds')
+ radars:GetValue('RadarCategory_Holds')
+ radars:GetValue('RadarCategory_Rolls');
end;
-- Determine whether marvelous timing is to be considered.
function IsW1Allowed(tapScore)
return tapScore == 'TapNoteScore_W2'
and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never'
or not (GAMESTATE:IsCourseMode() and
PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly'));
end;
-- Get the radar values directly. The individual steps aren't used much.
function GetDirectRadar(player)
return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player);
end;
-----------------------------------------------------------
--DDR 1st Mix and 2nd Mix Scoring
-----------------------------------------------------------
r['DDR 1stMIX'] = function(params, pss)
local dCombo = math.floor((pss:GetCurrentCombo()+1)/4);
local bScore = (dCombo^2+1) * 100;
local multLookup = { ['TapNoteScore_W1']=3, ['TapNoteScore_W2']=3, ['TapNoteScore_W3']=1 };
setmetatable(multLookup, ZeroIfNotFound);
--if score increases above the boundaries of a 32-bit signed
--(about 2.15 billion), it stops increasing. Conveniently,
--1st Mix clamped score as well.
pss:SetScore(clamp(pss:GetScore()+(bScore*multLookup[params.TapNoteScore]),0,999999999));
end;
-----------------------------------------------------------
--DDR 4th Mix/Extra Mix/Konamix/GB3/DDRPC Scoring
-----------------------------------------------------------
r['DDR 4thMIX'] = function(params, pss)
local scoreLookupTable = { ['TapNoteScore_W1']=777, ['TapNoteScore_W2']=777, ['TapNoteScore_W3']=555 };
setmetatable(scoreLookupTable, ZeroIfNotFound);
local comboBonusForThisStep = (pss:GetCurrentCombo()+1)*333;
pss:SetScore(clamp(pss:GetScore()+scoreLookupTable[params.TapNoteScore]+(scoreLookupTable[params.TapNoteScore] and comboBonusForThisStep or 0),0,999999999));
end;
-----------------------------------------------------------
--DDR MAX2/Extreme Scoring
--This scoring system doesn't work and is locked out.
-----------------------------------------------------------
r['DDR Extreme'] = function(params, pss)
local judgmentBase = {
['TapNoteScore_W1'] = 10,
['TapNoteScore_W2'] = 9,
['TapNoteScore_W3'] = 5
};
setmetatable(judgmentBase, ZeroIfNotFound);
local steps = GAMESTATE:GetCurrentSteps(params.Player);
local radarValues = steps:GetRadarValues(params.Player);
local baseScore = (steps:IsAnEdit() and
5 or steps:GetMeter()) * 10000000;
local currentStep = 0; -- TODO: Get current step/hold.
local totalItems = GetTotalItems(radarValues);
local singleStep = (1 + totalItems) * totalItems / 2;
local stepLast = math.floor(baseScore / singleStep) * currentStep;
local judgeScore = 0;
if (params.HoldNoteScore == 'HoldNoteScore_Held') then
judgeScore = judgmentBase['TapNoteScore_W1'];
else
judgeScore = judgmentBase[params.TapNoteScore];
if (IsW1Allowed(params.TapNoteScore)) then
judgeScore = judgmentBase['TapNoteScore_W1'];
end;
end;
local stepScore = judgeScore * stepLast;
pss:SetScore(pss:GetScore() + stepScore);
end;
-----------------------------------------------------------
--DDR SuperNOVA(-esque) scoring
-----------------------------------------------------------
r['DDR SuperNOVA'] = function(params, pss)
local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 };
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues);
local buildScore = (10000000 / totalItems * multLookup[params.TapNoteScore]) + (10000000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0));
pss:SetScore(pss:GetScore() + math.round(buildScore));
end;
-----------------------------------------------------------
--DDR SuperNOVA 2(-esque) scoring
-----------------------------------------------------------
r['DDR SuperNOVA 2'] = function(params, pss)
local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 };
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues);
local buildScore = (100000 / totalItems * multLookup[params.TapNoteScore] - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + (100000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0));
pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10));
end;
-----------------------------------------------------------
--Radar Master (doesn't work in 1.2.1, disabled)
--don't try to "fix it up", either. you *cannot* make it work in 1.2.1.
-----------------------------------------------------------
r['[SSC] Radar Master'] = function(params, pss)
local masterTable = {
['RadarCategory_Stream'] = 0,
['RadarCategory_Voltage'] = 0,
['RadarCategory_Air'] = 0,
['RadarCategory_Freeze'] = 0,
['RadarCategory_Chaos'] = 0
};
local totalRadar = 0;
local finalScore = 0;
for k,v in pairs(masterTable) do
local firstRadar = GetDirectRadar(params.Player):GetValue(k);
if firstRadar == 0 then
masterTable[k] = nil;
else
masterTable[k] = firstRadar;
totalRadar = totalRadar + firstRadar;
end;
end;
--two loops are needed because we need to calculate totalRadar
--to actually calculate any part of the score
for k,v in pairs(masterTable) do
local curPortion = pss:GetRadarActual():GetValue(k) / v;
finalScore = finalScore + curPortion*(500000000*(v/totalRadar));
end;
pss:SetScore(finalScore);
end;
------------------------------------------------------------
--Marvelous Incorporated Grading System (or MIGS for short)
--basically like DP scoring with locked DP values
------------------------------------------------------------
r['MIGS'] = function(params,pss)
local curScore = 0;
local tapScoreTable = { ['TapNoteScore_W1'] = 3, ['TapNoteScore_W2'] = 2, ['TapNoteScore_W3'] = 1, ['TapNoteScore_W5'] = -4, ['TapNoteScore_Miss'] = -8 };
for k,v in pairs(tapScoreTable) do
curScore = curScore + ( pss:GetTapNoteScores(k) * v );
end;
curScore = curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 );
pss:SetScore(clamp(curScore,0,math.huge));
end;
SpecialScoring = {};
setmetatable(SpecialScoring, {
__metatable = { "Letting you change the metatable sort of defeats the purpose." };
__index = function(tbl, key)
for v in ivalues(DisabledScoringModes) do
if key == v then return r['DDR 1stMIX']; end;
end;
return r[key];
end;
}
);
+25 -25
View File
@@ -1,25 +1,25 @@
#!/bin/bash
set -e
if test "$1" = ""; then
echo Expected argument
exit 1
fi
if ! test -e $1; then
echo "File $1 doesn't exist"
exit 1
fi
PRODUCT=`cat $1 | grep -w '^.define PRODUCT_FAMILY_BARE' | sed -re 's/.*_BARE +(.*)/\1/'`
VER=`cat $1 | grep -w '^.define PRODUCT_VER_BARE' | sed -re 's/.*_BARE +(.*)/\1/'`
# "3.9 alpha 1" -> "3.9 alpha1"
VER=`echo "$VER" | sed -e 's/alpha /alpha/'`
# "3.9 beta 1" -> "3.9 beta1"
VER=`echo "$VER" | sed -e 's/beta /beta/'`
# "3.9 alpha1" -> "3.9-alpha1"
VER=`echo "$VER" | sed -e 's/ /-/g'`
PRODUCTVER="$PRODUCT-$VER"
#!/bin/bash
set -e
if test "$1" = ""; then
echo Expected argument
exit 1
fi
if ! test -e $1; then
echo "File $1 doesn't exist"
exit 1
fi
PRODUCT=`cat $1 | grep -w '^.define PRODUCT_FAMILY_BARE' | sed -re 's/.*_BARE +(.*)/\1/'`
VER=`cat $1 | grep -w '^.define PRODUCT_VER_BARE' | sed -re 's/.*_BARE +(.*)/\1/'`
# "3.9 alpha 1" -> "3.9 alpha1"
VER=`echo "$VER" | sed -e 's/alpha /alpha/'`
# "3.9 beta 1" -> "3.9 beta1"
VER=`echo "$VER" | sed -e 's/beta /beta/'`
# "3.9 alpha1" -> "3.9-alpha1"
VER=`echo "$VER" | sed -e 's/ /-/g'`
PRODUCTVER="$PRODUCT-$VER"
+65 -65
View File
@@ -1,65 +1,65 @@
#!/bin/bash
set -e
test -e ProductInfo.h && cd ..
if ! test -d src; then
echo Run this script from the top directory.
exit 1
fi
source Utils/GetProductVer.sh src/ProductInfo.h
PRODUCTVER="$PRODUCTVER-src"
if test -e $PRODUCTVER; then
echo "\"$PRODUCTVER\" already exists."
exit 1
fi
echo Copying...
mkdir $PRODUCTVER
cp -dpR autoconf $PRODUCTVER/
#cp -dpR Utils $PRODUCTVER/
cp -dpR src $PRODUCTVER/
cp Docs/Copying.MAD Docs/Licenses.txt Makefile.am aclocal.m4 \
configure Makefile.in configure.ac $PRODUCTVER
echo Pruning...
cd $PRODUCTVER/src
# Obsolete and going away:
rm -rf SDL-1.2.5
rm -rf SDL-1.2.6
# Incomplete:
rm -rf Texture Font Generator
# Xbox:
rm -rf SDLx-0.02
# Unused:
rm -rf smlobby
# Windows-only stuff. Let's leave some in the archive to make the GPL happy.
# I don't want to spend an extra half hour to upload separate Windows and
# *nix source archives.
#rm -rf mad-0.15.0b
rm -rf lua-5.0
rm -rf vorbis
rm -rf BaseClasses
rm -rf ddk
rm -rf smpackage
rm -rf sdl_xbox_includes
rm -rf SDLx-0.02.rar
cd ..
find . -type d -name 'CVS' | xargs rm -rf
find . -type f -name '*.lib' | xargs rm -rf
find . -type f -name '*.exe' | xargs rm -rf
find . -type f -name '*.a' | xargs rm -rf
find . -type f -name '*.o' | xargs rm -rf
cd ..
#rm -rf Utils/Font\ generation/
echo Archiving...
tar zchvf "$PRODUCTVER".tar.gz $PRODUCTVER/
#!/bin/bash
set -e
test -e ProductInfo.h && cd ..
if ! test -d src; then
echo Run this script from the top directory.
exit 1
fi
source Utils/GetProductVer.sh src/ProductInfo.h
PRODUCTVER="$PRODUCTVER-src"
if test -e $PRODUCTVER; then
echo "\"$PRODUCTVER\" already exists."
exit 1
fi
echo Copying...
mkdir $PRODUCTVER
cp -dpR autoconf $PRODUCTVER/
#cp -dpR Utils $PRODUCTVER/
cp -dpR src $PRODUCTVER/
cp Docs/Copying.MAD Docs/Licenses.txt Makefile.am aclocal.m4 \
configure Makefile.in configure.ac $PRODUCTVER
echo Pruning...
cd $PRODUCTVER/src
# Obsolete and going away:
rm -rf SDL-1.2.5
rm -rf SDL-1.2.6
# Incomplete:
rm -rf Texture Font Generator
# Xbox:
rm -rf SDLx-0.02
# Unused:
rm -rf smlobby
# Windows-only stuff. Let's leave some in the archive to make the GPL happy.
# I don't want to spend an extra half hour to upload separate Windows and
# *nix source archives.
#rm -rf mad-0.15.0b
rm -rf lua-5.0
rm -rf vorbis
rm -rf BaseClasses
rm -rf ddk
rm -rf smpackage
rm -rf sdl_xbox_includes
rm -rf SDLx-0.02.rar
cd ..
find . -type d -name 'CVS' | xargs rm -rf
find . -type f -name '*.lib' | xargs rm -rf
find . -type f -name '*.exe' | xargs rm -rf
find . -type f -name '*.a' | xargs rm -rf
find . -type f -name '*.o' | xargs rm -rf
cd ..
#rm -rf Utils/Font\ generation/
echo Archiving...
tar zchvf "$PRODUCTVER".tar.gz $PRODUCTVER/
+15 -15
View File
@@ -1,15 +1,15 @@
#!/bin/sh
for i in ffmpeg/libavcodec/ppc/*.[hc] \
ffmpeg/libswscale/yuv2rgb_altivec.c; do
sed -i '' -e '1i\
#ifdef __ppc__
$a\
#endif' $i
done
for i in ffmpeg/libavcodec/i386/*.[hc]; do
sed -i '' -e '1i\
#ifdef __i386__
$a\
#endif' $i
done
#!/bin/sh
for i in ffmpeg/libavcodec/ppc/*.[hc] \
ffmpeg/libswscale/yuv2rgb_altivec.c; do
sed -i '' -e '1i\
#ifdef __ppc__
$a\
#endif' $i
done
for i in ffmpeg/libavcodec/i386/*.[hc]; do
sed -i '' -e '1i\
#ifdef __i386__
$a\
#endif' $i
done
+764 -764
View File
File diff suppressed because it is too large Load Diff
+63 -63
View File
@@ -1,63 +1,63 @@
#ifndef NOTES_LOADER_SMA_H
#define NOTES_LOADER_SMA_H
#include "GameConstantsAndTypes.h"
#include "BackgroundUtil.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/** @brief Reads a Song from a .SMA file. */
namespace SMALoader
{
void LoadFromSMATokens( RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out );
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
bool LoadFromSMAFile( const RString &sPath, Song &out );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadTimingFromFile( const RString &fn, TimingData &out );
void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
};
#endif
/**
* @file
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef NOTES_LOADER_SMA_H
#define NOTES_LOADER_SMA_H
#include "GameConstantsAndTypes.h"
#include "BackgroundUtil.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/** @brief Reads a Song from a .SMA file. */
namespace SMALoader
{
void LoadFromSMATokens( RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out );
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
bool LoadFromSMAFile( const RString &sPath, Song &out );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadTimingFromFile( const RString &fn, TimingData &out );
void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
};
#endif
/**
* @file
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1260 -1260
View File
File diff suppressed because it is too large Load Diff
+103 -103
View File
@@ -1,103 +1,103 @@
/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */
#ifndef NotesLoaderSSC_H
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/**
* @brief The various states while parsing a .ssc file.
*/
enum SSCLoadingStates
{
GETTING_SONG_INFO, /**< Retrieving song information. */
GETTING_STEP_INFO, /**< Retrieving step information. */
GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */
GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */
NUM_SSCLoadingStates /**< The number of states used. */
};
const float VERSION_RADAR_FAKE = 0.53f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
*/
namespace SSCLoader
{
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
bool LoadFromDir( const RString &sPath, Song &out );
/**
* @brief Attempt to load the specified ssc file.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .ssc files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
/**
* @brief Attempt to load an edit from the hard drive.
* @param sEditFilePath a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Attempt to parse the edit file in question.
* @param msd the edit file itself.
* @param sEditFilePath a const reference to a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
void TidyUpData( Song &song, bool bFromCache );
}
#endif
/**
* @file
* @author Jason Felds (c) 2011
*
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */
#ifndef NotesLoaderSSC_H
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
/**
* @brief The various states while parsing a .ssc file.
*/
enum SSCLoadingStates
{
GETTING_SONG_INFO, /**< Retrieving song information. */
GETTING_STEP_INFO, /**< Retrieving step information. */
GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */
GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */
NUM_SSCLoadingStates /**< The number of states used. */
};
const float VERSION_RADAR_FAKE = 0.53f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
*/
namespace SSCLoader
{
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
bool LoadFromDir( const RString &sPath, Song &out );
/**
* @brief Attempt to load the specified ssc file.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .ssc files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
/**
* @brief Attempt to load an edit from the hard drive.
* @param sEditFilePath a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Attempt to parse the edit file in question.
* @param msd the edit file itself.
* @param sEditFilePath a const reference to a path on the hard drive to check.
* @param slot the Profile of the user with the edit.
* @param bAddStepsToSong a flag to determine if we add the edit steps to the song file.
* @return its success or failure.
*/
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
void TidyUpData( Song &song, bool bFromCache );
}
#endif
/**
* @file
* @author Jason Felds (c) 2011
*
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+46 -46
View File
@@ -1,46 +1,46 @@
#ifndef RAGE_FILE_MANAGER_READAHEAD_H
#define RAGE_FILE_MANAGER_READAHEAD_H
#include "RageFileBasic.h"
/** @brief Utilities for reading the RageFiles. */
namespace RageFileManagerReadAhead
{
void Init();
void Shutdown();
// Nonblockingly read ahead iBytes in pFile, starting at the current file position.
void ReadAhead( RageFileBasic *pFile, int iBytes );
/* Discard iBytes of kernel cache, starting at the current file position plus
* iRelativePosition (which may be negative). */
void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes );
void CacheHintStreaming( RageFileBasic *pFile );
};
#endif
/*
* Copyright (c) 2010 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef RAGE_FILE_MANAGER_READAHEAD_H
#define RAGE_FILE_MANAGER_READAHEAD_H
#include "RageFileBasic.h"
/** @brief Utilities for reading the RageFiles. */
namespace RageFileManagerReadAhead
{
void Init();
void Shutdown();
// Nonblockingly read ahead iBytes in pFile, starting at the current file position.
void ReadAhead( RageFileBasic *pFile, int iBytes );
/* Discard iBytes of kernel cache, starting at the current file position plus
* iRelativePosition (which may be negative). */
void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes );
void CacheHintStreaming( RageFileBasic *pFile );
};
#endif
/*
* Copyright (c) 2010 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+318 -318
View File
@@ -1,318 +1,318 @@
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS) || defined(_XBOX)
# include "libpng/include/png.h"
# if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <png.h>
#endif
#if defined(_XBOX)
# include <malloc.h> // for alloca
# include "archutils/Xbox/VirtualMemory.h"
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
#if defined(XBOX)
while(png == NULL)
{
if(!vmem_Manager.DecommitLRU())
break;
png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
}
#endif
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS) || defined(_XBOX)
# include "libpng/include/png.h"
# if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <png.h>
#endif
#if defined(_XBOX)
# include <malloc.h> // for alloca
# include "archutils/Xbox/VirtualMemory.h"
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
#if defined(XBOX)
while(png == NULL)
{
if(!vmem_Manager.DecommitLRU())
break;
png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
}
#endif
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+168 -168
View File
@@ -1,168 +1,168 @@
#include "global.h"
#include "RageSurface_Save_PNG.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageFile.h"
#include "RageLog.h"
#include "RageUtil.h"
#if defined(WINDOWS) || defined(_XBOX)
#include "libpng/include/png.h"
#if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
#endif
#else
#include <png.h>
#endif
static void SafePngError( png_struct *pPng, const RString &sStr )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns, it may never be destructed and leak. */
static char error[256];
strncpy( error, sStr, sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( pPng, error );
}
static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Write( pData, iSize );
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
static void RageFile_png_flush( png_struct *pPng )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Flush();
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
struct error_info
{
char *szErr;
};
static void PNG_Error( png_struct *pPng, const char *szError )
{
error_info *pInfo = (error_info *) png_get_error_ptr(pPng);
strncpy( pInfo->szErr, szError, 1024 );
pInfo->szErr[1023] = 0;
longjmp( png_jmpbuf(pPng), 1 );
}
static void PNG_Warning( png_struct *png, const char *warning )
{
LOG->Trace( "saving PNG: warning: %s", warning );
}
/* Since libpng forces us to use longjmp, this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn )
{
bool bAlpha = pImgIn->format->Amask != 0;
RageSurface *pImg;
bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( 0x000000FF ) );
if( !bDeleteImg )
pImg = pImgIn;
error_info error;
error.szErr = szErrorbuf;
png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( pPng == NULL )
{
sprintf( szErrorbuf, "creating png_create_write_struct failed");
return false;
}
png_info *pInfo = png_create_info_struct(pPng);
if( pInfo == NULL )
{
png_destroy_read_struct( &pPng, NULL, NULL );
if( bDeleteImg )
delete pImg;
sprintf( szErrorbuf, "creating png_create_info_struct failed");
return false;
}
if( setjmp(png_jmpbuf(pPng)) )
{
png_destroy_read_struct( &pPng, &pInfo, NULL );
return false;
}
png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush );
png_set_compression_level( pPng, 1 );
png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
png_write_info( pPng, pInfo );
png_set_filler( pPng, 0, PNG_FILLER_AFTER );
png_byte *pixels = (png_byte *) pImg->pixels;
for( int y = 0; y < pImg->h; y++ )
png_write_row( pPng, pixels + pImg->pitch*y );
png_write_end( pPng, pInfo );
png_destroy_write_struct( &pPng, &pInfo );
/* Free the converted image. */
if( bDeleteImg )
delete pImg;
return true;
}
bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError )
{
char szErrorBuf[1024];
if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) )
{
sError = szErrorBuf;
return false;
}
return true;
}
/*
* (c) 2004-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Save_PNG.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageFile.h"
#include "RageLog.h"
#include "RageUtil.h"
#if defined(WINDOWS) || defined(_XBOX)
#include "libpng/include/png.h"
#if defined(_MSC_VER)
# if defined(_XBOX)
# pragma comment(lib, "libpng/lib/xboxlibpng.lib")
# else
# pragma comment(lib, "libpng/lib/libpng.lib")
# endif
#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
#endif
#else
#include <png.h>
#endif
static void SafePngError( png_struct *pPng, const RString &sStr )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns, it may never be destructed and leak. */
static char error[256];
strncpy( error, sStr, sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( pPng, error );
}
static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Write( pData, iSize );
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
static void RageFile_png_flush( png_struct *pPng )
{
RageFile *pFile = (RageFile *) png_get_io_ptr(pPng);
int iGot = pFile->Flush();
if( iGot == -1 )
SafePngError( pPng, pFile->GetError() );
}
struct error_info
{
char *szErr;
};
static void PNG_Error( png_struct *pPng, const char *szError )
{
error_info *pInfo = (error_info *) png_get_error_ptr(pPng);
strncpy( pInfo->szErr, szError, 1024 );
pInfo->szErr[1023] = 0;
longjmp( png_jmpbuf(pPng), 1 );
}
static void PNG_Warning( png_struct *png, const char *warning )
{
LOG->Trace( "saving PNG: warning: %s", warning );
}
/* Since libpng forces us to use longjmp, this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn )
{
bool bAlpha = pImgIn->format->Amask != 0;
RageSurface *pImg;
bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( 0x000000FF ) );
if( !bDeleteImg )
pImg = pImgIn;
error_info error;
error.szErr = szErrorbuf;
png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( pPng == NULL )
{
sprintf( szErrorbuf, "creating png_create_write_struct failed");
return false;
}
png_info *pInfo = png_create_info_struct(pPng);
if( pInfo == NULL )
{
png_destroy_read_struct( &pPng, NULL, NULL );
if( bDeleteImg )
delete pImg;
sprintf( szErrorbuf, "creating png_create_info_struct failed");
return false;
}
if( setjmp(png_jmpbuf(pPng)) )
{
png_destroy_read_struct( &pPng, &pInfo, NULL );
return false;
}
png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush );
png_set_compression_level( pPng, 1 );
png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
png_write_info( pPng, pInfo );
png_set_filler( pPng, 0, PNG_FILLER_AFTER );
png_byte *pixels = (png_byte *) pImg->pixels;
for( int y = 0; y < pImg->h; y++ )
png_write_row( pPng, pixels + pImg->pitch*y );
png_write_end( pPng, pInfo );
png_destroy_write_struct( &pPng, &pInfo );
/* Free the converted image. */
if( bDeleteImg )
delete pImg;
return true;
}
bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError )
{
char szErrorBuf[1024];
if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) )
{
sError = szErrorBuf;
return false;
}
return true;
}
/*
* (c) 2004-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+447 -447
View File
@@ -1,447 +1,447 @@
#include "global.h"
#include "InputHandler_Linux_Event.h"
#include "RageLog.h"
#include "RageUtil.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event );
bool InputHandler_Linux_Event::m_bFoundAnyJoysticks;
static RString BustypeToString( int iBus )
{
switch( iBus )
{
// case BUS_ADB:
// case BUS_AMIGA: return "amiga input";
case BUS_BLUETOOTH: return "Bluetooth";
case BUS_GAMEPORT: return "gameport";
// case BUS_HIL:
// case BUS_HOST:
// case BUS_I2C:
case BUS_I8042: return "keyboard";
case BUS_ISA: return "ISA";
case BUS_ISAPNP: return "ISAPNP";
case BUS_PARPORT: return "parallel port";
case BUS_PCI: return "PCI";
case BUS_RS232: return "serial port";
case BUS_USB: return "USB";
case BUS_XTKBD: return "XT keyboard";
default: return ssprintf("unknown bus %x", iBus);
}
}
struct EventDevice
{
EventDevice();
~EventDevice();
bool Open( RString sFile, InputDevice dev );
bool IsOpen() const { return m_iFD != -1; }
void Close()
{
if( m_iFD != -1 )
close( m_iFD );
m_iFD = -1;
}
int m_iFD;
RString m_sPath;
RString m_sName;
InputDevice m_Dev;
int aiAbsMin[ABS_MAX];
int aiAbsMax[ABS_MAX];
DeviceButton aiAbsMappingHigh[ABS_MAX];
DeviceButton aiAbsMappingLow[ABS_MAX];
};
static vector<EventDevice *> g_apEventDevices;
/* Return true if the numbered event device exists. sysfs may not always be
* there; return false if we don't know. */
static bool EventDeviceExists( int iNum )
{
RString sDir = ssprintf( "/sys/class" );
struct stat st;
if( stat(sDir, &st) == -1 )
return true;
RString sFile = ssprintf( "/sys/class/input/event%i", iNum );
return stat(sFile, &st) == 0;
}
static bool BitIsSet( const uint8_t *pArray, uint32_t iBit )
{
return !!(pArray[iBit/8] & (1<<(iBit%8)));
}
EventDevice::EventDevice()
{
m_iFD = -1;
}
bool EventDevice::Open( RString sFile, InputDevice dev )
{
m_sPath = sFile;
m_Dev = dev;
m_iFD = open( sFile, O_RDWR );
if( m_iFD == -1 )
{
if( errno == ENODEV )
return false;
if( !EventDeviceExists(m_iFD) )
return false;
LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) );
return false;
}
static bool bLogged = false;
if( !bLogged )
{
bLogged = true;
int iVersion;
if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 )
LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) );
else
LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF );
}
char szName[1024];
if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 )
{
LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) );
m_sName = "(unknown)";
}
else
{
m_sName = szName;
}
input_id DevInfo;
if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 )
{
LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) );
}
else
{
LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(),
BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product,
DevInfo.version, m_sName.c_str() );
}
uint8_t iABSMask[ABS_MAX/8 + 1];
memset( iABSMask, 0, sizeof(iABSMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) );
if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) )
{
LOG->Info( " Not a joystick; ignored" );
Close();
return false;
}
uint8_t iKeyMask[KEY_MAX/8 + 1];
memset( iKeyMask, 0, sizeof(iKeyMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) );
uint8_t iEventTypes[EV_MAX/8];
memset( iEventTypes, 0, sizeof(iEventTypes) );
if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 )
LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) );
{
vector<RString> setEventTypes;
if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" );
if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" );
if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" );
if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" );
if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" );
if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" );
if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" );
if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" );
if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" );
if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" );
if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" );
if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" );
LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() );
}
int iTotalKeys = 0;
for( int i = 0; i < KEY_MAX; ++i )
{
if( !BitIsSet(iKeyMask, i) )
continue;
++iTotalKeys;
}
int iTotalAxes = 0;
const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 };
int iNextExtraAxis = 0;
for( int i = 0; i < ABS_MAX; ++i )
{
if( !BitIsSet(iABSMask, i) )
continue;
struct input_absinfo absinfo;
if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 )
{
LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) );
continue;
}
//LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i",
// i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat );
aiAbsMin[i] = absinfo.minimum;
aiAbsMax[i] = absinfo.maximum;
aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i);
aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i);
if( i == ABS_X )
{
aiAbsMappingHigh[i] = JOY_RIGHT;
aiAbsMappingLow[i] = JOY_LEFT;
}
else if( i == ABS_Y )
{
aiAbsMappingHigh[i] = JOY_DOWN;
aiAbsMappingLow[i] = JOY_UP;
}
else if( i == ABS_Z )
{
aiAbsMappingHigh[i] = JOY_Z_DOWN;
aiAbsMappingLow[i] = JOY_Z_UP;
}
else if( i == ABS_RX )
{
aiAbsMappingHigh[i] = JOY_ROT_RIGHT;
aiAbsMappingLow[i] = JOY_ROT_LEFT;
}
else if( i == ABS_RY )
{
aiAbsMappingHigh[i] = JOY_ROT_DOWN;
aiAbsMappingLow[i] = JOY_ROT_UP;
}
else if( i == ABS_RZ )
{
aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN;
aiAbsMappingLow[i] = JOY_ROT_Z_UP;
}
else if( i == ABS_HAT0X )
{
aiAbsMappingHigh[i] = JOY_HAT_RIGHT;
aiAbsMappingLow[i] = JOY_HAT_LEFT;
}
else if( i == ABS_HAT0Y )
{
aiAbsMappingHigh[i] = JOY_HAT_UP;
aiAbsMappingLow[i] = JOY_HAT_DOWN;
}
else
{
if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) )
{
aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis];
aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 );
++iNextExtraAxis;
}
}
++iTotalAxes;
}
LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes );
return true;
}
EventDevice::~EventDevice()
{
Close();
}
InputHandler_Linux_Event::InputHandler_Linux_Event()
{
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" );
return;
}
/* Permission problems are likely. We want to warn about them only if there's actually
* an underlying device, but if we can't open the device, the only way we can tell if
* there'd be anything there is sysfs. That won't always be there. */
m_bFoundAnyJoysticks = false;
InputDevice NextDevice = DEVICE_JOY1;
for( int i = 0; i < 64; ++i )
{
RString sFile = ssprintf( "/dev/input/event%i", i );
g_apEventDevices.push_back( new EventDevice );
EventDevice *pDev = g_apEventDevices.back();
if( !pDev->Open(sFile, NextDevice) )
{
delete pDev;
g_apEventDevices.pop_back();
continue;
}
NextDevice = enum_add2(NextDevice, 1);
m_bFoundAnyJoysticks = true;
}
m_bShutdown = false;
if( m_bFoundAnyJoysticks )
{
m_InputThread.SetName( "Event input thread" );
m_InputThread.Create( InputThread_Start, this );
/* We loaded joysticks, so disable joydev. */
}
}
InputHandler_Linux_Event::~InputHandler_Linux_Event()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
delete g_apEventDevices[i];
g_apEventDevices.clear();
}
int InputHandler_Linux_Event::InputThread_Start( void *p )
{
((InputHandler_Linux_Event *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Event::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO( &fdset );
int iMaxFD = -1;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
int iFD = g_apEventDevices[i]->m_iFD;
if( !g_apEventDevices[i]->IsOpen() )
continue;
FD_SET( iFD, &fdset );
iMaxFD = max( iMaxFD, iFD );
}
if( iMaxFD == -1 )
break;
struct timeval zero = {0,100000};
if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
if( !g_apEventDevices[i]->IsOpen() )
continue;
if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) )
continue;
input_event event;
int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) );
if( ret == -1 )
{
LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) );
g_apEventDevices[i]->Close();
continue;
}
if( ret != sizeof(event) )
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
g_apEventDevices[i]->Close();
continue;
}
switch (event.type) {
case EV_KEY: {
int iNum = event.code;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) );
break;
}
case EV_ABS: {
ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) );
DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code];
DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code];
float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) );
break;
}
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for( unsigned i = 0; i < g_apEventDevices.size(); ++i )
{
EventDevice *pDev = g_apEventDevices[i];
vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) );
}
}
/*
* (c) 2003-2008 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "InputHandler_Linux_Event.h"
#include "RageLog.h"
#include "RageUtil.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event );
bool InputHandler_Linux_Event::m_bFoundAnyJoysticks;
static RString BustypeToString( int iBus )
{
switch( iBus )
{
// case BUS_ADB:
// case BUS_AMIGA: return "amiga input";
case BUS_BLUETOOTH: return "Bluetooth";
case BUS_GAMEPORT: return "gameport";
// case BUS_HIL:
// case BUS_HOST:
// case BUS_I2C:
case BUS_I8042: return "keyboard";
case BUS_ISA: return "ISA";
case BUS_ISAPNP: return "ISAPNP";
case BUS_PARPORT: return "parallel port";
case BUS_PCI: return "PCI";
case BUS_RS232: return "serial port";
case BUS_USB: return "USB";
case BUS_XTKBD: return "XT keyboard";
default: return ssprintf("unknown bus %x", iBus);
}
}
struct EventDevice
{
EventDevice();
~EventDevice();
bool Open( RString sFile, InputDevice dev );
bool IsOpen() const { return m_iFD != -1; }
void Close()
{
if( m_iFD != -1 )
close( m_iFD );
m_iFD = -1;
}
int m_iFD;
RString m_sPath;
RString m_sName;
InputDevice m_Dev;
int aiAbsMin[ABS_MAX];
int aiAbsMax[ABS_MAX];
DeviceButton aiAbsMappingHigh[ABS_MAX];
DeviceButton aiAbsMappingLow[ABS_MAX];
};
static vector<EventDevice *> g_apEventDevices;
/* Return true if the numbered event device exists. sysfs may not always be
* there; return false if we don't know. */
static bool EventDeviceExists( int iNum )
{
RString sDir = ssprintf( "/sys/class" );
struct stat st;
if( stat(sDir, &st) == -1 )
return true;
RString sFile = ssprintf( "/sys/class/input/event%i", iNum );
return stat(sFile, &st) == 0;
}
static bool BitIsSet( const uint8_t *pArray, uint32_t iBit )
{
return !!(pArray[iBit/8] & (1<<(iBit%8)));
}
EventDevice::EventDevice()
{
m_iFD = -1;
}
bool EventDevice::Open( RString sFile, InputDevice dev )
{
m_sPath = sFile;
m_Dev = dev;
m_iFD = open( sFile, O_RDWR );
if( m_iFD == -1 )
{
if( errno == ENODEV )
return false;
if( !EventDeviceExists(m_iFD) )
return false;
LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) );
return false;
}
static bool bLogged = false;
if( !bLogged )
{
bLogged = true;
int iVersion;
if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 )
LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) );
else
LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF );
}
char szName[1024];
if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 )
{
LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) );
m_sName = "(unknown)";
}
else
{
m_sName = szName;
}
input_id DevInfo;
if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 )
{
LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) );
}
else
{
LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(),
BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product,
DevInfo.version, m_sName.c_str() );
}
uint8_t iABSMask[ABS_MAX/8 + 1];
memset( iABSMask, 0, sizeof(iABSMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) );
if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) )
{
LOG->Info( " Not a joystick; ignored" );
Close();
return false;
}
uint8_t iKeyMask[KEY_MAX/8 + 1];
memset( iKeyMask, 0, sizeof(iKeyMask) );
if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 )
LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) );
uint8_t iEventTypes[EV_MAX/8];
memset( iEventTypes, 0, sizeof(iEventTypes) );
if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 )
LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) );
{
vector<RString> setEventTypes;
if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" );
if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" );
if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" );
if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" );
if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" );
if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" );
if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" );
if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" );
if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" );
if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" );
if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" );
if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" );
LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() );
}
int iTotalKeys = 0;
for( int i = 0; i < KEY_MAX; ++i )
{
if( !BitIsSet(iKeyMask, i) )
continue;
++iTotalKeys;
}
int iTotalAxes = 0;
const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 };
int iNextExtraAxis = 0;
for( int i = 0; i < ABS_MAX; ++i )
{
if( !BitIsSet(iABSMask, i) )
continue;
struct input_absinfo absinfo;
if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 )
{
LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) );
continue;
}
//LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i",
// i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat );
aiAbsMin[i] = absinfo.minimum;
aiAbsMax[i] = absinfo.maximum;
aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i);
aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i);
if( i == ABS_X )
{
aiAbsMappingHigh[i] = JOY_RIGHT;
aiAbsMappingLow[i] = JOY_LEFT;
}
else if( i == ABS_Y )
{
aiAbsMappingHigh[i] = JOY_DOWN;
aiAbsMappingLow[i] = JOY_UP;
}
else if( i == ABS_Z )
{
aiAbsMappingHigh[i] = JOY_Z_DOWN;
aiAbsMappingLow[i] = JOY_Z_UP;
}
else if( i == ABS_RX )
{
aiAbsMappingHigh[i] = JOY_ROT_RIGHT;
aiAbsMappingLow[i] = JOY_ROT_LEFT;
}
else if( i == ABS_RY )
{
aiAbsMappingHigh[i] = JOY_ROT_DOWN;
aiAbsMappingLow[i] = JOY_ROT_UP;
}
else if( i == ABS_RZ )
{
aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN;
aiAbsMappingLow[i] = JOY_ROT_Z_UP;
}
else if( i == ABS_HAT0X )
{
aiAbsMappingHigh[i] = JOY_HAT_RIGHT;
aiAbsMappingLow[i] = JOY_HAT_LEFT;
}
else if( i == ABS_HAT0Y )
{
aiAbsMappingHigh[i] = JOY_HAT_UP;
aiAbsMappingLow[i] = JOY_HAT_DOWN;
}
else
{
if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) )
{
aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis];
aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 );
++iNextExtraAxis;
}
}
++iTotalAxes;
}
LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes );
return true;
}
EventDevice::~EventDevice()
{
Close();
}
InputHandler_Linux_Event::InputHandler_Linux_Event()
{
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" );
return;
}
/* Permission problems are likely. We want to warn about them only if there's actually
* an underlying device, but if we can't open the device, the only way we can tell if
* there'd be anything there is sysfs. That won't always be there. */
m_bFoundAnyJoysticks = false;
InputDevice NextDevice = DEVICE_JOY1;
for( int i = 0; i < 64; ++i )
{
RString sFile = ssprintf( "/dev/input/event%i", i );
g_apEventDevices.push_back( new EventDevice );
EventDevice *pDev = g_apEventDevices.back();
if( !pDev->Open(sFile, NextDevice) )
{
delete pDev;
g_apEventDevices.pop_back();
continue;
}
NextDevice = enum_add2(NextDevice, 1);
m_bFoundAnyJoysticks = true;
}
m_bShutdown = false;
if( m_bFoundAnyJoysticks )
{
m_InputThread.SetName( "Event input thread" );
m_InputThread.Create( InputThread_Start, this );
/* We loaded joysticks, so disable joydev. */
}
}
InputHandler_Linux_Event::~InputHandler_Linux_Event()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
delete g_apEventDevices[i];
g_apEventDevices.clear();
}
int InputHandler_Linux_Event::InputThread_Start( void *p )
{
((InputHandler_Linux_Event *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Event::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO( &fdset );
int iMaxFD = -1;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
int iFD = g_apEventDevices[i]->m_iFD;
if( !g_apEventDevices[i]->IsOpen() )
continue;
FD_SET( iFD, &fdset );
iMaxFD = max( iMaxFD, iFD );
}
if( iMaxFD == -1 )
break;
struct timeval zero = {0,100000};
if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
{
if( !g_apEventDevices[i]->IsOpen() )
continue;
if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) )
continue;
input_event event;
int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) );
if( ret == -1 )
{
LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) );
g_apEventDevices[i]->Close();
continue;
}
if( ret != sizeof(event) )
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
g_apEventDevices[i]->Close();
continue;
}
switch (event.type) {
case EV_KEY: {
int iNum = event.code;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) );
break;
}
case EV_ABS: {
ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) );
DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code];
DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code];
float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) );
break;
}
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for( unsigned i = 0; i < g_apEventDevices.size(); ++i )
{
EventDevice *pDev = g_apEventDevices[i];
vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) );
}
}
/*
* (c) 2003-2008 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -1,227 +1,227 @@
#include "global.h"
#include "InputHandler_Linux_Joystick.h"
#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks
#include "RageLog.h"
#include "RageUtil.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/joystick.h>
#include <set>
REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick );
static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] =
{
"/dev/js0",
"/dev/js1",
"/dev/input/js0",
"/dev/input/js1",
};
InputHandler_Linux_Joystick::InputHandler_Linux_Joystick()
{
LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" );
for(int i = 0; i < NUM_JOYSTICKS; ++i)
fds[i] = -1;
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" );
return;
}
/* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably
* the same device; keep track of device IDs so we don't open the same joystick
* twice. */
set< pair<int,int> > devices;
bool bFoundAnyJoysticks = false;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
struct stat st;
if( stat( Paths[i], &st ) == -1 )
{
if( errno != ENOENT )
LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) );
continue;
}
if( !S_ISCHR( st.st_mode ) )
{
LOG->Warn( "Ignoring %s: not a character device", Paths[i] );
continue;
}
pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) );
if( devices.find(dev) != devices.end() )
continue; /* dupe */
devices.insert( dev );
fds[i] = open( Paths[i], O_RDONLY );
if(fds[i] != -1)
{
char szName[1024];
ZERO( szName );
if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 )
m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] );
else
m_sDescription[i] = szName;
LOG->Info("Opened %s", Paths[i]);
bFoundAnyJoysticks = true;
}
}
m_bShutdown = false;
if( bFoundAnyJoysticks )
{
m_InputThread.SetName( "Joystick thread" );
m_InputThread.Create( InputThread_Start, this );
InputHandler_Linux_Event::m_bFoundAnyJoysticks = true;
}
}
InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for(int i = 0; i < NUM_JOYSTICKS; ++i)
if(fds[i] != -1) close(fds[i]);
}
int InputHandler_Linux_Joystick::InputThread_Start( void *p )
{
((InputHandler_Linux_Joystick *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Joystick::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO(&fdset);
int max_fd = -1;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
FD_SET(fds[i], &fdset);
max_fd = max(max_fd, fds[i]);
}
if(max_fd == -1)
break;
struct timeval zero = {0,100000};
if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if( fds[i] == -1 )
continue;
if(!FD_ISSET(fds[i], &fdset))
continue;
js_event event;
int ret = read(fds[i], &event, sizeof(event));
if(ret != sizeof(event))
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
close(fds[i]);
fds[i] = -1;
continue;
}
InputDevice id = InputDevice(DEVICE_JOY1 + i);
event.type &= ~JS_EVENT_INIT;
switch (event.type) {
case JS_EVENT_BUTTON: {
int iNum = event.number;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) );
break;
}
case JS_EVENT_AXIS: {
DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number);
DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number);
float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f );
ButtonPressed( DeviceInput(id, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(id, pos, max(+l,0), now) );
break;
}
default:
LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i);
close(fds[i]);
fds[i] = -1;
continue;
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) );
}
}
/*
* (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "InputHandler_Linux_Joystick.h"
#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks
#include "RageLog.h"
#include "RageUtil.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/joystick.h>
#include <set>
REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick );
static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] =
{
"/dev/js0",
"/dev/js1",
"/dev/input/js0",
"/dev/input/js1",
};
InputHandler_Linux_Joystick::InputHandler_Linux_Joystick()
{
LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" );
for(int i = 0; i < NUM_JOYSTICKS; ++i)
fds[i] = -1;
if( InputHandler_Linux_Event::m_bFoundAnyJoysticks )
{
LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" );
return;
}
/* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably
* the same device; keep track of device IDs so we don't open the same joystick
* twice. */
set< pair<int,int> > devices;
bool bFoundAnyJoysticks = false;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
struct stat st;
if( stat( Paths[i], &st ) == -1 )
{
if( errno != ENOENT )
LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) );
continue;
}
if( !S_ISCHR( st.st_mode ) )
{
LOG->Warn( "Ignoring %s: not a character device", Paths[i] );
continue;
}
pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) );
if( devices.find(dev) != devices.end() )
continue; /* dupe */
devices.insert( dev );
fds[i] = open( Paths[i], O_RDONLY );
if(fds[i] != -1)
{
char szName[1024];
ZERO( szName );
if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 )
m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] );
else
m_sDescription[i] = szName;
LOG->Info("Opened %s", Paths[i]);
bFoundAnyJoysticks = true;
}
}
m_bShutdown = false;
if( bFoundAnyJoysticks )
{
m_InputThread.SetName( "Joystick thread" );
m_InputThread.Create( InputThread_Start, this );
InputHandler_Linux_Event::m_bFoundAnyJoysticks = true;
}
}
InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick()
{
if( m_InputThread.IsCreated() )
{
m_bShutdown = true;
LOG->Trace( "Shutting down joystick thread ..." );
m_InputThread.Wait();
LOG->Trace( "Joystick thread shut down." );
}
for(int i = 0; i < NUM_JOYSTICKS; ++i)
if(fds[i] != -1) close(fds[i]);
}
int InputHandler_Linux_Joystick::InputThread_Start( void *p )
{
((InputHandler_Linux_Joystick *) p)->InputThread();
return 0;
}
void InputHandler_Linux_Joystick::InputThread()
{
while( !m_bShutdown )
{
fd_set fdset;
FD_ZERO(&fdset);
int max_fd = -1;
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
FD_SET(fds[i], &fdset);
max_fd = max(max_fd, fds[i]);
}
if(max_fd == -1)
break;
struct timeval zero = {0,100000};
if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 )
continue;
RageTimer now;
printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if( fds[i] == -1 )
continue;
if(!FD_ISSET(fds[i], &fdset))
continue;
js_event event;
int ret = read(fds[i], &event, sizeof(event));
if(ret != sizeof(event))
{
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
close(fds[i]);
fds[i] = -1;
continue;
}
InputDevice id = InputDevice(DEVICE_JOY1 + i);
event.type &= ~JS_EVENT_INIT;
switch (event.type) {
case JS_EVENT_BUTTON: {
int iNum = event.number;
// In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button)
// is being reported as 32 instead of 0. Correct for this.
wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant?
ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) );
break;
}
case JS_EVENT_AXIS: {
DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number);
DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number);
float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f );
ButtonPressed( DeviceInput(id, neg, max(-l,0), now) );
ButtonPressed( DeviceInput(id, pos, max(+l,0), now) );
break;
}
default:
LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i);
close(fds[i]);
fds[i] = -1;
continue;
}
}
}
InputHandler::UpdateTimer();
}
void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut )
{
for(int i = 0; i < NUM_JOYSTICKS; ++i)
{
if (fds[i] < 0)
continue;
vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) );
}
}
/*
* (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
@@ -1,392 +1,392 @@
#include "global.h"
#include "MemoryCardDriverThreaded_Linux.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageTimer.h"
#include <cerrno>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice )
{
if( access(pDevice->sOsMountDir, W_OK) == -1 )
{
pDevice->SetError( "TestFailed" );
return false;
}
return true;
}
static bool ExecuteCommand( const RString &sCommand )
{
LOG->Trace( "executing '%s'", sCommand.c_str() );
int ret = system(sCommand);
LOG->Trace( "done executing '%s'", sCommand.c_str() );
if( ret != 0 )
{
RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret);
if( ret == -1 )
sError += ssprintf(": %s", sCommand.c_str());
LOG->Warn( "%s", sError.c_str() );
}
return ret == 0;
}
static bool ReadFile( const RString &sPath, RString &sBuf )
{
sBuf.clear();
int fd = open( sPath, O_RDONLY );
if( fd == -1 )
{
LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
while(1)
{
char buf[1024];
int iGot = read( fd, buf, sizeof(buf) );
if( iGot == -1 )
{
close(fd);
LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
sBuf.append( buf, iGot );
if( iGot < (int) sizeof(buf) )
break;
}
close(fd);
return true;
}
static void GetFileList( const RString &sPath, vector<RString> &out )
{
out.clear();
DIR *dp = opendir( sPath );
if( dp == NULL )
return; // false; // XXX warn
while( const struct dirent *ent = readdir(dp) )
out.push_back( ent->d_name );
closedir( dp );
}
bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged()
{
RString sThisDevices;
/* If a device is removed and reinserted, the inode of the /sys/block entry
* will change. */
RString sDevicePath = "/sys/block/";
vector<RString> asDevices;
GetFileList( sDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
struct stat buf;
if( stat( sDevicePath + asDevices[i], &buf ) == -1 )
continue; // XXX warn
sThisDevices += ssprintf( "%i,", (int) buf.st_ino );
}
bool bChanged = sThisDevices != m_sLastDevices;
m_sLastDevices = sThisDevices;
if( bChanged )
LOG->Trace( "Change in USB storage devices detected." );
return bChanged;
}
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut )
{
LOG->Trace( "GetUSBStorageDevices" );
vDevicesOut.clear();
{
vector<RString> asDevices;
RString sBlockDevicePath = "/sys/block/";
GetFileList( sBlockDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
const RString &sDevice = asDevices[i];
if( sDevice == "." || sDevice == ".." )
continue;
UsbStorageDevice usbd;
RString sPath = sBlockDevicePath + sDevice + "/";
usbd.sSysPath = sPath;
/* Ignore non-removable devices. */
RString sBuf;
if( !ReadFile( sPath + "removable", sBuf ) )
continue; // already warned
if( atoi(sBuf) != 1 )
continue;
/*
* The kernel isn't exposing all of /sys atomically, so we end up missing
* the partition due to it not being shown yet. It won't show up until the
* kernel has scanned the partition table, which can take a variable amount
* of time, sometimes over a second. Watch for the "queue" sysfs directory,
* which is created after this, to tell when partition directories are created.
*/
RageTimer WaitUntil;
WaitUntil += 5;
RString sQueueFilePath = usbd.sSysPath + "queue";
while(1)
{
if( WaitUntil.Ago() >= 0 )
{
LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() );
break;
}
if( access(usbd.sSysPath, F_OK) == -1 )
{
LOG->Warn( "Block directory %s went away while we were waiting for %s",
usbd.sSysPath.c_str(), sQueueFilePath.c_str() );
break;
}
if( access(sQueueFilePath, F_OK) != -1 )
break;
usleep(10000);
}
/* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */
if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 )
{
LOG->Trace("OK");
usbd.sDevice = "/dev/" + sDevice + "1";
}
else
{
LOG->Trace("error %s", strerror(errno));
usbd.sDevice = "/dev/" + sDevice;
}
/*
* sPath/device should be a symlink to the actual device. For USB
* devices, it looks like this:
*
* device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0
*
* "2-1" is "bus-port".
*/
char szLink[256];
int iRet = readlink( sPath + "device", szLink, sizeof(szLink) );
if( iRet == -1 )
{
LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) );
}
else
{
/*
* The full path looks like
*
* ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0
*
* In newer kernels, it looks like:
*
* ../../../3-2.1:1.0
*
* Each path element refers to a new hop in the chain.
* "usb2" = second USB host
* 2- second USB host,
* -2 port 1 on the host,
* .1 port 1 on an attached hub
* .2 ... port 2 on the next hub ...
*
* We want the bus number and the port of the last hop. The level is
* the number of hops.
*/
szLink[iRet] = 0;
vector<RString> asBits;
split( szLink, "/", asBits );
RString sHostPort = asBits[asBits.size()-1];
if( !sHostPort.empty() )
{
/* Strip off the endpoint information after the colon. */
size_t pos = sHostPort.find(':');
if( pos != string::npos )
sHostPort.erase( pos );
/* sHostPort is eg. 2-2.1. */
sHostPort.Replace( "-", "." );
asBits.clear();
split( sHostPort, ".", asBits );
if( asBits.size() > 1 )
{
usbd.iBus = atoi( asBits[0] );
usbd.iPort = atoi( asBits[asBits.size()-1] );
usbd.iLevel = asBits.size() - 1;
}
}
}
if( ReadFile( sPath + "device/../idVendor", sBuf ) )
sscanf( sBuf, "%x", &usbd.idVendor );
if( ReadFile( sPath + "device/../idProduct", sBuf ) )
sscanf( sBuf, "%x", &usbd.idProduct );
if( ReadFile( sPath + "device/../serial", sBuf ) )
{
usbd.sSerial = sBuf;
TrimRight( usbd.sSerial );
}
if( ReadFile( sPath + "device/../product", sBuf ) )
{
usbd.sProduct = sBuf;
TrimRight( usbd.sProduct );
}
if( ReadFile( sPath + "device/../manufacturer", sBuf ) )
{
usbd.sVendor = sBuf;
TrimRight( usbd.sVendor );
}
vDevicesOut.push_back( usbd );
}
}
{
// Find where each device is mounted. Output looks like:
// /dev/sda1 /mnt/flash1 auto noauto,owner 0 0
// /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0
// /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0
RString fn = "/rootfs/etc/fstab";
RageFile f;
if( !f.Open(fn) )
{
LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
RString sLine;
while( !f.AtEOF() )
{
switch( f.GetLine(sLine) )
{
case 0: continue; /* eof */
case -1:
LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
char szScsiDevice[1024];
char szMountPoint[1024];
int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint );
if( iRet != 2 )
continue; // don't process this line
RString sMountPoint = szMountPoint;
TrimLeft( sMountPoint );
TrimRight( sMountPoint );
// search for the mountpoint corresponding to the device
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sDevice == szScsiDevice ) // found our match
{
usbd.sOsMountDir = sMountPoint;
break; // stop looking for a match
}
}
}
}
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s",
usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(),
usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() );
}
/* Remove any devices that we couldn't find a mountpoint for. */
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sOsMountDir.empty() )
{
LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() );
vDevicesOut.erase( vDevicesOut.begin()+i );
--i;
}
}
LOG->Trace( "Done with GetUSBStorageDevices" );
}
bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice )
{
ASSERT( !pDevice->sDevice.empty() );
RString sCommand = "mount " + pDevice->sDevice;
bool bMountedSuccessfully = ExecuteCommand( sCommand );
return bMountedSuccessfully;
}
void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice )
{
if( pDevice->sDevice.empty() )
return;
/* Use umount -l, so we unmount the device even if it's in use. Open
* files remain usable, and the device (eg. /dev/sda) won't be reused
* by new devices until those are closed. Without this, if something
* causes the device to not unmount here, we'll never unmount it; that
* causes a device name leak, eventually running us out of mountpoints. */
RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\"";
ExecuteCommand( sCommand );
}
/*
* (c) 2003-2005 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "MemoryCardDriverThreaded_Linux.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageTimer.h"
#include <cerrno>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice )
{
if( access(pDevice->sOsMountDir, W_OK) == -1 )
{
pDevice->SetError( "TestFailed" );
return false;
}
return true;
}
static bool ExecuteCommand( const RString &sCommand )
{
LOG->Trace( "executing '%s'", sCommand.c_str() );
int ret = system(sCommand);
LOG->Trace( "done executing '%s'", sCommand.c_str() );
if( ret != 0 )
{
RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret);
if( ret == -1 )
sError += ssprintf(": %s", sCommand.c_str());
LOG->Warn( "%s", sError.c_str() );
}
return ret == 0;
}
static bool ReadFile( const RString &sPath, RString &sBuf )
{
sBuf.clear();
int fd = open( sPath, O_RDONLY );
if( fd == -1 )
{
LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
while(1)
{
char buf[1024];
int iGot = read( fd, buf, sizeof(buf) );
if( iGot == -1 )
{
close(fd);
LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) );
return false;
}
sBuf.append( buf, iGot );
if( iGot < (int) sizeof(buf) )
break;
}
close(fd);
return true;
}
static void GetFileList( const RString &sPath, vector<RString> &out )
{
out.clear();
DIR *dp = opendir( sPath );
if( dp == NULL )
return; // false; // XXX warn
while( const struct dirent *ent = readdir(dp) )
out.push_back( ent->d_name );
closedir( dp );
}
bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged()
{
RString sThisDevices;
/* If a device is removed and reinserted, the inode of the /sys/block entry
* will change. */
RString sDevicePath = "/sys/block/";
vector<RString> asDevices;
GetFileList( sDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
struct stat buf;
if( stat( sDevicePath + asDevices[i], &buf ) == -1 )
continue; // XXX warn
sThisDevices += ssprintf( "%i,", (int) buf.st_ino );
}
bool bChanged = sThisDevices != m_sLastDevices;
m_sLastDevices = sThisDevices;
if( bChanged )
LOG->Trace( "Change in USB storage devices detected." );
return bChanged;
}
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut )
{
LOG->Trace( "GetUSBStorageDevices" );
vDevicesOut.clear();
{
vector<RString> asDevices;
RString sBlockDevicePath = "/sys/block/";
GetFileList( sBlockDevicePath, asDevices );
for( unsigned i = 0; i < asDevices.size(); ++i )
{
const RString &sDevice = asDevices[i];
if( sDevice == "." || sDevice == ".." )
continue;
UsbStorageDevice usbd;
RString sPath = sBlockDevicePath + sDevice + "/";
usbd.sSysPath = sPath;
/* Ignore non-removable devices. */
RString sBuf;
if( !ReadFile( sPath + "removable", sBuf ) )
continue; // already warned
if( atoi(sBuf) != 1 )
continue;
/*
* The kernel isn't exposing all of /sys atomically, so we end up missing
* the partition due to it not being shown yet. It won't show up until the
* kernel has scanned the partition table, which can take a variable amount
* of time, sometimes over a second. Watch for the "queue" sysfs directory,
* which is created after this, to tell when partition directories are created.
*/
RageTimer WaitUntil;
WaitUntil += 5;
RString sQueueFilePath = usbd.sSysPath + "queue";
while(1)
{
if( WaitUntil.Ago() >= 0 )
{
LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() );
break;
}
if( access(usbd.sSysPath, F_OK) == -1 )
{
LOG->Warn( "Block directory %s went away while we were waiting for %s",
usbd.sSysPath.c_str(), sQueueFilePath.c_str() );
break;
}
if( access(sQueueFilePath, F_OK) != -1 )
break;
usleep(10000);
}
/* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */
if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 )
{
LOG->Trace("OK");
usbd.sDevice = "/dev/" + sDevice + "1";
}
else
{
LOG->Trace("error %s", strerror(errno));
usbd.sDevice = "/dev/" + sDevice;
}
/*
* sPath/device should be a symlink to the actual device. For USB
* devices, it looks like this:
*
* device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0
*
* "2-1" is "bus-port".
*/
char szLink[256];
int iRet = readlink( sPath + "device", szLink, sizeof(szLink) );
if( iRet == -1 )
{
LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) );
}
else
{
/*
* The full path looks like
*
* ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0
*
* In newer kernels, it looks like:
*
* ../../../3-2.1:1.0
*
* Each path element refers to a new hop in the chain.
* "usb2" = second USB host
* 2- second USB host,
* -2 port 1 on the host,
* .1 port 1 on an attached hub
* .2 ... port 2 on the next hub ...
*
* We want the bus number and the port of the last hop. The level is
* the number of hops.
*/
szLink[iRet] = 0;
vector<RString> asBits;
split( szLink, "/", asBits );
RString sHostPort = asBits[asBits.size()-1];
if( !sHostPort.empty() )
{
/* Strip off the endpoint information after the colon. */
size_t pos = sHostPort.find(':');
if( pos != string::npos )
sHostPort.erase( pos );
/* sHostPort is eg. 2-2.1. */
sHostPort.Replace( "-", "." );
asBits.clear();
split( sHostPort, ".", asBits );
if( asBits.size() > 1 )
{
usbd.iBus = atoi( asBits[0] );
usbd.iPort = atoi( asBits[asBits.size()-1] );
usbd.iLevel = asBits.size() - 1;
}
}
}
if( ReadFile( sPath + "device/../idVendor", sBuf ) )
sscanf( sBuf, "%x", &usbd.idVendor );
if( ReadFile( sPath + "device/../idProduct", sBuf ) )
sscanf( sBuf, "%x", &usbd.idProduct );
if( ReadFile( sPath + "device/../serial", sBuf ) )
{
usbd.sSerial = sBuf;
TrimRight( usbd.sSerial );
}
if( ReadFile( sPath + "device/../product", sBuf ) )
{
usbd.sProduct = sBuf;
TrimRight( usbd.sProduct );
}
if( ReadFile( sPath + "device/../manufacturer", sBuf ) )
{
usbd.sVendor = sBuf;
TrimRight( usbd.sVendor );
}
vDevicesOut.push_back( usbd );
}
}
{
// Find where each device is mounted. Output looks like:
// /dev/sda1 /mnt/flash1 auto noauto,owner 0 0
// /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0
// /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0
RString fn = "/rootfs/etc/fstab";
RageFile f;
if( !f.Open(fn) )
{
LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
RString sLine;
while( !f.AtEOF() )
{
switch( f.GetLine(sLine) )
{
case 0: continue; /* eof */
case -1:
LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() );
return;
}
char szScsiDevice[1024];
char szMountPoint[1024];
int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint );
if( iRet != 2 )
continue; // don't process this line
RString sMountPoint = szMountPoint;
TrimLeft( sMountPoint );
TrimRight( sMountPoint );
// search for the mountpoint corresponding to the device
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sDevice == szScsiDevice ) // found our match
{
usbd.sOsMountDir = sMountPoint;
break; // stop looking for a match
}
}
}
}
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s",
usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(),
usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() );
}
/* Remove any devices that we couldn't find a mountpoint for. */
for( unsigned i=0; i<vDevicesOut.size(); i++ )
{
UsbStorageDevice& usbd = vDevicesOut[i];
if( usbd.sOsMountDir.empty() )
{
LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() );
vDevicesOut.erase( vDevicesOut.begin()+i );
--i;
}
}
LOG->Trace( "Done with GetUSBStorageDevices" );
}
bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice )
{
ASSERT( !pDevice->sDevice.empty() );
RString sCommand = "mount " + pDevice->sDevice;
bool bMountedSuccessfully = ExecuteCommand( sCommand );
return bMountedSuccessfully;
}
void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice )
{
if( pDevice->sDevice.empty() )
return;
/* Use umount -l, so we unmount the device even if it's in use. Open
* files remain usable, and the device (eg. /dev/sda) won't be reused
* by new devices until those are closed. Without this, if something
* causes the device to not unmount here, we'll never unmount it; that
* causes a device name leak, eventually running us out of mountpoints. */
RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\"";
ExecuteCommand( sCommand );
}
/*
* (c) 2003-2005 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+272 -272
View File
@@ -1,272 +1,272 @@
/*
* unbuffered io for ffmpeg system
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVIO_H
#define AVIO_H
/* output byte stream handling */
typedef int64_t offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data;
#if LIBAVFORMAT_VERSION_INT >= (52<<16)
char *filename; /**< specified filename */
#else
char filename[1]; /**< specified filename */
#endif
};
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
typedef int URLInterruptCB(void);
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/**
* Return the maximum packet size associated to packetized file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h file handle
* @return maximum packet size in bytes
*/
int url_get_max_packet_size(URLContext *h);
void url_get_filename(URLContext *h, char *buf, int buf_size);
/**
* the callback is called in blocking functions to test regulary if
* asynchronous interruption is needed. AVERROR(EINTR) is returned
* in this case by the interrupted function. 'NULL' means no interrupt
* callback is given. i
*/
void url_set_interrupt_cb(URLInterruptCB *interrupt_cb);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
/**
* passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere, supporting this is optional
* if its not supprted then the seek function will return <0
*/
#define AVSEEK_SIZE 0x10000
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
extern URLInterruptCB *url_interrupt_cb;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
offset_t (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int is_streamed;
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; ///< contains the error code or 0 if no error happened
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size);
void put_le64(ByteIOContext *s, uint64_t val);
void put_be64(ByteIOContext *s, uint64_t val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le24(ByteIOContext *s, unsigned int val);
void put_be24(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, const char *tag);
void put_strz(ByteIOContext *s, const char *buf);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
offset_t url_fsize(ByteIOContext *s);
int url_feof(ByteIOContext *s);
int url_ferror(ByteIOContext *s);
#define URL_EOF (-1)
/** @note return URL_EOF (-1) if EOF */
int url_fgetc(ByteIOContext *s);
/** @warning currently size is limited */
#ifdef __GNUC__
int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
#else
int url_fprintf(ByteIOContext *s, const char *fmt, ...);
#endif
/** @note unlike fgets, the EOL character is not returned and a whole
line is parsed. return NULL if first char read was EOF */
char *url_fgets(ByteIOContext *s, char *buf, int buf_size);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size);
/** @note return 0 if EOF, so you cannot use it if EOF handling is
necessary */
int get_byte(ByteIOContext *s);
unsigned int get_le24(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
uint64_t get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
char *get_strz(ByteIOContext *s, char *buf, int maxlen);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be24(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
uint64_t get_be64(ByteIOContext *s);
static inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
/** @warning must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size);
/** @note when opened as read/write, the buffers are only used for
reading */
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
/**
* Return the maximum packet size associated to packetized buffered file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h buffered file handle
* @return maximum packet size in bytes
*/
int url_fget_max_packet_size(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags);
/** return the written or read size */
int url_close_buf(ByteIOContext *s);
/**
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int url_open_dyn_buf(ByteIOContext *s);
/**
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size);
/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* @param s IO context
* @param pointer to a byte buffer
* @return the length of the byte buffer
*/
int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer);
unsigned long get_checksum(ByteIOContext *s);
void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
int udp_set_remote_url(URLContext *h, const char *uri);
int udp_get_local_port(URLContext *h);
int udp_get_file_handle(URLContext *h);
/* tcp.c */
extern URLProtocol tcp_protocol;
/* http.c */
extern URLProtocol http_protocol;
#endif
/*
* unbuffered io for ffmpeg system
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVIO_H
#define AVIO_H
/* output byte stream handling */
typedef int64_t offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /**< true if streamed (no seek possible), default = false */
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
void *priv_data;
#if LIBAVFORMAT_VERSION_INT >= (52<<16)
char *filename; /**< specified filename */
#else
char filename[1]; /**< specified filename */
#endif
};
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
typedef int URLInterruptCB(void);
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
/**
* Return the maximum packet size associated to packetized file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h file handle
* @return maximum packet size in bytes
*/
int url_get_max_packet_size(URLContext *h);
void url_get_filename(URLContext *h, char *buf, int buf_size);
/**
* the callback is called in blocking functions to test regulary if
* asynchronous interruption is needed. AVERROR(EINTR) is returned
* in this case by the interrupted function. 'NULL' means no interrupt
* callback is given. i
*/
void url_set_interrupt_cb(URLInterruptCB *interrupt_cb);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
/**
* passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere, supporting this is optional
* if its not supprted then the seek function will return <0
*/
#define AVSEEK_SIZE 0x10000
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
extern URLInterruptCB *url_interrupt_cb;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
offset_t (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int is_streamed;
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; ///< contains the error code or 0 if no error happened
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size);
void put_le64(ByteIOContext *s, uint64_t val);
void put_be64(ByteIOContext *s, uint64_t val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le24(ByteIOContext *s, unsigned int val);
void put_be24(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, const char *tag);
void put_strz(ByteIOContext *s, const char *buf);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
offset_t url_fsize(ByteIOContext *s);
int url_feof(ByteIOContext *s);
int url_ferror(ByteIOContext *s);
#define URL_EOF (-1)
/** @note return URL_EOF (-1) if EOF */
int url_fgetc(ByteIOContext *s);
/** @warning currently size is limited */
#ifdef __GNUC__
int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
#else
int url_fprintf(ByteIOContext *s, const char *fmt, ...);
#endif
/** @note unlike fgets, the EOL character is not returned and a whole
line is parsed. return NULL if first char read was EOF */
char *url_fgets(ByteIOContext *s, char *buf, int buf_size);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size);
/** @note return 0 if EOF, so you cannot use it if EOF handling is
necessary */
int get_byte(ByteIOContext *s);
unsigned int get_le24(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
uint64_t get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
char *get_strz(ByteIOContext *s, char *buf, int maxlen);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be24(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
uint64_t get_be64(ByteIOContext *s);
static inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
/** @warning must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size);
/** @note when opened as read/write, the buffers are only used for
reading */
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
/**
* Return the maximum packet size associated to packetized buffered file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h buffered file handle
* @return maximum packet size in bytes
*/
int url_fget_max_packet_size(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags);
/** return the written or read size */
int url_close_buf(ByteIOContext *s);
/**
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int url_open_dyn_buf(ByteIOContext *s);
/**
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size);
/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* @param s IO context
* @param pointer to a byte buffer
* @return the length of the byte buffer
*/
int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer);
unsigned long get_checksum(ByteIOContext *s);
void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
int udp_set_remote_url(URLContext *h, const char *uri);
int udp_get_local_port(URLContext *h);
int udp_get_file_handle(URLContext *h);
/* tcp.c */
extern URLProtocol tcp_protocol;
/* http.c */
extern URLProtocol http_protocol;
#endif
+137 -137
View File
@@ -1,137 +1,137 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_H
#define AVUTIL_H
/**
* @file avutil.h
* external api header.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s
#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0)
#define LIBAVUTIL_VERSION 49.4.0
#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
#include "common.h"
#include "mathematics.h"
#include "rational.h"
#include "integer.h"
#include "intfloat_readwrite.h"
#include "log.h"
/**
* Pixel format. Notes:
*
* PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA
* color is put together as:
* (A << 24) | (R << 16) | (G << 8) | B
* This is stored as BGRA on little endian CPU architectures and ARGB on
* big endian CPUs.
*
* When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is
* formatted the same as in PIX_FMT_RGB32 described above (i.e., it is
* also endian-specific). Note also that the individual RGB palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
* to run on the IBM VGA graphics adapter use 6-bit palette components.
*/
enum PixelFormat {
PIX_FMT_NONE= -1,
PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB...
PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR...
PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness
PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness
PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0
PIX_FMT_GRAY8, ///< Y , 8bpp
PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white
PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black
PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg)
PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg)
PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg)
PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h)
PIX_FMT_XVMC_MPEG2_IDCT,
PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness
PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness
PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1
PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
PIX_FMT_NV21, ///< as above, but U and V bytes are swapped
PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness
PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness
PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian
PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian
PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
};
#ifdef WORDS_BIGENDIAN
#define PIX_FMT_RGBA PIX_FMT_RGB32_1
#define PIX_FMT_BGRA PIX_FMT_BGR32_1
#define PIX_FMT_ARGB PIX_FMT_RGB32
#define PIX_FMT_ABGR PIX_FMT_BGR32
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE
#else
#define PIX_FMT_RGBA PIX_FMT_BGR32
#define PIX_FMT_BGRA PIX_FMT_RGB32
#define PIX_FMT_ARGB PIX_FMT_BGR32_1
#define PIX_FMT_ABGR PIX_FMT_RGB32_1
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411
#define PIX_FMT_RGBA32 PIX_FMT_RGB32
#define PIX_FMT_YUV422 PIX_FMT_YUYV422
#endif
#ifdef __cplusplus
}
#endif
#endif /* AVUTIL_H */
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_H
#define AVUTIL_H
/**
* @file avutil.h
* external api header.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s
#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0)
#define LIBAVUTIL_VERSION 49.4.0
#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
#include "common.h"
#include "mathematics.h"
#include "rational.h"
#include "integer.h"
#include "intfloat_readwrite.h"
#include "log.h"
/**
* Pixel format. Notes:
*
* PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA
* color is put together as:
* (A << 24) | (R << 16) | (G << 8) | B
* This is stored as BGRA on little endian CPU architectures and ARGB on
* big endian CPUs.
*
* When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is
* formatted the same as in PIX_FMT_RGB32 described above (i.e., it is
* also endian-specific). Note also that the individual RGB palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
* to run on the IBM VGA graphics adapter use 6-bit palette components.
*/
enum PixelFormat {
PIX_FMT_NONE= -1,
PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB...
PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR...
PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness
PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness
PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0
PIX_FMT_GRAY8, ///< Y , 8bpp
PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white
PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black
PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg)
PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg)
PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg)
PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h)
PIX_FMT_XVMC_MPEG2_IDCT,
PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness
PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness
PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1
PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb)
PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
PIX_FMT_NV21, ///< as above, but U and V bytes are swapped
PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness
PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness
PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian
PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian
PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
};
#ifdef WORDS_BIGENDIAN
#define PIX_FMT_RGBA PIX_FMT_RGB32_1
#define PIX_FMT_BGRA PIX_FMT_BGR32_1
#define PIX_FMT_ARGB PIX_FMT_RGB32
#define PIX_FMT_ABGR PIX_FMT_BGR32
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE
#else
#define PIX_FMT_RGBA PIX_FMT_BGR32
#define PIX_FMT_BGRA PIX_FMT_RGB32
#define PIX_FMT_ARGB PIX_FMT_BGR32_1
#define PIX_FMT_ABGR PIX_FMT_RGB32_1
#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411
#define PIX_FMT_RGBA32 PIX_FMT_RGB32
#define PIX_FMT_YUV422 PIX_FMT_YUYV422
#endif
#ifdef __cplusplus
}
#endif
#endif /* AVUTIL_H */
+328 -328
View File
@@ -1,328 +1,328 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file common.h
* common internal and external api header.
*/
#ifndef COMMON_H
#define COMMON_H
#if 0
#include <inttypes.h>
#endif
#ifdef HAVE_AV_CONFIG_H
/* only include the following when compiling package */
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <limits.h>
# include <errno.h>
# include <math.h>
#endif /* HAVE_AV_CONFIG_H */
#ifndef av_always_inline
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define av_always_inline __attribute__((always_inline)) inline
# define av_noinline __attribute__((noinline))
#else
# define av_always_inline inline
# define av_noinline
#endif
#endif
#ifdef HAVE_AV_CONFIG_H
# include "internal.h"
#endif /* HAVE_AV_CONFIG_H */
#ifndef attribute_deprecated
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define attribute_deprecated __attribute__((deprecated))
#else
# define attribute_deprecated
#endif
#endif
#include "mem.h"
//rounded divison & shift
#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
/* assume b>0 */
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
/* misc math functions */
extern const uint8_t ff_log2_tab[256];
static inline int av_log2(unsigned int v)
{
int n;
n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
static inline int av_log2_16bit(unsigned int v)
{
int n;
n = 0;
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
/* median of 3 */
static inline int mid_pred(int a, int b, int c)
{
#ifdef HAVE_CMOV
int i=b;
asm volatile(
"cmp %2, %1 \n\t"
"cmovg %1, %0 \n\t"
"cmovg %2, %1 \n\t"
"cmp %3, %1 \n\t"
"cmovl %3, %1 \n\t"
"cmp %1, %0 \n\t"
"cmovg %1, %0 \n\t"
:"+&r"(i), "+&r"(a)
:"r"(b), "r"(c)
);
return i;
#elif 0
int t= (a-b)&((a-b)>>31);
a-=t;
b+=t;
b-= (b-c)&((b-c)>>31);
b+= (a-b)&((a-b)>>31);
return b;
#else
if(a>b){
if(c>b){
if(c>a) b=a;
else b=c;
}
}else{
if(b>c){
if(c>a) b=c;
else b=a;
}
}
return b;
#endif
}
/**
* clip a signed integer value into the amin-amax range
* @param a value to clip
* @param amin minimum value of the clip range
* @param amax maximum value of the clip range
* @return clipped value
*/
static inline int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
/**
* clip a signed integer value into the 0-255 range
* @param a value to clip
* @return clipped value
*/
static inline uint8_t av_clip_uint8(int a)
{
if (a&(~255)) return (-a)>>31;
else return a;
}
/* math */
int64_t ff_gcd(int64_t a, int64_t b);
/**
* converts fourcc string to int
*/
static inline int ff_get_fourcc(const char *s){
#ifdef HAVE_AV_CONFIG_H
assert( strlen(s)==4 );
#endif
return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24);
}
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
/*!
* \def GET_UTF8(val, GET_BYTE, ERROR)
* converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form
* \param val is the output and should be of type uint32_t. It holds the converted
* ucs-4 character and should be a left value.
* \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be
* a function or a statement whose return value or evaluated value is of type
* uint8_t. It will be executed up to 4 times for values in the valid utf-8 range,
* and up to 7 times in the general case.
* \param ERROR action that should be taken when an invalid utf-8 byte is returned
* from GET_BYTE. It should be a statement that jumps out of the macro,
* like exit(), goto, return, break, or continue.
*/
#define GET_UTF8(val, GET_BYTE, ERROR)\
val= GET_BYTE;\
{\
int ones= 7 - av_log2(val ^ 255);\
if(ones==1)\
ERROR\
val&= 127>>ones;\
while(--ones > 0){\
int tmp= GET_BYTE - 128;\
if(tmp>>6)\
ERROR\
val= (val<<6) + tmp;\
}\
}
/*!
* \def PUT_UTF8(val, tmp, PUT_BYTE)
* converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long).
* \param val is an input only argument and should be of type uint32_t. It holds
* a ucs4 encoded unicode character that is to be converted to utf-8. If
* val is given as a function it's executed only once.
* \param tmp is a temporary variable and should be of type uint8_t. It
* represents an intermediate value during conversion that is to be
* outputted by PUT_BYTE.
* \param PUT_BYTE writes the converted utf-8 bytes to any proper destination.
* It could be a function or a statement, and uses tmp as the input byte.
* For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be
* executed up to 4 times for values in the valid utf-8 range and up to
* 7 times in the general case, depending on the length of the converted
* unicode character.
*/
#define PUT_UTF8(val, tmp, PUT_BYTE)\
{\
int bytes, shift;\
uint32_t in = val;\
if (in < 0x80) {\
tmp = in;\
PUT_BYTE\
} else {\
bytes = (av_log2(in) + 4) / 5;\
shift = (bytes - 1) * 6;\
tmp = (256 - (256 >> bytes)) | (in >> shift);\
PUT_BYTE\
while (shift >= 6) {\
shift -= 6;\
tmp = 0x80 | ((in >> shift) & 0x3f);\
PUT_BYTE\
}\
}\
}
#if defined(ARCH_X86) || defined(ARCH_POWERPC)
#if defined(ARCH_X86_64)
static inline uint64_t read_time(void)
{
uint64_t a, d;
asm volatile( "rdtsc\n\t"
: "=a" (a), "=d" (d)
);
return (d << 32) | (a & 0xffffffff);
}
#elif defined(ARCH_X86_32)
static inline long long read_time(void)
{
long long l;
asm volatile( "rdtsc\n\t"
: "=A" (l)
);
return l;
}
#else //FIXME check ppc64
static inline uint64_t read_time(void)
{
uint32_t tbu, tbl, temp;
/* from section 2.2.1 of the 32-bit PowerPC PEM */
__asm__ __volatile__(
"1:\n"
"mftbu %2\n"
"mftb %0\n"
"mftbu %1\n"
"cmpw %2,%1\n"
"bne 1b\n"
: "=r"(tbl), "=r"(tbu), "=r"(temp)
:
: "cc");
return (((uint64_t)tbu)<<32) | (uint64_t)tbl;
}
#endif
#define START_TIMER \
uint64_t tend;\
uint64_t tstart= read_time();\
#define STOP_TIMER(id) \
tend= read_time();\
{\
static uint64_t tsum=0;\
static int tcount=0;\
static int tskip_count=0;\
if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\
tsum+= tend - tstart;\
tcount++;\
}else\
tskip_count++;\
if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\
}\
}
#else
#define START_TIMER
#define STOP_TIMER(id) {}
#endif
#endif /* COMMON_H */
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file common.h
* common internal and external api header.
*/
#ifndef COMMON_H
#define COMMON_H
#if 0
#include <inttypes.h>
#endif
#ifdef HAVE_AV_CONFIG_H
/* only include the following when compiling package */
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <limits.h>
# include <errno.h>
# include <math.h>
#endif /* HAVE_AV_CONFIG_H */
#ifndef av_always_inline
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define av_always_inline __attribute__((always_inline)) inline
# define av_noinline __attribute__((noinline))
#else
# define av_always_inline inline
# define av_noinline
#endif
#endif
#ifdef HAVE_AV_CONFIG_H
# include "internal.h"
#endif /* HAVE_AV_CONFIG_H */
#ifndef attribute_deprecated
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define attribute_deprecated __attribute__((deprecated))
#else
# define attribute_deprecated
#endif
#endif
#include "mem.h"
//rounded divison & shift
#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
/* assume b>0 */
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
/* misc math functions */
extern const uint8_t ff_log2_tab[256];
static inline int av_log2(unsigned int v)
{
int n;
n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
static inline int av_log2_16bit(unsigned int v)
{
int n;
n = 0;
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += ff_log2_tab[v];
return n;
}
/* median of 3 */
static inline int mid_pred(int a, int b, int c)
{
#ifdef HAVE_CMOV
int i=b;
asm volatile(
"cmp %2, %1 \n\t"
"cmovg %1, %0 \n\t"
"cmovg %2, %1 \n\t"
"cmp %3, %1 \n\t"
"cmovl %3, %1 \n\t"
"cmp %1, %0 \n\t"
"cmovg %1, %0 \n\t"
:"+&r"(i), "+&r"(a)
:"r"(b), "r"(c)
);
return i;
#elif 0
int t= (a-b)&((a-b)>>31);
a-=t;
b+=t;
b-= (b-c)&((b-c)>>31);
b+= (a-b)&((a-b)>>31);
return b;
#else
if(a>b){
if(c>b){
if(c>a) b=a;
else b=c;
}
}else{
if(b>c){
if(c>a) b=c;
else b=a;
}
}
return b;
#endif
}
/**
* clip a signed integer value into the amin-amax range
* @param a value to clip
* @param amin minimum value of the clip range
* @param amax maximum value of the clip range
* @return clipped value
*/
static inline int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
/**
* clip a signed integer value into the 0-255 range
* @param a value to clip
* @return clipped value
*/
static inline uint8_t av_clip_uint8(int a)
{
if (a&(~255)) return (-a)>>31;
else return a;
}
/* math */
int64_t ff_gcd(int64_t a, int64_t b);
/**
* converts fourcc string to int
*/
static inline int ff_get_fourcc(const char *s){
#ifdef HAVE_AV_CONFIG_H
assert( strlen(s)==4 );
#endif
return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24);
}
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
/*!
* \def GET_UTF8(val, GET_BYTE, ERROR)
* converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form
* \param val is the output and should be of type uint32_t. It holds the converted
* ucs-4 character and should be a left value.
* \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be
* a function or a statement whose return value or evaluated value is of type
* uint8_t. It will be executed up to 4 times for values in the valid utf-8 range,
* and up to 7 times in the general case.
* \param ERROR action that should be taken when an invalid utf-8 byte is returned
* from GET_BYTE. It should be a statement that jumps out of the macro,
* like exit(), goto, return, break, or continue.
*/
#define GET_UTF8(val, GET_BYTE, ERROR)\
val= GET_BYTE;\
{\
int ones= 7 - av_log2(val ^ 255);\
if(ones==1)\
ERROR\
val&= 127>>ones;\
while(--ones > 0){\
int tmp= GET_BYTE - 128;\
if(tmp>>6)\
ERROR\
val= (val<<6) + tmp;\
}\
}
/*!
* \def PUT_UTF8(val, tmp, PUT_BYTE)
* converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long).
* \param val is an input only argument and should be of type uint32_t. It holds
* a ucs4 encoded unicode character that is to be converted to utf-8. If
* val is given as a function it's executed only once.
* \param tmp is a temporary variable and should be of type uint8_t. It
* represents an intermediate value during conversion that is to be
* outputted by PUT_BYTE.
* \param PUT_BYTE writes the converted utf-8 bytes to any proper destination.
* It could be a function or a statement, and uses tmp as the input byte.
* For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be
* executed up to 4 times for values in the valid utf-8 range and up to
* 7 times in the general case, depending on the length of the converted
* unicode character.
*/
#define PUT_UTF8(val, tmp, PUT_BYTE)\
{\
int bytes, shift;\
uint32_t in = val;\
if (in < 0x80) {\
tmp = in;\
PUT_BYTE\
} else {\
bytes = (av_log2(in) + 4) / 5;\
shift = (bytes - 1) * 6;\
tmp = (256 - (256 >> bytes)) | (in >> shift);\
PUT_BYTE\
while (shift >= 6) {\
shift -= 6;\
tmp = 0x80 | ((in >> shift) & 0x3f);\
PUT_BYTE\
}\
}\
}
#if defined(ARCH_X86) || defined(ARCH_POWERPC)
#if defined(ARCH_X86_64)
static inline uint64_t read_time(void)
{
uint64_t a, d;
asm volatile( "rdtsc\n\t"
: "=a" (a), "=d" (d)
);
return (d << 32) | (a & 0xffffffff);
}
#elif defined(ARCH_X86_32)
static inline long long read_time(void)
{
long long l;
asm volatile( "rdtsc\n\t"
: "=A" (l)
);
return l;
}
#else //FIXME check ppc64
static inline uint64_t read_time(void)
{
uint32_t tbu, tbl, temp;
/* from section 2.2.1 of the 32-bit PowerPC PEM */
__asm__ __volatile__(
"1:\n"
"mftbu %2\n"
"mftb %0\n"
"mftbu %1\n"
"cmpw %2,%1\n"
"bne 1b\n"
: "=r"(tbl), "=r"(tbu), "=r"(temp)
:
: "cc");
return (((uint64_t)tbu)<<32) | (uint64_t)tbl;
}
#endif
#define START_TIMER \
uint64_t tend;\
uint64_t tstart= read_time();\
#define STOP_TIMER(id) \
tend= read_time();\
{\
static uint64_t tsum=0;\
static int tcount=0;\
static int tskip_count=0;\
if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\
tsum+= tend - tstart;\
tcount++;\
}else\
tskip_count++;\
if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\
}\
}
#else
#define START_TIMER
#define STOP_TIMER(id) {}
#endif
#endif /* COMMON_H */
+82 -82
View File
@@ -1,82 +1,82 @@
/*
* arbitrary precision integers
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file integer.h
* arbitrary precision integers
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#ifndef INTEGER_H
#define INTEGER_H
#define AV_INTEGER_SIZE 8
typedef struct AVInteger{
uint16_t v[AV_INTEGER_SIZE];
} AVInteger;
AVInteger av_add_i(AVInteger a, AVInteger b);
AVInteger av_sub_i(AVInteger a, AVInteger b);
/**
* returns the rounded down value of the logarithm of base 2 of the given AVInteger.
* this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0
*/
int av_log2_i(AVInteger a);
AVInteger av_mul_i(AVInteger a, AVInteger b);
/**
* returns 0 if a==b, 1 if a>b and -1 if a<b.
*/
int av_cmp_i(AVInteger a, AVInteger b);
/**
* bitwise shift.
* @param s the number of bits by which the value should be shifted right, may be negative for shifting left
*/
AVInteger av_shr_i(AVInteger a, int s);
/**
* returns a % b.
* @param quot a/b will be stored here
*/
AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
/**
* returns a/b.
*/
AVInteger av_div_i(AVInteger a, AVInteger b);
/**
* converts the given int64_t to an AVInteger.
*/
AVInteger av_int2i(int64_t a);
/**
* converts the given AVInteger to an int64_t.
* if the AVInteger is too large to fit into an int64_t,
* then only the least significant 64bit will be used
*/
int64_t av_i2int(AVInteger a);
#endif // INTEGER_H
/*
* arbitrary precision integers
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file integer.h
* arbitrary precision integers
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#ifndef INTEGER_H
#define INTEGER_H
#define AV_INTEGER_SIZE 8
typedef struct AVInteger{
uint16_t v[AV_INTEGER_SIZE];
} AVInteger;
AVInteger av_add_i(AVInteger a, AVInteger b);
AVInteger av_sub_i(AVInteger a, AVInteger b);
/**
* returns the rounded down value of the logarithm of base 2 of the given AVInteger.
* this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0
*/
int av_log2_i(AVInteger a);
AVInteger av_mul_i(AVInteger a, AVInteger b);
/**
* returns 0 if a==b, 1 if a>b and -1 if a<b.
*/
int av_cmp_i(AVInteger a, AVInteger b);
/**
* bitwise shift.
* @param s the number of bits by which the value should be shifted right, may be negative for shifting left
*/
AVInteger av_shr_i(AVInteger a, int s);
/**
* returns a % b.
* @param quot a/b will be stored here
*/
AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
/**
* returns a/b.
*/
AVInteger av_div_i(AVInteger a, AVInteger b);
/**
* converts the given int64_t to an AVInteger.
*/
AVInteger av_int2i(int64_t a);
/**
* converts the given AVInteger to an int64_t.
* if the AVInteger is too large to fit into an int64_t,
* then only the least significant 64bit will be used
*/
int64_t av_i2int(AVInteger a);
#endif // INTEGER_H
+39 -39
View File
@@ -1,39 +1,39 @@
/*
* copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INTFLOAT_READWRITE_H
#define INTFLOAT_READWRITE_H
#include "common.h"
/* IEEE 80 bits extended float */
typedef struct AVExtFloat {
uint8_t exponent[2];
uint8_t mantissa[8];
} AVExtFloat;
double av_int2dbl(int64_t v);
float av_int2flt(int32_t v);
double av_ext2dbl(const AVExtFloat ext);
int64_t av_dbl2int(double d);
int32_t av_flt2int(float d);
AVExtFloat av_dbl2ext(double d);
#endif /* INTFLOAT_READWRITE_H */
/*
* copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef INTFLOAT_READWRITE_H
#define INTFLOAT_READWRITE_H
#include "common.h"
/* IEEE 80 bits extended float */
typedef struct AVExtFloat {
uint8_t exponent[2];
uint8_t mantissa[8];
} AVExtFloat;
double av_int2dbl(int64_t v);
float av_int2flt(int32_t v);
double av_ext2dbl(const AVExtFloat ext);
int64_t av_dbl2int(double d);
int32_t av_flt2int(float d);
AVExtFloat av_dbl2ext(double d);
#endif /* INTFLOAT_READWRITE_H */
+116 -116
View File
@@ -1,116 +1,116 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
/**
* Used by av_log
*/
typedef struct AVCLASS AVClass;
struct AVCLASS {
const char* class_name;
const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext
or AVFormatContext, which begin with an AVClass.
Needed because av_log is in libavcodec and has no visibility
of AVIn/OutputFormat */
const struct AVOption *option;
};
/* av_log API */
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define AV_LOG_QUIET -1
#define AV_LOG_FATAL 0
#define AV_LOG_ERROR 0
#define AV_LOG_WARNING 1
#define AV_LOG_INFO 1
#define AV_LOG_VERBOSE 1
#define AV_LOG_DEBUG 2
#else
#define AV_LOG_QUIET -8
/**
* something went really wrong and we will crash now
*/
#define AV_LOG_PANIC 0
/**
* something went wrong and recovery is not possible
* like no header in a format which depends on it or a combination
* of parameters which are not allowed
*/
#define AV_LOG_FATAL 8
/**
* something went wrong and cannot losslessly be recovered
* but not all future data is affected
*/
#define AV_LOG_ERROR 16
/**
* something somehow does not look correct / something which may or may not
* lead to some problems like use of -vstrict -2
*/
#define AV_LOG_WARNING 24
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
/**
* stuff which is only useful for libav* developers
*/
#define AV_LOG_DEBUG 48
#endif
extern int av_log_level;
/**
* Send the specified message to the log if the level is less than or equal to
* the current av_log_level. By default, all logging messages are sent to
* stderr. This behavior can be altered by setting a different av_vlog callback
* function.
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
* pointer to an AVClass struct.
* @param level The importance level of the message, lower values signifying
* higher importance.
* @param fmt The format string (printf-compatible) that specifies how
* subsequent arguments are converted to output.
* @see av_vlog
*/
#ifdef __GNUC__
extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
#else
extern void av_log(void*, int level, const char *fmt, ...);
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
extern void av_vlog(void*, int level, const char *fmt, va_list);
extern int av_log_get_level(void);
extern void av_log_set_level(int);
extern void av_log_set_callback(void (*)(void*, int, const char*, va_list));
extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
#else
extern void (*av_vlog)(void*, int, const char*, va_list);
#endif
#endif /* LOG_H */
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
/**
* Used by av_log
*/
typedef struct AVCLASS AVClass;
struct AVCLASS {
const char* class_name;
const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext
or AVFormatContext, which begin with an AVClass.
Needed because av_log is in libavcodec and has no visibility
of AVIn/OutputFormat */
const struct AVOption *option;
};
/* av_log API */
#if LIBAVUTIL_VERSION_INT < (50<<16)
#define AV_LOG_QUIET -1
#define AV_LOG_FATAL 0
#define AV_LOG_ERROR 0
#define AV_LOG_WARNING 1
#define AV_LOG_INFO 1
#define AV_LOG_VERBOSE 1
#define AV_LOG_DEBUG 2
#else
#define AV_LOG_QUIET -8
/**
* something went really wrong and we will crash now
*/
#define AV_LOG_PANIC 0
/**
* something went wrong and recovery is not possible
* like no header in a format which depends on it or a combination
* of parameters which are not allowed
*/
#define AV_LOG_FATAL 8
/**
* something went wrong and cannot losslessly be recovered
* but not all future data is affected
*/
#define AV_LOG_ERROR 16
/**
* something somehow does not look correct / something which may or may not
* lead to some problems like use of -vstrict -2
*/
#define AV_LOG_WARNING 24
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
/**
* stuff which is only useful for libav* developers
*/
#define AV_LOG_DEBUG 48
#endif
extern int av_log_level;
/**
* Send the specified message to the log if the level is less than or equal to
* the current av_log_level. By default, all logging messages are sent to
* stderr. This behavior can be altered by setting a different av_vlog callback
* function.
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
* pointer to an AVClass struct.
* @param level The importance level of the message, lower values signifying
* higher importance.
* @param fmt The format string (printf-compatible) that specifies how
* subsequent arguments are converted to output.
* @see av_vlog
*/
#ifdef __GNUC__
extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
#else
extern void av_log(void*, int level, const char *fmt, ...);
#endif
#if LIBAVUTIL_VERSION_INT < (50<<16)
extern void av_vlog(void*, int level, const char *fmt, va_list);
extern int av_log_get_level(void);
extern void av_log_set_level(int);
extern void av_log_set_callback(void (*)(void*, int, const char*, va_list));
extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
#else
extern void (*av_vlog)(void*, int, const char*, va_list);
#endif
#endif /* LOG_H */
+51 -51
View File
@@ -1,51 +1,51 @@
/*
* copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MATHEMATICS_H
#define MATHEMATICS_H
#include "rational.h"
enum AVRounding {
AV_ROUND_ZERO = 0, ///< round toward zero
AV_ROUND_INF = 1, ///< round away from zero
AV_ROUND_DOWN = 2, ///< round toward -infinity
AV_ROUND_UP = 3, ///< round toward +infinity
AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero
};
/**
* rescale a 64bit integer with rounding to nearest.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale(int64_t a, int64_t b, int64_t c);
/**
* rescale a 64bit integer with specified rounding.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding);
/**
* rescale a 64bit integer by 2 rational numbers.
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq);
#endif /* MATHEMATICS_H */
/*
* copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MATHEMATICS_H
#define MATHEMATICS_H
#include "rational.h"
enum AVRounding {
AV_ROUND_ZERO = 0, ///< round toward zero
AV_ROUND_INF = 1, ///< round away from zero
AV_ROUND_DOWN = 2, ///< round toward -infinity
AV_ROUND_UP = 3, ///< round toward +infinity
AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero
};
/**
* rescale a 64bit integer with rounding to nearest.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale(int64_t a, int64_t b, int64_t c);
/**
* rescale a 64bit integer with specified rounding.
* a simple a*b/c isn't possible as it can overflow
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding);
/**
* rescale a 64bit integer by 2 rational numbers.
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq);
#endif /* MATHEMATICS_H */
+65 -65
View File
@@ -1,65 +1,65 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file mem.h
* Memory handling functions.
*/
#ifndef AV_MEM_H
#define AV_MEM_H
#ifdef __GNUC__
#define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n)))
#else
#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v
#endif
/**
* Memory allocation of size byte with alignment suitable for all
* memory accesses (including vectors if available on the
* CPU). av_malloc(0) must return a non NULL pointer.
*/
void *av_malloc(unsigned int size);
/**
* av_realloc semantics (same as glibc): if ptr is NULL and size > 0,
* identical to malloc(size). If size is zero, it is identical to
* free(ptr) and NULL is returned.
*/
void *av_realloc(void *ptr, unsigned int size);
/**
* Free memory which has been allocated with av_malloc(z)() or av_realloc().
* NOTE: ptr = NULL is explicetly allowed
* Note2: it is recommended that you use av_freep() instead
*/
void av_free(void *ptr);
void *av_mallocz(unsigned int size);
char *av_strdup(const char *s);
/**
* Frees memory and sets the pointer to NULL.
* @param ptr pointer to the pointer which should be freed
*/
void av_freep(void *ptr);
#endif /* AV_MEM_H */
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file mem.h
* Memory handling functions.
*/
#ifndef AV_MEM_H
#define AV_MEM_H
#ifdef __GNUC__
#define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n)))
#else
#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v
#endif
/**
* Memory allocation of size byte with alignment suitable for all
* memory accesses (including vectors if available on the
* CPU). av_malloc(0) must return a non NULL pointer.
*/
void *av_malloc(unsigned int size);
/**
* av_realloc semantics (same as glibc): if ptr is NULL and size > 0,
* identical to malloc(size). If size is zero, it is identical to
* free(ptr) and NULL is returned.
*/
void *av_realloc(void *ptr, unsigned int size);
/**
* Free memory which has been allocated with av_malloc(z)() or av_realloc().
* NOTE: ptr = NULL is explicetly allowed
* Note2: it is recommended that you use av_freep() instead
*/
void av_free(void *ptr);
void *av_mallocz(unsigned int size);
char *av_strdup(const char *s);
/**
* Frees memory and sets the pointer to NULL.
* @param ptr pointer to the pointer which should be freed
*/
void av_freep(void *ptr);
#endif /* AV_MEM_H */
+114 -114
View File
@@ -1,114 +1,114 @@
/*
* Rational numbers
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file rational.h
* Rational numbers.
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#ifndef RATIONAL_H
#define RATIONAL_H
/**
* Rational number num/den.
*/
typedef struct AVRational{
int num; ///< numerator
int den; ///< denominator
} AVRational;
/**
* Compare two rationals.
* @param a first rational
* @param b second rational
* @return 0 if a==b, 1 if a>b and -1 if a<b.
*/
static inline int av_cmp_q(AVRational a, AVRational b){
const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
if(tmp) return (int)((tmp>>63)|1);
else return 0;
}
/**
* Rational to double conversion.
* @param a rational to convert
* @return (double) a
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
/**
* Reduce a fraction.
* This is useful for framerate calculations.
* @param dst_nom destination numerator
* @param dst_den destination denominator
* @param nom source numerator
* @param den source denominator
* @param max the maximum allowed for dst_nom & dst_den
* @return 1 if exact, 0 otherwise
*/
int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max);
/**
* Multiplies two rationals.
* @param b first rational.
* @param c second rational.
* @return b*c.
*/
AVRational av_mul_q(AVRational b, AVRational c);
/**
* Divides one rational by another.
* @param b first rational.
* @param c second rational.
* @return b/c.
*/
AVRational av_div_q(AVRational b, AVRational c);
/**
* Adds two rationals.
* @param b first rational.
* @param c second rational.
* @return b+c.
*/
AVRational av_add_q(AVRational b, AVRational c);
/**
* Subtracts one rational from another.
* @param b first rational.
* @param c second rational.
* returns b-c.
*/
AVRational av_sub_q(AVRational b, AVRational c);
/**
* Converts a double precision floating point number to a rational.
* @param d double to convert
* @param max the maximum allowed numerator and denominator
* @return (AVRational) d.
*/
AVRational av_d2q(double d, int max);
#endif // RATIONAL_H
/*
* Rational numbers
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file rational.h
* Rational numbers.
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#ifndef RATIONAL_H
#define RATIONAL_H
/**
* Rational number num/den.
*/
typedef struct AVRational{
int num; ///< numerator
int den; ///< denominator
} AVRational;
/**
* Compare two rationals.
* @param a first rational
* @param b second rational
* @return 0 if a==b, 1 if a>b and -1 if a<b.
*/
static inline int av_cmp_q(AVRational a, AVRational b){
const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
if(tmp) return (int)((tmp>>63)|1);
else return 0;
}
/**
* Rational to double conversion.
* @param a rational to convert
* @return (double) a
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
/**
* Reduce a fraction.
* This is useful for framerate calculations.
* @param dst_nom destination numerator
* @param dst_den destination denominator
* @param nom source numerator
* @param den source denominator
* @param max the maximum allowed for dst_nom & dst_den
* @return 1 if exact, 0 otherwise
*/
int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max);
/**
* Multiplies two rationals.
* @param b first rational.
* @param c second rational.
* @return b*c.
*/
AVRational av_mul_q(AVRational b, AVRational c);
/**
* Divides one rational by another.
* @param b first rational.
* @param c second rational.
* @return b/c.
*/
AVRational av_div_q(AVRational b, AVRational c);
/**
* Adds two rationals.
* @param b first rational.
* @param c second rational.
* @return b+c.
*/
AVRational av_add_q(AVRational b, AVRational c);
/**
* Subtracts one rational from another.
* @param b first rational.
* @param c second rational.
* returns b-c.
*/
AVRational av_sub_q(AVRational b, AVRational c);
/**
* Converts a double precision floating point number to a rational.
* @param d double to convert
* @param max the maximum allowed numerator and denominator
* @return (AVRational) d.
*/
AVRational av_d2q(double d, int max);
#endif // RATIONAL_H
+127 -127
View File
@@ -1,127 +1,127 @@
/*
* RTP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTP_H
#define RTP_H
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_init(void);
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
/** return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec);
typedef struct RTPDemuxContext RTPDemuxContext;
typedef struct rtp_payload_data_s rtp_payload_data_s;
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data);
int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
const uint8_t *buf, int len);
void rtp_parse_close(RTPDemuxContext *s);
extern AVOutputFormat rtp_muxer;
extern AVInputFormat rtp_demuxer;
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
*/
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count);
extern URLProtocol rtp_protocol;
#define RTP_PT_PRIVATE 96
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /**< maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
/** Structure listing useful vars to parse RTP packet payload*/
typedef struct rtp_payload_data_s
{
int sizelength;
int indexlength;
int indexdeltalength;
int profile_level_id;
int streamtype;
int objecttype;
char *mode;
/** mpeg 4 AU headers */
struct AUHeaders {
int size;
int index;
int cts_flag;
int cts;
int dts_flag;
int dts;
int rap_flag;
int streamstate;
} *au_headers;
int nb_au_headers;
int au_headers_length_bytes;
int cur_au_index;
} rtp_payload_data_t;
typedef struct AVRtpPayloadType_s
{
int pt;
const char enc_name[50]; /* XXX: why 50 ? */
enum CodecType codec_type;
enum CodecID codec_id;
int clock_rate;
int audio_channels;
} AVRtpPayloadType_t;
#if 0
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
#endif
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
#endif /* RTP_H */
/*
* RTP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTP_H
#define RTP_H
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_init(void);
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
/** return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec);
typedef struct RTPDemuxContext RTPDemuxContext;
typedef struct rtp_payload_data_s rtp_payload_data_s;
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data);
int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
const uint8_t *buf, int len);
void rtp_parse_close(RTPDemuxContext *s);
extern AVOutputFormat rtp_muxer;
extern AVInputFormat rtp_demuxer;
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
*/
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count);
extern URLProtocol rtp_protocol;
#define RTP_PT_PRIVATE 96
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /**< maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
/** Structure listing useful vars to parse RTP packet payload*/
typedef struct rtp_payload_data_s
{
int sizelength;
int indexlength;
int indexdeltalength;
int profile_level_id;
int streamtype;
int objecttype;
char *mode;
/** mpeg 4 AU headers */
struct AUHeaders {
int size;
int index;
int cts_flag;
int cts;
int dts_flag;
int dts;
int rap_flag;
int streamstate;
} *au_headers;
int nb_au_headers;
int au_headers_length_bytes;
int cur_au_index;
} rtp_payload_data_t;
typedef struct AVRtpPayloadType_s
{
int pt;
const char enc_name[50]; /* XXX: why 50 ? */
enum CodecType codec_type;
enum CodecID codec_id;
int clock_rate;
int audio_channels;
} AVRtpPayloadType_t;
#if 0
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
#endif
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
#endif /* RTP_H */
+94 -94
View File
@@ -1,94 +1,94 @@
/*
* RTSP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTSP_H
#define RTSP_H
#include "rtspcodes.h"
enum RTSPProtocol {
RTSP_PROTOCOL_RTP_UDP = 0,
RTSP_PROTOCOL_RTP_TCP = 1,
RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2,
};
#define RTSP_DEFAULT_PORT 554
#define RTSP_MAX_TRANSPORTS 8
#define RTSP_TCP_MAX_PACKET_SIZE 1472
#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2
#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
#define RTSP_RTP_PORT_MIN 5000
#define RTSP_RTP_PORT_MAX 10000
typedef struct RTSPTransportField {
int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */
int port_min, port_max; /**< RTP ports */
int client_port_min, client_port_max; /**< RTP ports */
int server_port_min, server_port_max; /**< RTP ports */
int ttl; /**< ttl value */
uint32_t destination; /**< destination IP address */
enum RTSPProtocol protocol;
} RTSPTransportField;
typedef struct RTSPHeader {
int content_length;
enum RTSPStatusCode status_code; /**< response code from server */
int nb_transports;
/** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */
int64_t range_start, range_end;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /**< sequence number */
char session_id[512];
} RTSPHeader;
/** the callback can be used to extend the connection setup/teardown step */
enum RTSPCallbackAction {
RTSP_ACTION_SERVER_SETUP,
RTSP_ACTION_SERVER_TEARDOWN,
RTSP_ACTION_CLIENT_SETUP,
RTSP_ACTION_CLIENT_TEARDOWN,
};
typedef struct RTSPActionServerSetup {
uint32_t ipaddr;
char transport_option[512];
} RTSPActionServerSetup;
typedef int FFRTSPCallback(enum RTSPCallbackAction action,
const char *session_id,
char *buf, int buf_size,
void *arg);
/** useful for modules: set RTSP callback function */
void rtsp_set_callback(FFRTSPCallback *rtsp_cb);
int rtsp_init(void);
void rtsp_parse_line(RTSPHeader *reply, const char *buf);
extern int rtsp_default_protocols;
extern int rtsp_rtp_port_min;
extern int rtsp_rtp_port_max;
extern FFRTSPCallback *ff_rtsp_callback;
extern AVInputFormat rtsp_demuxer;
int rtsp_pause(AVFormatContext *s);
int rtsp_resume(AVFormatContext *s);
#endif /* RTSP_H */
/*
* RTSP definitions
* Copyright (c) 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTSP_H
#define RTSP_H
#include "rtspcodes.h"
enum RTSPProtocol {
RTSP_PROTOCOL_RTP_UDP = 0,
RTSP_PROTOCOL_RTP_TCP = 1,
RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2,
};
#define RTSP_DEFAULT_PORT 554
#define RTSP_MAX_TRANSPORTS 8
#define RTSP_TCP_MAX_PACKET_SIZE 1472
#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2
#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
#define RTSP_RTP_PORT_MIN 5000
#define RTSP_RTP_PORT_MAX 10000
typedef struct RTSPTransportField {
int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */
int port_min, port_max; /**< RTP ports */
int client_port_min, client_port_max; /**< RTP ports */
int server_port_min, server_port_max; /**< RTP ports */
int ttl; /**< ttl value */
uint32_t destination; /**< destination IP address */
enum RTSPProtocol protocol;
} RTSPTransportField;
typedef struct RTSPHeader {
int content_length;
enum RTSPStatusCode status_code; /**< response code from server */
int nb_transports;
/** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */
int64_t range_start, range_end;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /**< sequence number */
char session_id[512];
} RTSPHeader;
/** the callback can be used to extend the connection setup/teardown step */
enum RTSPCallbackAction {
RTSP_ACTION_SERVER_SETUP,
RTSP_ACTION_SERVER_TEARDOWN,
RTSP_ACTION_CLIENT_SETUP,
RTSP_ACTION_CLIENT_TEARDOWN,
};
typedef struct RTSPActionServerSetup {
uint32_t ipaddr;
char transport_option[512];
} RTSPActionServerSetup;
typedef int FFRTSPCallback(enum RTSPCallbackAction action,
const char *session_id,
char *buf, int buf_size,
void *arg);
/** useful for modules: set RTSP callback function */
void rtsp_set_callback(FFRTSPCallback *rtsp_cb);
int rtsp_init(void);
void rtsp_parse_line(RTSPHeader *reply, const char *buf);
extern int rtsp_default_protocols;
extern int rtsp_rtp_port_min;
extern int rtsp_rtp_port_max;
extern FFRTSPCallback *ff_rtsp_callback;
extern AVInputFormat rtsp_demuxer;
int rtsp_pause(AVFormatContext *s);
int rtsp_resume(AVFormatContext *s);
#endif /* RTSP_H */
+36 -36
View File
@@ -1,36 +1,36 @@
/*
* RTSP definitions
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** RTSP handling */
enum RTSPStatusCode {
RTSP_STATUS_OK =200, /**< OK */
RTSP_STATUS_METHOD =405, /**< Method Not Allowed */
RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */
RTSP_STATUS_SESSION =454, /**< Session Not Found */
RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */
RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */
RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */
RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */
RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */
RTSP_STATUS_SERVICE =503, /**< Service Unavailable */
RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */
};
/*
* RTSP definitions
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** RTSP handling */
enum RTSPStatusCode {
RTSP_STATUS_OK =200, /**< OK */
RTSP_STATUS_METHOD =405, /**< Method Not Allowed */
RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */
RTSP_STATUS_SESSION =454, /**< Session Not Found */
RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */
RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */
RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */
RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */
RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */
RTSP_STATUS_SERVICE =503, /**< Service Unavailable */
RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */
};
+117 -117
View File
@@ -1,117 +1,117 @@
* Introduction:
=============
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of
value, and a collection of name/value pairs.
JsonCpp is a simple API to manipulate JSON value, handle serialization
and unserialization to string.
It can also preserve existing comment in unserialization/serialization steps,
making it a convenient format to store user input files.
Unserialization parsing is user friendly and provides precise error reports.
* Building/Testing:
=================
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
python to be installed (http://www.python.org).
You download scons-local distribution from the following url:
http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375
Unzip it in the directory where you found this README file. scons.py Should be
at the same level as README.
python scons.py platform=PLTFRM [TARGET]
where PLTFRM may be one of:
suncc Sun C++ (Solaris)
vacpp Visual Age C++ (AIX)
mingw
msvc6 Microsoft Visual Studio 6 service pack 5-6
msvc70 Microsoft Visual Studio 2002
msvc71 Microsoft Visual Studio 2003
msvc80 Microsoft Visual Studio 2005
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
adding platform is fairly simple. You need to change the Sconstruct file
to do so.
and TARGET may be:
check: build library and run unit tests.
* Running the test manually:
==========================
cd test
# This will run the Reader/Writer tests
python runjsontests.py "path to jsontest.exe"
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker "path to jsontest.exe"
# This will run the unit tests (mostly Value)
python rununittests.py "path to test_lib_json.exe"
You can run the tests using valgrind:
python rununittests.py --valgrind "path to test_lib_json.exe"
* Building the documentation:
===========================
Run the python script doxybuild.py from the top directory:
python doxybuild.py --open --with-dot
See doxybuild.py --help for options.
* Adding a reader/writer test:
============================
To add a test, you need to create two files in test/data:
- a TESTNAME.json file, that contains the input document in JSON format.
- a TESTNAME.expected file, that contains a flatened representation of
the input document.
TESTNAME.expected file format:
- each line represents a JSON element of the element tree represented
by the input document.
- each line has two parts: the path to access the element separated from
the element value by '='. Array and object values are always empty
(e.g. represented by either [] or {}).
- element path: '.' represented the root element, and is used to separate
object members. [N] is used to specify the value of an array element
at index N.
See test_complex_01.json and test_complex_01.expected to better understand
element path.
* Understanding reader/writer test output:
========================================
When a test is run, output files are generated aside the input test files.
Below is a short description of the content of each file:
- test_complex_01.json: input JSON document
- test_complex_01.expected: flattened JSON element tree used to check if
parsing was corrected.
- test_complex_01.actual: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.json
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
Json::Value parsed from test_complex_01.json and serialized using
Json::StyledWritter.
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.rewrite.
test_complex_01.process-output: jsontest.exe output, typically useful to
understand parsing error.
* Introduction:
=============
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of
value, and a collection of name/value pairs.
JsonCpp is a simple API to manipulate JSON value, handle serialization
and unserialization to string.
It can also preserve existing comment in unserialization/serialization steps,
making it a convenient format to store user input files.
Unserialization parsing is user friendly and provides precise error reports.
* Building/Testing:
=================
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
python to be installed (http://www.python.org).
You download scons-local distribution from the following url:
http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375
Unzip it in the directory where you found this README file. scons.py Should be
at the same level as README.
python scons.py platform=PLTFRM [TARGET]
where PLTFRM may be one of:
suncc Sun C++ (Solaris)
vacpp Visual Age C++ (AIX)
mingw
msvc6 Microsoft Visual Studio 6 service pack 5-6
msvc70 Microsoft Visual Studio 2002
msvc71 Microsoft Visual Studio 2003
msvc80 Microsoft Visual Studio 2005
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
adding platform is fairly simple. You need to change the Sconstruct file
to do so.
and TARGET may be:
check: build library and run unit tests.
* Running the test manually:
==========================
cd test
# This will run the Reader/Writer tests
python runjsontests.py "path to jsontest.exe"
# This will run the Reader/Writer tests, using JSONChecker test suite
# (http://www.json.org/JSON_checker/).
# Notes: not all tests pass: JsonCpp is too lenient (for example,
# it allows an integer to start with '0'). The goal is to improve
# strict mode parsing to get all tests to pass.
python runjsontests.py --with-json-checker "path to jsontest.exe"
# This will run the unit tests (mostly Value)
python rununittests.py "path to test_lib_json.exe"
You can run the tests using valgrind:
python rununittests.py --valgrind "path to test_lib_json.exe"
* Building the documentation:
===========================
Run the python script doxybuild.py from the top directory:
python doxybuild.py --open --with-dot
See doxybuild.py --help for options.
* Adding a reader/writer test:
============================
To add a test, you need to create two files in test/data:
- a TESTNAME.json file, that contains the input document in JSON format.
- a TESTNAME.expected file, that contains a flatened representation of
the input document.
TESTNAME.expected file format:
- each line represents a JSON element of the element tree represented
by the input document.
- each line has two parts: the path to access the element separated from
the element value by '='. Array and object values are always empty
(e.g. represented by either [] or {}).
- element path: '.' represented the root element, and is used to separate
object members. [N] is used to specify the value of an array element
at index N.
See test_complex_01.json and test_complex_01.expected to better understand
element path.
* Understanding reader/writer test output:
========================================
When a test is run, output files are generated aside the input test files.
Below is a short description of the content of each file:
- test_complex_01.json: input JSON document
- test_complex_01.expected: flattened JSON element tree used to check if
parsing was corrected.
- test_complex_01.actual: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.json
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
Json::Value parsed from test_complex_01.json and serialized using
Json::StyledWritter.
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
jsontest.exe from reading test_complex_01.rewrite.
test_complex_01.process-output: jsontest.exe output, typically useful to
understand parsing error.
+1 -1
View File
@@ -1 +1 @@
The documentation is generated using doxygen (http://www.doxygen.org).
The documentation is generated using doxygen (http://www.doxygen.org).
+19 -19
View File
@@ -1,19 +1,19 @@
#ifndef JSON_AUTOLINK_H_INCLUDED
# define JSON_AUTOLINK_H_INCLUDED
# include "config.h"
# ifdef JSON_IN_CPPTL
# include <cpptl/cpptl_autolink.h>
# endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
# define CPPTL_AUTOLINK_NAME "json"
# undef CPPTL_AUTOLINK_DLL
# ifdef JSON_DLL
# define CPPTL_AUTOLINK_DLL
# endif
# include "autolink.h"
# endif
#endif // JSON_AUTOLINK_H_INCLUDED
#ifndef JSON_AUTOLINK_H_INCLUDED
# define JSON_AUTOLINK_H_INCLUDED
# include "config.h"
# ifdef JSON_IN_CPPTL
# include <cpptl/cpptl_autolink.h>
# endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
# define CPPTL_AUTOLINK_NAME "json"
# undef CPPTL_AUTOLINK_DLL
# ifdef JSON_DLL
# define CPPTL_AUTOLINK_DLL
# endif
# include "autolink.h"
# endif
#endif // JSON_AUTOLINK_H_INCLUDED
+43 -43
View File
@@ -1,43 +1,43 @@
#ifndef JSON_CONFIG_H_INCLUDED
# define JSON_CONFIG_H_INCLUDED
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL!
//# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation
/// instead of C assert macro.
# define JSON_USE_EXCEPTION 1
# ifdef JSON_IN_CPPTL
# include <cpptl/config.h>
# ifndef JSON_USE_CPPTL
# define JSON_USE_CPPTL 1
# endif
# endif
# ifdef JSON_IN_CPPTL
# define JSON_API CPPTL_API
# elif defined(JSON_DLL_BUILD)
# define JSON_API __declspec(dllexport)
# elif defined(JSON_DLL)
# define JSON_API __declspec(dllimport)
# else
# define JSON_API
# endif
#endif // JSON_CONFIG_H_INCLUDED
#ifndef JSON_CONFIG_H_INCLUDED
# define JSON_CONFIG_H_INCLUDED
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL!
//# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation
/// instead of C assert macro.
# define JSON_USE_EXCEPTION 1
# ifdef JSON_IN_CPPTL
# include <cpptl/config.h>
# ifndef JSON_USE_CPPTL
# define JSON_USE_CPPTL 1
# endif
# endif
# ifdef JSON_IN_CPPTL
# define JSON_API CPPTL_API
# elif defined(JSON_DLL_BUILD)
# define JSON_API __declspec(dllexport)
# elif defined(JSON_DLL)
# define JSON_API __declspec(dllimport)
# else
# define JSON_API
# endif
#endif // JSON_CONFIG_H_INCLUDED
+42 -42
View File
@@ -1,42 +1,42 @@
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
# define CPPTL_JSON_FEATURES_H_INCLUDED
# include "forwards.h"
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features
{
public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_;
};
} // namespace Json
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
# define CPPTL_JSON_FEATURES_H_INCLUDED
# include "forwards.h"
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features
{
public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_;
};
} // namespace Json
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+39 -39
View File
@@ -1,39 +1,39 @@
#ifndef JSON_FORWARDS_H_INCLUDED
# define JSON_FORWARDS_H_INCLUDED
# include "config.h"
namespace Json {
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
#ifdef JSON_VALUE_USE_INTERNAL_MAP
class ValueAllocator;
class ValueMapAllocator;
class ValueInternalLink;
class ValueInternalArray;
class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED
#ifndef JSON_FORWARDS_H_INCLUDED
# define JSON_FORWARDS_H_INCLUDED
# include "config.h"
namespace Json {
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
#ifdef JSON_VALUE_USE_INTERNAL_MAP
class ValueAllocator;
class ValueMapAllocator;
class ValueInternalLink;
class ValueInternalArray;
class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED
+10 -10
View File
@@ -1,10 +1,10 @@
#ifndef JSON_JSON_H_INCLUDED
# define JSON_JSON_H_INCLUDED
# include "autolink.h"
# include "value.h"
# include "reader.h"
# include "writer.h"
# include "features.h"
#endif // JSON_JSON_H_INCLUDED
#ifndef JSON_JSON_H_INCLUDED
# define JSON_JSON_H_INCLUDED
# include "autolink.h"
# include "value.h"
# include "reader.h"
# include "writer.h"
# include "features.h"
#endif // JSON_JSON_H_INCLUDED
+196 -196
View File
@@ -1,196 +1,196 @@
#ifndef CPPTL_JSON_READER_H_INCLUDED
# define CPPTL_JSON_READER_H_INCLUDED
# include "features.h"
# include "value.h"
# include <deque>
# include <stack>
# include <string>
# include <iostream>
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
*
*/
class JSON_API Reader
{
public:
typedef char Char;
typedef const Char *Location;
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader( const Features &features );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const std::string &document,
Value &root,
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const char *beginDoc, const char *endDoc,
Value &root,
bool collectComments = true );
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse( std::istream &is,
Value &root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document.
* \return Formatted error message with the list of errors with their location in
* the parsed document. An empty string is returned if no error occurred
* during parsing.
*/
std::string getFormatedErrorMessages() const;
private:
enum TokenType
{
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token
{
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo
{
public:
Token token_;
std::string message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool expectToken( TokenType type, Token &token, const char *message );
bool readToken( Token &token );
void skipSpaces();
bool match( Location pattern,
int patternLength );
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject( Token &token );
bool readArray( Token &token );
bool decodeNumber( Token &token );
bool decodeString( Token &token );
bool decodeString( Token &token, std::string &decoded );
bool decodeDouble( Token &token );
bool decodeUnicodeCodePoint( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool decodeUnicodeEscapeSequence( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool addError( const std::string &message,
Token &token,
Location extra = 0 );
bool recoverFromError( TokenType skipUntilToken );
bool addErrorAndRecover( const std::string &message,
Token &token,
TokenType skipUntilToken );
void skipUntilSpace();
Value &currentValue();
Char getNextChar();
void getLocationLineAndColumn( Location location,
int &line,
int &column ) const;
std::string getLocationLineAndColumn( Location location ) const;
void addComment( Location begin,
Location end,
CommentPlacement placement );
void skipCommentTokens( Token &token );
typedef std::stack<Value *> Nodes;
Nodes nodes_;
Errors errors_;
std::string document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value *lastValue_;
std::string commentsBefore_;
Features features_;
bool collectComments_;
};
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
std::istream& operator>>( std::istream&, Value& );
} // namespace Json
#endif // CPPTL_JSON_READER_H_INCLUDED
#ifndef CPPTL_JSON_READER_H_INCLUDED
# define CPPTL_JSON_READER_H_INCLUDED
# include "features.h"
# include "value.h"
# include <deque>
# include <stack>
# include <string>
# include <iostream>
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
*
*/
class JSON_API Reader
{
public:
typedef char Char;
typedef const Char *Location;
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader( const Features &features );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const std::string &document,
Value &root,
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse( const char *beginDoc, const char *endDoc,
Value &root,
bool collectComments = true );
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse( std::istream &is,
Value &root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document.
* \return Formatted error message with the list of errors with their location in
* the parsed document. An empty string is returned if no error occurred
* during parsing.
*/
std::string getFormatedErrorMessages() const;
private:
enum TokenType
{
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token
{
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo
{
public:
Token token_;
std::string message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool expectToken( TokenType type, Token &token, const char *message );
bool readToken( Token &token );
void skipSpaces();
bool match( Location pattern,
int patternLength );
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject( Token &token );
bool readArray( Token &token );
bool decodeNumber( Token &token );
bool decodeString( Token &token );
bool decodeString( Token &token, std::string &decoded );
bool decodeDouble( Token &token );
bool decodeUnicodeCodePoint( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool decodeUnicodeEscapeSequence( Token &token,
Location &current,
Location end,
unsigned int &unicode );
bool addError( const std::string &message,
Token &token,
Location extra = 0 );
bool recoverFromError( TokenType skipUntilToken );
bool addErrorAndRecover( const std::string &message,
Token &token,
TokenType skipUntilToken );
void skipUntilSpace();
Value &currentValue();
Char getNextChar();
void getLocationLineAndColumn( Location location,
int &line,
int &column ) const;
std::string getLocationLineAndColumn( Location location ) const;
void addComment( Location begin,
Location end,
CommentPlacement placement );
void skipCommentTokens( Token &token );
typedef std::stack<Value *> Nodes;
Nodes nodes_;
Errors errors_;
std::string document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value *lastValue_;
std::string commentsBefore_;
Features features_;
bool collectComments_;
};
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
std::istream& operator>>( std::istream&, Value& );
} // namespace Json
#endif // CPPTL_JSON_READER_H_INCLUDED
File diff suppressed because it is too large Load Diff
+174 -174
View File
@@ -1,174 +1,174 @@
#ifndef JSON_WRITER_H_INCLUDED
# define JSON_WRITER_H_INCLUDED
# include "value.h"
# include <vector>
# include <string>
# include <iostream>
namespace Json {
class Value;
/** \brief Abstract class for writers.
*/
class JSON_API Writer
{
public:
virtual ~Writer();
virtual std::string write( const Value &root ) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human' consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
*/
class JSON_API FastWriter : public Writer
{
public:
FastWriter();
virtual ~FastWriter(){}
void enableYAMLCompatibility();
public: // overridden from Writer
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
std::string document_;
bool yamlCompatiblityEnabled_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledWriter: public Writer
{
public:
StyledWriter();
virtual ~StyledWriter(){}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string document_;
std::string indentString_;
int rightMargin_;
int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledStreamWriter
{
public:
StyledStreamWriter( std::string indentation="\t" );
~StyledStreamWriter(){}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value.
*/
void write( std::ostream &out, const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::ostream* document_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
};
std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt value );
std::string JSON_API valueToString( double value );
std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *value );
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
std::ostream& operator<<( std::ostream&, const Value &root );
} // namespace Json
#endif // JSON_WRITER_H_INCLUDED
#ifndef JSON_WRITER_H_INCLUDED
# define JSON_WRITER_H_INCLUDED
# include "value.h"
# include <vector>
# include <string>
# include <iostream>
namespace Json {
class Value;
/** \brief Abstract class for writers.
*/
class JSON_API Writer
{
public:
virtual ~Writer();
virtual std::string write( const Value &root ) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human' consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
*/
class JSON_API FastWriter : public Writer
{
public:
FastWriter();
virtual ~FastWriter(){}
void enableYAMLCompatibility();
public: // overridden from Writer
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
std::string document_;
bool yamlCompatiblityEnabled_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledWriter: public Writer
{
public:
StyledWriter();
virtual ~StyledWriter(){}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string document_;
std::string indentString_;
int rightMargin_;
int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledStreamWriter
{
public:
StyledStreamWriter( std::string indentation="\t" );
~StyledStreamWriter(){}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value.
*/
void write( std::ostream &out, const Value &root );
private:
void writeValue( const Value &value );
void writeArrayValue( const Value &value );
bool isMultineArray( const Value &value );
void pushValue( const std::string &value );
void writeIndent();
void writeWithIndent( const std::string &value );
void indent();
void unindent();
void writeCommentBeforeValue( const Value &root );
void writeCommentAfterValueOnSameLine( const Value &root );
bool hasCommentForValue( const Value &value );
static std::string normalizeEOL( const std::string &text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::ostream* document_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
};
std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt value );
std::string JSON_API valueToString( double value );
std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *value );
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
std::ostream& operator<<( std::ostream&, const Value &root );
} // namespace Json
#endif // JSON_WRITER_H_INCLUDED
+125 -125
View File
@@ -1,125 +1,125 @@
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
# include <stdlib.h>
# include <assert.h>
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
namespace Json {
/* Fast memory allocator.
*
* This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page).
*
* It does not allow the destruction of a single object. All the allocated objects
* can be destroyed at once. The memory can be either released or reused for future
* allocation.
*
* The in-place new operator must be used to construct the object using the pointer
* returned by allocate.
*/
template<typename AllocatedType
,const unsigned int objectPerAllocation>
class BatchAllocator
{
public:
typedef AllocatedType Type;
BatchAllocator( unsigned int objectsPerPage = 255 )
: freeHead_( 0 )
, objectsPerPage_( objectsPerPage )
{
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
assert( objectsPerPage >= 16 );
batches_ = allocateBatch( 0 ); // allocated a dummy page
currentBatch_ = batches_;
}
~BatchAllocator()
{
for ( BatchInfo *batch = batches_; batch; )
{
BatchInfo *nextBatch = batch->next_;
free( batch );
batch = nextBatch;
}
}
/// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors.
AllocatedType *allocate()
{
if ( freeHead_ ) // returns node from free list.
{
AllocatedType *object = freeHead_;
freeHead_ = *(AllocatedType **)object;
return object;
}
if ( currentBatch_->used_ == currentBatch_->end_ )
{
currentBatch_ = currentBatch_->next_;
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
currentBatch_ = currentBatch_->next_;
if ( !currentBatch_ ) // no free batch found, allocate a new one
{
currentBatch_ = allocateBatch( objectsPerPage_ );
currentBatch_->next_ = batches_; // insert at the head of the list
batches_ = currentBatch_;
}
}
AllocatedType *allocated = currentBatch_->used_;
currentBatch_->used_ += objectPerAllocation;
return allocated;
}
/// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object.
void release( AllocatedType *object )
{
assert( object != 0 );
*(AllocatedType **)object = freeHead_;
freeHead_ = object;
}
private:
struct BatchInfo
{
BatchInfo *next_;
AllocatedType *used_;
AllocatedType *end_;
AllocatedType buffer_[objectPerAllocation];
};
// disabled copy constructor and assignement operator.
BatchAllocator( const BatchAllocator & );
void operator =( const BatchAllocator &);
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
{
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
batch->next_ = 0;
batch->used_ = batch->buffer_;
batch->end_ = batch->buffer_ + objectsPerPage;
return batch;
}
BatchInfo *batches_;
BatchInfo *currentBatch_;
/// Head of a single linked list within the allocated space of freeed object
AllocatedType *freeHead_;
unsigned int objectsPerPage_;
};
} // namespace Json
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
# include <stdlib.h>
# include <assert.h>
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
namespace Json {
/* Fast memory allocator.
*
* This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page).
*
* It does not allow the destruction of a single object. All the allocated objects
* can be destroyed at once. The memory can be either released or reused for future
* allocation.
*
* The in-place new operator must be used to construct the object using the pointer
* returned by allocate.
*/
template<typename AllocatedType
,const unsigned int objectPerAllocation>
class BatchAllocator
{
public:
typedef AllocatedType Type;
BatchAllocator( unsigned int objectsPerPage = 255 )
: freeHead_( 0 )
, objectsPerPage_( objectsPerPage )
{
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
assert( objectsPerPage >= 16 );
batches_ = allocateBatch( 0 ); // allocated a dummy page
currentBatch_ = batches_;
}
~BatchAllocator()
{
for ( BatchInfo *batch = batches_; batch; )
{
BatchInfo *nextBatch = batch->next_;
free( batch );
batch = nextBatch;
}
}
/// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors.
AllocatedType *allocate()
{
if ( freeHead_ ) // returns node from free list.
{
AllocatedType *object = freeHead_;
freeHead_ = *(AllocatedType **)object;
return object;
}
if ( currentBatch_->used_ == currentBatch_->end_ )
{
currentBatch_ = currentBatch_->next_;
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
currentBatch_ = currentBatch_->next_;
if ( !currentBatch_ ) // no free batch found, allocate a new one
{
currentBatch_ = allocateBatch( objectsPerPage_ );
currentBatch_->next_ = batches_; // insert at the head of the list
batches_ = currentBatch_;
}
}
AllocatedType *allocated = currentBatch_->used_;
currentBatch_->used_ += objectPerAllocation;
return allocated;
}
/// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object.
void release( AllocatedType *object )
{
assert( object != 0 );
*(AllocatedType **)object = freeHead_;
freeHead_ = object;
}
private:
struct BatchInfo
{
BatchInfo *next_;
AllocatedType *used_;
AllocatedType *end_;
AllocatedType buffer_[objectPerAllocation];
};
// disabled copy constructor and assignement operator.
BatchAllocator( const BatchAllocator & );
void operator =( const BatchAllocator &);
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
{
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
batch->next_ = 0;
batch->used_ = batch->buffer_;
batch->end_ = batch->buffer_ + objectsPerPage;
return batch;
}
BatchInfo *batches_;
BatchInfo *currentBatch_;
/// Head of a single linked list within the allocated space of freeed object
AllocatedType *freeHead_;
unsigned int objectsPerPage_;
};
} // namespace Json
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6398 -6398
View File
File diff suppressed because it is too large Load Diff