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:
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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
@@ -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 |
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
""
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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)
|
||||
};
|
||||
@@ -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)
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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/
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+63
-63
@@ -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
File diff suppressed because it is too large
Load Diff
+103
-103
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
+3073
-3073
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+272
-272
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 @@
|
||||
The documentation is generated using doxygen (http://www.doxygen.org).
|
||||
The documentation is generated using doxygen (http://www.doxygen.org).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
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 ¤tValue();
|
||||
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 ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
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 ¤tValue();
|
||||
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
|
||||
|
||||
+1069
-1069
File diff suppressed because it is too large
Load Diff
+174
-174
@@ -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
|
||||
|
||||
@@ -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
+1718
-1718
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+6398
-6398
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user