Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
YGOMobile-Cn-Ko-En
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fallenstardust
YGOMobile-Cn-Ko-En
Commits
f9b63108
Commit
f9b63108
authored
Nov 14, 2019
by
Unicorn369
Committed by
fallenstardust
Dec 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add sound_openal (by kevinlul)
parent
b538dc43
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1173 additions
and
0 deletions
+1173
-0
Classes/gframe/sound_manager.cpp
Classes/gframe/sound_manager.cpp
+211
-0
Classes/gframe/sound_manager.h
Classes/gframe/sound_manager.h
+92
-0
Classes/gframe/sound_openal.cpp
Classes/gframe/sound_openal.cpp
+219
-0
Classes/gframe/sound_openal.h
Classes/gframe/sound_openal.h
+55
-0
Classes/gframe/utils.cpp
Classes/gframe/utils.cpp
+540
-0
Classes/gframe/utils.h
Classes/gframe/utils.h
+56
-0
No files found.
Classes/gframe/sound_manager.cpp
0 → 100644
View file @
f9b63108
#include "sound_manager.h"
#include "config.h"
#ifdef IRRKLANG_STATIC
#include "../ikpmp3/ikpMP3.h"
#endif
namespace
ygo
{
bool
SoundManager
::
Init
(
double
sounds_volume
,
double
music_volume
,
bool
sounds_enabled
,
bool
music_enabled
,
void
*
payload
)
{
soundsEnabled
=
sounds_enabled
;
musicEnabled
=
music_enabled
;
rnd
.
seed
(
time
(
0
));
bgm_scene
=
-
1
;
RefreshBGMList
();
RefreshChantsList
();
#ifdef YGOPRO_USE_IRRKLANG
soundEngine
=
irrklang
::
createIrrKlangDevice
();
if
(
!
soundEngine
)
{
return
soundsEnabled
=
musicEnabled
=
false
;
}
else
{
#ifdef IRRKLANG_STATIC
irrklang
::
ikpMP3Init
(
soundEngine
);
#endif
sfxVolume
=
sounds_volume
;
bgmVolume
=
music_volume
;
return
true
;
}
#else
try
{
openal
=
std
::
make_unique
<
YGOpen
::
OpenALSingleton
>
();
sfx
=
std
::
make_unique
<
YGOpen
::
OpenALSoundLayer
>
(
openal
);
bgm
=
std
::
make_unique
<
YGOpen
::
OpenALSoundLayer
>
(
openal
);
sfx
->
setVolume
(
sounds_volume
);
bgm
->
setVolume
(
music_volume
);
return
true
;
}
catch
(
std
::
runtime_error
&
e
)
{
return
soundsEnabled
=
musicEnabled
=
false
;
}
#endif // YGOPRO_USE_IRRKLANG
}
SoundManager
::~
SoundManager
()
{
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundBGM
)
soundBGM
->
drop
();
if
(
soundEngine
)
soundEngine
->
drop
();
#endif
}
void
SoundManager
::
RefreshBGMList
()
{
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/duel"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/menu"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/deck"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/advantage"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/disadvantage"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/win"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/BGM/lose"
));
Utils
::
Makedirectory
(
TEXT
(
"./sound/chants"
));
RefreshBGMDir
(
TEXT
(
""
),
BGM
::
DUEL
);
RefreshBGMDir
(
TEXT
(
"duel"
),
BGM
::
DUEL
);
RefreshBGMDir
(
TEXT
(
"menu"
),
BGM
::
MENU
);
RefreshBGMDir
(
TEXT
(
"deck"
),
BGM
::
DECK
);
RefreshBGMDir
(
TEXT
(
"advantage"
),
BGM
::
ADVANTAGE
);
RefreshBGMDir
(
TEXT
(
"disadvantage"
),
BGM
::
DISADVANTAGE
);
RefreshBGMDir
(
TEXT
(
"win"
),
BGM
::
WIN
);
RefreshBGMDir
(
TEXT
(
"lose"
),
BGM
::
LOSE
);
}
void
SoundManager
::
RefreshBGMDir
(
path_string
path
,
BGM
scene
)
{
for
(
auto
&
file
:
Utils
::
FindfolderFiles
(
TEXT
(
"./sound/BGM/"
)
+
path
,
{
TEXT
(
"mp3"
),
TEXT
(
"ogg"
),
TEXT
(
"wav"
)
}))
{
auto
conv
=
Utils
::
ToUTF8IfNeeded
(
path
+
TEXT
(
"/"
)
+
file
);
BGMList
[
BGM
::
ALL
].
push_back
(
conv
);
BGMList
[
scene
].
push_back
(
conv
);
}
}
void
SoundManager
::
RefreshChantsList
()
{
for
(
auto
&
file
:
Utils
::
FindfolderFiles
(
TEXT
(
"./sound/chants"
),
{
TEXT
(
"mp3"
),
TEXT
(
"ogg"
),
TEXT
(
"wav"
)
}))
{
auto
scode
=
Utils
::
GetFileName
(
TEXT
(
"./sound/chants/"
)
+
file
);
unsigned
int
code
=
std
::
stoi
(
scode
);
if
(
code
&&
!
ChantsList
.
count
(
code
))
ChantsList
[
code
]
=
Utils
::
ToUTF8IfNeeded
(
file
);
}
}
void
SoundManager
::
PlaySoundEffect
(
SFX
sound
)
{
static
const
std
::
map
<
SFX
,
const
char
*>
fx
=
{
{
SUMMON
,
"./sound/summon.wav"
},
{
SPECIAL_SUMMON
,
"./sound/specialsummon.wav"
},
{
ACTIVATE
,
"./sound/activate.wav"
},
{
SET
,
"./sound/set.wav"
},
{
FLIP
,
"./sound/flip.wav"
},
{
REVEAL
,
"./sound/reveal.wav"
},
{
EQUIP
,
"./sound/equip.wav"
},
{
DESTROYED
,
"./sound/destroyed.wav"
},
{
BANISHED
,
"./sound/banished.wav"
},
{
TOKEN
,
"./sound/token.wav"
},
{
ATTACK
,
"./sound/attack.wav"
},
{
DIRECT_ATTACK
,
"./sound/directattack.wav"
},
{
DRAW
,
"./sound/draw.wav"
},
{
SHUFFLE
,
"./sound/shuffle.wav"
},
{
DAMAGE
,
"./sound/damage.wav"
},
{
RECOVER
,
"./sound/gainlp.wav"
},
{
COUNTER_ADD
,
"./sound/addcounter.wav"
},
{
COUNTER_REMOVE
,
"./sound/removecounter.wav"
},
{
COIN
,
"./sound/coinflip.wav"
},
{
DICE
,
"./sound/diceroll.wav"
},
{
NEXT_TURN
,
"./sound/nextturn.wav"
},
{
PHASE
,
"./sound/phase.wav"
},
{
PLAYER_ENTER
,
"./sound/playerenter.wav"
},
{
CHAT
,
"./sound/chatmessage.wav"
}
};
if
(
!
soundsEnabled
)
return
;
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundEngine
)
{
auto
sfx
=
soundEngine
->
play2D
(
fx
.
at
(
sound
),
false
,
true
);
sfx
->
setVolume
(
sfxVolume
);
sfx
->
setIsPaused
(
false
);
}
#else
if
(
sfx
)
sfx
->
play
(
fx
.
at
(
sound
),
false
);
#endif
}
void
SoundManager
::
PlayMusic
(
const
std
::
string
&
song
,
bool
loop
)
{
if
(
!
musicEnabled
)
return
;
#ifdef YGOPRO_USE_IRRKLANG
if
(
!
soundBGM
||
soundBGM
->
getSoundSource
()
->
getName
()
!=
song
)
{
StopBGM
();
if
(
soundEngine
)
{
soundBGM
=
soundEngine
->
play2D
(
song
.
c_str
(),
loop
,
false
,
true
);
soundBGM
->
setVolume
(
bgmVolume
);
}
}
#else
StopBGM
();
if
(
bgm
)
bgmCurrent
=
bgm
->
play
(
song
,
loop
);
#endif
}
void
SoundManager
::
PlayBGM
(
BGM
scene
)
{
auto
&
list
=
BGMList
[
scene
];
int
count
=
list
.
size
();
#ifdef YGOPRO_USE_IRRKLANG
if
(
musicEnabled
&&
(
scene
!=
bgm_scene
||
(
soundBGM
&&
soundBGM
->
isFinished
())
||
!
soundBGM
)
&&
count
>
0
)
{
#else
if
(
musicEnabled
&&
(
scene
!=
bgm_scene
||
!
bgm
->
exists
(
bgmCurrent
))
&&
count
>
0
)
{
#endif
bgm_scene
=
scene
;
int
bgm
=
(
std
::
uniform_int_distribution
<>
(
0
,
count
-
1
))(
rnd
);
std
::
string
BGMName
=
"./sound/BGM/"
+
list
[
bgm
];
PlayMusic
(
BGMName
,
true
);
}
}
void
SoundManager
::
StopBGM
()
{
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundBGM
)
{
soundBGM
->
stop
();
soundBGM
->
drop
();
soundBGM
=
nullptr
;
}
#else
bgm
->
stopAll
();
#endif
}
bool
SoundManager
::
PlayChant
(
unsigned
int
code
)
{
if
(
ChantsList
.
count
(
code
))
{
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundEngine
&&
!
soundEngine
->
isCurrentlyPlaying
((
"./sound/chants/"
+
ChantsList
[
code
]).
c_str
()))
{
auto
chant
=
soundEngine
->
play2D
((
"./sound/chants/"
+
ChantsList
[
code
]).
c_str
());
chant
->
setVolume
(
sfxVolume
);
chant
->
setIsPaused
(
false
);
}
#else
if
(
bgm
)
bgm
->
play
(
"./sound/chants/"
+
ChantsList
[
code
],
false
);
#endif
return
true
;
}
return
false
;
}
void
SoundManager
::
SetSoundVolume
(
double
volume
)
{
#ifdef YGOPRO_USE_IRRKLANG
sfxVolume
=
volume
;
#else
if
(
sfx
)
sfx
->
setVolume
(
volume
);
#endif
}
void
SoundManager
::
SetMusicVolume
(
double
volume
)
{
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundBGM
)
soundBGM
->
setVolume
(
volume
);
bgmVolume
=
volume
;
#else
if
(
bgm
)
bgm
->
setVolume
(
volume
);
#endif
}
void
SoundManager
::
EnableSounds
(
bool
enable
)
{
soundsEnabled
=
enable
;
}
void
SoundManager
::
EnableMusic
(
bool
enable
)
{
musicEnabled
=
enable
;
if
(
!
musicEnabled
)
{
#ifdef YGOPRO_USE_IRRKLANG
if
(
soundBGM
){
if
(
!
soundBGM
->
isFinished
())
soundBGM
->
stop
();
soundBGM
->
drop
();
soundBGM
=
nullptr
;
}
#else
StopBGM
();
#endif
}
}
}
// namespace ygo
Classes/gframe/sound_manager.h
0 → 100644
View file @
f9b63108
#ifndef SOUNDMANAGER_H
#define SOUNDMANAGER_H
#include <random>
#ifdef YGOPRO_USE_IRRKLANG
#include <irrKlang.h>
#else
#include "sound_openal.h"
#endif
#include "utils.h"
namespace
ygo
{
class
SoundManager
{
public:
enum
SFX
{
SUMMON
,
SPECIAL_SUMMON
,
ACTIVATE
,
SET
,
FLIP
,
REVEAL
,
EQUIP
,
DESTROYED
,
BANISHED
,
TOKEN
,
ATTACK
,
DIRECT_ATTACK
,
DRAW
,
SHUFFLE
,
DAMAGE
,
RECOVER
,
COUNTER_ADD
,
COUNTER_REMOVE
,
COIN
,
DICE
,
NEXT_TURN
,
PHASE
,
PLAYER_ENTER
,
CHAT
};
enum
BGM
{
ALL
,
DUEL
,
MENU
,
DECK
,
ADVANTAGE
,
DISADVANTAGE
,
WIN
,
LOSE
};
#ifndef YGOPRO_USE_IRRKLANG
SoundManager
()
:
openal
(
nullptr
),
sfx
(
nullptr
)
{}
#endif
~
SoundManager
();
bool
Init
(
double
sounds_volume
,
double
music_volume
,
bool
sounds_enabled
,
bool
music_enabled
,
void
*
payload
=
nullptr
);
void
RefreshBGMList
();
void
PlaySoundEffect
(
SFX
sound
);
void
PlayMusic
(
const
std
::
string
&
song
,
bool
loop
);
void
PlayBGM
(
BGM
scene
);
void
StopBGM
();
bool
PlayChant
(
unsigned
int
code
);
void
SetSoundVolume
(
double
volume
);
void
SetMusicVolume
(
double
volume
);
void
EnableSounds
(
bool
enable
);
void
EnableMusic
(
bool
enable
);
private:
std
::
vector
<
std
::
string
>
BGMList
[
8
];
std
::
map
<
unsigned
int
,
std
::
string
>
ChantsList
;
int
bgm_scene
=
-
1
;
std
::
mt19937
rnd
;
#ifdef YGOPRO_USE_IRRKLANG
irrklang
::
ISoundEngine
*
soundEngine
;
irrklang
::
ISound
*
soundBGM
;
double
sfxVolume
=
1.0
;
double
bgmVolume
=
1.0
;
#else
std
::
unique_ptr
<
YGOpen
::
OpenALSingleton
>
openal
;
std
::
unique_ptr
<
YGOpen
::
OpenALSoundLayer
>
sfx
;
std
::
unique_ptr
<
YGOpen
::
OpenALSoundLayer
>
bgm
;
int
bgmCurrent
=
-
1
;
#endif
void
RefreshBGMDir
(
path_string
path
,
BGM
scene
);
void
RefreshChantsList
();
bool
soundsEnabled
=
false
;
bool
musicEnabled
=
false
;
};
}
#endif //SOUNDMANAGER_H
\ No newline at end of file
Classes/gframe/sound_openal.cpp
0 → 100644
View file @
f9b63108
#include "sound_openal.h"
#include <array>
#include <iterator>
#include <mpg123.h>
#include <sndfile.h>
#include "utils.h"
namespace
YGOpen
{
static
void
delete_ALCdevice
(
ALCdevice
*
ptr
)
{
if
(
ptr
)
{
alcCloseDevice
(
ptr
);
}
}
static
void
delete_ALCcontext
(
ALCcontext
*
ptr
)
{
if
(
ptr
)
{
alcMakeContextCurrent
(
nullptr
);
alcDestroyContext
(
ptr
);
}
}
OpenALSingleton
::
OpenALSingleton
()
:
device
(
nullptr
,
delete_ALCdevice
),
context
(
nullptr
,
delete_ALCcontext
)
{
device
.
reset
(
alcOpenDevice
(
nullptr
));
if
(
!
device
)
{
throw
std
::
runtime_error
(
"Failed to create OpenAL audio device!"
);
}
context
.
reset
(
alcCreateContext
(
device
.
get
(),
nullptr
));
if
(
!
alcMakeContextCurrent
(
context
.
get
()))
{
throw
std
::
runtime_error
(
"Failed to set OpenAL audio context!"
);
}
mpg123_init
();
}
OpenALSingleton
::~
OpenALSingleton
()
{
mpg123_exit
();
}
OpenALSoundLayer
::
OpenALSoundLayer
(
const
std
::
unique_ptr
<
OpenALSingleton
>&
openal
)
:
openal
(
openal
),
buffers
(),
playing
()
{}
OpenALSoundLayer
::~
OpenALSoundLayer
()
{
stopAll
();
for
(
const
auto
&
iter
:
buffers
)
{
alDeleteBuffers
(
1
,
&
iter
.
second
->
id
);
}
}
static
inline
bool
alUtilInitBuffer
(
std
::
shared_ptr
<
OpenALSoundBuffer
>
data
)
{
alGetError
();
alGenBuffers
(
1
,
&
data
->
id
);
ALenum
error
=
alGetError
();
if
(
error
!=
AL_NO_ERROR
)
return
false
;
alBufferData
(
data
->
id
,
data
->
format
,
data
->
buffer
.
data
(),
data
->
buffer
.
size
(),
data
->
frequency
);
error
=
alGetError
();
if
(
error
!=
AL_NO_ERROR
)
return
false
;
return
true
;
}
static
inline
ALenum
alUtilFormatFromMp3
(
const
int
channels
,
const
int
encoding
)
{
if
(
channels
&
MPG123_STEREO
)
{
if
(
encoding
&
MPG123_ENC_SIGNED_16
)
{
return
AL_FORMAT_STEREO16
;
}
else
{
return
AL_FORMAT_STEREO8
;
}
}
else
{
if
(
encoding
&
MPG123_ENC_SIGNED_16
)
{
return
AL_FORMAT_MONO16
;
}
else
{
return
AL_FORMAT_MONO8
;
}
}
}
static
std
::
shared_ptr
<
OpenALSoundBuffer
>
loadMp3
(
const
std
::
string
&
filename
)
{
auto
data
=
std
::
make_shared
<
OpenALSoundBuffer
>
();
std
::
vector
<
unsigned
char
>
buffer
;
size_t
bufferSize
;
int
mpgError
,
channels
,
encoding
;
long
rate
;
auto
mpgHandle
=
mpg123_new
(
nullptr
,
&
mpgError
);
if
(
!
mpgHandle
)
return
nullptr
;
if
(
mpg123_open
(
mpgHandle
,
filename
.
c_str
())
!=
MPG123_OK
||
mpg123_getformat
(
mpgHandle
,
&
rate
,
&
channels
,
&
encoding
)
!=
MPG123_OK
)
{
mpg123_delete
(
mpgHandle
);
return
nullptr
;
}
mpg123_format_none
(
mpgHandle
);
mpg123_format
(
mpgHandle
,
rate
,
channels
,
encoding
);
bufferSize
=
mpg123_outblock
(
mpgHandle
);
buffer
.
resize
(
bufferSize
);
for
(
size_t
read
=
1
;
read
!=
0
&&
mpgError
==
MPG123_OK
;
)
{
mpgError
=
mpg123_read
(
mpgHandle
,
buffer
.
data
(),
bufferSize
,
&
read
);
data
->
buffer
.
insert
(
data
->
buffer
.
end
(),
buffer
.
begin
(),
buffer
.
end
());
}
mpg123_close
(
mpgHandle
);
mpg123_delete
(
mpgHandle
);
if
(
mpgError
!=
MPG123_DONE
)
return
nullptr
;
data
->
format
=
alUtilFormatFromMp3
(
channels
,
encoding
);
data
->
frequency
=
rate
;
return
alUtilInitBuffer
(
data
)
?
data
:
nullptr
;
}
static
std
::
shared_ptr
<
OpenALSoundBuffer
>
loadSnd
(
const
std
::
string
&
filename
)
{
auto
data
=
std
::
make_shared
<
OpenALSoundBuffer
>
();
SF_INFO
info
;
std
::
unique_ptr
<
SNDFILE
,
std
::
function
<
void
(
SNDFILE
*
)
>>
file
(
sf_open
(
filename
.
c_str
(),
SFM_READ
,
&
info
),
[](
SNDFILE
*
ptr
)
{
sf_close
(
ptr
);
});
if
(
!
file
)
return
nullptr
;
data
->
frequency
=
info
.
samplerate
;
data
->
format
=
info
.
channels
==
1
?
AL_FORMAT_MONO16
:
AL_FORMAT_STEREO16
;
data
->
buffer
.
resize
(
info
.
frames
*
info
.
channels
*
sizeof
(
short
));
if
(
sf_readf_short
(
file
.
get
(),
reinterpret_cast
<
short
*>
(
data
->
buffer
.
data
()),
info
.
frames
)
!=
info
.
frames
)
return
nullptr
;
return
alUtilInitBuffer
(
data
)
?
data
:
nullptr
;
}
bool
OpenALSoundLayer
::
load
(
const
std
::
string
&
filename
)
{
std
::
shared_ptr
<
OpenALSoundBuffer
>
data
(
nullptr
);
auto
ext
=
ygo
::
Utils
::
GetFileExtension
(
filename
);
if
(
ext
==
"mp3"
)
{
data
=
loadMp3
(
filename
);
}
else
{
data
=
loadSnd
(
filename
);
}
if
(
!
data
)
return
false
;
buffers
[
filename
]
=
data
;
return
true
;
}
int
OpenALSoundLayer
::
play
(
const
std
::
string
&
filename
,
bool
loop
)
{
maintain
();
if
(
buffers
.
find
(
filename
)
==
buffers
.
end
())
{
if
(
!
load
(
filename
))
return
-
1
;
}
ALuint
buffer
=
buffers
.
at
(
filename
)
->
id
;
ALuint
source
;
alGetError
();
alGenSources
(
1
,
&
source
);
ALenum
error
=
alGetError
();
if
(
error
!=
AL_NO_ERROR
)
return
-
1
;
alSourcei
(
source
,
AL_BUFFER
,
buffer
);
alSourcei
(
source
,
AL_LOOPING
,
loop
?
AL_TRUE
:
AL_FALSE
);
alSourcef
(
source
,
AL_GAIN
,
volume
);
alSourcePlay
(
source
);
error
=
alGetError
();
if
(
error
!=
AL_NO_ERROR
)
{
alDeleteSources
(
1
,
&
source
);
return
-
1
;
}
playing
.
insert
(
source
);
return
source
;
}
bool
OpenALSoundLayer
::
exists
(
int
sound
)
{
maintain
();
return
playing
.
find
(
sound
)
!=
playing
.
end
();
}
void
OpenALSoundLayer
::
stop
(
int
sound
)
{
maintain
();
const
auto
iter
=
playing
.
find
(
sound
);
if
(
playing
.
find
(
sound
)
!=
playing
.
end
())
{
alSourceStop
(
sound
);
alDeleteSources
(
1
,
&*
iter
);
playing
.
erase
(
iter
);
}
}
void
OpenALSoundLayer
::
stopAll
()
{
for
(
const
auto
&
iter
:
playing
)
{
alSourceStop
(
iter
);
alDeleteSources
(
1
,
&
iter
);
}
playing
.
clear
();
}
void
OpenALSoundLayer
::
setVolume
(
float
gain
)
{
volume
=
gain
;
for
(
const
auto
&
iter
:
playing
)
{
alSourcef
(
iter
,
AL_GAIN
,
volume
);
}
}
void
OpenALSoundLayer
::
maintain
()
{
std
::
unordered_set
<
ALuint
>
toDelete
;
for
(
const
auto
&
iter
:
playing
)
{
ALint
state
;
alGetSourcei
(
iter
,
AL_SOURCE_STATE
,
&
state
);
if
(
state
!=
AL_PLAYING
)
{
toDelete
.
insert
(
iter
);
}
}
for
(
const
auto
&
iter
:
toDelete
)
{
alSourceStop
(
iter
);
alDeleteSources
(
1
,
&
iter
);
playing
.
erase
(
iter
);
}
}
}
// namespace YGOpen
Classes/gframe/sound_openal.h
0 → 100644
View file @
f9b63108
#ifndef YGOPEN_SOUND_OPENAL_H
#define YGOPEN_SOUND_OPENAL_H
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <AL/al.h>
#include <AL/alc.h>
namespace
YGOpen
{
/* Modified from minetest: src/client/sound.h, src/client/sound_openal.cpp
* https://github.com/minetest/minetest
* Licensed under GNU LGPLv2.1
*/
struct
OpenALSoundBuffer
{
ALenum
format
;
ALsizei
frequency
;
ALuint
id
;
std
::
vector
<
char
>
buffer
;
};
class
OpenALSingleton
{
public:
OpenALSingleton
();
~
OpenALSingleton
();
std
::
unique_ptr
<
ALCdevice
,
void
(
*
)(
ALCdevice
*
ptr
)
>
device
;
std
::
unique_ptr
<
ALCcontext
,
void
(
*
)(
ALCcontext
*
ptr
)
>
context
;
};
class
OpenALSoundLayer
{
public:
OpenALSoundLayer
(
const
std
::
unique_ptr
<
OpenALSingleton
>&
openal
);
~
OpenALSoundLayer
();
bool
load
(
const
std
::
string
&
filename
);
int
play
(
const
std
::
string
&
filename
,
bool
loop
);
bool
exists
(
int
sound
);
void
stop
(
int
sound
);
void
stopAll
();
void
setVolume
(
float
gain
);
private:
void
maintain
();
const
std
::
unique_ptr
<
OpenALSingleton
>&
openal
;
std
::
unordered_map
<
std
::
string
,
std
::
shared_ptr
<
OpenALSoundBuffer
>>
buffers
;
std
::
unordered_set
<
ALuint
>
playing
;
float
volume
=
1.0
f
;
};
}
#endif //YGOPEN_SOUND_OPENAL_H
Classes/gframe/utils.cpp
0 → 100644
View file @
f9b63108
#include "utils.h"
#include "game.h"
#include <fstream>
#include "bufferio.h"
#ifdef _WIN32
#include "../irrlicht/src/CIrrDeviceWin32.h"
#elif defined(__linux__)
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#elif defined(__APPLE__)
#include "osx_menu.h"
#endif
namespace
ygo
{
bool
Utils
::
Makedirectory
(
const
path_string
&
path
)
{
#ifdef _WIN32
return
CreateDirectory
(
path
.
c_str
(),
NULL
)
||
ERROR_ALREADY_EXISTS
==
GetLastError
();
#else
return
!
mkdir
(
&
path
[
0
],
0777
)
||
errno
==
EEXIST
;
#endif
}
bool
Utils
::
Movefile
(
const
path_string
&
_source
,
const
path_string
&
_destination
)
{
path_string
source
=
ParseFilename
(
_source
);
path_string
destination
=
ParseFilename
(
_destination
);
if
(
source
==
destination
)
return
false
;
std
::
ifstream
src
(
source
,
std
::
ios
::
binary
);
if
(
!
src
.
is_open
())
return
false
;
std
::
ofstream
dst
(
destination
,
std
::
ios
::
binary
);
if
(
!
dst
.
is_open
())
return
false
;
dst
<<
src
.
rdbuf
();
src
.
close
();
Deletefile
(
source
);
return
true
;
}
bool
Utils
::
Deletefile
(
const
path_string
&
source
)
{
#ifdef _WIN32
return
DeleteFile
(
source
.
c_str
());
#else
return
remove
(
source
.
c_str
())
==
0
;
#endif
}
bool
Utils
::
ClearDirectory
(
const
path_string
&
path
)
{
#ifdef _WIN32
WIN32_FIND_DATA
fdata
;
HANDLE
fh
=
FindFirstFile
((
path
+
TEXT
(
"*.*"
)).
c_str
(),
&
fdata
);
if
(
fh
!=
INVALID_HANDLE_VALUE
)
{
do
{
path_string
name
=
fdata
.
cFileName
;
if
(
fdata
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
)
{
if
(
name
==
TEXT
(
".."
)
||
name
==
TEXT
(
"."
))
{
continue
;
}
Deletedirectory
(
path
+
name
+
TEXT
(
"/"
));
continue
;
}
else
{
Deletefile
(
path
+
name
);
}
}
while
(
FindNextFile
(
fh
,
&
fdata
));
FindClose
(
fh
);
}
return
true
;
#else
DIR
*
dir
;
struct
dirent
*
dirp
=
nullptr
;
if
((
dir
=
opendir
(
path
.
c_str
()))
!=
nullptr
)
{
struct
stat
fileStat
;
while
((
dirp
=
readdir
(
dir
))
!=
nullptr
)
{
stat
((
path
+
dirp
->
d_name
).
c_str
(),
&
fileStat
);
std
::
string
name
=
dirp
->
d_name
;
if
(
S_ISDIR
(
fileStat
.
st_mode
))
{
if
(
name
==
".."
||
name
==
"."
)
{
continue
;
}
Deletedirectory
(
path
+
name
+
"/"
);
continue
;
}
else
{
Deletefile
(
path
+
name
);
}
}
closedir
(
dir
);
}
return
true
;
#endif
}
bool
Utils
::
Deletedirectory
(
const
path_string
&
source
)
{
ClearDirectory
(
source
);
#ifdef _WIN32
return
RemoveDirectory
(
source
.
c_str
());
#else
return
rmdir
(
source
.
c_str
())
==
0
;
#endif
}
void
Utils
::
CreateResourceFolders
()
{
//create directories if missing
Makedirectory
(
TEXT
(
"deck"
));
Makedirectory
(
TEXT
(
"puzzles"
));
Makedirectory
(
TEXT
(
"pics"
));
Makedirectory
(
TEXT
(
"pics/field"
));
Makedirectory
(
TEXT
(
"pics/cover"
));
Makedirectory
(
TEXT
(
"pics/temp/"
));
ClearDirectory
(
TEXT
(
"pics/temp/"
));
Makedirectory
(
TEXT
(
"replay"
));
Makedirectory
(
TEXT
(
"screenshots"
));
}
void
Utils
::
takeScreenshot
(
irr
::
IrrlichtDevice
*
device
)
{
irr
::
video
::
IVideoDriver
*
const
driver
=
device
->
getVideoDriver
();
//get image from the last rendered frame
irr
::
video
::
IImage
*
const
image
=
driver
->
createScreenShot
();
if
(
image
)
//should always be true, but you never know. ;)
{
//construct a filename, consisting of local time and file extension
irr
::
c8
filename
[
64
];
snprintf
(
filename
,
64
,
"screenshots/ygopro_%u.png"
,
device
->
getTimer
()
->
getRealTime
());
//write screenshot to file
if
(
!
driver
->
writeImageToFile
(
image
,
filename
))
device
->
getLogger
()
->
log
(
L"Failed to take screenshot."
,
irr
::
ELL_WARNING
);
//Don't forget to drop image since we don't need it anymore.
image
->
drop
();
}
}
void
Utils
::
ToggleFullscreen
()
{
#ifdef _WIN32
static
RECT
nonFullscreenSize
;
static
std
::
vector
<
RECT
>
monitors
;
static
bool
maximized
=
false
;
if
(
monitors
.
empty
())
{
EnumDisplayMonitors
(
0
,
0
,
[](
HMONITOR
hMon
,
HDC
hdc
,
LPRECT
lprcMonitor
,
LPARAM
pData
)
->
BOOL
{
auto
monitors
=
reinterpret_cast
<
std
::
vector
<
RECT
>*>
(
pData
);
monitors
->
push_back
(
*
lprcMonitor
);
return
TRUE
;
},
(
LPARAM
)
&
monitors
);
}
mainGame
->
is_fullscreen
=
!
mainGame
->
is_fullscreen
;
HWND
hWnd
;
irr
::
video
::
SExposedVideoData
exposedData
=
mainGame
->
driver
->
getExposedVideoData
();
if
(
mainGame
->
driver
->
getDriverType
()
==
irr
::
video
::
EDT_DIRECT3D9
)
hWnd
=
reinterpret_cast
<
HWND
>
(
exposedData
.
D3D9
.
HWnd
);
else
hWnd
=
reinterpret_cast
<
HWND
>
(
exposedData
.
OpenGLWin32
.
HWnd
);
LONG_PTR
style
=
WS_POPUP
;
RECT
clientSize
=
{};
if
(
mainGame
->
is_fullscreen
)
{
if
(
GetWindowLong
(
hWnd
,
GWL_STYLE
)
&
WS_MAXIMIZE
)
{
maximized
=
true
;
}
GetWindowRect
(
hWnd
,
&
nonFullscreenSize
);
style
=
WS_SYSMENU
|
WS_CLIPCHILDREN
|
WS_CLIPSIBLINGS
;
for
(
auto
&
rect
:
monitors
)
{
POINT
windowCenter
=
{
(
nonFullscreenSize
.
left
+
(
nonFullscreenSize
.
right
-
nonFullscreenSize
.
left
)
/
2
),
(
nonFullscreenSize
.
top
+
(
nonFullscreenSize
.
bottom
-
nonFullscreenSize
.
top
)
/
2
)
};
if
(
PtInRect
(
&
rect
,
windowCenter
))
{
clientSize
=
rect
;
break
;
}
}
}
else
{
style
=
WS_THICKFRAME
|
WS_SYSMENU
|
WS_CAPTION
|
WS_CLIPCHILDREN
|
WS_CLIPSIBLINGS
|
WS_MINIMIZEBOX
|
WS_MAXIMIZEBOX
;
clientSize
=
nonFullscreenSize
;
if
(
maximized
)
{
style
|=
WS_MAXIMIZE
;
maximized
=
false
;
}
}
if
(
!
SetWindowLongPtr
(
hWnd
,
GWL_STYLE
,
style
))
mainGame
->
ErrorLog
(
"Could not change window style."
);
const
s32
width
=
clientSize
.
right
-
clientSize
.
left
;
const
s32
height
=
clientSize
.
bottom
-
clientSize
.
top
;
SetWindowPos
(
hWnd
,
HWND_TOP
,
clientSize
.
left
,
clientSize
.
top
,
width
,
height
,
SWP_FRAMECHANGED
|
SWP_SHOWWINDOW
);
static_cast
<
irr
::
CIrrDeviceWin32
::
CCursorControl
*>
(
mainGame
->
device
->
getCursorControl
())
->
updateBorderSize
(
mainGame
->
is_fullscreen
,
true
);
#elif defined(__linux__)
struct
{
unsigned
long
flags
;
unsigned
long
functions
;
unsigned
long
decorations
;
long
inputMode
;
unsigned
long
status
;
}
hints
=
{};
Display
*
display
=
XOpenDisplay
(
NULL
);;
Window
window
;
static
bool
wasHorizontalMaximized
=
false
,
wasVerticalMaximized
=
false
;
Window
child
;
int
revert
;
mainGame
->
is_fullscreen
=
!
mainGame
->
is_fullscreen
;
XGetInputFocus
(
display
,
&
window
,
&
revert
);
Atom
wm_state
=
XInternAtom
(
display
,
"_NET_WM_STATE"
,
false
);
Atom
max_horz
=
XInternAtom
(
display
,
"_NET_WM_STATE_MAXIMIZED_HORZ"
,
false
);
Atom
max_vert
=
XInternAtom
(
display
,
"_NET_WM_STATE_MAXIMIZED_VERT"
,
false
);
auto
checkMaximized
=
[
&
]()
{
long
maxLength
=
1024
;
Atom
actualType
;
int
actualFormat
;
unsigned
long
i
,
numItems
,
bytesAfter
;
unsigned
char
*
propertyValue
=
NULL
;
if
(
XGetWindowProperty
(
display
,
window
,
wm_state
,
0l
,
maxLength
,
false
,
XA_ATOM
,
&
actualType
,
&
actualFormat
,
&
numItems
,
&
bytesAfter
,
&
propertyValue
)
==
Success
)
{
Atom
*
atoms
=
(
Atom
*
)
propertyValue
;
for
(
i
=
0
;
i
<
numItems
;
++
i
)
{
if
(
atoms
[
i
]
==
max_vert
)
{
wasVerticalMaximized
=
true
;
}
else
if
(
atoms
[
i
]
==
max_horz
)
{
wasHorizontalMaximized
=
true
;
}
}
XFree
(
propertyValue
);
}
};
if
(
mainGame
->
is_fullscreen
)
checkMaximized
();
if
(
!
wasHorizontalMaximized
&&
!
wasVerticalMaximized
)
{
XEvent
xev
=
{};
xev
.
type
=
ClientMessage
;
xev
.
xclient
.
window
=
window
;
xev
.
xclient
.
message_type
=
wm_state
;
xev
.
xclient
.
format
=
32
;
xev
.
xclient
.
data
.
l
[
0
]
=
mainGame
->
is_fullscreen
?
1
:
0
;
int
i
=
1
;
if
(
!
wasHorizontalMaximized
)
xev
.
xclient
.
data
.
l
[
i
++
]
=
max_horz
;
if
(
!
wasVerticalMaximized
)
xev
.
xclient
.
data
.
l
[
i
++
]
=
max_vert
;
if
(
i
==
2
)
xev
.
xclient
.
data
.
l
[
i
]
=
0
;
XSendEvent
(
display
,
DefaultRootWindow
(
display
),
False
,
SubstructureNotifyMask
,
&
xev
);
}
Atom
property
=
XInternAtom
(
display
,
"_MOTIF_WM_HINTS"
,
true
);
hints
.
flags
=
2
;
hints
.
decorations
=
mainGame
->
is_fullscreen
?
0
:
1
;
XChangeProperty
(
display
,
window
,
property
,
property
,
32
,
PropModeReplace
,
(
unsigned
char
*
)
&
hints
,
5
);
XMapWindow
(
display
,
window
);
XFlush
(
display
);
#elif defined(__APPLE__)
EDOPRO_ToggleFullScreen
();
#endif
}
void
Utils
::
changeCursor
(
irr
::
gui
::
ECURSOR_ICON
icon
)
{
irr
::
gui
::
ICursorControl
*
cursor
=
mainGame
->
device
->
getCursorControl
();
if
(
cursor
->
getActiveIcon
()
!=
icon
)
{
cursor
->
setActiveIcon
(
icon
);
}
}
void
Utils
::
FindfolderFiles
(
const
path_string
&
path
,
const
std
::
function
<
void
(
path_string
,
bool
,
void
*
)
>&
cb
,
void
*
payload
)
{
#ifdef _WIN32
WIN32_FIND_DATA
fdataw
;
HANDLE
fh
=
FindFirstFile
((
NormalizePath
(
path
)
+
TEXT
(
"*.*"
)).
c_str
(),
&
fdataw
);
if
(
fh
!=
INVALID_HANDLE_VALUE
)
{
do
{
cb
(
fdataw
.
cFileName
,
!!
(
fdataw
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
),
payload
);
}
while
(
FindNextFile
(
fh
,
&
fdataw
));
FindClose
(
fh
);
}
#else
DIR
*
dir
;
struct
dirent
*
dirp
=
nullptr
;
auto
_path
=
NormalizePath
(
path
);
if
((
dir
=
opendir
(
_path
.
c_str
()))
!=
nullptr
)
{
struct
stat
fileStat
;
while
((
dirp
=
readdir
(
dir
))
!=
nullptr
)
{
stat
((
_path
+
dirp
->
d_name
).
c_str
(),
&
fileStat
);
cb
(
dirp
->
d_name
,
!!
S_ISDIR
(
fileStat
.
st_mode
),
payload
);
}
closedir
(
dir
);
}
#endif
}
std
::
vector
<
path_string
>
Utils
::
FindfolderFiles
(
const
path_string
&
path
,
std
::
vector
<
path_string
>
extensions
,
int
subdirectorylayers
)
{
std
::
vector
<
path_string
>
res
;
FindfolderFiles
(
path
,
[
&
res
,
extensions
,
path
,
subdirectorylayers
](
path_string
name
,
bool
isdir
,
void
*
payload
)
{
if
(
isdir
)
{
if
(
subdirectorylayers
)
{
if
(
name
==
TEXT
(
".."
)
||
name
==
TEXT
(
"."
))
{
return
;
}
std
::
vector
<
path_string
>
res2
=
FindfolderFiles
(
path
+
name
+
TEXT
(
"/"
),
extensions
,
subdirectorylayers
-
1
);
for
(
auto
&
file
:
res2
)
{
file
=
name
+
TEXT
(
"/"
)
+
file
;
}
res
.
insert
(
res
.
end
(),
res2
.
begin
(),
res2
.
end
());
}
return
;
}
else
{
if
(
extensions
.
size
()
&&
std
::
find
(
extensions
.
begin
(),
extensions
.
end
(),
Utils
::
GetFileExtension
(
name
))
==
extensions
.
end
())
return
;
res
.
push_back
(
name
.
c_str
());
}
});
return
res
;
}
void
Utils
::
FindfolderFiles
(
IrrArchiveHelper
&
archive
,
const
path_string
&
path
,
const
std
::
function
<
bool
(
int
,
path_string
,
bool
,
void
*
)
>&
cb
,
void
*
payload
)
{
auto
_path
=
ParseFilename
(
NormalizePath
(
path
,
false
));
auto
&
indexfolders
=
archive
.
folderindexes
[
_path
].
first
;
auto
&
indexfiles
=
archive
.
folderindexes
[
_path
].
second
;
for
(
int
i
=
indexfolders
.
first
;
i
<
indexfolders
.
second
&&
cb
(
i
,
archive
.
archive
->
getFileList
()
->
getFileName
(
i
).
c_str
(),
true
,
payload
);
i
++
)
{}
for
(
int
i
=
indexfiles
.
first
;
i
<
indexfiles
.
second
&&
cb
(
i
,
archive
.
archive
->
getFileList
()
->
getFileName
(
i
).
c_str
(),
false
,
payload
);
i
++
)
{}
}
std
::
vector
<
int
>
Utils
::
FindfolderFiles
(
IrrArchiveHelper
&
archive
,
const
path_string
&
path
,
std
::
vector
<
path_string
>
extensions
,
int
subdirectorylayers
)
{
std
::
vector
<
int
>
res
;
FindfolderFiles
(
archive
,
path
,
[
&
res
,
arc
=
archive
.
archive
,
extensions
,
path
,
subdirectorylayers
,
&
archive
](
int
index
,
path_string
name
,
bool
isdir
,
void
*
payload
)
->
bool
{
if
(
isdir
)
{
if
(
subdirectorylayers
)
{
if
(
name
==
TEXT
(
".."
)
||
name
==
TEXT
(
"."
))
{
return
true
;
}
std
::
vector
<
int
>
res2
=
FindfolderFiles
(
archive
,
path
+
name
+
TEXT
(
"/"
),
extensions
,
subdirectorylayers
-
1
);
res
.
insert
(
res
.
end
(),
res2
.
begin
(),
res2
.
end
());
}
return
true
;
}
else
{
if
(
extensions
.
size
()
&&
std
::
find
(
extensions
.
begin
(),
extensions
.
end
(),
Utils
::
GetFileExtension
(
name
))
==
extensions
.
end
())
return
true
;
res
.
push_back
(
index
);
}
return
true
;
});
return
res
;
}
irr
::
io
::
IReadFile
*
Utils
::
FindandOpenFileFromArchives
(
const
path_string
&
path
,
const
path_string
&
name
)
{
for
(
auto
&
archive
:
mainGame
->
archives
)
{
int
res
=
-
1
;
Utils
::
FindfolderFiles
(
archive
,
path
,
[
match
=
&
name
,
&
res
](
int
index
,
path_string
name
,
bool
isdir
,
void
*
payload
)
->
bool
{
if
(
isdir
)
return
false
;
if
(
name
==
(
*
match
))
{
res
=
index
;
return
false
;
}
return
true
;
});
if
(
res
!=
-
1
)
{
auto
reader
=
archive
.
archive
->
createAndOpenFile
(
res
);
if
(
reader
)
return
reader
;
}
}
return
nullptr
;
}
std
::
wstring
Utils
::
NormalizePath
(
std
::
wstring
path
,
bool
trailing_slash
)
{
std
::
replace
(
path
.
begin
(),
path
.
end
(),
L'\\'
,
L'/'
);
std
::
vector
<
std
::
wstring
>
paths
=
ygo
::
Game
::
TokenizeString
<
std
::
wstring
>
(
path
,
L"/"
);
if
(
paths
.
empty
())
return
path
;
std
::
wstring
normalpath
;
if
(
paths
.
front
()
==
L"."
)
{
paths
.
erase
(
paths
.
begin
());
normalpath
+=
L"."
;
}
for
(
auto
it
=
paths
.
begin
();
it
!=
paths
.
end
();)
{
if
((
*
it
).
empty
())
{
it
=
paths
.
erase
(
it
);
continue
;
}
if
((
*
it
)
==
L"."
)
{
it
=
paths
.
erase
(
it
);
continue
;
}
if
((
*
it
)
==
L".."
&&
it
!=
paths
.
begin
()
&&
(
*
(
it
-
1
))
!=
L".."
)
{
it
=
paths
.
erase
(
paths
.
erase
(
it
-
1
,
it
));
continue
;
}
it
++
;
}
if
(
!
paths
.
empty
())
{
if
(
!
normalpath
.
empty
())
normalpath
+=
L"/"
;
for
(
auto
it
=
paths
.
begin
();
it
!=
(
paths
.
end
()
-
1
);
it
++
)
{
normalpath
+=
*
it
+
L"/"
;
}
normalpath
+=
paths
.
back
();
}
if
(
trailing_slash
&&
normalpath
.
back
()
!=
L'/'
)
normalpath
+=
L"/"
;
return
normalpath
;
}
std
::
wstring
Utils
::
GetFileExtension
(
std
::
wstring
file
)
{
size_t
dotpos
=
file
.
find_last_of
(
L"."
);
if
(
dotpos
==
std
::
wstring
::
npos
)
return
L""
;
std
::
wstring
extension
=
file
.
substr
(
dotpos
+
1
);
std
::
transform
(
extension
.
begin
(),
extension
.
end
(),
extension
.
begin
(),
::
towlower
);
return
extension
;
}
std
::
wstring
Utils
::
GetFilePath
(
std
::
wstring
file
)
{
std
::
replace
(
file
.
begin
(),
file
.
end
(),
L'\\'
,
L'/'
);
size_t
slashpos
=
file
.
find_last_of
(
L'/'
);
if
(
slashpos
==
std
::
wstring
::
npos
)
return
file
;
std
::
wstring
extension
=
file
.
substr
(
0
,
slashpos
);
std
::
transform
(
extension
.
begin
(),
extension
.
end
(),
extension
.
begin
(),
::
towlower
);
return
extension
;
}
std
::
wstring
Utils
::
GetFileName
(
std
::
wstring
file
)
{
std
::
replace
(
file
.
begin
(),
file
.
end
(),
L'\\'
,
L'/'
);
size_t
dashpos
=
file
.
find_last_of
(
L"/"
);
if
(
dashpos
==
std
::
wstring
::
npos
)
dashpos
=
0
;
else
dashpos
++
;
size_t
dotpos
=
file
.
find_last_of
(
L"."
);
if
(
dotpos
==
std
::
wstring
::
npos
)
dotpos
=
file
.
size
();
std
::
wstring
name
=
file
.
substr
(
dashpos
,
dotpos
-
dashpos
);
return
name
;
}
std
::
string
Utils
::
NormalizePath
(
std
::
string
path
,
bool
trailing_slash
)
{
std
::
replace
(
path
.
begin
(),
path
.
end
(),
'\\'
,
'/'
);
std
::
vector
<
std
::
string
>
paths
=
ygo
::
Game
::
TokenizeString
<
std
::
string
>
(
path
,
"/"
);
if
(
paths
.
empty
())
return
path
;
std
::
string
normalpath
;
for
(
auto
it
=
paths
.
begin
();
it
!=
paths
.
end
();)
{
if
((
*
it
).
empty
())
{
it
=
paths
.
erase
(
it
);
continue
;
}
if
((
*
it
)
==
"."
&&
it
!=
paths
.
begin
())
{
it
=
paths
.
erase
(
it
);
continue
;
}
if
((
*
it
)
!=
".."
&&
it
!=
paths
.
begin
()
&&
(
it
+
1
)
!=
paths
.
end
()
&&
(
*
(
it
+
1
))
==
".."
)
{
it
=
paths
.
erase
(
paths
.
erase
(
it
));
continue
;
}
it
++
;
}
for
(
auto
it
=
paths
.
begin
();
it
!=
(
paths
.
end
()
-
1
);
it
++
)
{
normalpath
+=
*
it
+
"/"
;
}
normalpath
+=
paths
.
back
();
if
(
trailing_slash
)
normalpath
+=
"/"
;
return
normalpath
;
}
std
::
string
Utils
::
GetFileExtension
(
std
::
string
file
)
{
size_t
dotpos
=
file
.
find_last_of
(
"."
);
if
(
dotpos
==
std
::
string
::
npos
)
return
""
;
std
::
string
extension
=
file
.
substr
(
dotpos
+
1
);
std
::
transform
(
extension
.
begin
(),
extension
.
end
(),
extension
.
begin
(),
::
tolower
);
return
extension
;
}
std
::
string
Utils
::
GetFilePath
(
std
::
string
file
)
{
std
::
replace
(
file
.
begin
(),
file
.
end
(),
'\\'
,
'/'
);
size_t
slashpos
=
file
.
find_last_of
(
"."
);
if
(
slashpos
==
std
::
string
::
npos
)
return
file
;
std
::
string
extension
=
file
.
substr
(
0
,
slashpos
);
std
::
transform
(
extension
.
begin
(),
extension
.
end
(),
extension
.
begin
(),
::
towlower
);
return
extension
;
}
std
::
string
Utils
::
GetFileName
(
std
::
string
file
)
{
std
::
replace
(
file
.
begin
(),
file
.
end
(),
'\\'
,
'/'
);
size_t
dashpos
=
file
.
find_last_of
(
"/"
);
if
(
dashpos
==
std
::
wstring
::
npos
)
dashpos
=
0
;
else
dashpos
++
;
size_t
dotpos
=
file
.
find_last_of
(
"."
);
if
(
dotpos
==
std
::
string
::
npos
)
dotpos
=
file
.
size
();
std
::
string
name
=
file
.
substr
(
dashpos
,
dotpos
-
dashpos
);
return
name
;
}
path_string
Utils
::
ParseFilename
(
const
std
::
wstring
&
input
)
{
#ifdef UNICODE
return
input
;
#else
return
BufferIO
::
EncodeUTF8s
(
input
);
#endif
}
path_string
Utils
::
ParseFilename
(
const
std
::
string
&
input
)
{
#ifdef UNICODE
return
BufferIO
::
DecodeUTF8s
(
input
);
#else
return
input
;
#endif
}
std
::
string
Utils
::
ToUTF8IfNeeded
(
const
path_string
&
input
)
{
#ifdef UNICODE
return
BufferIO
::
EncodeUTF8s
(
input
);
#else
return
input
;
#endif
}
std
::
wstring
Utils
::
ToUnicodeIfNeeded
(
const
path_string
&
input
)
{
#ifdef UNICODE
return
input
;
#else
return
BufferIO
::
DecodeUTF8s
(
input
);
#endif
}
void
Utils
::
IrrArchiveHelper
::
ParseList
(
irr
::
io
::
IFileArchive
*
_archive
)
{
archive
=
_archive
;
auto
list
=
archive
->
getFileList
();
std
::
vector
<
path_string
>
list_full
;
folderindexes
[
TEXT
(
"."
)]
=
{
{
-
1
,
-
1
},
{
-
1
,
-
1
}
};
for
(
u32
i
=
0
;
i
<
list
->
getFileCount
();
++
i
)
{
list_full
.
push_back
(
list
->
getFullFileName
(
i
).
c_str
());
if
(
list
->
isDirectory
(
i
))
{
folderindexes
[
list
->
getFullFileName
(
i
).
c_str
()]
=
{
{
-
1
,
-
1
},
{
-
1
,
-
1
}
};
auto
&
name_path
=
list
->
getFullFileName
(
i
);
auto
&
name
=
list
->
getFileName
(
i
);
if
(
name_path
.
size
()
==
name
.
size
())
{
/*special case, root folder*/
folderindexes
[
TEXT
(
""
)]
=
{
{
std
::
min
((
unsigned
)
folderindexes
[
TEXT
(
""
)].
first
.
first
,
i
),
i
+
1
},
folderindexes
[
TEXT
(
""
)].
second
};
}
else
{
path_string
path
=
NormalizePath
(
name_path
.
subString
(
0
,
name_path
.
size
()
-
name
.
size
()
-
1
).
c_str
(),
false
);
folderindexes
[
path
]
=
{
{
std
::
min
((
unsigned
)
folderindexes
[
path
].
first
.
first
,
i
),
i
+
1
},
folderindexes
[
path
].
second
};
}
}
else
{
auto
&
name_path
=
list
->
getFullFileName
(
i
);
auto
&
name
=
list
->
getFileName
(
i
);
if
(
name_path
.
size
()
==
name
.
size
())
{
/*special case, root folder*/
folderindexes
[
TEXT
(
""
)]
=
{
folderindexes
[
TEXT
(
""
)].
first
,
{
std
::
min
((
unsigned
)
folderindexes
[
TEXT
(
""
)].
second
.
first
,
i
),
i
+
1
}
};
}
else
{
path_string
path
=
NormalizePath
(
name_path
.
subString
(
0
,
name_path
.
size
()
-
name
.
size
()
-
1
).
c_str
(),
false
);
folderindexes
[
path
]
=
{
folderindexes
[
path
].
first
,
{
std
::
min
((
unsigned
)
folderindexes
[
path
].
second
.
first
,
i
),
i
+
1
}
};
}
}
}
}
}
Classes/gframe/utils.h
0 → 100644
View file @
f9b63108
#ifndef UTILS_H
#define UTILS_H
#include <irrlicht.h>
#include <string>
#include <vector>
#include <functional>
#include <fstream>
#include <map>
#ifndef _WIN32
#include <dirent.h>
#include <sys/stat.h>
#endif
using
path_string
=
std
::
basic_string
<
irr
::
fschar_t
>
;
namespace
ygo
{
class
Utils
{
public:
class
IrrArchiveHelper
{
public:
irr
::
io
::
IFileArchive
*
archive
;
std
::
map
<
path_string
/*folder name*/
,
std
::
pair
<
std
::
pair
<
int
/*begin folder offset*/
,
int
/*end folder offset*/
>
,
std
::
pair
<
int
/*begin file offset*/
,
int
/*end file offset*/
>>>
folderindexes
;
IrrArchiveHelper
(
irr
::
io
::
IFileArchive
*
archive
)
{
ParseList
(
archive
);
};
void
ParseList
(
irr
::
io
::
IFileArchive
*
archive
);
};
static
bool
Makedirectory
(
const
path_string
&
path
);
static
bool
Movefile
(
const
path_string
&
source
,
const
path_string
&
destination
);
static
path_string
ParseFilename
(
const
std
::
wstring
&
input
);
static
path_string
ParseFilename
(
const
std
::
string
&
input
);
static
std
::
string
ToUTF8IfNeeded
(
const
path_string
&
input
);
static
std
::
wstring
ToUnicodeIfNeeded
(
const
path_string
&
input
);
static
bool
Deletefile
(
const
path_string
&
source
);
static
bool
ClearDirectory
(
const
path_string
&
path
);
static
bool
Deletedirectory
(
const
path_string
&
source
);
static
void
CreateResourceFolders
();
static
void
takeScreenshot
(
irr
::
IrrlichtDevice
*
device
);
static
void
ToggleFullscreen
();
static
void
changeCursor
(
irr
::
gui
::
ECURSOR_ICON
icon
);
static
void
FindfolderFiles
(
const
path_string
&
path
,
const
std
::
function
<
void
(
path_string
,
bool
,
void
*
)
>&
cb
,
void
*
payload
=
nullptr
);
static
std
::
vector
<
path_string
>
FindfolderFiles
(
const
path_string
&
path
,
std
::
vector
<
path_string
>
extensions
,
int
subdirectorylayers
=
0
);
static
void
FindfolderFiles
(
IrrArchiveHelper
&
archive
,
const
path_string
&
path
,
const
std
::
function
<
bool
(
int
,
path_string
,
bool
,
void
*
)
>&
cb
,
void
*
payload
=
nullptr
);
static
std
::
vector
<
int
>
FindfolderFiles
(
IrrArchiveHelper
&
archive
,
const
path_string
&
path
,
std
::
vector
<
path_string
>
extensions
,
int
subdirectorylayers
=
0
);
static
irr
::
io
::
IReadFile
*
FindandOpenFileFromArchives
(
const
path_string
&
path
,
const
path_string
&
name
);
static
std
::
wstring
NormalizePath
(
std
::
wstring
path
,
bool
trailing_slash
=
true
);
static
std
::
wstring
GetFileExtension
(
std
::
wstring
file
);
static
std
::
wstring
GetFilePath
(
std
::
wstring
file
);
static
std
::
wstring
GetFileName
(
std
::
wstring
file
);
static
std
::
string
NormalizePath
(
std
::
string
path
,
bool
trailing_slash
=
true
);
static
std
::
string
GetFileExtension
(
std
::
string
file
);
static
std
::
string
GetFilePath
(
std
::
string
file
);
static
std
::
string
GetFileName
(
std
::
string
file
);
};
}
#endif //UTILS_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment