1
0
mirror of synced 2024-11-28 01:10:53 +01:00

Squashed commit of the following:

commit c99443a7d3
Author: Ashiro12138 <ashiro12138@gmail.com>
Date:   Fri Jul 26 01:29:15 2024 +1000

    Chore/add editor config (#656)

    * Create .editorconfig

    * format ENTIRE project

    * Remove unnecessary import or usings

    Sort Imports or usings
    Apply file header preferences

    * Fix build error by adding import
This commit is contained in:
0auBSQ 2024-07-26 01:07:31 +09:00
parent c47c9c9400
commit 88a15defc1
274 changed files with 62002 additions and 76846 deletions

189
.editorconfig Normal file
View File

@ -0,0 +1,189 @@
# editorconfig.org
# top-most EditorConfig file
root = true
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
[project.json]
indent_size = 2
# Generated code
[*{_AssemblyInfo.cs,.notsupported.cs}]
generated_code = true
# C# files
[*.cs]
# New line preferences
csharp_new_line_before_open_brace = none
csharp_new_line_before_else = false
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# avoid this. unless absolutely necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Types: use keywords instead of BCL types, and permit var only when the type is clear
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:none
csharp_style_var_elsewhere = false:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# static fields should have s_ prefix
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
csharp_prefer_braces = true:silent
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
csharp_prefer_static_local_function = true:suggestion
csharp_prefer_simple_using_statement = false:none
csharp_style_prefer_switch_expression = true:suggestion
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
csharp_prefer_simple_default_expression = true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods = true:silent
csharp_style_expression_bodied_constructors = true:silent
csharp_style_expression_bodied_operators = true:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = true:silent
# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Null checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Other features
csharp_style_prefer_index_operator = false:none
csharp_style_prefer_range_operator = false:none
csharp_style_pattern_local_over_anonymous_function = false:none
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# C++ Files
[*.{cpp,h,in}]
curly_bracket_next_line = true
indent_brace_style = Allman
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2
[*.{csproj,vbproj,proj,nativeproj,locproj}]
charset = utf-8
# Xml build files
[*.builds]
indent_size = 2
# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2
# Xml config files
[*.{props,targets,config,nuspec}]
indent_size = 2
# YAML config files
[*.{yml,yaml}]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf

View File

@ -1,22 +1,13 @@
using System; namespace FDK {
using System.Collections.Generic; public class CActivity {
using System.Text;
namespace FDK
{
public class CActivity
{
// プロパティ // プロパティ
public bool IsActivated { get; private set; } public bool IsActivated { get; private set; }
public bool IsDeActivated public bool IsDeActivated {
{ get {
get
{
return !this.IsActivated; return !this.IsActivated;
} }
set set {
{
this.IsActivated = !value; this.IsActivated = !value;
} }
} }
@ -29,11 +20,10 @@ namespace FDK
/// </summary> /// </summary>
protected bool IsFirstDraw = true; protected bool IsFirstDraw = true;
// コンストラクタ // コンストラクタ
public CActivity() public CActivity() {
{
this.IsDeActivated = true; this.IsDeActivated = true;
this.ChildActivities = new List<CActivity>(); this.ChildActivities = new List<CActivity>();
} }
@ -44,29 +34,27 @@ namespace FDK
#region [ override ] #region [ override ]
//----------------- //-----------------
public virtual void Activate() public virtual void Activate() {
{
// すでに活性化してるなら何もしない。 // すでに活性化してるなら何もしない。
if( this.IsActivated ) if (this.IsActivated)
return; return;
this.IsActivated = true; // このフラグは、以下の処理をする前にセットする。 this.IsActivated = true; // このフラグは、以下の処理をする前にセットする。
// 自身のリソースを作成する。 // 自身のリソースを作成する。
//this.CreateManagedResource(); //this.CreateManagedResource();
//this.CreateUnmanagedResource(); //this.CreateUnmanagedResource();
// すべての子 Activity を活性化する。 // すべての子 Activity を活性化する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.Activate(); activity.Activate();
// その他の初期化 // その他の初期化
this.IsFirstDraw = true; this.IsFirstDraw = true;
} }
public virtual void DeActivate() public virtual void DeActivate() {
{
// 活性化してないなら何もしない。 // 活性化してないなら何もしない。
if( this.IsDeActivated ) if (this.IsDeActivated)
return; return;
// 自身のリソースを解放する。 // 自身のリソースを解放する。
@ -74,10 +62,10 @@ namespace FDK
//this.ReleaseManagedResource(); //this.ReleaseManagedResource();
// すべての 子Activity を非活性化する。 // すべての 子Activity を非活性化する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.DeActivate(); activity.DeActivate();
this.IsDeActivated = true; // このフラグは、以上のメソッドを呼び出した後にセットする。 this.IsDeActivated = true; // このフラグは、以上のメソッドを呼び出した後にセットする。
} }
/// <summary> /// <summary>
@ -87,10 +75,9 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成されるか分からないので、 /// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para> /// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary> /// </summary>
public virtual void CreateManagedResource() public virtual void CreateManagedResource() {
{
// すべての 子Activity の Managed リソースを作成する。 // すべての 子Activity の Managed リソースを作成する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.CreateManagedResource(); activity.CreateManagedResource();
} }
@ -101,27 +88,25 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成またはリセットされるか分からないので、 /// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para> /// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary> /// </summary>
public virtual void CreateUnmanagedResource() public virtual void CreateUnmanagedResource() {
{
// すべての 子Activity の Unmanaged リソースを作成する。 // すべての 子Activity の Unmanaged リソースを作成する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.CreateUnmanagedResource(); activity.CreateUnmanagedResource();
} }
/// <summary> /// <summary>
/// <para>Unmanaged リソースの解放を行う。</para> /// <para>Unmanaged リソースの解放を行う。</para>
/// <para>Direct3D デバイスの解放直前またはリセット直前に呼び出される。</para> /// <para>Direct3D デバイスの解放直前またはリセット直前に呼び出される。</para>
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放またはリセットされるか分からないので、 /// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para> /// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary> /// </summary>
public virtual void ReleaseUnmanagedResource() public virtual void ReleaseUnmanagedResource() {
{
// 活性化してないなら何もしない。 // 活性化してないなら何もしない。
if( this.IsDeActivated ) if (this.IsDeActivated)
return; return;
// すべての 子Activity の Unmanaged リソースを解放する。 // すべての 子Activity の Unmanaged リソースを解放する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.ReleaseUnmanagedResource(); activity.ReleaseUnmanagedResource();
} }
@ -132,14 +117,13 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放されるか分からないので、 /// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para> /// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary> /// </summary>
public virtual void ReleaseManagedResource() public virtual void ReleaseManagedResource() {
{
// 活性化してないなら何もしない。 // 活性化してないなら何もしない。
if( this.IsDeActivated ) if (this.IsDeActivated)
return; return;
// すべての 子Activity の Managed リソースを解放する。 // すべての 子Activity の Managed リソースを解放する。
foreach( CActivity activity in this.ChildActivities ) foreach (CActivity activity in this.ChildActivities)
activity.ReleaseManagedResource(); activity.ReleaseManagedResource();
} }
@ -148,10 +132,9 @@ namespace FDK
/// <para>このメソッドは BeginScene() の後に呼び出されるので、メソッド内でいきなり描画を行ってかまわない。</para> /// <para>このメソッドは BeginScene() の後に呼び出されるので、メソッド内でいきなり描画を行ってかまわない。</para>
/// </summary> /// </summary>
/// <returns>任意の整数。呼び出し元との整合性を合わせておくこと。</returns> /// <returns>任意の整数。呼び出し元との整合性を合わせておくこと。</returns>
public virtual int Draw() public virtual int Draw() {
{
// 活性化してないなら何もしない。 // 活性化してないなら何もしない。
if( this.IsDeActivated ) if (this.IsDeActivated)
return 0; return 0;
@ -161,8 +144,8 @@ namespace FDK
// 戻り値とその意味は子クラスで自由に決めていい。 // 戻り値とその意味は子クラスで自由に決めていい。
return 0; return 0;
} }
//----------------- //-----------------
#endregion #endregion
} }
} }

View File

@ -1,254 +1,223 @@
using System; namespace FDK {
using System.Collections.Generic; public class CConversion {
using System.Text;
namespace FDK
{
public class CConversion
{
// プロパティ // プロパティ
public static readonly string str16進数文字 = "0123456789ABCDEFabcdef"; public static readonly string str16進数文字 = "0123456789ABCDEFabcdef";
public static readonly string str36進数文字 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; public static readonly string str36進数文字 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
// メソッド // メソッド
public static bool bONorOFF( char c ) public static bool bONorOFF(char c) {
{ return (c != '0');
return ( c != '0' );
} }
public static double DegreeToRadian( double angle ) public static double DegreeToRadian(double angle) {
{ return ((Math.PI * angle) / 180.0);
return ( ( Math.PI * angle ) / 180.0 );
} }
public static double RadianToDegree( double angle ) public static double RadianToDegree(double angle) {
{ return (angle * 180.0 / Math.PI);
return ( angle * 180.0 / Math.PI );
} }
public static float DegreeToRadian( float angle ) public static float DegreeToRadian(float angle) {
{ return (float)DegreeToRadian((double)angle);
return (float) DegreeToRadian( (double) angle );
} }
public static float RadianToDegree( float angle ) public static float RadianToDegree(float angle) {
{ return (float)RadianToDegree((double)angle);
return (float) RadianToDegree( (double) angle );
} }
public static int n値を範囲内に丸めて返す( int value, int min, int max ) public static int n値を範囲内に丸めて返す(int value, int min, int max) {
{ if (value < min)
if( value < min )
return min; return min;
if( value > max ) if (value > max)
return max; return max;
return value; return value;
} }
public static int n値を文字列から取得して範囲内に丸めて返す( string text, int min, int max, int defaultValue ) public static int n値を文字列から取得して範囲内に丸めて返す(string text, int min, int max, int defaultValue) {
{
int num; int num;
if( ( int.TryParse( text, out num ) && ( num >= min ) ) && ( num <= max ) ) if ((int.TryParse(text, out num) && (num >= min)) && (num <= max))
return num; return num;
return defaultValue; return defaultValue;
} }
public static double db値を文字列から取得して範囲内に丸めて返す( string text, double min, double max, double defaultValue ) public static double db値を文字列から取得して範囲内に丸めて返す(string text, double min, double max, double defaultValue) {
{ double num;
double num; if ((double.TryParse(text, out num) && (num >= min)) && (num <= max))
if( ( double.TryParse( text, out num ) && ( num >= min ) ) && ( num <= max ) ) return num;
return num;
return defaultValue; return defaultValue;
} }
// #23568 2010.11.04 ikanick add // #23568 2010.11.04 ikanick add
public static int n値を文字列から取得して範囲内にちゃんと丸めて返す(string text, int min, int max, int defaultValue) public static int n値を文字列から取得して範囲内にちゃんと丸めて返す(string text, int min, int max, int defaultValue) {
{ // 1 と違って範囲外の場合ちゃんと丸めて返します。
// 1 と違って範囲外の場合ちゃんと丸めて返します。
int num;
if (int.TryParse(text, out num)) {
if ((num >= min) && (num <= max))
return num;
if ( num < min )
return min;
if ( num > max )
return max;
}
return defaultValue;
}
// --------------------ここまで-------------------------/
public static int StringToInt( string text, int defaultValue )
{
int num; int num;
if( !int.TryParse( text, out num ) ) if (int.TryParse(text, out num)) {
if ((num >= min) && (num <= max))
return num;
if (num < min)
return min;
if (num > max)
return max;
}
return defaultValue;
}
// --------------------ここまで-------------------------/
public static int StringToInt(string text, int defaultValue) {
int num;
if (!int.TryParse(text, out num))
num = defaultValue; num = defaultValue;
return num; return num;
} }
public static int n16進数2桁の文字列を数値に変換して返す( string strNum ) public static int n16進数2桁の文字列を数値に変換して返す(string strNum) {
{ if (strNum.Length < 2)
if( strNum.Length < 2 )
return -1; return -1;
int digit2 = str16進数文字.IndexOf( strNum[ 0 ] ); int digit2 = str16進数文字.IndexOf(strNum[0]);
if( digit2 < 0 ) if (digit2 < 0)
return -1; return -1;
if( digit2 >= 16 ) if (digit2 >= 16)
digit2 -= (16 - 10); // A,B,C... -> 1,2,3... digit2 -= (16 - 10); // A,B,C... -> 1,2,3...
int digit1 = str16進数文字.IndexOf( strNum[ 1 ] ); int digit1 = str16進数文字.IndexOf(strNum[1]);
if( digit1 < 0 ) if (digit1 < 0)
return -1; return -1;
if( digit1 >= 16 ) if (digit1 >= 16)
digit1 -= (16 - 10); digit1 -= (16 - 10);
return digit2 * 16 + digit1; return digit2 * 16 + digit1;
} }
public static int n36進数2桁の文字列を数値に変換して返す( string strNum ) public static int n36進数2桁の文字列を数値に変換して返す(string strNum) {
{ if (strNum.Length < 2)
if( strNum.Length < 2 )
return -1; return -1;
int digit2 = str36進数文字.IndexOf( strNum[ 0 ] ); int digit2 = str36進数文字.IndexOf(strNum[0]);
if( digit2 < 0 ) if (digit2 < 0)
return -1; return -1;
if( digit2 >= 36 ) if (digit2 >= 36)
digit2 -= (36 - 10); // A,B,C... -> 1,2,3... digit2 -= (36 - 10); // A,B,C... -> 1,2,3...
int digit1 = str36進数文字.IndexOf( strNum[ 1 ] ); int digit1 = str36進数文字.IndexOf(strNum[1]);
if( digit1 < 0 ) if (digit1 < 0)
return -1; return -1;
if( digit1 >= 36 ) if (digit1 >= 36)
digit1 -= (36 - 10); digit1 -= (36 - 10);
return digit2 * 36 + digit1; return digit2 * 36 + digit1;
} }
public static int n小節番号の文字列3桁を数値に変換して返す( string strNum ) public static int n小節番号の文字列3桁を数値に変換して返す(string strNum) {
{ if (strNum.Length >= 3) {
if( strNum.Length >= 3 ) int digit3 = str36進数文字.IndexOf(strNum[0]);
{ if (digit3 < 0)
int digit3 = str36進数文字.IndexOf( strNum[ 0 ] );
if( digit3 < 0 )
return -1; return -1;
if( digit3 >= 36 ) // 3桁目は36進数 if (digit3 >= 36) // 3桁目は36進数
digit3 -= (36 - 10); digit3 -= (36 - 10);
int digit2 = str16進数文字.IndexOf( strNum[ 1 ] ); // 2桁目は10進数 int digit2 = str16進数文字.IndexOf(strNum[1]); // 2桁目は10進数
if( ( digit2 < 0 ) || ( digit2 > 9 ) ) if ((digit2 < 0) || (digit2 > 9))
return -1; return -1;
int digit1 = str16進数文字.IndexOf( strNum[ 2 ] ); // 1桁目も10進数 int digit1 = str16進数文字.IndexOf(strNum[2]); // 1桁目も10進数
if( ( digit1 >= 0 ) && ( digit1 <= 9 ) ) if ((digit1 >= 0) && (digit1 <= 9))
return digit3 * 100 + digit2 * 10 + digit1; return digit3 * 100 + digit2 * 10 + digit1;
} }
return -1; return -1;
} }
public static string str小節番号を文字列3桁に変換して返す( int num ) public static string str小節番号を文字列3桁に変換して返す(int num) {
{ if ((num < 0) || (num >= 3600)) // 3600 == Z99 + 1
if( ( num < 0 ) || ( num >= 3600 ) ) // 3600 == Z99 + 1
return "000"; return "000";
int digit4 = num / 100; int digit4 = num / 100;
int digit2 = ( num % 100 ) / 10; int digit2 = (num % 100) / 10;
int digit1 = ( num % 100 ) % 10; int digit1 = (num % 100) % 10;
char ch3 = str36進数文字[ digit4 ]; char ch3 = str36進数文字[digit4];
char ch2 = str16進数文字[ digit2 ]; char ch2 = str16進数文字[digit2];
char ch1 = str16進数文字[ digit1 ]; char ch1 = str16進数文字[digit1];
return ( ch3.ToString() + ch2.ToString() + ch1.ToString() ); return (ch3.ToString() + ch2.ToString() + ch1.ToString());
} }
public static string str数値を16進数2桁に変換して返す( int num ) public static string str数値を16進数2桁に変換して返す(int num) {
{ if ((num < 0) || (num >= 0x100))
if( ( num < 0 ) || ( num >= 0x100 ) )
return "00"; return "00";
char ch2 = str16進数文字[ num / 0x10 ]; char ch2 = str16進数文字[num / 0x10];
char ch1 = str16進数文字[ num % 0x10 ]; char ch1 = str16進数文字[num % 0x10];
return ( ch2.ToString() + ch1.ToString() ); return (ch2.ToString() + ch1.ToString());
} }
public static string str数値を36進数2桁に変換して返す( int num ) public static string str数値を36進数2桁に変換して返す(int num) {
{ if ((num < 0) || (num >= 36 * 36))
if( ( num < 0 ) || ( num >= 36 * 36 ) )
return "00"; return "00";
char ch2 = str36進数文字[ num / 36 ]; char ch2 = str36進数文字[num / 36];
char ch1 = str36進数文字[ num % 36 ]; char ch1 = str36進数文字[num % 36];
return ( ch2.ToString() + ch1.ToString() ); return (ch2.ToString() + ch1.ToString());
} }
public static int[] StringToIntArray( string str ) public static int[] StringToIntArray(string str) {
{ //0,1,2 ...の形式で書かれたstringをint配列に変換する。
//0,1,2 ...の形式で書かれたstringをint配列に変換する。 //一応実装はしたものの、例外処理などはまだ完成していない。
//一応実装はしたものの、例外処理などはまだ完成していない。 //str = "0,1,2";
//str = "0,1,2"; if (String.IsNullOrEmpty(str))
if( String.IsNullOrEmpty( str ) ) return null;
return null;
string[] strArray = str.Split( ',' ); string[] strArray = str.Split(',');
List<int> listIntArray; List<int> listIntArray;
listIntArray = new List<int>(); listIntArray = new List<int>();
for( int n = 0; n < strArray.Length; n++ ) for (int n = 0; n < strArray.Length; n++) {
{ int n追加する数値 = Convert.ToInt32(strArray[n]);
int n追加する数値 = Convert.ToInt32( strArray[ n ] ); listIntArray.Add(n追加する数値);
listIntArray.Add( n追加する数値 ); }
} int[] nArray = new int[] { 1 };
int[] nArray = new int[] { 1 }; nArray = listIntArray.ToArray();
nArray = listIntArray.ToArray();
return nArray; return nArray;
} }
/// <summary> /// <summary>
/// 百分率数値を255段階数値に変換するメソッド。透明度用。 /// 百分率数値を255段階数値に変換するメソッド。透明度用。
/// </summary> /// </summary>
/// <param name="num"></param> /// <param name="num"></param>
/// <returns></returns> /// <returns></returns>
public static int nParsentTo255( double num ) public static int nParsentTo255(double num) {
{ return (int)(255.0 * num);
return (int)(255.0 * num); }
}
/// <summary> /// <summary>
/// 255段階数値を百分率に変換するメソッド。 /// 255段階数値を百分率に変換するメソッド。
/// </summary> /// </summary>
/// <param name="num"></param> /// <param name="num"></param>
/// <returns></returns> /// <returns></returns>
public static int n255ToParsent( int num ) public static int n255ToParsent(int num) {
{ return (int)(100.0 / num);
return (int)(100.0 / num); }
}
public static Color4 n255ToColor4( int nR, int nG, int nB ) public static Color4 n255ToColor4(int nR, int nG, int nB) {
{ float fR = n255ToParsent(nR);
float fR = n255ToParsent( nR ); float fG = n255ToParsent(nG);
float fG = n255ToParsent( nG ); float fB = n255ToParsent(nB);
float fB = n255ToParsent( nB );
return new Color4( fR, fG, fB, 1f ); return new Color4(fR, fG, fB, 1f);
} }
public static Color4 ColorToColor4(System.Drawing.Color col) public static Color4 ColorToColor4(System.Drawing.Color col) {
{
return new Color4(col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f); return new Color4(col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f);
} }
public static int[] SeparateDigits(int num) public static int[] SeparateDigits(int num) {
{
int[] digits = new int[num.ToString().Length]; int[] digits = new int[num.ToString().Length];
for (int i = 0; i < digits.Length; i++) for (int i = 0; i < digits.Length; i++) {
{
digits[i] = num % 10; digits[i] = num % 10;
num /= 10; num /= 10;
} }
@ -259,10 +228,9 @@ namespace FDK
//----------------- //-----------------
// private コンストラクタでインスタンス生成を禁止する。 // private コンストラクタでインスタンス生成を禁止する。
private CConversion() private CConversion() {
{
} }
//----------------- //-----------------
#endregion #endregion
} }
} }

View File

@ -1,315 +1,271 @@
using System; namespace FDK {
using System.Collections.Generic; /// <summary>
using System.Text; /// 一定間隔で単純増加する整数(カウント値)を扱う。
/// </summary>
/// <remarks>
/// ○使い方
/// 1.CCounterの変数をつくる。
/// 2.CCounterを生成
/// ctCounter = new CCounter( 0, 3, 10, CDTXMania.Timer );
/// 3.進行メソッドを使用する。
/// 4.ウマー。
///
/// double値を使う場合、t進行db、t進行LoopDbを使うこと。
/// また、double版では間隔の値はミリ秒単位ではなく、通常の秒単位になります。
/// </remarks>
public class CCounter {
public bool IsStarted {
get;
set;
}
// 値プロパティ
public double BeginValue {
get;
private set;
}
public double EndValue {
get;
set;
}
public int CurrentValue {
get;
set;
}
namespace FDK public double _Interval {
{ get {
/// <summary> return this.Interval;
/// 一定間隔で単純増加する整数(カウント値)を扱う。 }
/// </summary> set {
/// <remarks> this.Interval = value >= 0 ? value : value * -1;
/// ○使い方 }
/// 1.CCounterの変数をつくる。 }
/// 2.CCounterを生成
/// ctCounter = new CCounter( 0, 3, 10, CDTXMania.Timer );
/// 3.進行メソッドを使用する。
/// 4.ウマー。
///
/// double値を使う場合、t進行db、t進行LoopDbを使うこと。
/// また、double版では間隔の値はミリ秒単位ではなく、通常の秒単位になります。
/// </remarks>
public class CCounter
{
public bool IsStarted
{
get;
set;
}
// 値プロパティ
public double BeginValue
{
get;
private set;
}
public double EndValue
{
get;
set;
}
public int CurrentValue
{
get;
set;
}
public double _Interval public double NowTime {
{ get;
get set;
{ }
return this.Interval; // 状態プロパティ
}
set
{
this.Interval = value >= 0 ? value : value * -1;
}
}
public double NowTime public bool IsTicked {
{ get { return (this.NowTime != -1); }
get; }
set; public bool IsStoped {
} get { return !this.IsTicked; }
// 状態プロパティ }
public bool IsEnded {
get { return (this.CurrentValue >= this.EndValue); }
}
public bool IsUnEnded {
get { return !this.IsEnded; }
}
public bool IsTicked // コンストラクタ
{
get { return (this.NowTime != -1); }
}
public bool IsStoped
{
get { return !this.IsTicked; }
}
public bool IsEnded
{
get { return (this.CurrentValue >= this.EndValue); }
}
public bool IsUnEnded
{
get { return !this.IsEnded; }
}
// コンストラクタ public CCounter() {
this.NormalTimer = null;
this.BeginValue = 0;
this.EndValue = 0;
this.CurrentValue = 0;
this.CurrentValue = 0;
this.NowTime = CSoundTimer.UnusedNum;
}
public CCounter() /// <summary>生成と同時に開始する。</summary>
{ public CCounter(double begin, double end, double interval, CTimer timer)
this.NormalTimer = null; : this() {
this.BeginValue = 0; this.Start(begin, end, interval, timer);
this.EndValue = 0; }
this.CurrentValue = 0;
this.CurrentValue = 0;
this.NowTime = CSoundTimer.UnusedNum;
}
/// <summary>生成と同時に開始する。</summary> /// <summary>生成と同時に開始する。(double版)</summary>
public CCounter(double begin, double end, double interval, CTimer timer) public CCounter(double begin, double end, double interval, CSoundTimer timer)
: this() : this() {
{ this.Start(begin, end, interval * 1000.0f, timer);
this.Start(begin, end, interval, timer); }
}
/// <summary>生成と同時に開始する。(double版)</summary>
public CCounter(double begin, double end, double interval, CSoundTimer timer)
: this()
{
this.Start(begin, end, interval * 1000.0f, timer);
}
// 状態操作メソッド // 状態操作メソッド
/// <summary> /// <summary>
/// カウントを開始する。 /// カウントを開始する。
/// </summary> /// </summary>
/// <param name="begin">最初のカウント値。</param> /// <param name="begin">最初のカウント値。</param>
/// <param name="end">最後のカウント値。</param> /// <param name="end">最後のカウント値。</param>
/// <param name="interval">カウント値を1増加させるのにかける時間(ミリ秒単位)。</param> /// <param name="interval">カウント値を1増加させるのにかける時間(ミリ秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param> /// <param name="timer">カウントに使用するタイマ。</param>
public void Start(double begin, double end, double interval, CTimer timer) public void Start(double begin, double end, double interval, CTimer timer) {
{ this.BeginValue = begin;
this.BeginValue = begin; this.EndValue = end;
this.EndValue = end; this._Interval = interval;
this._Interval = interval; this.NormalTimer = timer;
this.NormalTimer = timer; this.NowTime = this.NormalTimer.NowTime;
this.NowTime = this.NormalTimer.NowTime; this.CurrentValue = (int)begin;
this.CurrentValue = (int)begin; this.IsStarted = true;
this.IsStarted = true; }
}
/// <summary> /// <summary>
/// カウントを開始する。(double版) /// カウントを開始する。(double版)
/// </summary> /// </summary>
/// <param name="begin">最初のカウント値。</param> /// <param name="begin">最初のカウント値。</param>
/// <param name="end">最後のカウント値。</param> /// <param name="end">最後のカウント値。</param>
/// <param name="interval">カウント値を1増加させるのにかける時間(秒単位)。</param> /// <param name="interval">カウント値を1増加させるのにかける時間(秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param> /// <param name="timer">カウントに使用するタイマ。</param>
public void Start(double begin, double end, double interval, CSoundTimer timer) public void Start(double begin, double end, double interval, CSoundTimer timer) {
{ this.BeginValue = begin;
this.BeginValue = begin; this.EndValue = end;
this.EndValue = end; this._Interval = interval;
this._Interval = interval; this.TimerDB = timer;
this.TimerDB = timer; this.NowTime = this.TimerDB.SystemTime_Double;
this.NowTime = this.TimerDB.SystemTime_Double; this.CurrentValue = (int)begin;
this.CurrentValue = (int)begin; this.IsStarted = true;
this.IsStarted = true; }
}
/// <summary> /// <summary>
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。 /// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。 /// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary> /// </summary>
public void Tick() public void Tick() {
{ if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) {
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) long num = this.NormalTimer.NowTime;
{ if (num < this.NowTime)
long num = this.NormalTimer.NowTime; this.NowTime = num;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval) while ((num - this.NowTime) >= this.Interval) {
{ if (++this.CurrentValue > this.EndValue)
if (++this.CurrentValue > this.EndValue) this.CurrentValue = (int)this.EndValue;
this.CurrentValue = (int)this.EndValue;
this.NowTime += this.Interval; this.NowTime += this.Interval;
} }
} }
} }
/// <summary> /// <summary>
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。 /// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。 /// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary> /// </summary>
public void TickDB() public void TickDB() {
{ if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) {
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) double num = this.TimerDB.NowTime;
{ if (num < this.NowTime)
double num = this.TimerDB.NowTime; this.NowTime = num;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval) while ((num - this.NowTime) >= this.Interval) {
{ if (++this.CurrentValue > this.EndValue)
if (++this.CurrentValue > this.EndValue) this.CurrentValue = (int)this.EndValue;
this.CurrentValue = (int)this.EndValue;
this.NowTime += this.Interval; this.NowTime += this.Interval;
} }
} }
} }
/// <summary> /// <summary>
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。 /// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。 /// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary> /// </summary>
public void TickLoop() public void TickLoop() {
{ if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) {
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) long num = this.NormalTimer.NowTime;
{ if (num < this.NowTime)
long num = this.NormalTimer.NowTime; this.NowTime = num;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval) while ((num - this.NowTime) >= this.Interval) {
{ if (++this.CurrentValue > this.EndValue)
if (++this.CurrentValue > this.EndValue) this.CurrentValue = (int)this.BeginValue;
this.CurrentValue = (int)this.BeginValue;
this.NowTime += this.Interval; this.NowTime += this.Interval;
} }
} }
} }
/// <summary> /// <summary>
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。 /// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。 /// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary> /// </summary>
public void TickLoopDB() public void TickLoopDB() {
{ if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) {
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) double num = this.TimerDB.NowTime;
{ if (num < this.NowTime)
double num = this.TimerDB.NowTime; this.NowTime = num;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval) while ((num - this.NowTime) >= this.Interval) {
{ if (++this.CurrentValue > this.EndValue)
if (++this.CurrentValue > this.EndValue) this.CurrentValue = (int)this.BeginValue;
this.CurrentValue = (int)this.BeginValue;
this.NowTime += this.Interval; this.NowTime += this.Interval;
} }
} }
} }
/// <summary> /// <summary>
/// カウントを停止する。 /// カウントを停止する。
/// これ以降に t進行() や t進行Loop() を呼び出しても何も処理されない。 /// これ以降に t進行() や t進行Loop() を呼び出しても何も処理されない。
/// </summary> /// </summary>
public void Stop() public void Stop() {
{ this.NowTime = CTimer.UnusedNum;
this.NowTime = CTimer.UnusedNum; }
}
public void ChangeInterval(double Value) public void ChangeInterval(double Value) {
{ this._Interval = Value;
this._Interval = Value; }
}
// その他 // その他
#region [ ] #region [ ]
//----------------- //-----------------
/// <summary> /// <summary>
/// <para>「bキー押下」引数が true の間中、「tキー処理」デリゲート引数を呼び出す。</para> /// <para>「bキー押下」引数が true の間中、「tキー処理」デリゲート引数を呼び出す。</para>
/// <para>ただし、2回目の呼び出しは1回目から 200ms の間を開けてから行い、3回目以降の呼び出しはそれぞれ 30ms の間隔で呼び出す。</para> /// <para>ただし、2回目の呼び出しは1回目から 200ms の間を開けてから行い、3回目以降の呼び出しはそれぞれ 30ms の間隔で呼び出す。</para>
/// <para>「bキー押下」が false の場合は何もせず、呼び出し回数を 0 にリセットする。</para> /// <para>「bキー押下」が false の場合は何もせず、呼び出し回数を 0 にリセットする。</para>
/// </summary> /// </summary>
/// <param name="pressFlag">キーが押下されている場合は true。</param> /// <param name="pressFlag">キーが押下されている場合は true。</param>
/// <param name="keyProcess">キーが押下されている場合に実行する処理。</param> /// <param name="keyProcess">キーが押下されている場合に実行する処理。</param>
public void KeyIntervalFunc(bool pressFlag, KeyProcess keyProcess) public void KeyIntervalFunc(bool pressFlag, KeyProcess keyProcess) {
{ const int first = 0;
const int first = 0; const int second = 1;
const int second = 1; const int later = 2;
const int later = 2;
if (pressFlag) if (pressFlag) {
{ switch (this.CurrentValue) {
switch (this.CurrentValue) case first:
{
case first:
keyProcess(); keyProcess();
this.CurrentValue = second; this.CurrentValue = second;
this.NowTime = this.NormalTimer.NowTime; this.NowTime = this.NormalTimer.NowTime;
return; return;
case second: case second:
if ((this.NormalTimer.NowTime - this.NowTime) > 200) if ((this.NormalTimer.NowTime - this.NowTime) > 200) {
{ keyProcess();
keyProcess(); this.NowTime = this.NormalTimer.NowTime;
this.NowTime = this.NormalTimer.NowTime; this.CurrentValue = later;
this.CurrentValue = later; }
} return;
return;
case later: case later:
if ((this.NormalTimer.NowTime - this.NowTime) > 30) if ((this.NormalTimer.NowTime - this.NowTime) > 30) {
{ keyProcess();
keyProcess(); this.NowTime = this.NormalTimer.NowTime;
this.NowTime = this.NormalTimer.NowTime; }
} return;
return; }
} } else {
} this.CurrentValue = first;
else }
{ }
this.CurrentValue = first; public delegate void KeyProcess();
}
}
public delegate void KeyProcess();
//----------------- //-----------------
#endregion #endregion
#region [ private ] #region [ private ]
//----------------- //-----------------
private CTimer NormalTimer; private CTimer NormalTimer;
private CSoundTimer TimerDB; private CSoundTimer TimerDB;
private double Interval; private double Interval;
//----------------- //-----------------
#endregion #endregion
} }
} }

View File

@ -1,25 +1,16 @@
using System; namespace FDK {
using System.Collections.Generic; public class CFPS {
using System.Text;
namespace FDK
{
public class CFPS
{
// プロパティ // プロパティ
public int NowFPS public int NowFPS {
{
get; get;
private set; private set;
} }
public double DeltaTime public double DeltaTime {
{
get; get;
private set; private set;
} }
public bool ChangedFPS public bool ChangedFPS {
{
get; get;
private set; private set;
} }
@ -27,11 +18,10 @@ namespace FDK
// コンストラクタ // コンストラクタ
public CFPS() public CFPS() {
{
this.NowFPS = 0; this.NowFPS = 0;
this.DeltaTime = 0; this.DeltaTime = 0;
this.FPSTimer = new CTimer( CTimer.TimerType.MultiMedia ); this.FPSTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.BeginTime = this.FPSTimer.NowTime; this.BeginTime = this.FPSTimer.NowTime;
this.CoreFPS = 0; this.CoreFPS = 0;
this.ChangedFPS = false; this.ChangedFPS = false;
@ -40,16 +30,14 @@ namespace FDK
// メソッド // メソッド
public void Update() public void Update() {
{
this.FPSTimer.Update(); this.FPSTimer.Update();
this.ChangedFPS = false; this.ChangedFPS = false;
const long INTERVAL = 1000; const long INTERVAL = 1000;
this.DeltaTime = (this.FPSTimer.NowTime - this.PrevFrameTime) / 1000.0; this.DeltaTime = (this.FPSTimer.NowTime - this.PrevFrameTime) / 1000.0;
PrevFrameTime = this.FPSTimer.NowTime; PrevFrameTime = this.FPSTimer.NowTime;
while ( ( this.FPSTimer.NowTime - this.BeginTime ) >= INTERVAL ) while ((this.FPSTimer.NowTime - this.BeginTime) >= INTERVAL) {
{
this.NowFPS = this.CoreFPS; this.NowFPS = this.CoreFPS;
this.CoreFPS = 0; this.CoreFPS = 0;
this.ChangedFPS = true; this.ChangedFPS = true;
@ -63,10 +51,10 @@ namespace FDK
#region [ private ] #region [ private ]
//----------------- //-----------------
private CTimer FPSTimer; private CTimer FPSTimer;
private long BeginTime; private long BeginTime;
private long PrevFrameTime; private long PrevFrameTime;
private int CoreFPS; private int CoreFPS;
//----------------- //-----------------
#endregion #endregion
} }

View File

@ -1,81 +1,66 @@
using System; using System.Text;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace FDK namespace FDK {
{
/// <summary> /// <summary>
/// 汎用的な .iniファイルを扱う。 /// 汎用的な .iniファイルを扱う。
/// </summary> /// </summary>
public class CIniFile public class CIniFile {
{
// プロパティ // プロパティ
public string FileName public string FileName {
{
get; get;
private set; private set;
} }
public List<CSection> Sections public List<CSection> Sections {
{
get; get;
set; set;
} }
public class CSection public class CSection {
{
public string SectionName = ""; public string SectionName = "";
public List<KeyValuePair<string,string>> Parameters = new List<KeyValuePair<string, string>>(); public List<KeyValuePair<string, string>> Parameters = new List<KeyValuePair<string, string>>();
} }
// コンストラクタ // コンストラクタ
public CIniFile() public CIniFile() {
{
this.FileName = ""; this.FileName = "";
this.Sections = new List<CSection>(); this.Sections = new List<CSection>();
} }
public CIniFile( string fileName ) public CIniFile(string fileName)
:this() : this() {
{ this.tRead(fileName);
this.tRead( fileName );
} }
// メソッド // メソッド
public void tRead( string fileName ) public void tRead(string fileName) {
{
this.FileName = fileName; this.FileName = fileName;
StreamReader sr = null; StreamReader sr = null;
CSection section = null; CSection section = null;
try try {
{ sr = new StreamReader(this.FileName, Encoding.GetEncoding("Shift_JIS")); // ファイルが存在しない場合は例外発生。
sr = new StreamReader( this.FileName, Encoding.GetEncoding("Shift_JIS") ); // ファイルが存在しない場合は例外発生。
string line; string line;
while( ( line = sr.ReadLine() ) != null ) while ((line = sr.ReadLine()) != null) {
{ line = line.Replace('\t', ' ').TrimStart(new char[] { '\t', ' ' });
line = line.Replace( '\t', ' ' ).TrimStart( new char[] { '\t', ' ' } ); if (string.IsNullOrEmpty(line) || line[0] == ';') // ';'以降はコメントとして無視
if( string.IsNullOrEmpty( line ) || line[ 0 ] == ';' ) // ';'以降はコメントとして無視
continue; continue;
if( line[ 0 ] == '[' ) if (line[0] == '[') {
{
#region [ ] #region [ ]
//----------------------------- //-----------------------------
var builder = new StringBuilder( 32 ); var builder = new StringBuilder(32);
int num = 1; int num = 1;
while( ( num < line.Length ) && ( line[ num ] != ']' ) ) while ((num < line.Length) && (line[num] != ']'))
builder.Append( line[ num++ ] ); builder.Append(line[num++]);
// 変数 section が使用中の場合は、List<CSection> に追加して新しい section を作成する。 // 変数 section が使用中の場合は、List<CSection> に追加して新しい section を作成する。
if( section != null ) if (section != null)
this.Sections.Add( section ); this.Sections.Add(section);
section = new CSection(); section = new CSection();
section.SectionName = builder.ToString(); section.SectionName = builder.ToString();
@ -85,49 +70,41 @@ namespace FDK
continue; continue;
} }
string[] strArray = line.Split( new char[] { '=' } ); string[] strArray = line.Split(new char[] { '=' });
if( strArray.Length != 2 ) if (strArray.Length != 2)
continue; continue;
string key = strArray[ 0 ].Trim(); string key = strArray[0].Trim();
string value = strArray[ 1 ].Trim(); string value = strArray[1].Trim();
if( section != null && !string.IsNullOrEmpty( key ) && !string.IsNullOrEmpty( value ) ) if (section != null && !string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
section.Parameters.Add( new KeyValuePair<string, string>( key, value ) ); section.Parameters.Add(new KeyValuePair<string, string>(key, value));
} }
if( section != null ) if (section != null)
this.Sections.Add( section ); this.Sections.Add(section);
} } finally {
finally if (sr != null)
{
if( sr != null )
sr.Close(); sr.Close();
} }
} }
public void tWrite( string fileName ) public void tWrite(string fileName) {
{
this.FileName = fileName; this.FileName = fileName;
this.tWrite(); this.tWrite();
} }
public void tWrite() public void tWrite() {
{
StreamWriter sw = null; StreamWriter sw = null;
try try {
{ sw = new StreamWriter(this.FileName, false, Encoding.GetEncoding("Shift_JIS")); // オープン失敗の場合は例外発生。
sw = new StreamWriter( this.FileName, false, Encoding.GetEncoding( "Shift_JIS" ) ); // オープン失敗の場合は例外発生。
foreach( CSection section in this.Sections ) foreach (CSection section in this.Sections) {
{ sw.WriteLine("[{0}]", section.SectionName);
sw.WriteLine( "[{0}]", section.SectionName );
foreach( KeyValuePair<string,string> kvp in section.Parameters ) foreach (KeyValuePair<string, string> kvp in section.Parameters)
sw.WriteLine( "{0}={1}", kvp.Key, kvp.Value ); sw.WriteLine("{0}={1}", kvp.Key, kvp.Value);
} }
} } finally {
finally if (sw != null)
{
if( sw != null )
sw.Close(); sw.Close();
} }
} }

View File

@ -1,41 +1,33 @@
using System; namespace FDK {
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary> /// <summary>
/// <para>一定の間隔で処理を行うテンプレートパターンの定義。</para> /// <para>一定の間隔で処理を行うテンプレートパターンの定義。</para>
/// <para>たとえば、t進行() で 5ms ごとに行う処理を前回のt進行()の呼び出しから 15ms 後に呼び出した場合は、処理が 3回 実行される。</para> /// <para>たとえば、t進行() で 5ms ごとに行う処理を前回のt進行()の呼び出しから 15ms 後に呼び出した場合は、処理が 3回 実行される。</para>
/// </summary> /// </summary>
public class CIntervalProcessing : IDisposable public class CIntervalProcessing : IDisposable {
{
public delegate void dgProc(); public delegate void dgProc();
public void Tick( long interval, dgProc proc ) public void Tick(long interval, dgProc proc) {
{
// タイマ更新 // タイマ更新
if( this.timer == null ) if (this.timer == null)
return; return;
this.timer.Update(); this.timer.Update();
// 初めての進行処理 // 初めての進行処理
if( this.PrevTime == CTimer.UnusedNum ) if (this.PrevTime == CTimer.UnusedNum)
this.PrevTime = this.timer.NowTimeMs; this.PrevTime = this.timer.NowTimeMs;
// タイマが一回りしてしまった時のため…… // タイマが一回りしてしまった時のため……
if( this.timer.NowTimeMs < this.PrevTime ) if (this.timer.NowTimeMs < this.PrevTime)
this.PrevTime = this.timer.NowTimeMs; this.PrevTime = this.timer.NowTimeMs;
// 時間内の処理を実行。 // 時間内の処理を実行。
while( ( this.timer.NowTimeMs - this.PrevTime ) >= interval ) while ((this.timer.NowTimeMs - this.PrevTime) >= interval) {
{
proc(); proc();
this.PrevTime += interval; this.PrevTime += interval;
@ -44,8 +36,7 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{
timer.Dispose(); timer.Dispose();
} }
//----------------- //-----------------
@ -53,7 +44,7 @@ namespace FDK
#region [ protected ] #region [ protected ]
//----------------- //-----------------
protected CTimer timer = new CTimer( CTimer.TimerType.MultiMedia ); protected CTimer timer = new CTimer(CTimer.TimerType.MultiMedia);
protected long PrevTime = CTimer.UnusedNum; protected long PrevTime = CTimer.UnusedNum;
//----------------- //-----------------
#endregion #endregion

View File

@ -1,25 +1,17 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.IO;
using System.Diagnostics;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ public class CJudgeTextEncoding {
public class CJudgeTextEncoding
{
/// <summary> /// <summary>
/// Hnc8様のReadJEncを使用して文字コードの判別をする。 /// Hnc8様のReadJEncを使用して文字コードの判別をする。
/// </summary> /// </summary>
public static Encoding JudgeFileEncoding(string path) public static Encoding JudgeFileEncoding(string path) {
{
if (!File.Exists(path)) return null; if (!File.Exists(path)) return null;
Encoding enc; Encoding enc;
FileInfo file = new FileInfo(path); FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) {
{
// 判別読み出し実行。判別結果はReadメソッドの戻り値で把握できます // 判別読み出し実行。判別結果はReadメソッドの戻り値で把握できます
Hnx8.ReadJEnc.CharCode c = reader.Read(file); Hnx8.ReadJEnc.CharCode c = reader.Read(file);
// 戻り値のNameプロパティから文字コード名を取得できます // 戻り値のNameプロパティから文字コード名を取得できます
@ -30,8 +22,7 @@ namespace TJAPlayer3
} }
Debug.Print(path + " Encoding=" + enc.CodePage); Debug.Print(path + " Encoding=" + enc.CodePage);
if (enc == null) if (enc == null) {
{
enc = Encoding.GetEncoding(932); enc = Encoding.GetEncoding(932);
} }
return enc; return enc;
@ -42,14 +33,12 @@ namespace TJAPlayer3
/// </summary> /// </summary>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public static string ReadTextFile(string path) public static string ReadTextFile(string path) {
{
if (!File.Exists(path)) return null; if (!File.Exists(path)) return null;
string str = null; string str = null;
FileInfo file = new FileInfo(path); FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) {
{
reader.Read(file); reader.Read(file);
str = reader.Text; str = reader.Text;
} }
@ -66,8 +55,7 @@ namespace TJAPlayer3
/// </summary> /// </summary>
/// <param name="str"></param> /// <param name="str"></param>
/// <returns></returns> /// <returns></returns>
public static string JudgeNewLine(string str) public static string JudgeNewLine(string str) {
{
if (str.Contains("\r\n")) if (str.Contains("\r\n"))
return ("\r\n"); return ("\r\n");
@ -78,4 +66,4 @@ namespace TJAPlayer3
} }
} }
} }

View File

@ -1,31 +1,19 @@
using System; namespace FDK {
using System.Collections.Generic; public class CTimer : CTimerBase {
using System.Text; public enum TimerType {
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FDK
{
public class CTimer : CTimerBase
{
public enum TimerType
{
Unknown = -1, Unknown = -1,
PerformanceCounter = 0, PerformanceCounter = 0,
MultiMedia = 1, MultiMedia = 1,
GetTickCount = 2, GetTickCount = 2,
} }
public TimerType CurrentTimerType public TimerType CurrentTimerType {
{
get; get;
protected set; protected set;
} }
public override long SystemTimeMs public override long SystemTimeMs {
{ get {
get
{
/* /*
switch( this.eタイマ種別 ) switch( this.eタイマ種別 )
{ {
@ -52,9 +40,8 @@ namespace FDK
} }
} }
public CTimer( TimerType timerType ) public CTimer(TimerType timerType)
:base() : base() {
{
this.CurrentTimerType = timerType; this.CurrentTimerType = timerType;
/* /*
@ -81,23 +68,21 @@ namespace FDK
} }
} }
*/ */
base.Reset(); base.Reset();
ReferenceCount[ (int) this.CurrentTimerType ]++; ReferenceCount[(int)this.CurrentTimerType]++;
} }
public override void Dispose() public override void Dispose() {
{ if (this.CurrentTimerType == TimerType.Unknown)
if( this.CurrentTimerType == TimerType.Unknown )
return; return;
int type = (int) this.CurrentTimerType; int type = (int)this.CurrentTimerType;
ReferenceCount[ type ] = Math.Max( ReferenceCount[ type ] - 1, 0 ); ReferenceCount[type] = Math.Max(ReferenceCount[type] - 1, 0);
if( ReferenceCount[ type ] == 0 ) if (ReferenceCount[type] == 0) {
{
/* /*
if( this.eタイマ種別 == E種別.MultiMedia ) if( this.eタイマ種別 == E種別.MultiMedia )
timeEndPeriod( this.timeCaps.wPeriodMin ); timeEndPeriod( this.timeCaps.wPeriodMin );
@ -110,11 +95,10 @@ namespace FDK
#region [ protected ] #region [ protected ]
//----------------- //-----------------
protected long CurrentFrequency; protected long CurrentFrequency;
protected static int[] ReferenceCount = new int[ 3 ]; protected static int[] ReferenceCount = new int[3];
//protected TimeCaps timeCaps; //protected TimeCaps timeCaps;
protected bool GetSetTickCount() protected bool GetSetTickCount() {
{
this.CurrentTimerType = TimerType.GetTickCount; this.CurrentTimerType = TimerType.GetTickCount;
return true; return true;
} }

View File

@ -1,177 +1,142 @@
using System; namespace FDK {
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary> /// <summary>
/// <para>タイマの抽象クラス。</para> /// <para>タイマの抽象クラス。</para>
/// <para>このクラスを継承し、override したクラスを作成することで、任意のクロックを持つタイマを作成できる。</para> /// <para>このクラスを継承し、override したクラスを作成することで、任意のクロックを持つタイマを作成できる。</para>
/// </summary> /// </summary>
public abstract class CTimerBase : IDisposable public abstract class CTimerBase : IDisposable {
{
public const long UnusedNum = -1; public const long UnusedNum = -1;
// この2つを override する。 // この2つを override する。
public abstract long SystemTimeMs public abstract long SystemTimeMs {
{
get; get;
} }
public double SystemTimeMs_Double public double SystemTimeMs_Double {
{ get;
get; set;
set; }
}
public abstract void Dispose(); public abstract void Dispose();
#region [ DTXMania用にmsのつかない宣言を追加 ] #region [ DTXMania用にmsのつかない宣言を追加 ]
public long SystemTime public long SystemTime {
{
get { return SystemTimeMs; } get { return SystemTimeMs; }
} }
public long NowTime public long NowTime {
{
get { return NowTimeMs; } get { return NowTimeMs; }
set { NowTimeMs = value; } set { NowTimeMs = value; }
} }
public long PrevResetTime public long PrevResetTime {
{
get { return PrevResetTimeMs; } get { return PrevResetTimeMs; }
} }
//double //double
public double SystemTime_Double public double SystemTime_Double {
{
get { return SystemTimeMs_Double; } get { return SystemTimeMs_Double; }
} }
public double NowTime_Double public double NowTime_Double {
{
get { return NowTimeMs_Double; } get { return NowTimeMs_Double; }
set { NowTimeMs_Double = value; } set { NowTimeMs_Double = value; }
} }
public double PrevResetTime_Double public double PrevResetTime_Double {
{
get { return PrevResetTimeMs_Double; } get { return PrevResetTimeMs_Double; }
} }
#endregion #endregion
public long NowTimeMs public long NowTimeMs {
{ get {
get if (this.StopCount > 0)
{ return (this.PauseSystemTimeMs - this.PrevResetTimeMs);
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs - this.PrevResetTimeMs );
return ( this.UpdateSystemTime - this.PrevResetTimeMs ); return (this.UpdateSystemTime - this.PrevResetTimeMs);
} }
set set {
{ if (this.StopCount > 0)
if( this.StopCount > 0 )
this.PrevResetTimeMs = this.PauseSystemTimeMs - value; this.PrevResetTimeMs = this.PauseSystemTimeMs - value;
else else
this.PrevResetTimeMs = this.UpdateSystemTime - value; this.PrevResetTimeMs = this.UpdateSystemTime - value;
} }
} }
public long RealNowTimeMs public long RealNowTimeMs {
{ get {
get if (this.StopCount > 0)
{ return (this.PauseSystemTimeMs - this.PrevResetTimeMs);
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs - this.PrevResetTimeMs );
return ( this.SystemTimeMs - this.PrevResetTimeMs ); return (this.SystemTimeMs - this.PrevResetTimeMs);
} }
} }
public long PrevResetTimeMs public long PrevResetTimeMs {
{
get; get;
protected set; protected set;
} }
public double NowTimeMs_Double public double NowTimeMs_Double {
{ get {
get if (this.StopCount > 0)
{ return (this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double);
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double );
return ( this.UpdateSystemTime_Double - this.PrevResetTimeMs_Double ); return (this.UpdateSystemTime_Double - this.PrevResetTimeMs_Double);
} }
set set {
{ if (this.StopCount > 0)
if( this.StopCount > 0 )
this.PrevResetTimeMs_Double = this.PauseSystemTimeMs_Double - value; this.PrevResetTimeMs_Double = this.PauseSystemTimeMs_Double - value;
else else
this.PrevResetTimeMs_Double = this.UpdateSystemTime_Double - value; this.PrevResetTimeMs_Double = this.UpdateSystemTime_Double - value;
} }
} }
public double RealNowTimeMs_Double public double RealNowTimeMs_Double {
{ get {
get if (this.StopCount > 0)
{ return (this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double);
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double );
return ( this.SystemTimeMs_Double - this.PrevResetTimeMs_Double ); return (this.SystemTimeMs_Double - this.PrevResetTimeMs_Double);
} }
} }
public double PrevResetTimeMs_Double public double PrevResetTimeMs_Double {
{
get; get;
protected set; protected set;
} }
public bool IsUnStoped public bool IsUnStoped {
{ get {
get return (this.StopCount == 0);
{ }
return ( this.StopCount == 0 ); }
}
}
public void Reset() public void Reset() {
{
this.Update(); this.Update();
this.PrevResetTimeMs = this.UpdateSystemTime; this.PrevResetTimeMs = this.UpdateSystemTime;
this.PauseSystemTimeMs = this.UpdateSystemTime; this.PauseSystemTimeMs = this.UpdateSystemTime;
this.StopCount = 0; this.StopCount = 0;
} }
public void Pause() public void Pause() {
{ if (this.StopCount == 0) {
if( this.StopCount == 0 )
{
this.PauseSystemTimeMs = this.UpdateSystemTime; this.PauseSystemTimeMs = this.UpdateSystemTime;
this.PauseSystemTimeMs_Double = this.UpdateSystemTime_Double; this.PauseSystemTimeMs_Double = this.UpdateSystemTime_Double;
} }
this.StopCount++; this.StopCount++;
} }
public void Update() public void Update() {
{
this.UpdateSystemTime = this.SystemTimeMs; this.UpdateSystemTime = this.SystemTimeMs;
this.UpdateSystemTime_Double = this.SystemTimeMs_Double; this.UpdateSystemTime_Double = this.SystemTimeMs_Double;
} }
public void Resume() public void Resume() {
{ if (this.StopCount > 0) {
if( this.StopCount > 0 )
{
this.StopCount--; this.StopCount--;
if( this.StopCount == 0 ) if (this.StopCount == 0) {
{
this.Update(); this.Update();
this.PrevResetTimeMs += this.UpdateSystemTime - this.PauseSystemTimeMs; this.PrevResetTimeMs += this.UpdateSystemTime - this.PauseSystemTimeMs;
this.PrevResetTimeMs_Double += this.UpdateSystemTime_Double - this.PauseSystemTimeMs_Double; this.PrevResetTimeMs_Double += this.UpdateSystemTime_Double - this.PauseSystemTimeMs_Double;
} }
} }
} }
#region [ protected ] #region [ protected ]
//----------------- //-----------------
protected long PauseSystemTimeMs = 0; protected long PauseSystemTimeMs = 0;
protected long UpdateSystemTime = 0; protected long UpdateSystemTime = 0;
protected double PauseSystemTimeMs_Double = 0; protected double PauseSystemTimeMs_Double = 0;
protected double UpdateSystemTime_Double = 0; protected double UpdateSystemTime_Double = 0;
protected int StopCount = 0; protected int StopCount = 0;
//----------------- //-----------------
#endregion #endregion

View File

@ -1,127 +1,86 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace FDK namespace FDK {
{ public class CTraceLogListener : TraceListener {
public class CTraceLogListener : TraceListener public CTraceLogListener(StreamWriter stream) {
{
public CTraceLogListener( StreamWriter stream )
{
this.LogStreamWriter = stream; this.LogStreamWriter = stream;
} }
public override void Flush() public override void Flush() {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{
try
{
this.LogStreamWriter.Flush(); this.LogStreamWriter.Flush();
} } catch (ObjectDisposedException) {
catch( ObjectDisposedException )
{
} }
} }
} }
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message ) public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{ this.LogEventType(eventType);
try
{
this.LogEventType( eventType );
this.LogIndent(); this.LogIndent();
this.LogStreamWriter.WriteLine( message ); this.LogStreamWriter.WriteLine(message);
} } catch (ObjectDisposedException) {
catch( ObjectDisposedException )
{
} }
} }
} }
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args ) public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{ this.LogEventType(eventType);
try
{
this.LogEventType( eventType );
this.LogIndent(); this.LogIndent();
this.LogStreamWriter.WriteLine( string.Format( format, args ) ); this.LogStreamWriter.WriteLine(string.Format(format, args));
} } catch (ObjectDisposedException) {
catch( ObjectDisposedException )
{
} }
} }
} }
public override void Write( string message ) public override void Write(string message) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{ this.LogStreamWriter.Write(message);
try } catch (ObjectDisposedException) {
{
this.LogStreamWriter.Write( message );
}
catch( ObjectDisposedException )
{
} }
} }
} }
public override void WriteLine( string message ) public override void WriteLine(string message) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{ this.LogStreamWriter.WriteLine(message);
try } catch (ObjectDisposedException) {
{
this.LogStreamWriter.WriteLine( message );
}
catch( ObjectDisposedException )
{
} }
} }
} }
protected override void Dispose( bool disposing ) protected override void Dispose(bool disposing) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{
try
{
this.LogStreamWriter.Close(); this.LogStreamWriter.Close();
} } catch {
catch
{
} }
this.LogStreamWriter = null; this.LogStreamWriter = null;
} }
base.Dispose( disposing ); base.Dispose(disposing);
} }
#region [ private ] #region [ private ]
//----------------- //-----------------
private StreamWriter LogStreamWriter; private StreamWriter LogStreamWriter;
private void LogEventType( TraceEventType eventType ) private void LogEventType(TraceEventType eventType) {
{ if (this.LogStreamWriter != null) {
if( this.LogStreamWriter != null ) try {
{
try
{
var now = DateTime.Now; var now = DateTime.Now;
this.LogStreamWriter.Write( string.Format( "{0:D4}/{1:D2}/{2:D2} {3:D2}:{4:D2}:{5:D2}.{6:D3} ", new object[] { now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond } ) ); this.LogStreamWriter.Write(string.Format("{0:D4}/{1:D2}/{2:D2} {3:D2}:{4:D2}:{5:D2}.{6:D3} ", new object[] { now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond }));
switch( eventType ) switch (eventType) {
{
case TraceEventType.Error: case TraceEventType.Error:
this.LogStreamWriter.Write( "[ERROR] " ); this.LogStreamWriter.Write("[ERROR] ");
return; return;
case ( TraceEventType.Error | TraceEventType.Critical ): case (TraceEventType.Error | TraceEventType.Critical):
return; return;
case TraceEventType.Warning: case TraceEventType.Warning:
this.LogStreamWriter.Write( "[WARNING] " ); this.LogStreamWriter.Write("[WARNING] ");
return; return;
case TraceEventType.Information: case TraceEventType.Information:
@ -130,24 +89,17 @@ namespace FDK
default: default:
return; return;
} }
this.LogStreamWriter.Write( "[INFO] " ); this.LogStreamWriter.Write("[INFO] ");
} } catch (ObjectDisposedException) {
catch( ObjectDisposedException )
{
} }
} }
} }
private void LogIndent() private void LogIndent() {
{ if ((this.LogStreamWriter != null) && (base.IndentLevel > 0)) {
if( ( this.LogStreamWriter != null ) && ( base.IndentLevel > 0 ) ) try {
{ for (int i = 0; i < base.IndentLevel; i++)
try this.LogStreamWriter.Write(" ");
{ } catch (ObjectDisposedException) {
for( int i = 0; i < base.IndentLevel; i++ )
this.LogStreamWriter.Write( " " );
}
catch( ObjectDisposedException )
{
} }
} }
} }

View File

@ -1,20 +1,13 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace FDK namespace FDK {
{ public class CUtility {
public class CUtility
{
public static void RunCompleteGC() public static void RunCompleteGC() {
{ GC.Collect(); // アクセス不可能なオブジェクトを除去し、ファイナライぜーション実施。
GC.Collect(); // アクセス不可能なオブジェクトを除去し、ファイナライぜーション実施。 GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッドを待機。
GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッドを待機。 GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放。
GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放。
// 出展: http://msdn.microsoft.com/ja-jp/library/ms998547.aspx#scalenetchapt05_topic10 // 出展: http://msdn.microsoft.com/ja-jp/library/ms998547.aspx#scalenetchapt05_topic10
} }
@ -22,116 +15,95 @@ namespace FDK
// ログ // ログ
public static void LogBlock( string name, Action method ) public static void LogBlock(string name, Action method) {
{ Trace.TraceInformation("--------------------");
Trace.TraceInformation( "--------------------" ); Trace.TraceInformation("開始 - " + name);
Trace.TraceInformation( "開始 - " + name );
Trace.Indent(); Trace.Indent();
try try {
{
method(); method();
} } finally {
finally
{
Trace.Unindent(); Trace.Unindent();
Trace.TraceInformation( "終了 - " + name ); Trace.TraceInformation("終了 - " + name);
Trace.TraceInformation( "--------------------" ); Trace.TraceInformation("--------------------");
} }
} }
public static void LogException( Exception e ) public static void LogException(Exception e) {
{ Trace.WriteLine("---例外ここから----");
Trace.WriteLine( "---例外ここから----" ); Trace.WriteLine(e.ToString());
Trace.WriteLine( e.ToString() ); Trace.WriteLine("---例外ここまで----");
Trace.WriteLine( "---例外ここまで----" );
} }
// IO // IO
public static string t指定した拡張子を持つファイルを検索し最初に見つけたファイルの絶対パスを返す( string strフォルダパス, List<string> extensions ) public static string t指定した拡張子を持つファイルを検索し最初に見つけたファイルの絶対パスを返す(string strフォルダパス, List<string> extensions) {
{ string[] files = Directory.GetFiles(strフォルダパス); // GetFiles() は完全パスを返す。
string[] files = Directory.GetFiles( strフォルダパス ); // GetFiles() は完全パスを返す。
// ファイル順より拡張子順を優先して検索する。→ 拡張子リストの前方の拡張子ほど先に発見されるようにするため。 // ファイル順より拡張子順を優先して検索する。→ 拡張子リストの前方の拡張子ほど先に発見されるようにするため。
foreach( string ext in extensions ) foreach (string ext in extensions) {
{ foreach (string file in files) {
foreach( string file in files ) string fileExt = Path.GetExtension(file);
{
string fileExt = Path.GetExtension( file );
if( fileExt.Equals( ext, StringComparison.OrdinalIgnoreCase ) ) if (fileExt.Equals(ext, StringComparison.OrdinalIgnoreCase))
return file; // あった return file; // あった
} }
} }
return null; // なかった return null; // なかった
} }
public static void ReadXML<T>( string fileName, out T xmlObject ) public static void ReadXML<T>(string fileName, out T xmlObject) {
{ xmlObject = default(T);
xmlObject = default( T );
FileStream fs = null; FileStream fs = null;
StreamReader sr = null; StreamReader sr = null;
try try {
{ fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // FileShare を付けとかないと、Close() 後もロックがかかる。
fs = new FileStream( fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。 sr = new StreamReader(fs, Encoding.UTF8);
sr = new StreamReader( fs, Encoding.UTF8 ); var xmlsl = new System.Xml.Serialization.XmlSerializer(typeof(T));
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) ); xmlObject = (T)xmlsl.Deserialize(sr);
xmlObject = (T) xmlsl.Deserialize( sr ); } finally {
} if (sr != null)
finally sr.Close(); // fr も一緒にClose()される
{
if( sr != null )
sr.Close(); // fr も一緒にClose()される
} }
} }
public static void WriteXML<T>( string fileName, T xmlObject ) public static void WriteXML<T>(string fileName, T xmlObject) {
{
FileStream fs = null; FileStream fs = null;
StreamWriter sw = null; StreamWriter sw = null;
try try {
{ fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); // FileShare を付けとかないと、Close() 後もロックがかかる。
fs = new FileStream( fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。 sw = new StreamWriter(fs, Encoding.UTF8);
sw = new StreamWriter( fs, Encoding.UTF8 ); var xmlsl = new System.Xml.Serialization.XmlSerializer(typeof(T));
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) ); xmlsl.Serialize(sw, xmlObject);
xmlsl.Serialize( sw, xmlObject ); } finally {
} if (sw != null)
finally sw.Close(); // fs も一緒にClose()される
{
if( sw != null )
sw.Close(); // fs も一緒にClose()される
} }
} }
// 数学 // 数学
public static double DegreeToRadian( double angle ) public static double DegreeToRadian(double angle) {
{ return ((Math.PI * angle) / 180.0);
return ( ( Math.PI * angle ) / 180.0 );
} }
public static double RadianToDegree( double angle ) public static double RadianToDegree(double angle) {
{ return (angle * 180.0 / Math.PI);
return ( angle * 180.0 / Math.PI );
} }
public static float DegreeToRadian( float angle ) public static float DegreeToRadian(float angle) {
{ return (float)DegreeToRadian((double)angle);
return (float) DegreeToRadian( (double) angle );
} }
public static float RadianToDegree( float angle ) public static float RadianToDegree(float angle) {
{ return (float)RadianToDegree((double)angle);
return (float) RadianToDegree( (double) angle );
} }
public static bool ToggleBoolian( ref bool bFlag ) public static bool ToggleBoolian(ref bool bFlag) {
{ if (bFlag == true) bFlag = false;
if( bFlag == true ) bFlag = false; else if (bFlag == false) bFlag = true;
else if( bFlag == false ) bFlag = true;
return true; return true;
} }
} }
} }

View File

@ -1,32 +1,22 @@
using System; namespace FDK {
using System.Collections.Generic; public class Color4 {
using System.Linq; public float Red;
using System.Text; public float Green;
using System.Threading.Tasks; public float Blue;
public float Alpha;
namespace FDK public Color4(float r, float g, float b, float a) {
{ Red = r;
public class Color4 Green = g;
{ Blue = b;
public float Red; Alpha = a;
public float Green; }
public float Blue;
public float Alpha;
public Color4(float r, float g, float b, float a) public Color4(int rgba) {
{ Alpha = ((rgba >> 24) & 255) / 255.0f;
Red = r; Blue = ((rgba >> 16) & 255) / 255.0f;
Green = g; Green = ((rgba >> 8) & 255) / 255.0f;
Blue = b; Red = (rgba & 255) / 255.0f;
Alpha = a; }
} }
public Color4(int rgba)
{
Alpha = ((rgba >> 24) & 255) / 255.0f;
Blue = ((rgba >> 16) & 255) / 255.0f;
Green = ((rgba >> 8) & 255) / 255.0f;
Red = (rgba & 255) / 255.0f;
}
}
} }

View File

@ -1,12 +1,7 @@
using System; namespace FDK.ExtensionMethods {
public static class DoubleExtensions {
namespace FDK.ExtensionMethods public static double Clamp(this double value, double min, double max) {
{ return Math.Min(Math.Max(value, min), max);
public static class DoubleExtensions }
{ }
public static double Clamp(this double value, double min, double max) }
{
return Math.Min(Math.Max(value, min), max);
}
}
}

View File

@ -1,12 +1,7 @@
using System; namespace FDK.ExtensionMethods {
public static class Int32Extensions {
namespace FDK.ExtensionMethods public static int Clamp(this int value, int min, int max) {
{ return Math.Min(Math.Max(value, min), max);
public static class Int32Extensions }
{ }
public static int Clamp(this int value, int min, int max)
{
return Math.Min(Math.Max(value, min), max);
}
}
} }

View File

@ -1,16 +1,16 @@
/* /*
* Copyright (c) 2007-2009 SlimDX Group * Copyright (c) 2007-2009 SlimDX Group
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,318 +19,265 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
using System; using FDK;
using System.ComponentModel; using Silk.NET.Core;
using System.Threading; using Silk.NET.GLFW;
using System.Collections.ObjectModel;
using Silk.NET.Windowing;
using Silk.NET.Maths; using Silk.NET.Maths;
using Silk.NET.OpenGLES; using Silk.NET.OpenGLES;
using Silk.NET.Windowing;
using SkiaSharp; using SkiaSharp;
using FDK;
using Silk.NET.GLFW;
using System.Runtime.InteropServices;
using Silk.NET.Core;
namespace SampleFramework namespace SampleFramework {
{ /// <summary>
/// <summary> /// Presents an easy to use wrapper for making games and samples.
/// Presents an easy to use wrapper for making games and samples. /// </summary>
/// </summary> public abstract class Game : IDisposable {
public abstract class Game : IDisposable public static GL Gl { get; private set; }
{ public static Silk.NET.Core.Contexts.IGLContext Context { get; private set; }
public static GL Gl { get; private set; }
public static Silk.NET.Core.Contexts.IGLContext Context { get; private set; }
public static List<Action> AsyncActions { get; private set; } = new(); public static List<Action> AsyncActions { get; private set; } = new();
private string strIconFileName; private string strIconFileName;
protected string _Text = ""; protected string _Text = "";
protected string Text protected string Text {
{ get {
get return _Text;
{ }
return _Text; set {
} _Text = value;
set if (Window_ != null) {
{ Window_.Title = value;
_Text = value; }
if (Window_ != null) }
{ }
Window_.Title = value;
}
}
}
public static AnglePlatformType GraphicsDeviceType_ = AnglePlatformType.OpenGL; public static AnglePlatformType GraphicsDeviceType_ = AnglePlatformType.OpenGL;
public IWindow Window_; public IWindow Window_;
private Vector2D<int> _WindowSize; private Vector2D<int> _WindowSize;
public Vector2D<int> WindowSize public Vector2D<int> WindowSize {
{ get {
get return _WindowSize;
{ }
return _WindowSize; set {
} _WindowSize = value;
set if (Window_ != null) {
{ Window_.Size = value;
_WindowSize = value; }
if (Window_ != null) }
{ }
Window_.Size = value;
}
}
}
private Vector2D<int> _WindowPosition; private Vector2D<int> _WindowPosition;
public Vector2D<int> WindowPosition public Vector2D<int> WindowPosition {
{ get {
get return _WindowPosition;
{ }
return _WindowPosition; set {
} _WindowPosition = value;
set if (Window_ != null) {
{ Window_.Position = value;
_WindowPosition = value; }
if (Window_ != null) }
{ }
Window_.Position = value;
}
}
}
private int _Framerate; private int _Framerate;
public int Framerate public int Framerate {
{ get {
get return _Framerate;
{ }
return _Framerate; set {
} _Framerate = value;
set if (Window_ != null) {
{ UpdateWindowFramerate(VSync, value);
_Framerate = value; }
if (Window_ != null) }
{ }
UpdateWindowFramerate(VSync, value);
}
}
}
private bool _FullScreen; private bool _FullScreen;
public bool FullScreen public bool FullScreen {
{ get {
get return _FullScreen;
{ }
return _FullScreen; set {
} _FullScreen = value;
set if (Window_ != null) {
{ Window_.WindowState = value ? WindowState.Fullscreen : WindowState.Normal;
_FullScreen = value; }
if (Window_ != null) }
{ }
Window_.WindowState = value ? WindowState.Fullscreen : WindowState.Normal;
}
}
}
private bool _VSync; private bool _VSync;
public bool VSync public bool VSync {
{ get {
get return _VSync;
{ }
return _VSync; set {
} _VSync = value;
set if (Window_ != null) {
{ UpdateWindowFramerate(value, Framerate);
_VSync = value; Window_.VSync = value;
if (Window_ != null) }
{ }
UpdateWindowFramerate(value, Framerate); }
Window_.VSync = value;
}
}
}
public static int MainThreadID { get; private set; } public static int MainThreadID { get; private set; }
private Vector2D<int> ViewPortSize = new Vector2D<int>();
private Vector2D<int> ViewPortOffset = new Vector2D<int>();
public unsafe SKBitmap GetScreenShot() private Vector2D<int> ViewPortSize = new Vector2D<int>();
{ private Vector2D<int> ViewPortOffset = new Vector2D<int>();
int ViewportWidth = ViewPortSize.X;
int ViewportHeight = ViewPortSize.Y;
fixed(uint* pixels = new uint[(uint)ViewportWidth * (uint)ViewportHeight])
{
Gl.ReadBuffer(GLEnum.Front);
Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pixels);
fixed(uint* pixels2 = new uint[(uint)ViewportWidth * (uint)ViewportHeight]) public unsafe SKBitmap GetScreenShot() {
{ int ViewportWidth = ViewPortSize.X;
for(int x = 0; x < ViewportWidth; x++) int ViewportHeight = ViewPortSize.Y;
{ fixed (uint* pixels = new uint[(uint)ViewportWidth * (uint)ViewportHeight]) {
for(int y = 1; y < ViewportHeight; y++) Gl.ReadBuffer(GLEnum.Front);
{ Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pixels);
int pos = x + ((y - 1) * ViewportWidth);
int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
var p = pixels[pos2];
pixels2[pos] = p;
}
}
using SKBitmap sKBitmap = new(ViewportWidth, ViewportHeight - 1);
sKBitmap.SetPixels((IntPtr)pixels2);
return sKBitmap.Copy();
}
}
}
public unsafe void GetScreenShotAsync(Action<SKBitmap> action) fixed (uint* pixels2 = new uint[(uint)ViewportWidth * (uint)ViewportHeight]) {
{ for (int x = 0; x < ViewportWidth; x++) {
int ViewportWidth = ViewPortSize.X; for (int y = 1; y < ViewportHeight; y++) {
int ViewportHeight = ViewPortSize.Y; int pos = x + ((y - 1) * ViewportWidth);
byte[] pixels = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4]; int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
Gl.ReadBuffer(GLEnum.Front); var p = pixels[pos2];
fixed(byte* pix = pixels) pixels2[pos] = p;
{ }
Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pix); }
}
Task.Run(() =>{ using SKBitmap sKBitmap = new(ViewportWidth, ViewportHeight - 1);
fixed(byte* pixels2 = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4]) sKBitmap.SetPixels((IntPtr)pixels2);
{ return sKBitmap.Copy();
for(int x = 0; x < ViewportWidth; x++) }
{ }
for(int y = 1; y < ViewportHeight; y++) }
{
int pos = x + ((y - 1) * ViewportWidth);
int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
pixels2[(pos * 4) + 0] = pixels[(pos2 * 4) + 0];
pixels2[(pos * 4) + 1] = pixels[(pos2 * 4) + 1];
pixels2[(pos * 4) + 2] = pixels[(pos2 * 4) + 2];
pixels2[(pos * 4) + 3] = 255;
}
}
using SKBitmap sKBitmap = new(ViewportWidth, ViewportHeight - 1);
sKBitmap.SetPixels((IntPtr)pixels2);
action(sKBitmap);
}
});
}
public static long TimeMs; public unsafe void GetScreenShotAsync(Action<SKBitmap> action) {
int ViewportWidth = ViewPortSize.X;
int ViewportHeight = ViewPortSize.Y;
byte[] pixels = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4];
Gl.ReadBuffer(GLEnum.Front);
fixed (byte* pix = pixels) {
Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pix);
}
public static Matrix4X4<float> Camera; Task.Run(() => {
fixed (byte* pixels2 = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4]) {
for (int x = 0; x < ViewportWidth; x++) {
for (int y = 1; y < ViewportHeight; y++) {
int pos = x + ((y - 1) * ViewportWidth);
int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
pixels2[(pos * 4) + 0] = pixels[(pos2 * 4) + 0];
pixels2[(pos * 4) + 1] = pixels[(pos2 * 4) + 1];
pixels2[(pos * 4) + 2] = pixels[(pos2 * 4) + 2];
pixels2[(pos * 4) + 3] = 255;
}
}
public static float ScreenAspect using SKBitmap sKBitmap = new(ViewportWidth, ViewportHeight - 1);
{ sKBitmap.SetPixels((IntPtr)pixels2);
get action(sKBitmap);
{ }
return (float)GameWindowSize.Width / GameWindowSize.Height; });
} }
}
//[DllImportAttribute("libEGL", EntryPoint = "eglGetError")] public static long TimeMs;
//public static extern Silk.NET.OpenGLES.ErrorCode GetError();
/// <summary> public static Matrix4X4<float> Camera;
/// Initializes the <see cref="Game"/> class.
/// </summary>
static Game()
{
//GlfwProvider.UninitializedGLFW.Value.InitHint(InitHint.AnglePlatformType, (int)AnglePlatformType.OpenGL);
//GlfwProvider.UninitializedGLFW.Value.Init();
//GetError();
}
private RawImage GetIconData(string fileName) public static float ScreenAspect {
{ get {
SKCodec codec = SKCodec.Create(fileName); return (float)GameWindowSize.Width / GameWindowSize.Height;
using SKBitmap bitmap = SKBitmap.Decode(codec, new SKImageInfo(codec.Info.Width, codec.Info.Height, SKColorType.Rgba8888)); }
return new RawImage(bitmap.Width, bitmap.Height, bitmap.GetPixelSpan().ToArray()); }
}
/// <summary> //[DllImportAttribute("libEGL", EntryPoint = "eglGetError")]
/// Initializes a new instance of the <see cref="Game"/> class. //public static extern Silk.NET.OpenGLES.ErrorCode GetError();
/// </summary>
protected Game(string iconFileName)
{
strIconFileName = iconFileName;
MainThreadID = Thread.CurrentThread.ManagedThreadId; /// <summary>
Configuration(); /// Initializes the <see cref="Game"/> class.
/// </summary>
static Game() {
//GlfwProvider.UninitializedGLFW.Value.InitHint(InitHint.AnglePlatformType, (int)AnglePlatformType.OpenGL);
//GlfwProvider.UninitializedGLFW.Value.Init();
//GetError();
}
//GlfwProvider.GLFW.Value.WindowHint(WindowHintContextApi.ContextCreationApi, ContextApi.EglContextApi); private RawImage GetIconData(string fileName) {
SKCodec codec = SKCodec.Create(fileName);
WindowOptions options = WindowOptions.Default; using SKBitmap bitmap = SKBitmap.Decode(codec, new SKImageInfo(codec.Info.Width, codec.Info.Height, SKColorType.Rgba8888));
return new RawImage(bitmap.Width, bitmap.Height, bitmap.GetPixelSpan().ToArray());
}
options.Size = WindowSize; /// <summary>
options.Position = WindowPosition; /// Initializes a new instance of the <see cref="Game"/> class.
options.UpdatesPerSecond = VSync ? 0 : Framerate; /// </summary>
options.FramesPerSecond = VSync ? 0 : Framerate; protected Game(string iconFileName) {
options.WindowState = FullScreen ? WindowState.Fullscreen : WindowState.Normal; strIconFileName = iconFileName;
options.VSync = VSync;
//options.API = new GraphicsAPI( ContextAPI.OpenGLES, ContextProfile.Core, ContextFlags.Default, new APIVersion(2, 0)); MainThreadID = Thread.CurrentThread.ManagedThreadId;
options.API = GraphicsAPI.None; Configuration();
options.WindowBorder = WindowBorder.Resizable;
options.Title = Text; //GlfwProvider.GLFW.Value.WindowHint(WindowHintContextApi.ContextCreationApi, ContextApi.EglContextApi);
WindowOptions options = WindowOptions.Default;
options.Size = WindowSize;
options.Position = WindowPosition;
options.UpdatesPerSecond = VSync ? 0 : Framerate;
options.FramesPerSecond = VSync ? 0 : Framerate;
options.WindowState = FullScreen ? WindowState.Fullscreen : WindowState.Normal;
options.VSync = VSync;
//options.API = new GraphicsAPI( ContextAPI.OpenGLES, ContextProfile.Core, ContextFlags.Default, new APIVersion(2, 0));
options.API = GraphicsAPI.None;
options.WindowBorder = WindowBorder.Resizable;
options.Title = Text;
Silk.NET.Windowing.Glfw.GlfwWindowing.Use(); Silk.NET.Windowing.Glfw.GlfwWindowing.Use();
//Silk.NET.Windowing.Sdl.SdlWindowing.Use(); //Silk.NET.Windowing.Sdl.SdlWindowing.Use();
Window_ = Window.Create(options); Window_ = Window.Create(options);
ViewPortSize.X = Window_.Size.X; ViewPortSize.X = Window_.Size.X;
ViewPortSize.Y = Window_.Size.Y; ViewPortSize.Y = Window_.Size.Y;
ViewPortOffset.X = 0; ViewPortOffset.X = 0;
ViewPortOffset.Y = 0; ViewPortOffset.Y = 0;
Window_.Load += Window_Load; Window_.Load += Window_Load;
Window_.Closing += Window_Closing; Window_.Closing += Window_Closing;
Window_.Update += Window_Update; Window_.Update += Window_Update;
Window_.Render += Window_Render; Window_.Render += Window_Render;
Window_.Resize += Window_Resize; Window_.Resize += Window_Resize;
Window_.Move += Window_Move; Window_.Move += Window_Move;
Window_.FramebufferResize += Window_FramebufferResize; Window_.FramebufferResize += Window_FramebufferResize;
} }
private void UpdateWindowFramerate(bool vsync, int value) private void UpdateWindowFramerate(bool vsync, int value) {
{ if (vsync) {
if (vsync) Window_.UpdatesPerSecond = 0;
{ Window_.FramesPerSecond = 0;
Window_.UpdatesPerSecond = 0; Context.SwapInterval(1);
Window_.FramesPerSecond = 0; } else {
Context.SwapInterval(1); Window_.UpdatesPerSecond = value;
} Window_.FramesPerSecond = value;
else Context.SwapInterval(0);
{ }
Window_.UpdatesPerSecond = value; }
Window_.FramesPerSecond = value;
Context.SwapInterval(0);
}
}
/// <summary> /// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary> /// </summary>
public void Dispose() public void Dispose() {
{ Window_.Dispose();
Window_.Dispose(); }
}
public void Exit() public void Exit() {
{ Window_.Close();
Window_.Close(); }
}
protected void ToggleWindowMode() protected void ToggleWindowMode() {
{ /*
/*
DeviceSettings settings = base.GraphicsDeviceManager.CurrentSettings.Clone(); DeviceSettings settings = base.GraphicsDeviceManager.CurrentSettings.Clone();
if ( ( ConfigIni != null ) && ( ConfigIni.bウィンドウモード != settings.Windowed ) ) if ( ( ConfigIni != null ) && ( ConfigIni.bウィンドウモード != settings.Windowed ) )
{ {
@ -353,153 +300,132 @@ namespace SampleFramework
} }
*/ */
FullScreen = !FullScreen; FullScreen = !FullScreen;
} }
/// <summary> /// <summary>
/// Runs the game. /// Runs the game.
/// </summary> /// </summary>
public void Run() public void Run() {
{ Window_.Run();
Window_.Run(); }
}
protected virtual void Configuration() protected virtual void Configuration() {
{
} }
protected virtual void Initialize() protected virtual void Initialize() {
{
} }
protected virtual void LoadContent() protected virtual void LoadContent() {
{
} }
protected virtual void UnloadContent() protected virtual void UnloadContent() {
{
} }
protected virtual void OnExiting() protected virtual void OnExiting() {
{
} }
protected virtual void Update() protected virtual void Update() {
{
} }
protected virtual void Draw() protected virtual void Draw() {
{
} }
/// <summary> /// <summary>
/// Releases unmanaged and - optionally - managed resources /// Releases unmanaged and - optionally - managed resources
/// </summary> /// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected internal virtual void Dispose(bool disposing) protected internal virtual void Dispose(bool disposing) {
{
} }
public void Window_Load() public void Window_Load() {
{ Window_.SetWindowIcon(new ReadOnlySpan<RawImage>(GetIconData(strIconFileName)));
Window_.SetWindowIcon(new ReadOnlySpan<RawImage>(GetIconData(strIconFileName)));
Context = new AngleContext(GraphicsDeviceType_, Window_); Context = new AngleContext(GraphicsDeviceType_, Window_);
Context.MakeCurrent(); Context.MakeCurrent();
Gl = GL.GetApi(Context); Gl = GL.GetApi(Context);
//Gl = Window_.CreateOpenGLES(); //Gl = Window_.CreateOpenGLES();
Gl.Enable(GLEnum.Blend); Gl.Enable(GLEnum.Blend);
BlendHelper.SetBlend(BlendType.Normal); BlendHelper.SetBlend(BlendType.Normal);
CTexture.Init(); CTexture.Init();
Gl.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); Gl.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gl.Viewport(0, 0, (uint)Window_.Size.X, (uint)Window_.Size.Y); Gl.Viewport(0, 0, (uint)Window_.Size.X, (uint)Window_.Size.Y);
Context.SwapInterval(VSync ? 1 : 0); Context.SwapInterval(VSync ? 1 : 0);
Initialize(); Initialize();
LoadContent(); LoadContent();
} }
public void Window_Closing() public void Window_Closing() {
{ CTexture.Terminate();
CTexture.Terminate();
UnloadContent();
OnExiting();
Context.Dispose(); UnloadContent();
} OnExiting();
public void Window_Update(double deltaTime) Context.Dispose();
{ }
double fps = 1.0f / deltaTime;
TimeMs = (long)(Window_.Time * 1000);
Update(); public void Window_Update(double deltaTime) {
} double fps = 1.0f / deltaTime;
TimeMs = (long)(Window_.Time * 1000);
public void Window_Render(double deltaTime) Update();
{ }
Camera = Matrix4X4<float>.Identity;
if (AsyncActions.Count > 0)
{
AsyncActions[0]?.Invoke();
AsyncActions.Remove(AsyncActions[0]);
}
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Draw(); public void Window_Render(double deltaTime) {
Camera = Matrix4X4<float>.Identity;
double fps = 1.0f / deltaTime; if (AsyncActions.Count > 0) {
AsyncActions[0]?.Invoke();
AsyncActions.Remove(AsyncActions[0]);
}
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Context.SwapBuffers(); Draw();
}
public void Window_Resize(Vector2D<int> size) double fps = 1.0f / deltaTime;
{
if (size.X > 0 && size.Y > 0)
{
float resolutionAspect = (float)GameWindowSize.Width / GameWindowSize.Height;
float windowAspect = (float)size.X / size.Y;
if (windowAspect > resolutionAspect)
{
ViewPortSize.X = (int)(size.Y * resolutionAspect);
ViewPortSize.Y = size.Y;
}
else
{
ViewPortSize.X = size.X;
ViewPortSize.Y = (int)(size.X / resolutionAspect);
}
}
ViewPortOffset.X = (size.X - ViewPortSize.X) / 2; Context.SwapBuffers();
ViewPortOffset.Y = (size.Y - ViewPortSize.Y) / 2; }
WindowSize = size; public void Window_Resize(Vector2D<int> size) {
Gl.Viewport(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewPortSize.X, (uint)ViewPortSize.Y); if (size.X > 0 && size.Y > 0) {
} float resolutionAspect = (float)GameWindowSize.Width / GameWindowSize.Height;
float windowAspect = (float)size.X / size.Y;
if (windowAspect > resolutionAspect) {
ViewPortSize.X = (int)(size.Y * resolutionAspect);
ViewPortSize.Y = size.Y;
} else {
ViewPortSize.X = size.X;
ViewPortSize.Y = (int)(size.X / resolutionAspect);
}
}
public void Window_Move(Vector2D<int> size) ViewPortOffset.X = (size.X - ViewPortSize.X) / 2;
{ ViewPortOffset.Y = (size.Y - ViewPortSize.Y) / 2;
WindowPosition = size;
}
public void Window_FramebufferResize(Vector2D<int> size) WindowSize = size;
{ Gl.Viewport(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewPortSize.X, (uint)ViewPortSize.Y);
} }
}
public void Window_Move(Vector2D<int> size) {
WindowPosition = size;
}
public void Window_FramebufferResize(Vector2D<int> size) {
}
}
} }

View File

@ -1,9 +1,5 @@
using System; namespace SampleFramework {
public static class GameWindowSize {
namespace SampleFramework
{
public static class GameWindowSize
{
public static int Width = 1280; public static int Width = 1280;
public static int Height = 720; public static int Height = 720;
} }

View File

@ -1,157 +1,136 @@
using OpenTK.Graphics.Egl; //OpenTKさん ありがとう!
using Silk.NET.Core.Contexts; using Silk.NET.Core.Contexts;
using Silk.NET.GLFW; using Silk.NET.GLFW;
using OpenTK.Graphics.Egl; //OpenTKさん ありがとう!
using Silk.NET.Windowing; using Silk.NET.Windowing;
using Silk.NET.OpenGLES;
namespace SampleFramework; namespace SampleFramework;
public class AngleContext : IGLContext public class AngleContext : IGLContext {
{ private nint Display;
private nint Display; private nint Context;
private nint Context; private nint Surface;
private nint Surface;
public AngleContext(AnglePlatformType anglePlatformType, IWindow window) public AngleContext(AnglePlatformType anglePlatformType, IWindow window) {
{ nint windowHandle;
nint windowHandle; nint display;
nint display; if (window.Native.Kind.HasFlag(NativeWindowFlags.Win32)) {
if (window.Native.Kind.HasFlag(NativeWindowFlags.Win32)) windowHandle = window.Native.Win32.Value.Hwnd;
{ display = window.Native.Win32.Value.HDC;
windowHandle = window.Native.Win32.Value.Hwnd; } else if (window.Native.Kind.HasFlag(NativeWindowFlags.X11)) {
display = window.Native.Win32.Value.HDC; windowHandle = (nint)window.Native.X11.Value.Window;
} // Temporary fix for the segfaults
else if (window.Native.Kind.HasFlag(NativeWindowFlags.X11)) // Note than X11 Display number is NOT always 0, it can be 1, 2 and so on for example in cases of user switching
{ display = 0;// Egl.GetDisplay(window.Native.X11.Value.Display);
windowHandle = (nint)window.Native.X11.Value.Window; } else if (window.Native.Kind.HasFlag(NativeWindowFlags.Cocoa)) {
// Temporary fix for the segfaults windowHandle = window.Native.Cocoa.Value;
// Note than X11 Display number is NOT always 0, it can be 1, 2 and so on for example in cases of user switching display = 0;
display = 0;// Egl.GetDisplay(window.Native.X11.Value.Display); } else if (window.Native.Kind.HasFlag(NativeWindowFlags.Wayland)) {
} windowHandle = window.Native.Wayland.Value.Surface;
else if (window.Native.Kind.HasFlag(NativeWindowFlags.Cocoa)) display = window.Native.Wayland.Value.Display;
{ } else {
windowHandle = window.Native.Cocoa.Value; throw new Exception("Window not found");
display = 0; }
}
else if (window.Native.Kind.HasFlag(NativeWindowFlags.Wayland))
{
windowHandle = window.Native.Wayland.Value.Surface;
display = window.Native.Wayland.Value.Display;
}
else
{
throw new Exception("Window not found");
}
Source = window;
int platform = 0; Source = window;
switch(anglePlatformType)
{
case AnglePlatformType.OpenGL:
platform = Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
break;
case AnglePlatformType.OpenGLES:
platform = Egl.PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
break;
case AnglePlatformType.D3D9:
platform = Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
break;
case AnglePlatformType.D3D11:
platform = Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
break;
case AnglePlatformType.Vulkan:
platform = Egl.PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
break;
case AnglePlatformType.Metal:
platform = Egl.PLATFORM_ANGLE_TYPE_METAL_ANGLE;
break;
}
int[] platformAttributes = new int[]
{
Egl.PLATFORM_ANGLE_TYPE_ANGLE, platform,
Egl.NONE
};
//getEGLNativeDisplay int platform = 0;
Display = Egl.GetPlatformDisplayEXT(Egl.PLATFORM_ANGLE_ANGLE, display, platformAttributes); switch (anglePlatformType) {
case AnglePlatformType.OpenGL:
platform = Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
break;
case AnglePlatformType.OpenGLES:
platform = Egl.PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
break;
case AnglePlatformType.D3D9:
platform = Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
break;
case AnglePlatformType.D3D11:
platform = Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
break;
case AnglePlatformType.Vulkan:
platform = Egl.PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
break;
case AnglePlatformType.Metal:
platform = Egl.PLATFORM_ANGLE_TYPE_METAL_ANGLE;
break;
}
int[] platformAttributes = new int[]
{
Egl.PLATFORM_ANGLE_TYPE_ANGLE, platform,
Egl.NONE
};
Egl.Initialize(Display, out int major, out int minor); //getEGLNativeDisplay
Egl.BindAPI(RenderApi.ES); Display = Egl.GetPlatformDisplayEXT(Egl.PLATFORM_ANGLE_ANGLE, display, platformAttributes);
IntPtr[] configs = new IntPtr[1];
int[] configAttributes = new int[]
{
Egl.RENDERABLE_TYPE, Egl.OPENGL_ES2_BIT,
Egl.BUFFER_SIZE, 0,
Egl.NONE
};
unsafe
{
Egl.ChooseConfig(Display, configAttributes, configs, configs.Length, out int num_config);
}
int[] contextAttributes = new int[] Egl.Initialize(Display, out int major, out int minor);
{ Egl.BindAPI(RenderApi.ES);
IntPtr[] configs = new IntPtr[1];
int[] configAttributes = new int[]
{
Egl.RENDERABLE_TYPE, Egl.OPENGL_ES2_BIT,
Egl.BUFFER_SIZE, 0,
Egl.NONE
};
unsafe {
Egl.ChooseConfig(Display, configAttributes, configs, configs.Length, out int num_config);
}
int[] contextAttributes = new int[]
{
//Egl.CONTEXT_CLIENT_VERSION, 2, //Egl.CONTEXT_CLIENT_VERSION, 2,
Egl.CONTEXT_MAJOR_VERSION, 2, Egl.CONTEXT_MAJOR_VERSION, 2,
Egl.CONTEXT_MINOR_VERSION, 0, Egl.CONTEXT_MINOR_VERSION, 0,
Egl.NONE Egl.NONE
}; };
Context = Egl.CreateContext(Display, configs[0], 0, contextAttributes); Context = Egl.CreateContext(Display, configs[0], 0, contextAttributes);
int[] surfaceAttributes = new int[]
{
Egl.NONE
};
//Surface = Egl.CreatePlatformWindowSurfaceEXT(Display, configs[0], windowHandle, null); int[] surfaceAttributes = new int[]
Surface = Egl.CreateWindowSurface(Display, configs[0], windowHandle, 0); {
Egl.NONE
};
var error1 = Egl.GetError(); //Surface = Egl.CreatePlatformWindowSurfaceEXT(Display, configs[0], windowHandle, null);
} Surface = Egl.CreateWindowSurface(Display, configs[0], windowHandle, 0);
public nint Handle { get; set; } var error1 = Egl.GetError();
}
public IGLContextSource? Source { get; set; } public nint Handle { get; set; }
public bool IsCurrent { get; set; } = true; public IGLContextSource? Source { get; set; }
public nint GetProcAddress(string proc, int? slot = null) public bool IsCurrent { get; set; } = true;
{
nint addr = Egl.GetProcAddress(proc);
return addr;
}
public bool TryGetProcAddress(string proc, out nint addr, int? slot = null) public nint GetProcAddress(string proc, int? slot = null) {
{ nint addr = Egl.GetProcAddress(proc);
addr = Egl.GetProcAddress(proc); return addr;
return addr != 0; }
}
public void SwapInterval(int interval) public bool TryGetProcAddress(string proc, out nint addr, int? slot = null) {
{ addr = Egl.GetProcAddress(proc);
Egl.SwapInterval(Display, interval); return addr != 0;
} }
public void SwapBuffers() public void SwapInterval(int interval) {
{ Egl.SwapInterval(Display, interval);
Egl.SwapBuffers(Display, Surface); }
}
public void MakeCurrent() public void SwapBuffers() {
{ Egl.SwapBuffers(Display, Surface);
Egl.MakeCurrent(Display, Surface, Surface, Context); }
}
public void Clear() public void MakeCurrent() {
{ Egl.MakeCurrent(Display, Surface, Surface, Context);
} }
public void Dispose() public void Clear() {
{ }
Egl.DestroyContext(Display, Context);
Egl.DestroySurface(Display, Surface); public void Dispose() {
Egl.Terminate(Display); Egl.DestroyContext(Display, Context);
} Egl.DestroySurface(Display, Surface);
} Egl.Terminate(Display);
}
}

View File

@ -23,7 +23,6 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// //
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@ -31,390 +30,376 @@ using System.Runtime.InteropServices;
#pragma warning disable 1591 // Missing XML comments #pragma warning disable 1591 // Missing XML comments
namespace OpenTK.Graphics.Egl namespace OpenTK.Graphics.Egl {
{ using EGLClientBuffer = IntPtr;
using EGLNativeDisplayType = IntPtr; using EGLConfig = IntPtr;
using EGLNativeWindowType = IntPtr; using EGLContext = IntPtr;
using EGLNativePixmapType = IntPtr; using EGLDisplay = IntPtr;
using EGLConfig = IntPtr; using EGLNativeDisplayType = IntPtr;
using EGLContext = IntPtr; using EGLNativePixmapType = IntPtr;
using EGLDisplay = IntPtr; using EGLNativeWindowType = IntPtr;
using EGLSurface = IntPtr; using EGLSurface = IntPtr;
using EGLClientBuffer = IntPtr;
public enum RenderApi public enum RenderApi {
{ ES = Egl.OPENGL_ES_API,
ES = Egl.OPENGL_ES_API, GL = Egl.OPENGL_API,
GL = Egl.OPENGL_API, VG = Egl.OPENVG_API
VG = Egl.OPENVG_API }
}
[Flags] [Flags]
public enum RenderableFlags public enum RenderableFlags {
{ ES = Egl.OPENGL_ES_BIT,
ES = Egl.OPENGL_ES_BIT, ES2 = Egl.OPENGL_ES2_BIT,
ES2 = Egl.OPENGL_ES2_BIT, ES3 = Egl.OPENGL_ES3_BIT,
ES3 = Egl.OPENGL_ES3_BIT, GL = Egl.OPENGL_BIT,
GL = Egl.OPENGL_BIT, VG = Egl.OPENVG_BIT,
VG = Egl.OPENVG_BIT, }
}
public enum ErrorCode public enum ErrorCode {
{ SUCCESS = 12288,
SUCCESS = 12288, NOT_INITIALIZED = 12289,
NOT_INITIALIZED = 12289, BAD_ACCESS = 12290,
BAD_ACCESS = 12290, BAD_ALLOC = 12291,
BAD_ALLOC = 12291, BAD_ATTRIBUTE = 12292,
BAD_ATTRIBUTE = 12292, BAD_CONFIG = 12293,
BAD_CONFIG = 12293, BAD_CONTEXT = 12294,
BAD_CONTEXT = 12294, BAD_CURRENT_SURFACE = 12295,
BAD_CURRENT_SURFACE = 12295, BAD_DISPLAY = 12296,
BAD_DISPLAY = 12296, BAD_MATCH = 12297,
BAD_MATCH = 12297, BAD_NATIVE_PIXMAP = 12298,
BAD_NATIVE_PIXMAP = 12298, BAD_NATIVE_WINDOW = 12299,
BAD_NATIVE_WINDOW = 12299, BAD_PARAMETER = 12300,
BAD_PARAMETER = 12300, BAD_SURFACE = 12301,
BAD_SURFACE = 12301, CONTEXT_LOST = 12302,
CONTEXT_LOST = 12302, }
}
public enum SurfaceType public enum SurfaceType {
{ PBUFFER_BIT = 0x0001,
PBUFFER_BIT = 0x0001, PIXMAP_BIT = 0x0002,
PIXMAP_BIT = 0x0002, WINDOW_BIT = 0x0004,
WINDOW_BIT = 0x0004, VG_COLORSPACE_LINEAR_BIT = 0x0020,
VG_COLORSPACE_LINEAR_BIT = 0x0020, VG_ALPHA_FORMAT_PRE_BIT = 0x0040,
VG_ALPHA_FORMAT_PRE_BIT = 0x0040, MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200,
MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200, SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400,
SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400, }
}
public class EglException : Exception public class EglException : Exception {
{ public EglException() : base() { }
public EglException() : base()
{ }
public EglException(string message) : base(message) public EglException(string message) : base(message) { }
{ } }
}
public static partial class Egl public static partial class Egl {
{ public const int CONTEXT_MAJOR_VERSION = 0x3098;
public const int CONTEXT_MAJOR_VERSION = 0x3098; public const int CONTEXT_MINOR_VERSION = 0x30FB;
public const int CONTEXT_MINOR_VERSION = 0x30FB;
public const int VERSION_1_0 = 1; public const int VERSION_1_0 = 1;
public const int VERSION_1_1 = 1; public const int VERSION_1_1 = 1;
public const int VERSION_1_2 = 1; public const int VERSION_1_2 = 1;
public const int VERSION_1_3 = 1; public const int VERSION_1_3 = 1;
public const int VERSION_1_4 = 1; public const int VERSION_1_4 = 1;
public const int FALSE = 0; public const int FALSE = 0;
public const int TRUE = 1; public const int TRUE = 1;
public const int DONT_CARE = -1; public const int DONT_CARE = -1;
public const int CONTEXT_LOST = 12302; public const int CONTEXT_LOST = 12302;
public const int BUFFER_SIZE = 12320; public const int BUFFER_SIZE = 12320;
public const int ALPHA_SIZE = 12321; public const int ALPHA_SIZE = 12321;
public const int BLUE_SIZE = 12322; public const int BLUE_SIZE = 12322;
public const int GREEN_SIZE = 12323; public const int GREEN_SIZE = 12323;
public const int RED_SIZE = 12324; public const int RED_SIZE = 12324;
public const int DEPTH_SIZE = 12325; public const int DEPTH_SIZE = 12325;
public const int STENCIL_SIZE = 12326; public const int STENCIL_SIZE = 12326;
public const int CONFIG_CAVEAT = 12327; public const int CONFIG_CAVEAT = 12327;
public const int CONFIG_ID = 12328; public const int CONFIG_ID = 12328;
public const int LEVEL = 12329; public const int LEVEL = 12329;
public const int MAX_PBUFFER_HEIGHT = 12330; public const int MAX_PBUFFER_HEIGHT = 12330;
public const int MAX_PBUFFER_PIXELS = 12331; public const int MAX_PBUFFER_PIXELS = 12331;
public const int MAX_PBUFFER_WIDTH = 12332; public const int MAX_PBUFFER_WIDTH = 12332;
public const int NATIVE_RENDERABLE = 12333; public const int NATIVE_RENDERABLE = 12333;
public const int NATIVE_VISUAL_ID = 12334; public const int NATIVE_VISUAL_ID = 12334;
public const int NATIVE_VISUAL_TYPE = 12335; public const int NATIVE_VISUAL_TYPE = 12335;
public const int PRESERVED_RESOURCES = 12336; public const int PRESERVED_RESOURCES = 12336;
public const int SAMPLES = 12337; public const int SAMPLES = 12337;
public const int SAMPLE_BUFFERS = 12338; public const int SAMPLE_BUFFERS = 12338;
public const int SURFACE_TYPE = 12339; public const int SURFACE_TYPE = 12339;
public const int TRANSPARENT_TYPE = 12340; public const int TRANSPARENT_TYPE = 12340;
public const int TRANSPARENT_BLUE_VALUE = 12341; public const int TRANSPARENT_BLUE_VALUE = 12341;
public const int TRANSPARENT_GREEN_VALUE = 12342; public const int TRANSPARENT_GREEN_VALUE = 12342;
public const int TRANSPARENT_RED_VALUE = 12343; public const int TRANSPARENT_RED_VALUE = 12343;
public const int NONE = 12344; public const int NONE = 12344;
public const int BIND_TO_TEXTURE_RGB = 12345; public const int BIND_TO_TEXTURE_RGB = 12345;
public const int BIND_TO_TEXTURE_RGBA = 12346; public const int BIND_TO_TEXTURE_RGBA = 12346;
public const int MIN_SWAP_INTERVAL = 12347; public const int MIN_SWAP_INTERVAL = 12347;
public const int MAX_SWAP_INTERVAL = 12348; public const int MAX_SWAP_INTERVAL = 12348;
public const int LUMINANCE_SIZE = 12349; public const int LUMINANCE_SIZE = 12349;
public const int ALPHA_MASK_SIZE = 12350; public const int ALPHA_MASK_SIZE = 12350;
public const int COLOR_BUFFER_TYPE = 12351; public const int COLOR_BUFFER_TYPE = 12351;
public const int RENDERABLE_TYPE = 12352; public const int RENDERABLE_TYPE = 12352;
public const int MATCH_NATIVE_PIXMAP = 12353; public const int MATCH_NATIVE_PIXMAP = 12353;
public const int CONFORMANT = 12354; public const int CONFORMANT = 12354;
public const int SLOW_CONFIG = 12368; public const int SLOW_CONFIG = 12368;
public const int NON_CONFORMANT_CONFIG = 12369; public const int NON_CONFORMANT_CONFIG = 12369;
public const int TRANSPARENT_RGB = 12370; public const int TRANSPARENT_RGB = 12370;
public const int RGB_BUFFER = 12430; public const int RGB_BUFFER = 12430;
public const int LUMINANCE_BUFFER = 12431; public const int LUMINANCE_BUFFER = 12431;
public const int NO_TEXTURE = 12380; public const int NO_TEXTURE = 12380;
public const int TEXTURE_RGB = 12381; public const int TEXTURE_RGB = 12381;
public const int TEXTURE_RGBA = 12382; public const int TEXTURE_RGBA = 12382;
public const int TEXTURE_2D = 12383; public const int TEXTURE_2D = 12383;
public const int PBUFFER_BIT = 1; public const int PBUFFER_BIT = 1;
public const int PIXMAP_BIT = 2; public const int PIXMAP_BIT = 2;
public const int WINDOW_BIT = 4; public const int WINDOW_BIT = 4;
public const int VG_COLORSPACE_LINEAR_BIT = 32; public const int VG_COLORSPACE_LINEAR_BIT = 32;
public const int VG_ALPHA_FORMAT_PRE_BIT = 64; public const int VG_ALPHA_FORMAT_PRE_BIT = 64;
public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512; public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512;
public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024; public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024;
public const int OPENGL_ES_BIT = 1; public const int OPENGL_ES_BIT = 1;
public const int OPENVG_BIT = 2; public const int OPENVG_BIT = 2;
public const int OPENGL_ES2_BIT = 4; public const int OPENGL_ES2_BIT = 4;
public const int OPENGL_BIT = 8; public const int OPENGL_BIT = 8;
public const int OPENGL_ES3_BIT = 64; public const int OPENGL_ES3_BIT = 64;
public const int VENDOR = 12371; public const int VENDOR = 12371;
public const int VERSION = 12372; public const int VERSION = 12372;
public const int EXTENSIONS = 12373; public const int EXTENSIONS = 12373;
public const int CLIENT_APIS = 12429; public const int CLIENT_APIS = 12429;
public const int HEIGHT = 12374; public const int HEIGHT = 12374;
public const int WIDTH = 12375; public const int WIDTH = 12375;
public const int LARGEST_PBUFFER = 12376; public const int LARGEST_PBUFFER = 12376;
public const int TEXTURE_FORMAT = 12416; public const int TEXTURE_FORMAT = 12416;
public const int TEXTURE_TARGET = 12417; public const int TEXTURE_TARGET = 12417;
public const int MIPMAP_TEXTURE = 12418; public const int MIPMAP_TEXTURE = 12418;
public const int MIPMAP_LEVEL = 12419; public const int MIPMAP_LEVEL = 12419;
public const int RENDER_BUFFER = 12422; public const int RENDER_BUFFER = 12422;
public const int VG_COLORSPACE = 12423; public const int VG_COLORSPACE = 12423;
public const int VG_ALPHA_FORMAT = 12424; public const int VG_ALPHA_FORMAT = 12424;
public const int HORIZONTAL_RESOLUTION = 12432; public const int HORIZONTAL_RESOLUTION = 12432;
public const int VERTICAL_RESOLUTION = 12433; public const int VERTICAL_RESOLUTION = 12433;
public const int PIXEL_ASPECT_RATIO = 12434; public const int PIXEL_ASPECT_RATIO = 12434;
public const int SWAP_BEHAVIOR = 12435; public const int SWAP_BEHAVIOR = 12435;
public const int MULTISAMPLE_RESOLVE = 12441; public const int MULTISAMPLE_RESOLVE = 12441;
public const int BACK_BUFFER = 12420; public const int BACK_BUFFER = 12420;
public const int SINGLE_BUFFER = 12421; public const int SINGLE_BUFFER = 12421;
public const int VG_COLORSPACE_sRGB = 12425; public const int VG_COLORSPACE_sRGB = 12425;
public const int VG_COLORSPACE_LINEAR = 12426; public const int VG_COLORSPACE_LINEAR = 12426;
public const int VG_ALPHA_FORMAT_NONPRE = 12427; public const int VG_ALPHA_FORMAT_NONPRE = 12427;
public const int VG_ALPHA_FORMAT_PRE = 12428; public const int VG_ALPHA_FORMAT_PRE = 12428;
public const int DISPLAY_SCALING = 10000; public const int DISPLAY_SCALING = 10000;
public const int UNKNOWN = -1; public const int UNKNOWN = -1;
public const int BUFFER_PRESERVED = 12436; public const int BUFFER_PRESERVED = 12436;
public const int BUFFER_DESTROYED = 12437; public const int BUFFER_DESTROYED = 12437;
public const int OPENVG_IMAGE = 12438; public const int OPENVG_IMAGE = 12438;
public const int CONTEXT_CLIENT_TYPE = 12439; public const int CONTEXT_CLIENT_TYPE = 12439;
public const int CONTEXT_CLIENT_VERSION = 12440; public const int CONTEXT_CLIENT_VERSION = 12440;
public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442; public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442;
public const int MULTISAMPLE_RESOLVE_BOX = 12443; public const int MULTISAMPLE_RESOLVE_BOX = 12443;
public const int OPENGL_ES_API = 12448; public const int OPENGL_ES_API = 12448;
public const int OPENVG_API = 12449; public const int OPENVG_API = 12449;
public const int OPENGL_API = 12450; public const int OPENGL_API = 12450;
public const int DRAW = 12377; public const int DRAW = 12377;
public const int READ = 12378; public const int READ = 12378;
public const int CORE_NATIVE_ENGINE = 12379; public const int CORE_NATIVE_ENGINE = 12379;
public const int COLORSPACE = VG_COLORSPACE; public const int COLORSPACE = VG_COLORSPACE;
public const int ALPHA_FORMAT = VG_ALPHA_FORMAT; public const int ALPHA_FORMAT = VG_ALPHA_FORMAT;
public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB; public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB;
public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR; public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR;
public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE; public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE;
public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE; public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
// EGL_ANGLE_d3d_share_handle_client_buffer // EGL_ANGLE_d3d_share_handle_client_buffer
public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
// EGL_ANGLE_window_fixed_size // EGL_ANGLE_window_fixed_size
public const int FIXED_SIZE_ANGLE = 0x3201; public const int FIXED_SIZE_ANGLE = 0x3201;
// EGL_ANGLE_query_surface_pointer // EGL_ANGLE_query_surface_pointer
[DllImport("libEGL", EntryPoint = "eglQuerySurfacePointerANGLE")] [DllImport("libEGL", EntryPoint = "eglQuerySurfacePointerANGLE")]
public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value); public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value);
[DllImport("libEGL", EntryPoint = "eglGetPlatformDisplayEXT")] [DllImport("libEGL", EntryPoint = "eglGetPlatformDisplayEXT")]
public static extern EGLDisplay GetPlatformDisplay(int platform, EGLNativeDisplayType displayId, int[] attribList); public static extern EGLDisplay GetPlatformDisplay(int platform, EGLNativeDisplayType displayId, int[] attribList);
// EGL_ANGLE_software_display // EGL_ANGLE_software_display
public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1); public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1);
// EGL_ANGLE_direct3d_display // EGL_ANGLE_direct3d_display
public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2); public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2);
public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3); public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3);
// EGL_ANGLE_device_d3d // EGL_ANGLE_device_d3d
public const int D3D9_DEVICE_ANGLE = 0x33A0; public const int D3D9_DEVICE_ANGLE = 0x33A0;
public const int D3D11_DEVICE_ANGLE = 0x33A1; public const int D3D11_DEVICE_ANGLE = 0x33A1;
// EGL_ANGLE_platform_angle // EGL_ANGLE_platform_angle
public const int PLATFORM_ANGLE_ANGLE = 0x3202; public const int PLATFORM_ANGLE_ANGLE = 0x3202;
public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203; public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204; public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205; public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206; public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
// EGL_ANGLE_platform_angle_d3d // EGL_ANGLE_platform_angle_d3d
public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207; public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208; public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
public const int PLATFORM_ANGLE_TYPE_VULKAN_ANGLE = 0x3450; public const int PLATFORM_ANGLE_TYPE_VULKAN_ANGLE = 0x3450;
public const int PLATFORM_ANGLE_TYPE_METAL_ANGLE = 0x3489; public const int PLATFORM_ANGLE_TYPE_METAL_ANGLE = 0x3489;
public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209; public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A; public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B; public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B;
public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C; public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C;
public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F; public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
// EGL_ANGLE_platform_angle_opengl // EGL_ANGLE_platform_angle_opengl
public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D; public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D;
public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E; public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E;
// See EGL_ANGLE_surface_d3d_texture_2d_share_handle // See EGL_ANGLE_surface_d3d_texture_2d_share_handle
public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
[DllImportAttribute("libEGL", EntryPoint = "eglGetError")] [DllImportAttribute("libEGL", EntryPoint = "eglGetError")]
public static extern ErrorCode GetError(); public static extern ErrorCode GetError();
[DllImportAttribute("libEGL", EntryPoint = "eglGetDisplay")] [DllImportAttribute("libEGL", EntryPoint = "eglGetDisplay")]
public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id); public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
[DllImportAttribute("libEGL", EntryPoint = "eglInitialize")] [DllImportAttribute("libEGL", EntryPoint = "eglInitialize")]
//[return: MarshalAs(UnmanagedType.I1)] //[return: MarshalAs(UnmanagedType.I1)]
public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor); public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor);
[DllImportAttribute("libEGL", EntryPoint = "eglTerminate")] [DllImportAttribute("libEGL", EntryPoint = "eglTerminate")]
//[return: MarshalAs(UnmanagedType.I1)] //[return: MarshalAs(UnmanagedType.I1)]
public static extern bool Terminate(EGLDisplay dpy); public static extern bool Terminate(EGLDisplay dpy);
[DllImportAttribute("libEGL", EntryPoint = "eglQueryString")] [DllImportAttribute("libEGL", EntryPoint = "eglQueryString")]
public static extern IntPtr QueryString(EGLDisplay dpy, int name); public static extern IntPtr QueryString(EGLDisplay dpy, int name);
[DllImportAttribute("libEGL", EntryPoint = "eglGetConfigs")] [DllImportAttribute("libEGL", EntryPoint = "eglGetConfigs")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config); public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config);
[DllImportAttribute("libEGL", EntryPoint = "eglChooseConfig")] [DllImportAttribute("libEGL", EntryPoint = "eglChooseConfig")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config); public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config);
[DllImportAttribute("libEGL", EntryPoint = "eglChooseConfig")] [DllImportAttribute("libEGL", EntryPoint = "eglChooseConfig")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public unsafe static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, EGLConfig* configs, int config_size, out int num_config); public unsafe static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, EGLConfig* configs, int config_size, out int num_config);
[DllImportAttribute("libEGL", EntryPoint = "eglGetConfigAttrib")] [DllImportAttribute("libEGL", EntryPoint = "eglGetConfigAttrib")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value); public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value);
[DllImportAttribute("libEGL", EntryPoint = "eglCreateWindowSurface")] [DllImportAttribute("libEGL", EntryPoint = "eglCreateWindowSurface")]
public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list); public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list);
[DllImportAttribute("libEGL", EntryPoint = "eglCreatePbufferSurface")] [DllImportAttribute("libEGL", EntryPoint = "eglCreatePbufferSurface")]
public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list); public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list);
[DllImportAttribute("libEGL", EntryPoint = "eglCreatePixmapSurface")] [DllImportAttribute("libEGL", EntryPoint = "eglCreatePixmapSurface")]
public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list); public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list);
[DllImportAttribute("libEGL", EntryPoint = "eglDestroySurface")] [DllImportAttribute("libEGL", EntryPoint = "eglDestroySurface")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface); public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface);
[DllImportAttribute("libEGL", EntryPoint = "eglQuerySurface")] [DllImportAttribute("libEGL", EntryPoint = "eglQuerySurface")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value); public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value);
[DllImportAttribute("libEGL", EntryPoint = "eglBindAPI")] [DllImportAttribute("libEGL", EntryPoint = "eglBindAPI")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool BindAPI(RenderApi api); public static extern bool BindAPI(RenderApi api);
[DllImportAttribute("libEGL", EntryPoint = "eglQueryAPI")] [DllImportAttribute("libEGL", EntryPoint = "eglQueryAPI")]
public static extern int QueryAPI(); public static extern int QueryAPI();
[DllImportAttribute("libEGL", EntryPoint = "eglWaitClient")] [DllImportAttribute("libEGL", EntryPoint = "eglWaitClient")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool WaitClient(); public static extern bool WaitClient();
[DllImportAttribute("libEGL", EntryPoint = "eglReleaseThread")] [DllImportAttribute("libEGL", EntryPoint = "eglReleaseThread")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool ReleaseThread(); public static extern bool ReleaseThread();
[DllImportAttribute("libEGL", EntryPoint = "eglCreatePbufferFromClientBuffer")] [DllImportAttribute("libEGL", EntryPoint = "eglCreatePbufferFromClientBuffer")]
public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list); public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list);
[DllImportAttribute("libEGL", EntryPoint = "eglSurfaceAttrib")] [DllImportAttribute("libEGL", EntryPoint = "eglSurfaceAttrib")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value); public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value);
[DllImportAttribute("libEGL", EntryPoint = "eglBindTexImage")] [DllImportAttribute("libEGL", EntryPoint = "eglBindTexImage")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer); public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
[DllImportAttribute("libEGL", EntryPoint = "eglReleaseTexImage")] [DllImportAttribute("libEGL", EntryPoint = "eglReleaseTexImage")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer); public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
[DllImportAttribute("libEGL", EntryPoint = "eglSwapInterval")] [DllImportAttribute("libEGL", EntryPoint = "eglSwapInterval")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool SwapInterval(EGLDisplay dpy, int interval); public static extern bool SwapInterval(EGLDisplay dpy, int interval);
[DllImportAttribute("libEGL", EntryPoint = "eglCreateContext")] [DllImportAttribute("libEGL", EntryPoint = "eglCreateContext")]
private static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list); private static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list);
public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list) public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list) {
{ IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list);
IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list); if (ptr == IntPtr.Zero) {
if (ptr == IntPtr.Zero) throw new EglException(string.Format("Failed to create EGL context, error: {0}.", Egl.GetError()));
{ }
throw new EglException(string.Format("Failed to create EGL context, error: {0}.", Egl.GetError())); return ptr;
} }
return ptr;
}
[DllImportAttribute("libEGL", EntryPoint = "eglDestroyContext")] [DllImportAttribute("libEGL", EntryPoint = "eglDestroyContext")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx); public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx);
[DllImportAttribute("libEGL", EntryPoint = "eglMakeCurrent")] [DllImportAttribute("libEGL", EntryPoint = "eglMakeCurrent")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
[DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentContext")] [DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentContext")]
public static extern EGLContext GetCurrentContext(); public static extern EGLContext GetCurrentContext();
[DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentSurface")] [DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentSurface")]
public static extern EGLSurface GetCurrentSurface(int readdraw); public static extern EGLSurface GetCurrentSurface(int readdraw);
[DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentDisplay")] [DllImportAttribute("libEGL", EntryPoint = "eglGetCurrentDisplay")]
public static extern EGLDisplay GetCurrentDisplay(); public static extern EGLDisplay GetCurrentDisplay();
[DllImportAttribute("libEGL", EntryPoint = "eglQueryContext")] [DllImportAttribute("libEGL", EntryPoint = "eglQueryContext")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value); public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value);
[DllImportAttribute("libEGL", EntryPoint = "eglWaitGL")] [DllImportAttribute("libEGL", EntryPoint = "eglWaitGL")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool WaitGL(); public static extern bool WaitGL();
[DllImportAttribute("libEGL", EntryPoint = "eglWaitNative")] [DllImportAttribute("libEGL", EntryPoint = "eglWaitNative")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool WaitNative(int engine); public static extern bool WaitNative(int engine);
[DllImportAttribute("libEGL", EntryPoint = "eglSwapBuffers")] [DllImportAttribute("libEGL", EntryPoint = "eglSwapBuffers")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface); public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface);
[DllImportAttribute("libEGL", EntryPoint = "eglCopyBuffers")] [DllImportAttribute("libEGL", EntryPoint = "eglCopyBuffers")]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
[DllImportAttribute("libEGL", EntryPoint = "eglGetProcAddress")] [DllImportAttribute("libEGL", EntryPoint = "eglGetProcAddress")]
public static extern IntPtr GetProcAddress(string funcname); public static extern IntPtr GetProcAddress(string funcname);
[DllImportAttribute("libEGL", EntryPoint = "eglGetProcAddress")] [DllImportAttribute("libEGL", EntryPoint = "eglGetProcAddress")]
public static extern IntPtr GetProcAddress(IntPtr funcname); public static extern IntPtr GetProcAddress(IntPtr funcname);
// EGL_EXT_platform_base // EGL_EXT_platform_base
[DllImport("libEGL", EntryPoint = "eglGetPlatformDisplayEXT")] [DllImport("libEGL", EntryPoint = "eglGetPlatformDisplayEXT")]
public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list); public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list);
[DllImport("libEGL", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")] [DllImport("libEGL", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")]
public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list); public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list);
[DllImport("libEGL", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")] [DllImport("libEGL", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")]
public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list); public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list);
// Returns true if Egl drivers exist on the system. // Returns true if Egl drivers exist on the system.
public static bool IsSupported public static bool IsSupported {
{ get {
get try { GetCurrentContext(); } catch (Exception) { return false; }
{ return true;
try { GetCurrentContext(); } }
catch (Exception) { return false; } }
return true; }
} }
}
}
}

View File

@ -2,41 +2,37 @@ using Silk.NET.OpenGLES;
namespace SampleFramework; namespace SampleFramework;
public enum BlendType public enum BlendType {
{ Normal,
Normal, Add,
Add, Screen,
Screen, Multi,
Multi, Sub
Sub
} }
public static class BlendHelper public static class BlendHelper {
{ public static void SetBlend(BlendType blendType) {
public static void SetBlend(BlendType blendType) switch (blendType) {
{ case BlendType.Normal:
switch(blendType) Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd);
{ Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.OneMinusSrcAlpha);
case BlendType.Normal: break;
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd); case BlendType.Add:
Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.OneMinusSrcAlpha); Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd);
break; Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.One);
case BlendType.Add: break;
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd); case BlendType.Screen:
Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.One); Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd);
break; Game.Gl.BlendFunc(GLEnum.One, GLEnum.OneMinusSrcColor);
case BlendType.Screen: break;
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd); case BlendType.Multi:
Game.Gl.BlendFunc(GLEnum.One, GLEnum.OneMinusSrcColor); Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd);
break; Game.Gl.BlendFunc(GLEnum.DstColor, GLEnum.OneMinusSrcAlpha);
case BlendType.Multi: break;
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd); case BlendType.Sub:
Game.Gl.BlendFunc(GLEnum.DstColor, GLEnum.OneMinusSrcAlpha); Game.Gl.BlendEquation(BlendEquationModeEXT.FuncReverseSubtract);
break; Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.One);
case BlendType.Sub: break;
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncReverseSubtract); }
Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.One); }
break; }
}
}
}

View File

@ -2,25 +2,22 @@ using ImGuiNET;
namespace LWGFW.Graphics; namespace LWGFW.Graphics;
public class ImGUIManager : IDisposable public class ImGUIManager : IDisposable {
{ private nint Context;
private nint Context;
public ImGUIManager() public ImGUIManager() {
{ Context = ImGui.CreateContext();
Context = ImGui.CreateContext(); ImGui.SetCurrentContext(Context);
ImGui.SetCurrentContext(Context);
ImGuiIOPtr imguiIO = ImGui.GetIO(); ImGuiIOPtr imguiIO = ImGui.GetIO();
imguiIO.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard; imguiIO.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
imguiIO.ConfigFlags |= ImGuiConfigFlags.NavEnableGamepad; imguiIO.ConfigFlags |= ImGuiConfigFlags.NavEnableGamepad;
ImGui.StyleColorsDark(); ImGui.StyleColorsDark();
} }
public void Dispose() public void Dispose() {
{ ImGui.DestroyContext(Context);
ImGui.DestroyContext(Context); }
} }
}

View File

@ -2,54 +2,50 @@ using Silk.NET.OpenGLES;
namespace SampleFramework; namespace SampleFramework;
public static class ShaderHelper public static class ShaderHelper {
{ public static uint CreateShader(string code, ShaderType shaderType) {
public static uint CreateShader(string code, ShaderType shaderType) uint vertexShader = Game.Gl.CreateShader(shaderType);
{
uint vertexShader = Game.Gl.CreateShader(shaderType);
Game.Gl.ShaderSource(vertexShader, code); Game.Gl.ShaderSource(vertexShader, code);
Game.Gl.CompileShader(vertexShader);
Game.Gl.GetShader(vertexShader, ShaderParameterName.CompileStatus, out int status); Game.Gl.CompileShader(vertexShader);
if (status != (int)GLEnum.True) Game.Gl.GetShader(vertexShader, ShaderParameterName.CompileStatus, out int status);
throw new Exception($"{shaderType} failed to compile:{Game.Gl.GetShaderInfoLog(vertexShader)}");
return vertexShader; if (status != (int)GLEnum.True)
} throw new Exception($"{shaderType} failed to compile:{Game.Gl.GetShaderInfoLog(vertexShader)}");
public static uint CreateShaderProgram(uint vertexShader, uint fragmentShader) return vertexShader;
{ }
uint program = Game.Gl.CreateProgram();
Game.Gl.AttachShader(program, vertexShader);
Game.Gl.AttachShader(program, fragmentShader);
Game.Gl.LinkProgram(program); public static uint CreateShaderProgram(uint vertexShader, uint fragmentShader) {
uint program = Game.Gl.CreateProgram();
Game.Gl.GetProgram(program, ProgramPropertyARB.LinkStatus, out int linkStatus); Game.Gl.AttachShader(program, vertexShader);
Game.Gl.AttachShader(program, fragmentShader);
if (linkStatus != (int)GLEnum.True)
throw new Exception($"Program failed to link:{Game.Gl.GetProgramInfoLog(program)}");
Game.Gl.DetachShader(program, vertexShader); Game.Gl.LinkProgram(program);
Game.Gl.DetachShader(program, fragmentShader);
return program; Game.Gl.GetProgram(program, ProgramPropertyARB.LinkStatus, out int linkStatus);
}
public static uint CreateShaderProgramFromSource(string vertexCode, string fragmentCode) if (linkStatus != (int)GLEnum.True)
{ throw new Exception($"Program failed to link:{Game.Gl.GetProgramInfoLog(program)}");
uint vertexShader = CreateShader(vertexCode, ShaderType.VertexShader);
uint fragmentShader = CreateShader(fragmentCode, ShaderType.FragmentShader);
uint program = CreateShaderProgram(vertexShader, fragmentShader);
Game.Gl.DeleteShader(vertexShader);
Game.Gl.DeleteShader(fragmentShader);
return program; Game.Gl.DetachShader(program, vertexShader);
} Game.Gl.DetachShader(program, fragmentShader);
}
return program;
}
public static uint CreateShaderProgramFromSource(string vertexCode, string fragmentCode) {
uint vertexShader = CreateShader(vertexCode, ShaderType.VertexShader);
uint fragmentShader = CreateShader(fragmentCode, ShaderType.FragmentShader);
uint program = CreateShaderProgram(vertexShader, fragmentShader);
Game.Gl.DeleteShader(vertexShader);
Game.Gl.DeleteShader(fragmentShader);
return program;
}
}

View File

@ -1,17 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input; using Silk.NET.Input;
namespace FDK namespace FDK {
{ public class CInputGamepad : IInputDevice, IDisposable {
public class CInputGamepad : IInputDevice, IDisposable
{
// コンストラクタ // コンストラクタ
public CInputGamepad(IGamepad gamepad) public CInputGamepad(IGamepad gamepad) {
{
this.CurrentType = InputDeviceType.Gamepad; this.CurrentType = InputDeviceType.Gamepad;
this.GUID = gamepad.Index.ToString(); this.GUID = gamepad.Index.ToString();
this.ID = gamepad.Index; this.ID = gamepad.Index;
@ -21,62 +14,49 @@ namespace FDK
gamepad.ButtonDown += Joystick_ButtonDown; gamepad.ButtonDown += Joystick_ButtonDown;
gamepad.ButtonUp += Joystick_ButtonUp; gamepad.ButtonUp += Joystick_ButtonUp;
} }
// メソッド // メソッド
public void SetID( int nID ) public void SetID(int nID) {
{
this.ID = nID; this.ID = nID;
} }
#region [ IInputDevice ] #region [ IInputDevice ]
//----------------- //-----------------
public InputDeviceType CurrentType public InputDeviceType CurrentType {
{
get; get;
private set; private set;
} }
public string GUID public string GUID {
{
get; get;
private set; private set;
} }
public int ID public int ID {
{
get;
private set;
}
public List<STInputEvent> InputEvents
{
get; get;
private set; private set;
} }
public string strDeviceName public List<STInputEvent> InputEvents {
{ get;
private set;
}
public string strDeviceName {
get; get;
set; set;
} }
public void Polling(bool useBufferInput) public void Polling(bool useBufferInput) {
{
InputEvents.Clear(); InputEvents.Clear();
for (int i = 0; i < ButtonStates.Length; i++) for (int i = 0; i < ButtonStates.Length; i++) {
{ if (ButtonStates[i].Item1) {
if (ButtonStates[i].Item1) if (ButtonStates[i].Item2 >= 1) {
{
if (ButtonStates[i].Item2 >= 1)
{
ButtonStates[i].Item2 = 2; ButtonStates[i].Item2 = 2;
} } else {
else
{
ButtonStates[i].Item2 = 1; ButtonStates[i].Item2 = 1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = true, Pressed = true,
Released = false, Released = false,
@ -85,20 +65,14 @@ namespace FDK
} }
); );
} }
} } else {
else if (ButtonStates[i].Item2 <= -1) {
{
if (ButtonStates[i].Item2 <= -1)
{
ButtonStates[i].Item2 = -2; ButtonStates[i].Item2 = -2;
} } else {
else
{
ButtonStates[i].Item2 = -1; ButtonStates[i].Item2 = -1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = false, Pressed = false,
Released = true, Released = true,
@ -111,20 +85,16 @@ namespace FDK
} }
} }
public bool KeyPressed(int nButton) public bool KeyPressed(int nButton) {
{
return ButtonStates[nButton].Item2 == 1; return ButtonStates[nButton].Item2 == 1;
} }
public bool KeyPressing(int nButton) public bool KeyPressing(int nButton) {
{
return ButtonStates[nButton].Item2 >= 1; return ButtonStates[nButton].Item2 >= 1;
} }
public bool KeyReleased(int nButton) public bool KeyReleased(int nButton) {
{
return ButtonStates[nButton].Item2 == -1; return ButtonStates[nButton].Item2 == -1;
} }
public bool KeyReleasing(int nButton) public bool KeyReleasing(int nButton) {
{
return ButtonStates[nButton].Item2 <= -1; return ButtonStates[nButton].Item2 <= -1;
} }
//----------------- //-----------------
@ -132,12 +102,9 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ if (!this.IsDisposed) {
if(!this.IsDisposed) if (this.InputEvents != null) {
{
if (this.InputEvents != null)
{
this.InputEvents = null; this.InputEvents = null;
} }
this.IsDisposed = true; this.IsDisposed = true;
@ -154,18 +121,14 @@ namespace FDK
private (bool, int)[] ButtonStates = new (bool, int)[15]; private (bool, int)[] ButtonStates = new (bool, int)[15];
private bool IsDisposed; private bool IsDisposed;
private void Joystick_ButtonDown(IGamepad joystick, Button button) private void Joystick_ButtonDown(IGamepad joystick, Button button) {
{ if (button.Name != ButtonName.Unknown) {
if (button.Name != ButtonName.Unknown)
{
ButtonStates[(int)button.Name].Item1 = true; ButtonStates[(int)button.Name].Item1 = true;
} }
} }
private void Joystick_ButtonUp(IGamepad joystick, Button button) private void Joystick_ButtonUp(IGamepad joystick, Button button) {
{ if (button.Name != ButtonName.Unknown) {
if (button.Name != ButtonName.Unknown)
{
ButtonStates[(int)button.Name].Item1 = false; ButtonStates[(int)button.Name].Item1 = false;
} }
} }

View File

@ -1,19 +1,12 @@
using System; using Silk.NET.Input;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
namespace FDK namespace FDK {
{ public class CInputJoystick : IInputDevice, IDisposable {
public class CInputJoystick : IInputDevice, IDisposable
{
// コンストラクタ // コンストラクタ
private IJoystick Joystick {get; set;} private IJoystick Joystick { get; set; }
public CInputJoystick(IJoystick joystick) public CInputJoystick(IJoystick joystick) {
{
Joystick = joystick; Joystick = joystick;
this.CurrentType = InputDeviceType.Joystick; this.CurrentType = InputDeviceType.Joystick;
this.GUID = joystick.Index.ToString(); this.GUID = joystick.Index.ToString();
@ -26,47 +19,40 @@ namespace FDK
joystick.AxisMoved += Joystick_AxisMoved; joystick.AxisMoved += Joystick_AxisMoved;
joystick.HatMoved += Joystick_HatMoved; joystick.HatMoved += Joystick_HatMoved;
} }
// メソッド // メソッド
public void SetID( int nID ) public void SetID(int nID) {
{
this.ID = nID; this.ID = nID;
} }
#region [ IInputDevice ] #region [ IInputDevice ]
//----------------- //-----------------
public InputDeviceType CurrentType public InputDeviceType CurrentType {
{
get; get;
private set; private set;
} }
public string GUID public string GUID {
{
get; get;
private set; private set;
} }
public int ID public int ID {
{
get;
private set;
}
public List<STInputEvent> InputEvents
{
get; get;
private set; private set;
} }
public string strDeviceName public List<STInputEvent> InputEvents {
{ get;
private set;
}
public string strDeviceName {
get; get;
set; set;
} }
public void Polling(bool useBufferInput) public void Polling(bool useBufferInput) {
{
InputEvents.Clear(); InputEvents.Clear();
// BUG: In Silk.NET, GLFW input does not fire events, so we have to poll // BUG: In Silk.NET, GLFW input does not fire events, so we have to poll
// them instead. // them instead.
// https://github.com/dotnet/Silk.NET/issues/1889 // https://github.com/dotnet/Silk.NET/issues/1889
@ -75,21 +61,15 @@ namespace FDK
ButtonStates[button.Index].Item1 = button.Pressed; ButtonStates[button.Index].Item1 = button.Pressed;
} }
for (int i = 0; i < ButtonStates.Length; i++) for (int i = 0; i < ButtonStates.Length; i++) {
{ if (ButtonStates[i].Item1) {
if (ButtonStates[i].Item1) if (ButtonStates[i].Item2 >= 1) {
{
if (ButtonStates[i].Item2 >= 1)
{
ButtonStates[i].Item2 = 2; ButtonStates[i].Item2 = 2;
} } else {
else
{
ButtonStates[i].Item2 = 1; ButtonStates[i].Item2 = 1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = true, Pressed = true,
Released = false, Released = false,
@ -98,20 +78,14 @@ namespace FDK
} }
); );
} }
} } else {
else if (ButtonStates[i].Item2 <= -1) {
{
if (ButtonStates[i].Item2 <= -1)
{
ButtonStates[i].Item2 = -2; ButtonStates[i].Item2 = -2;
} } else {
else
{
ButtonStates[i].Item2 = -1; ButtonStates[i].Item2 = -1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = false, Pressed = false,
Released = true, Released = true,
@ -124,20 +98,16 @@ namespace FDK
} }
} }
public bool KeyPressed(int nButton) public bool KeyPressed(int nButton) {
{
return ButtonStates[nButton].Item2 == 1; return ButtonStates[nButton].Item2 == 1;
} }
public bool KeyPressing(int nButton) public bool KeyPressing(int nButton) {
{
return ButtonStates[nButton].Item2 >= 1; return ButtonStates[nButton].Item2 >= 1;
} }
public bool KeyReleased(int nButton) public bool KeyReleased(int nButton) {
{
return ButtonStates[nButton].Item2 == -1; return ButtonStates[nButton].Item2 == -1;
} }
public bool KeyReleasing(int nButton) public bool KeyReleasing(int nButton) {
{
return ButtonStates[nButton].Item2 <= -1; return ButtonStates[nButton].Item2 <= -1;
} }
//----------------- //-----------------
@ -145,12 +115,9 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ if (!this.IsDisposed) {
if(!this.IsDisposed) if (this.InputEvents != null) {
{
if (this.InputEvents != null)
{
this.InputEvents = null; this.InputEvents = null;
} }
this.IsDisposed = true; this.IsDisposed = true;
@ -167,29 +134,23 @@ namespace FDK
private (bool, int)[] ButtonStates = new (bool, int)[18]; private (bool, int)[] ButtonStates = new (bool, int)[18];
private bool IsDisposed; private bool IsDisposed;
private void Joystick_ButtonDown(IJoystick joystick, Button button) private void Joystick_ButtonDown(IJoystick joystick, Button button) {
{ if (button.Name != ButtonName.Unknown) {
if (button.Name != ButtonName.Unknown)
{
ButtonStates[(int)button.Name].Item1 = true; ButtonStates[(int)button.Name].Item1 = true;
} }
} }
private void Joystick_ButtonUp(IJoystick joystick, Button button) private void Joystick_ButtonUp(IJoystick joystick, Button button) {
{ if (button.Name != ButtonName.Unknown) {
if (button.Name != ButtonName.Unknown)
{
ButtonStates[(int)button.Name].Item1 = false; ButtonStates[(int)button.Name].Item1 = false;
} }
} }
private void Joystick_AxisMoved(IJoystick joystick, Axis axis) private void Joystick_AxisMoved(IJoystick joystick, Axis axis) {
{
} }
private void Joystick_HatMoved(IJoystick joystick, Hat hat) private void Joystick_HatMoved(IJoystick joystick, Hat hat) {
{
} }
//----------------- //-----------------

View File

@ -1,23 +1,15 @@
using System; using Silk.NET.Input;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
namespace FDK namespace FDK {
{ public class CInputKeyboard : IInputDevice, IDisposable {
public class CInputKeyboard : IInputDevice, IDisposable
{
// コンストラクタ // コンストラクタ
public CInputKeyboard(IReadOnlyList<IKeyboard> keyboards) public CInputKeyboard(IReadOnlyList<IKeyboard> keyboards) {
{
this.CurrentType = InputDeviceType.Keyboard; this.CurrentType = InputDeviceType.Keyboard;
this.GUID = ""; this.GUID = "";
this.ID = 0; this.ID = 0;
foreach (var keyboard in keyboards) foreach (var keyboard in keyboards) {
{
keyboard.KeyDown += KeyDown; keyboard.KeyDown += KeyDown;
keyboard.KeyUp += KeyUp; keyboard.KeyUp += KeyUp;
keyboard.KeyChar += KeyChar; keyboard.KeyChar += KeyChar;
@ -39,24 +31,17 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; } public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; } public string strDeviceName { get; set; }
public void Polling(bool useBufferInput) public void Polling(bool useBufferInput) {
{
InputEvents.Clear(); InputEvents.Clear();
for (int i = 0; i < KeyStates.Length; i++) for (int i = 0; i < KeyStates.Length; i++) {
{ if (KeyStates[i].Item1) {
if (KeyStates[i].Item1) if (KeyStates[i].Item2 >= 1) {
{
if (KeyStates[i].Item2 >= 1)
{
KeyStates[i].Item2 = 2; KeyStates[i].Item2 = 2;
} } else {
else
{
KeyStates[i].Item2 = 1; KeyStates[i].Item2 = 1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = true, Pressed = true,
Released = false, Released = false,
@ -65,19 +50,13 @@ namespace FDK
} }
); );
} }
} } else {
else if (KeyStates[i].Item2 <= -1) {
{
if (KeyStates[i].Item2 <= -1)
{
KeyStates[i].Item2 = -2; KeyStates[i].Item2 = -2;
} } else {
else
{
KeyStates[i].Item2 = -1; KeyStates[i].Item2 = -1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = false, Pressed = false,
Released = true, Released = true,
@ -92,29 +71,25 @@ namespace FDK
/// <param name="nKey"> /// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。) /// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param> /// </param>
public bool KeyPressed(int nKey) public bool KeyPressed(int nKey) {
{
return KeyStates[nKey].Item2 == 1; return KeyStates[nKey].Item2 == 1;
} }
/// <param name="nKey"> /// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。) /// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param> /// </param>
public bool KeyPressing(int nKey) public bool KeyPressing(int nKey) {
{
return KeyStates[nKey].Item2 >= 1; return KeyStates[nKey].Item2 >= 1;
} }
/// <param name="nKey"> /// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。) /// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param> /// </param>
public bool KeyReleased(int nKey) public bool KeyReleased(int nKey) {
{
return KeyStates[nKey].Item2 == -1; return KeyStates[nKey].Item2 == -1;
} }
/// <param name="nKey"> /// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。) /// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param> /// </param>
public bool KeyReleasing(int nKey) public bool KeyReleasing(int nKey) {
{
return KeyStates[nKey].Item2 <= -1; return KeyStates[nKey].Item2 <= -1;
} }
//----------------- //-----------------
@ -122,12 +97,9 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ if (!this.IsDisposed) {
if(!this.IsDisposed) if (this.InputEvents != null) {
{
if (this.InputEvents != null)
{
this.InputEvents = null; this.InputEvents = null;
} }
this.IsDisposed = true; this.IsDisposed = true;
@ -147,26 +119,21 @@ namespace FDK
//private CTimer ct; //private CTimer ct;
private void KeyDown(IKeyboard keyboard, Key key, int keyCode) private void KeyDown(IKeyboard keyboard, Key key, int keyCode) {
{ if (key != Key.Unknown) {
if (key != Key.Unknown)
{
var keyNum = DeviceConstantConverter.DIKtoKey(key); var keyNum = DeviceConstantConverter.DIKtoKey(key);
KeyStates[(int)keyNum].Item1 = true; KeyStates[(int)keyNum].Item1 = true;
} }
} }
private void KeyUp(IKeyboard keyboard, Key key, int keyCode) private void KeyUp(IKeyboard keyboard, Key key, int keyCode) {
{ if (key != Key.Unknown) {
if (key != Key.Unknown)
{
var keyNum = DeviceConstantConverter.DIKtoKey(key); var keyNum = DeviceConstantConverter.DIKtoKey(key);
KeyStates[(int)keyNum].Item1 = false; KeyStates[(int)keyNum].Item1 = false;
} }
} }
private void KeyChar(IKeyboard keyboard, char ch) private void KeyChar(IKeyboard keyboard, char ch) {
{
} }
//----------------- //-----------------

View File

@ -1,12 +1,5 @@
using System; namespace FDK {
using System.Collections.Generic; public class CInputMIDI : IInputDevice, IDisposable {
using System.Text;
using System.Diagnostics;
namespace FDK
{
public class CInputMIDI : IInputDevice, IDisposable
{
// プロパティ // プロパティ
public IntPtr MidiInPtr; public IntPtr MidiInPtr;
@ -14,8 +7,7 @@ namespace FDK
// コンストラクタ // コンストラクタ
public CInputMIDI(uint nID) public CInputMIDI(uint nID) {
{
this.MidiInPtr = IntPtr.Zero; this.MidiInPtr = IntPtr.Zero;
this.EventBuffers = new List<STInputEvent>(32); this.EventBuffers = new List<STInputEvent>(32);
this.InputEvents = new List<STInputEvent>(32); this.InputEvents = new List<STInputEvent>(32);
@ -28,8 +20,7 @@ namespace FDK
// メソッド // メソッド
public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2, long n受信システム時刻) public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2, long n受信システム時刻) {
{
/* /*
if (wMsg == CWin32.MIM_DATA) if (wMsg == CWin32.MIM_DATA)
{ {
@ -71,8 +62,7 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; } public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; } public string strDeviceName { get; set; }
public void Polling(bool bWindowがアクティブ中) public void Polling(bool bWindowがアクティブ中) {
{
// this.list入力イベント = new List<STInputEvent>( 32 ); // this.list入力イベント = new List<STInputEvent>( 32 );
this.InputEvents.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new(); this.InputEvents.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
@ -81,27 +71,21 @@ namespace FDK
this.EventBuffers.Clear(); this.EventBuffers.Clear();
} }
public bool KeyPressed(int nKey) public bool KeyPressed(int nKey) {
{ foreach (STInputEvent event2 in this.InputEvents) {
foreach (STInputEvent event2 in this.InputEvents) if ((event2.nKey == nKey) && event2.Pressed) {
{
if ((event2.nKey == nKey) && event2.Pressed)
{
return true; return true;
} }
} }
return false; return false;
} }
public bool KeyPressing(int nKey) public bool KeyPressing(int nKey) {
{
return false; return false;
} }
public bool KeyReleased(int nKey) public bool KeyReleased(int nKey) {
{
return false; return false;
} }
public bool KeyReleasing(int nKey) public bool KeyReleasing(int nKey) {
{
return false; return false;
} }
//----------------- //-----------------
@ -109,14 +93,11 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ if (this.EventBuffers != null) {
if (this.EventBuffers != null)
{
this.EventBuffers = null; this.EventBuffers = null;
} }
if (this.InputEvents != null) if (this.InputEvents != null) {
{
this.InputEvents = null; this.InputEvents = null;
} }
} }

View File

@ -1,15 +1,9 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Silk.NET.Windowing;
using Silk.NET.Input; using Silk.NET.Input;
using Silk.NET.Windowing;
namespace FDK namespace FDK {
{ public class CInputManager : IDisposable {
public class CInputManager : IDisposable
{
// 定数 // 定数
public static int DefaultVolume = 110; public static int DefaultVolume = 110;
@ -17,23 +11,17 @@ namespace FDK
// プロパティ // プロパティ
public List<IInputDevice> InputDevices public List<IInputDevice> InputDevices {
{
get; get;
private set; private set;
} }
public IInputDevice Keyboard public IInputDevice Keyboard {
{ get {
get if (this._Keyboard != null) {
{
if (this._Keyboard != null)
{
return this._Keyboard; return this._Keyboard;
} }
foreach (IInputDevice device in this.InputDevices) foreach (IInputDevice device in this.InputDevices) {
{ if (device.CurrentType == InputDeviceType.Keyboard) {
if (device.CurrentType == InputDeviceType.Keyboard)
{
this._Keyboard = device; this._Keyboard = device;
return device; return device;
} }
@ -41,18 +29,13 @@ namespace FDK
return null; return null;
} }
} }
public IInputDevice Mouse public IInputDevice Mouse {
{ get {
get if (this._Mouse != null) {
{
if (this._Mouse != null)
{
return this._Mouse; return this._Mouse;
} }
foreach (IInputDevice device in this.InputDevices) foreach (IInputDevice device in this.InputDevices) {
{ if (device.CurrentType == InputDeviceType.Mouse) {
if (device.CurrentType == InputDeviceType.Mouse)
{
this._Mouse = device; this._Mouse = device;
return device; return device;
} }
@ -63,130 +46,98 @@ namespace FDK
// コンストラクタ // コンストラクタ
public CInputManager(IWindow window, bool bUseMidiIn = true) public CInputManager(IWindow window, bool bUseMidiIn = true) {
{
Initialize(window, bUseMidiIn); Initialize(window, bUseMidiIn);
} }
public void Initialize(IWindow window, bool bUseMidiIn) public void Initialize(IWindow window, bool bUseMidiIn) {
{
Context = window.CreateInput(); Context = window.CreateInput();
this.InputDevices = new List<IInputDevice>(10); this.InputDevices = new List<IInputDevice>(10);
#region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ] #region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
CInputKeyboard cinputkeyboard = null; CInputKeyboard cinputkeyboard = null;
CInputMouse cinputmouse = null; CInputMouse cinputmouse = null;
try try {
{
cinputkeyboard = new CInputKeyboard(Context.Keyboards); cinputkeyboard = new CInputKeyboard(Context.Keyboards);
cinputmouse = new CInputMouse(Context.Mice[0]); cinputmouse = new CInputMouse(Context.Mice[0]);
} catch {
} }
if (cinputkeyboard != null) {
catch
{
}
if (cinputkeyboard != null)
{
this.InputDevices.Add(cinputkeyboard); this.InputDevices.Add(cinputkeyboard);
} }
if (cinputmouse != null) if (cinputmouse != null) {
{
this.InputDevices.Add(cinputmouse); this.InputDevices.Add(cinputmouse);
} }
#endregion #endregion
#region [ Enumerate joypad ] #region [ Enumerate joypad ]
foreach (var joysticks in Context.Joysticks) foreach (var joysticks in Context.Joysticks) {
{
this.InputDevices.Add(new CInputJoystick(joysticks)); this.InputDevices.Add(new CInputJoystick(joysticks));
} }
foreach (var gamepad in Context.Gamepads) foreach (var gamepad in Context.Gamepads) {
{
this.InputDevices.Add(new CInputGamepad(gamepad)); this.InputDevices.Add(new CInputGamepad(gamepad));
} }
#endregion #endregion
Trace.TraceInformation("Found {0} Input Device{1}", InputDevices.Count, InputDevices.Count != 1 ? "s:" : ":"); Trace.TraceInformation("Found {0} Input Device{1}", InputDevices.Count, InputDevices.Count != 1 ? "s:" : ":");
for (int i = 0; i < InputDevices.Count; i++) for (int i = 0; i < InputDevices.Count; i++) {
{ try {
try
{
Trace.TraceInformation("Input Device #" + i + " (" + InputDevices[i].CurrentType.ToString() + ")"); Trace.TraceInformation("Input Device #" + i + " (" + InputDevices[i].CurrentType.ToString() + ")");
} } catch { }
catch { }
} }
} }
// メソッド // メソッド
public IInputDevice Joystick(int ID) public IInputDevice Joystick(int ID) {
{ foreach (IInputDevice device in this.InputDevices) {
foreach (IInputDevice device in this.InputDevices) if ((device.CurrentType == InputDeviceType.Joystick) && (device.ID == ID)) {
{
if ((device.CurrentType == InputDeviceType.Joystick) && (device.ID == ID))
{
return device; return device;
} }
} }
return null; return null;
} }
public IInputDevice Joystick(string GUID) public IInputDevice Joystick(string GUID) {
{ foreach (IInputDevice device in this.InputDevices) {
foreach (IInputDevice device in this.InputDevices) if ((device.CurrentType == InputDeviceType.Joystick) && device.GUID.Equals(GUID)) {
{
if ((device.CurrentType == InputDeviceType.Joystick) && device.GUID.Equals(GUID))
{
return device; return device;
} }
} }
return null; return null;
} }
public IInputDevice Gamepad(int ID) public IInputDevice Gamepad(int ID) {
{ foreach (IInputDevice device in this.InputDevices) {
foreach (IInputDevice device in this.InputDevices) if ((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == ID)) {
{
if ((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == ID))
{
return device; return device;
} }
} }
return null; return null;
} }
public IInputDevice Gamepad(string GUID) public IInputDevice Gamepad(string GUID) {
{ foreach (IInputDevice device in this.InputDevices) {
foreach (IInputDevice device in this.InputDevices) if ((device.CurrentType == InputDeviceType.Gamepad) && device.GUID.Equals(GUID)) {
{
if ((device.CurrentType == InputDeviceType.Gamepad) && device.GUID.Equals(GUID))
{
return device; return device;
} }
} }
return null; return null;
} }
public IInputDevice MidiIn(int ID) public IInputDevice MidiIn(int ID) {
{ foreach (IInputDevice device in this.InputDevices) {
foreach (IInputDevice device in this.InputDevices) if ((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == ID)) {
{
if ((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == ID))
{
return device; return device;
} }
} }
return null; return null;
} }
public void Polling(bool useBufferInput) public void Polling(bool useBufferInput) {
{ lock (this.objMidiIn排他用) {
lock (this.objMidiIn排他用)
{
// foreach( IInputDevice device in this.list入力デバイス ) // foreach( IInputDevice device in this.list入力デバイス )
for (int i = this.InputDevices.Count - 1; i >= 0; i--) // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove(). for (int i = this.InputDevices.Count - 1; i >= 0; i--) // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove().
{ {
IInputDevice device = this.InputDevices[i]; IInputDevice device = this.InputDevices[i];
try try {
{
device.Polling(useBufferInput); device.Polling(useBufferInput);
} } catch (Exception e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
catch (Exception e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items. {
{
this.InputDevices.Remove(device); this.InputDevices.Remove(device);
device.Dispose(); device.Dispose();
Trace.TraceError("tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。"); Trace.TraceError("tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。");
@ -197,30 +148,22 @@ namespace FDK
#region [ IDisposableα ] #region [ IDisposableα ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{
this.Dispose(true); this.Dispose(true);
} }
public void Dispose(bool disposeManagedObjects) public void Dispose(bool disposeManagedObjects) {
{ if (!this.bDisposed済み) {
if (!this.bDisposed済み) if (disposeManagedObjects) {
{ foreach (IInputDevice device in this.InputDevices) {
if (disposeManagedObjects)
{
foreach (IInputDevice device in this.InputDevices)
{
CInputMIDI tmidi = device as CInputMIDI; CInputMIDI tmidi = device as CInputMIDI;
if (tmidi != null) if (tmidi != null) {
{
Trace.TraceInformation("MIDI In: [{0}] を停止しました。", new object[] { tmidi.ID }); Trace.TraceInformation("MIDI In: [{0}] を停止しました。", new object[] { tmidi.ID });
} }
} }
foreach (IInputDevice device2 in this.InputDevices) foreach (IInputDevice device2 in this.InputDevices) {
{
device2.Dispose(); device2.Dispose();
} }
lock (this.objMidiIn排他用) lock (this.objMidiIn排他用) {
{
this.InputDevices.Clear(); this.InputDevices.Clear();
} }
@ -229,8 +172,7 @@ namespace FDK
this.bDisposed済み = true; this.bDisposed済み = true;
} }
} }
~CInputManager() ~CInputManager() {
{
this.Dispose(false); this.Dispose(false);
GC.KeepAlive(this); GC.KeepAlive(this);
} }

View File

@ -1,14 +1,9 @@
using System; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input; using Silk.NET.Input;
namespace FDK namespace FDK {
{ public class CInputMouse : IInputDevice, IDisposable {
public class CInputMouse : IInputDevice, IDisposable
{
// 定数 // 定数
public const int MouseButtonCount = 8; public const int MouseButtonCount = 8;
@ -16,18 +11,14 @@ namespace FDK
// コンストラクタ // コンストラクタ
public CInputMouse(IMouse mouse) public CInputMouse(IMouse mouse) {
{
this.CurrentType = InputDeviceType.Mouse; this.CurrentType = InputDeviceType.Mouse;
this.GUID = ""; this.GUID = "";
this.ID = 0; this.ID = 0;
try try {
{
Trace.TraceInformation(mouse.Name + " を生成しました。"); // なぜか0x00のゴミが出るので削除 Trace.TraceInformation(mouse.Name + " を生成しました。"); // なぜか0x00のゴミが出るので削除
this.strDeviceName = mouse.Name; this.strDeviceName = mouse.Name;
} } catch {
catch
{
Trace.TraceWarning("Mouse デバイスの生成に失敗しました。"); Trace.TraceWarning("Mouse デバイスの生成に失敗しました。");
throw; throw;
} }
@ -52,24 +43,17 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; } public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; } public string strDeviceName { get; set; }
public void Polling(bool useBufferInput) public void Polling(bool useBufferInput) {
{
InputEvents.Clear(); InputEvents.Clear();
for (int i = 0; i < MouseStates.Length; i++) for (int i = 0; i < MouseStates.Length; i++) {
{ if (MouseStates[i].Item1) {
if (MouseStates[i].Item1) if (MouseStates[i].Item2 >= 1) {
{
if (MouseStates[i].Item2 >= 1)
{
MouseStates[i].Item2 = 2; MouseStates[i].Item2 = 2;
} } else {
else
{
MouseStates[i].Item2 = 1; MouseStates[i].Item2 = 1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = true, Pressed = true,
Released = false, Released = false,
@ -78,19 +62,13 @@ namespace FDK
} }
); );
} }
} } else {
else if (MouseStates[i].Item2 <= -1) {
{
if (MouseStates[i].Item2 <= -1)
{
MouseStates[i].Item2 = -2; MouseStates[i].Item2 = -2;
} } else {
else
{
MouseStates[i].Item2 = -1; MouseStates[i].Item2 = -1;
InputEvents.Add( InputEvents.Add(
new STInputEvent() new STInputEvent() {
{
nKey = i, nKey = i,
Pressed = false, Pressed = false,
Released = true, Released = true,
@ -102,20 +80,16 @@ namespace FDK
} }
} }
} }
public bool KeyPressed(int nButton) public bool KeyPressed(int nButton) {
{
return MouseStates[nButton].Item2 == 1; return MouseStates[nButton].Item2 == 1;
} }
public bool KeyPressing(int nButton) public bool KeyPressing(int nButton) {
{
return MouseStates[nButton].Item2 >= 1; return MouseStates[nButton].Item2 >= 1;
} }
public bool KeyReleased(int nButton) public bool KeyReleased(int nButton) {
{
return MouseStates[nButton].Item2 == -1; return MouseStates[nButton].Item2 == -1;
} }
public bool KeyReleasing(int nButton) public bool KeyReleasing(int nButton) {
{
return MouseStates[nButton].Item2 <= -1; return MouseStates[nButton].Item2 <= -1;
} }
//----------------- //-----------------
@ -123,12 +97,9 @@ namespace FDK
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ if (!this.IsDisposed) {
if(!this.IsDisposed) if (this.InputEvents != null) {
{
if (this.InputEvents != null)
{
this.InputEvents = null; this.InputEvents = null;
} }
this.IsDisposed = true; this.IsDisposed = true;
@ -145,34 +116,27 @@ namespace FDK
private (bool, int)[] MouseStates = new (bool, int)[12]; private (bool, int)[] MouseStates = new (bool, int)[12];
private bool IsDisposed; private bool IsDisposed;
private void Mouse_Click(IMouse mouse, MouseButton mouseButton, Vector2 vector2) private void Mouse_Click(IMouse mouse, MouseButton mouseButton, Vector2 vector2) {
{
} }
private void Mouse_DoubleClick(IMouse mouse, MouseButton mouseButton, Vector2 vector2) private void Mouse_DoubleClick(IMouse mouse, MouseButton mouseButton, Vector2 vector2) {
{
} }
private void Mouse_MouseDown(IMouse mouse, MouseButton mouseButton) private void Mouse_MouseDown(IMouse mouse, MouseButton mouseButton) {
{ if (mouseButton != MouseButton.Unknown) {
if (mouseButton != MouseButton.Unknown)
{
MouseStates[(int)mouseButton].Item1 = true; MouseStates[(int)mouseButton].Item1 = true;
} }
} }
private void Mouse_MouseUp(IMouse mouse, MouseButton mouseButton) private void Mouse_MouseUp(IMouse mouse, MouseButton mouseButton) {
{ if (mouseButton != MouseButton.Unknown) {
if (mouseButton != MouseButton.Unknown)
{
MouseStates[(int)mouseButton].Item1 = false; MouseStates[(int)mouseButton].Item1 = false;
} }
} }
private void Mouse_MouseMove(IMouse mouse, Vector2 vector2) private void Mouse_MouseMove(IMouse mouse, Vector2 vector2) {
{
} }
//----------------- //-----------------

View File

@ -1,18 +1,12 @@
using System; using SlimDXKeys;
using System.Collections.Generic;
using System.Text;
using SlimDXKeys;
using SlimDXKey = SlimDXKeys.Key; using SlimDXKey = SlimDXKeys.Key;
namespace FDK namespace FDK {
{ public static class DeviceConstantConverter {
public static class DeviceConstantConverter
{
// メソッド // メソッド
public static Key DIKtoKey( Silk.NET.Input.Key key ) public static Key DIKtoKey(Silk.NET.Input.Key key) {
{
return _DIKtoKey[key]; return _DIKtoKey[key];
} }

View File

@ -1,41 +1,31 @@
using System; namespace FDK {
using System.Collections.Generic; public interface IInputDevice : IDisposable {
using System.Text;
namespace FDK
{
public interface IInputDevice : IDisposable
{
// プロパティ // プロパティ
InputDeviceType CurrentType InputDeviceType CurrentType {
{
get; get;
} }
string GUID string GUID {
{
get;
}
int ID
{
get; get;
} }
List<STInputEvent> InputEvents int ID {
{ get;
}
List<STInputEvent> InputEvents {
get; get;
} }
// メソッドインターフェース // メソッドインターフェース
void Polling( bool bバッファ入力を使用する ); void Polling(bool bバッファ入力を使用する);
bool KeyPressed( int nKey ); bool KeyPressed(int nKey);
bool KeyPressed( List<int> nKey ) { return nKey.Any(key => KeyPressed(key)); } bool KeyPressed(List<int> nKey) { return nKey.Any(key => KeyPressed(key)); }
bool KeyPressing( int nKey ); bool KeyPressing(int nKey);
bool KeyPressing( List<int> nKey ) { return nKey.Any(key => KeyPressing(key)); } bool KeyPressing(List<int> nKey) { return nKey.Any(key => KeyPressing(key)); }
bool KeyReleased( int nKey ); bool KeyReleased(int nKey);
bool KeyReleased( List<int> nKey ) { return nKey.Any(key => KeyReleased(key)); } bool KeyReleased(List<int> nKey) { return nKey.Any(key => KeyReleased(key)); }
bool KeyReleasing( int nKey ); bool KeyReleasing(int nKey);
bool KeyReleasing( List<int> nKey ) { return nKey.Any(key => KeyReleasing(key)); } bool KeyReleasing(List<int> nKey) { return nKey.Any(key => KeyReleasing(key)); }
} }
} }

View File

@ -1,13 +1,7 @@
using System; namespace FDK {
using System.Collections.Generic;
using System.Text;
namespace FDK
{
// 定数 // 定数
public enum InputDeviceType public enum InputDeviceType {
{
Keyboard, Keyboard,
Mouse, Mouse,
Joystick, Joystick,

View File

@ -1,15 +1,10 @@
using System; using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace FDK namespace FDK {
{
// 構造体 // 構造体
[StructLayout( LayoutKind.Sequential )] [StructLayout(LayoutKind.Sequential)]
public struct STInputEvent public struct STInputEvent {
{
public int nKey { get; set; } public int nKey { get; set; }
public bool Pressed { get; set; } public bool Pressed { get; set; }
public bool Released { get; set; } public bool Released { get; set; }

View File

@ -1,13 +1,5 @@
using System; namespace SlimDXKeys {
using System.Collections.Generic; public enum Key {
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SlimDXKeys
{
public enum Key
{
D0 = 0, D0 = 0,
D1 = 1, D1 = 1,
D2 = 2, D2 = 2,
@ -154,8 +146,7 @@ namespace SlimDXKeys
Yen = 143, Yen = 143,
Unknown = 144 Unknown = 144
} }
public enum MouseObject public enum MouseObject {
{
Button1 = 0, Button1 = 0,
Button2 = 1, Button2 = 1,
Button3 = 2, Button3 = 2,
@ -168,4 +159,4 @@ namespace SlimDXKeys
YAxis = 9, YAxis = 9,
ZAxis = 10 ZAxis = 10
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,23 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using FDK.ExtensionMethods;
using ManagedBass; using ManagedBass;
using ManagedBass.Asio; using ManagedBass.Asio;
using ManagedBass.Mix; using ManagedBass.Mix;
namespace FDK namespace FDK {
{
/// <summary> /// <summary>
/// 全ASIOデバイスを列挙する静的クラス。 /// 全ASIOデバイスを列挙する静的クラス。
/// BASS_Init()やBASS_ASIO_Init()の状態とは無関係に使用可能。 /// BASS_Init()やBASS_ASIO_Init()の状態とは無関係に使用可能。
/// </summary> /// </summary>
public static class CEnumerateAllAsioDevices public static class CEnumerateAllAsioDevices {
{ public static string[] GetAllASIODevices() {
public static string[] GetAllASIODevices() try {
{
try
{
string[] bassAsioDevName = new string[BassAsio.DeviceCount]; string[] bassAsioDevName = new string[BassAsio.DeviceCount];
for(int i = 0; i < bassAsioDevName.Length; i++) for (int i = 0; i < bassAsioDevName.Length; i++)
bassAsioDevName[i] = BassAsio.GetDeviceInfo(i).Name; bassAsioDevName[i] = BassAsio.GetDeviceInfo(i).Name;
if(bassAsioDevName.Length != 0) if (bassAsioDevName.Length != 0)
return bassAsioDevName; return bassAsioDevName;
} } catch (Exception e) {
catch(Exception e)
{
Trace.TraceWarning($"Exception occured in GetAllASIODevices ({e})"); Trace.TraceWarning($"Exception occured in GetAllASIODevices ({e})");
} }
@ -35,79 +25,62 @@ namespace FDK
} }
} }
internal class CSoundDeviceASIO : ISoundDevice internal class CSoundDeviceASIO : ISoundDevice {
{
// プロパティ // プロパティ
public ESoundDeviceType SoundDeviceType public ESoundDeviceType SoundDeviceType {
{
get; get;
protected set; protected set;
} }
public long OutputDelay public long OutputDelay {
{
get; get;
protected set; protected set;
} }
public long BufferSize public long BufferSize {
{
get; get;
protected set; protected set;
} }
public int ASIODevice public int ASIODevice {
{
get; get;
set; set;
} }
// CSoundTimer 用に公開しているプロパティ // CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs public long ElapsedTimeMs {
{
get; get;
protected set; protected set;
} }
public long UpdateSystemTimeMs public long UpdateSystemTimeMs {
{
get; get;
protected set; protected set;
} }
public CTimer SystemTimer public CTimer SystemTimer {
{
get; get;
protected set; protected set;
} }
// マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。 // マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume public int nMasterVolume {
{ get {
get
{
float f音量 = 0.0f; float f音量 = 0.0f;
bool b = Bass.ChannelGetAttribute( this.hMixer, ChannelAttribute.Volume, out f音量 ); bool b = Bass.ChannelGetAttribute(this.hMixer, ChannelAttribute.Volume, out f音量);
if ( !b ) if (!b) {
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation( "ASIO Master Volume Get Error: " + be.ToString() ); Trace.TraceInformation("ASIO Master Volume Get Error: " + be.ToString());
} } else {
else
{
//Trace.TraceInformation( "ASIO Master Volume Get Success: " + (f音量 * 100) ); //Trace.TraceInformation( "ASIO Master Volume Get Success: " + (f音量 * 100) );
} }
return (int) ( f音量 * 100 ); return (int)(f音量 * 100);
} }
set set {
{ bool b = Bass.ChannelSetAttribute(this.hMixer, ChannelAttribute.Volume, (float)(value / 100.0));
bool b = Bass.ChannelSetAttribute( this.hMixer, ChannelAttribute.Volume, (float) ( value / 100.0 ) ); if (!b) {
if ( !b )
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation( "ASIO Master Volume Set Error: " + be.ToString() ); Trace.TraceInformation("ASIO Master Volume Set Error: " + be.ToString());
} } else {
else
{
// int n = this.nMasterVolume; // int n = this.nMasterVolume;
// Trace.TraceInformation( "ASIO Master Volume Set Success: " + value ); // Trace.TraceInformation( "ASIO Master Volume Set Success: " + value );
} }
@ -116,56 +89,55 @@ namespace FDK
// メソッド // メソッド
public CSoundDeviceASIO( long bufferSize, int deviceIndex ) public CSoundDeviceASIO(long bufferSize, int deviceIndex) {
{
// 初期化。 // 初期化。
Trace.TraceInformation( "BASS (ASIO) の初期化を開始します。" ); Trace.TraceInformation("BASS (ASIO) の初期化を開始します。");
this.SoundDeviceType = ESoundDeviceType.Unknown; this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0; this.OutputDelay = 0;
this.ElapsedTimeMs = 0; this.ElapsedTimeMs = 0;
this.UpdateSystemTimeMs = CTimer.UnusedNum; this.UpdateSystemTimeMs = CTimer.UnusedNum;
this.SystemTimer = new CTimer( CTimer.TimerType.MultiMedia ); this.SystemTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.ASIODevice = deviceIndex; this.ASIODevice = deviceIndex;
// BASS の設定。 // BASS の設定。
this.bIsBASSFree = true; this.bIsBASSFree = true;
if (!Bass.Configure( Configuration.UpdatePeriod, 0 )) // 0:BASSストリームの自動更新を行わない。 if (!Bass.Configure(Configuration.UpdatePeriod, 0)) // 0:BASSストリームの自動更新を行わない。
{ {
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]"); Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]");
} }
if (!Bass.Configure( Configuration.UpdateThreads, 0 )) // 0:BASSストリームの自動更新を行わない。 if (!Bass.Configure(Configuration.UpdateThreads, 0)) // 0:BASSストリームの自動更新を行わない。
{ {
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]"); Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]");
} }
// BASS の初期化。 // BASS の初期化。
int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSASIO アドオンから行う。 int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSASIO アドオンから行う。
int n周波数 = 44100; // 仮決め。最終的な周波数はデバイス(≠ドライバ)が決める。 int n周波数 = 44100; // 仮決め。最終的な周波数はデバイス(≠ドライバ)が決める。
if( !Bass.Init( nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero ) ) if (!Bass.Init(nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero))
throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString() ) ); throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString()));
Bass.Configure(Configuration.LogarithmicVolumeCurve, true); Bass.Configure(Configuration.LogarithmicVolumeCurve, true);
//Debug.WriteLine( "BASS_Init()完了。" ); //Debug.WriteLine( "BASS_Init()完了。" );
#region [ : ASIOデバイスのenumerateと ] #region [ : ASIOデバイスのenumerateと ]
// CEnumerateAllAsioDevices.GetAllASIODevices(); // CEnumerateAllAsioDevices.GetAllASIODevices();
//Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" ); //Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" );
// int a, count = 0; // int a, count = 0;
// BASS_ASIO_DEVICEINFO asioDevInfo; // BASS_ASIO_DEVICEINFO asioDevInfo;
// for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ ) // for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ )
// { // {
// Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver ); // Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver );
// count++; // count it // count++; // count it
// } // }
#endregion #endregion
// BASS ASIO の初期化。 // BASS ASIO の初期化。
AsioInfo asioInfo; AsioInfo asioInfo;
if ( BassAsio.Init( ASIODevice, AsioInitFlags.Thread ) ) // 専用スレッドにて起動 if (BassAsio.Init(ASIODevice, AsioInitFlags.Thread)) // 専用スレッドにて起動
{ {
#region [ ASIO ] #region [ ASIO ]
//----------------- //-----------------
@ -173,13 +145,13 @@ namespace FDK
BassAsio.GetInfo(out asioInfo); BassAsio.GetInfo(out asioInfo);
this.n出力チャンネル数 = asioInfo.Outputs; this.n出力チャンネル数 = asioInfo.Outputs;
this.db周波数 = BassAsio.Rate; this.db周波数 = BassAsio.Rate;
this.fmtASIOデバイスフォーマット = BassAsio.ChannelGetFormat( false, 0 ); this.fmtASIOデバイスフォーマット = BassAsio.ChannelGetFormat(false, 0);
Trace.TraceInformation( "BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}{6}sample ({5:0.###}{7:0.###}ms), デバイスフォーマット:{8})", Trace.TraceInformation("BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}{6}sample ({5:0.###}{7:0.###}ms), デバイスフォーマット:{8})",
asioInfo.Name, asioInfo.Name,
asioInfo.Inputs, asioInfo.Inputs,
asioInfo.Outputs, asioInfo.Outputs,
this.db周波数.ToString( "0.###" ), this.db周波数.ToString("0.###"),
asioInfo.MinBufferLength, asioInfo.MinBufferLength * 1000 / this.db周波数, asioInfo.MinBufferLength, asioInfo.MinBufferLength * 1000 / this.db周波数,
asioInfo.MaxBufferLength, asioInfo.MaxBufferLength * 1000 / this.db周波数, asioInfo.MaxBufferLength, asioInfo.MaxBufferLength * 1000 / this.db周波数,
this.fmtASIOデバイスフォーマット.ToString() this.fmtASIOデバイスフォーマット.ToString()
@ -198,20 +170,17 @@ namespace FDK
#endregion #endregion
//----------------- //-----------------
#endregion #endregion
} } else {
else
{
#region [ ASIO ] #region [ ASIO ]
//----------------- //-----------------
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
string errmes = errcode.ToString(); string errmes = errcode.ToString();
if ( errcode == Errors.OK ) if (errcode == Errors.OK) {
{
errmes = "BASS_OK; The device may be dissconnected"; errmes = "BASS_OK; The device may be dissconnected";
} }
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes ) ); throw new Exception(string.Format("BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes));
//----------------- //-----------------
#endregion #endregion
} }
@ -219,66 +188,63 @@ namespace FDK
// ASIO 出力チャンネルの初期化。 // ASIO 出力チャンネルの初期化。
this.tAsioProc = new AsioProcedure( this.tAsio処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。 this.tAsioProc = new AsioProcedure(this.tAsio処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
if ( !BassAsio.ChannelEnable( false, 0, this.tAsioProc, IntPtr.Zero ) ) // 出力チャンネル0 の有効化。 if (!BassAsio.ChannelEnable(false, 0, this.tAsioProc, IntPtr.Zero)) // 出力チャンネル0 の有効化。
{ {
#region [ ASIO ] #region [ ASIO ]
//----------------- //-----------------
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.LastError.ToString() ) ); throw new Exception(string.Format("Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.LastError.ToString()));
//----------------- //-----------------
#endregion #endregion
} }
for ( int i = 1; i < this.n出力チャンネル数; i++ ) // 出力チャネルを全てチャネル0とグループ化する。 for (int i = 1; i < this.n出力チャンネル数; i++) // 出力チャネルを全てチャネル0とグループ化する。
{ // チャネル1だけを0とグループ化すると、3ch以上の出力をサポートしたカードでの動作がおかしくなる { // チャネル1だけを0とグループ化すると、3ch以上の出力をサポートしたカードでの動作がおかしくなる
if ( !BassAsio.ChannelJoin( false, i, 0 ) ) if (!BassAsio.ChannelJoin(false, i, 0)) {
{
#region [ ] #region [ ]
//----------------- //-----------------
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.LastError, i ) ); throw new Exception(string.Format("Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.LastError, i));
//----------------- //-----------------
#endregion #endregion
} }
} }
if ( !BassAsio.ChannelSetFormat( false, 0, this.fmtASIOチャンネルフォーマット ) ) // 出力チャンネル0のフォーマット if (!BassAsio.ChannelSetFormat(false, 0, this.fmtASIOチャンネルフォーマット)) // 出力チャンネル0のフォーマット
{ {
#region [ ASIO ] #region [ ASIO ]
//----------------- //-----------------
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.LastError.ToString() ) ); throw new Exception(string.Format("Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.LastError.ToString()));
//----------------- //-----------------
#endregion #endregion
} }
// ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。 // ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。
var flag = BassFlags.MixerNonStop | BassFlags.Decode; // デコードのみ発声しない。ASIO に出力されるだけ。 var flag = BassFlags.MixerNonStop | BassFlags.Decode; // デコードのみ発声しない。ASIO に出力されるだけ。
if( this.fmtASIOデバイスフォーマット == AsioSampleFormat.Float ) if (this.fmtASIOデバイスフォーマット == AsioSampleFormat.Float)
flag |= BassFlags.Float; flag |= BassFlags.Float;
this.hMixer = BassMix.CreateMixerStream( (int) this.db周波数, this.n出力チャンネル数, flag ); this.hMixer = BassMix.CreateMixerStream((int)this.db周波数, this.n出力チャンネル数, flag);
if ( this.hMixer == 0 ) if (this.hMixer == 0) {
{ Errors err = Bass.LastError;
Errors err = Bass.LastError;
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", err ) ); throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", err));
} }
// BASS ミキサーの1秒あたりのバイト数を算出。 // BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.ChannelGetInfo( this.hMixer ); var mixerInfo = Bass.ChannelGetInfo(this.hMixer);
int nサンプルサイズbyte = 0; int nサンプルサイズbyte = 0;
switch( this.fmtASIOチャンネルフォーマット ) switch (this.fmtASIOチャンネルフォーマット) {
{
case AsioSampleFormat.Bit16: nサンプルサイズbyte = 2; break; case AsioSampleFormat.Bit16: nサンプルサイズbyte = 2; break;
case AsioSampleFormat.Bit24: nサンプルサイズbyte = 3; break; case AsioSampleFormat.Bit24: nサンプルサイズbyte = 3; break;
case AsioSampleFormat.Bit32: nサンプルサイズbyte = 4; break; case AsioSampleFormat.Bit32: nサンプルサイズbyte = 4; break;
@ -294,124 +260,111 @@ namespace FDK
// そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、 // そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
// hMixerの音量制御を反映させる。 // hMixerの音量制御を反映させる。
this.hMixer_DeviceOut = BassMix.CreateMixerStream( this.hMixer_DeviceOut = BassMix.CreateMixerStream(
(int) this.db周波数, this.n出力チャンネル数, flag ); (int)this.db周波数, this.n出力チャンネル数, flag);
if ( this.hMixer_DeviceOut == 0 ) if (this.hMixer_DeviceOut == 0) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) ); throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode));
} }
{ {
bool b1 = BassMix.MixerAddChannel( this.hMixer_DeviceOut, this.hMixer, BassFlags.Default ); bool b1 = BassMix.MixerAddChannel(this.hMixer_DeviceOut, this.hMixer, BassFlags.Default);
if ( !b1 ) if (!b1) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) ); throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode));
}; };
} }
// 出力を開始。 // 出力を開始。
this.nバッファサイズsample = (int) ( bufferSize * this.db周波数 / 1000.0 ); this.nバッファサイズsample = (int)(bufferSize * this.db周波数 / 1000.0);
//this.nバッファサイズsample = (int) nバッファサイズbyte; //this.nバッファサイズsample = (int) nバッファサイズbyte;
if ( !BassAsio.Start( this.nバッファサイズsample ) ) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。 if (!BassAsio.Start(this.nバッファサイズsample)) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。
{ {
Errors err = BassAsio.LastError; Errors err = BassAsio.LastError;
BassAsio.Free(); BassAsio.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( "ASIO デバイス出力開始に失敗しました。" + err.ToString() ); throw new Exception("ASIO デバイス出力開始に失敗しました。" + err.ToString());
} } else {
else int n遅延sample = BassAsio.GetLatency(false); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。
{ int n希望遅延sample = (int)(bufferSize * this.db周波数 / 1000.0);
int n遅延sample = BassAsio.GetLatency( false ); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。 this.BufferSize = this.OutputDelay = (long)(n遅延sample * 1000.0f / this.db周波数);
int n希望遅延sample = (int) ( bufferSize * this.db周波数 / 1000.0 ); Trace.TraceInformation("ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.OutputDelay, bufferSize);
this.BufferSize = this.OutputDelay = (long) ( n遅延sample * 1000.0f / this.db周波数 );
Trace.TraceInformation( "ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.OutputDelay, bufferSize );
} }
} }
#region [ tサウンドを作成する() ] #region [ tサウンドを作成する() ]
public CSound tCreateSound( string strファイル名, ESoundGroup soundGroup ) public CSound tCreateSound(string strファイル名, ESoundGroup soundGroup) {
{
var sound = new CSound(soundGroup); var sound = new CSound(soundGroup);
sound.CreateASIOSound( strファイル名, this.hMixer ); sound.CreateASIOSound(strファイル名, this.hMixer);
return sound; return sound;
} }
public void tCreateSound( string strファイル名, CSound sound ) public void tCreateSound(string strファイル名, CSound sound) {
{ sound.CreateASIOSound(strファイル名, this.hMixer);
sound.CreateASIOSound( strファイル名, this.hMixer );
} }
#endregion #endregion
#region [ Dispose-Finallizeパターン実装 ] #region [ Dispose-Finallizeパターン実装 ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ this.Dispose(true);
this.Dispose( true ); GC.SuppressFinalize(this);
GC.SuppressFinalize( this );
} }
protected void Dispose( bool bManagedDispose ) protected void Dispose(bool bManagedDispose) {
{ SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (hMixer != -1) {
if ( hMixer != -1 ) Bass.StreamFree(hMixer);
{
Bass.StreamFree( hMixer );
} }
if ( !bIsBASSFree ) if (!bIsBASSFree) {
{ BassAsio.Free(); // システムタイマより先に呼び出すこと。tAsio処理() の中でシステムタイマを参照してるため)
BassAsio.Free(); // システムタイマより先に呼び出すこと。tAsio処理() の中でシステムタイマを参照してるため)
Bass.Free(); Bass.Free();
} }
if( bManagedDispose ) if (bManagedDispose) {
{
SystemTimer.Dispose(); SystemTimer.Dispose();
SystemTimer = null; SystemTimer = null;
} }
} }
~CSoundDeviceASIO() ~CSoundDeviceASIO() {
{ this.Dispose(false);
this.Dispose( false );
} }
//----------------- //-----------------
#endregion #endregion
protected int hMixer = -1; protected int hMixer = -1;
protected int hMixer_DeviceOut = -1; protected int hMixer_DeviceOut = -1;
protected int n出力チャンネル数 = 0; protected int n出力チャンネル数 = 0;
protected double db周波数 = 0.0; protected double db周波数 = 0.0;
protected int nバッファサイズsample = 0; protected int nバッファサイズsample = 0;
protected AsioSampleFormat fmtASIOデバイスフォーマット = AsioSampleFormat.Unknown; protected AsioSampleFormat fmtASIOデバイスフォーマット = AsioSampleFormat.Unknown;
protected AsioSampleFormat fmtASIOチャンネルフォーマット = AsioSampleFormat.Bit16; // 16bit 固定 protected AsioSampleFormat fmtASIOチャンネルフォーマット = AsioSampleFormat.Bit16; // 16bit 固定
//protected BASSASIOFormat fmtASIOチャンネルフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_32BIT;// 16bit 固定 //protected BASSASIOFormat fmtASIOチャンネルフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_32BIT;// 16bit 固定
protected AsioProcedure tAsioProc = null; protected AsioProcedure tAsioProc = null;
protected int tAsio処理( bool input, int channel, IntPtr buffer, int length, IntPtr user ) protected int tAsio処理(bool input, int channel, IntPtr buffer, int length, IntPtr user) {
{ if (input) return 0;
if( input ) return 0;
// BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。 // BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。
int num = Bass.ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ int num = Bass.ChannelGetData(this.hMixer_DeviceOut, buffer, length); // num = 実際に転送した長さ
if ( num == -1 ) num = 0; if (num == -1) num = 0;
// 経過時間を更新。 // 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。 // データの転送差分ではなく累積転送バイト数から算出する。
this.ElapsedTimeMs = ( this.n累積転送バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数 ) - this.OutputDelay; this.ElapsedTimeMs = (this.n累積転送バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数) - this.OutputDelay;
this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs; this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs;

View File

@ -1,48 +1,35 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using ManagedBass; using ManagedBass;
using ManagedBass.Mix; using ManagedBass.Mix;
namespace FDK namespace FDK {
{ public class CSoundDeviceBASS : ISoundDevice {
public class CSoundDeviceBASS : ISoundDevice
{
// プロパティ // プロパティ
public ESoundDeviceType SoundDeviceType public ESoundDeviceType SoundDeviceType {
{
get; get;
protected set; protected set;
} }
public long OutputDelay public long OutputDelay {
{
get; get;
protected set; protected set;
} }
public long BufferSize public long BufferSize {
{
get; get;
protected set; protected set;
} }
// CSoundTimer 用に公開しているプロパティ // CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs public long ElapsedTimeMs {
{
get; get;
protected set; protected set;
} }
public long UpdateSystemTimeMs public long UpdateSystemTimeMs {
{
get; get;
protected set; protected set;
} }
public CTimer SystemTimer public CTimer SystemTimer {
{
get; get;
protected set; protected set;
} }
@ -50,32 +37,26 @@ namespace FDK
public float CPUUsage => (float)Bass.CPUUsage; public float CPUUsage => (float)Bass.CPUUsage;
// マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。 // マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume public int nMasterVolume {
{ get {
get
{
float fVolume = 0.0f; float fVolume = 0.0f;
bool b = Bass.ChannelGetAttribute(this.MixerHandle, ChannelAttribute.Volume, out fVolume); bool b = Bass.ChannelGetAttribute(this.MixerHandle, ChannelAttribute.Volume, out fVolume);
if (!b) if (!b) {
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation("BASS Master Volume Get Error: " + be.ToString()); Trace.TraceInformation("BASS Master Volume Get Error: " + be.ToString());
} }
return (int)(fVolume * 100); return (int)(fVolume * 100);
} }
set set {
{
bool b = Bass.ChannelSetAttribute(this.MixerHandle, ChannelAttribute.Volume, (float)(value / 100.0)); bool b = Bass.ChannelSetAttribute(this.MixerHandle, ChannelAttribute.Volume, (float)(value / 100.0));
if (!b) if (!b) {
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation("BASS Master Volume Set Error: " + be.ToString()); Trace.TraceInformation("BASS Master Volume Set Error: " + be.ToString());
} }
} }
} }
public CSoundDeviceBASS(int updatePeriod, int bufferSize) public CSoundDeviceBASS(int updatePeriod, int bufferSize) {
{
Trace.TraceInformation("Start initialization of BASS"); Trace.TraceInformation("Start initialization of BASS");
this.SoundDeviceType = ESoundDeviceType.Unknown; this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0; this.OutputDelay = 0;
@ -88,30 +69,27 @@ namespace FDK
// BASS の初期化。 // BASS の初期化。
int freq = 44100; int freq = 44100;
if (!Bass.Init(-1, freq, DeviceInitFlags.Default)) if (!Bass.Init(-1, freq, DeviceInitFlags.Default))
throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString())); throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString()));
if (!Bass.Configure(Configuration.UpdatePeriod, updatePeriod)) if (!Bass.Configure(Configuration.UpdatePeriod, updatePeriod)) {
{
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError}]"); Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError}]");
} }
if (!Bass.Configure(Configuration.UpdateThreads, 1)) if (!Bass.Configure(Configuration.UpdateThreads, 1)) {
{
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError}]"); Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError}]");
} }
Bass.Configure(Configuration.PlaybackBufferLength, bufferSize); Bass.Configure(Configuration.PlaybackBufferLength, bufferSize);
Bass.Configure(Configuration.LogarithmicVolumeCurve, true); Bass.Configure(Configuration.LogarithmicVolumeCurve, true);
this.STREAMPROC = new StreamProcedure(StreamProc); this.STREAMPROC = new StreamProcedure(StreamProc);
this.MainStreamHandle = Bass.CreateStream(freq, 2, BassFlags.Default, this.STREAMPROC, IntPtr.Zero); this.MainStreamHandle = Bass.CreateStream(freq, 2, BassFlags.Default, this.STREAMPROC, IntPtr.Zero);
var flag = BassFlags.MixerNonStop| BassFlags.Decode; // デコードのみ=発声しない。 var flag = BassFlags.MixerNonStop | BassFlags.Decode; // デコードのみ=発声しない。
this.MixerHandle = BassMix.CreateMixerStream(freq, 2, flag); this.MixerHandle = BassMix.CreateMixerStream(freq, 2, flag);
if (this.MixerHandle == 0) if (this.MixerHandle == 0) {
{
Errors err = Bass.LastError; Errors err = Bass.LastError;
Bass.Free(); Bass.Free();
this.IsBASSSoundFree = true; this.IsBASSSoundFree = true;
@ -133,8 +111,7 @@ namespace FDK
// hMixerの音量制御を反映させる。 // hMixerの音量制御を反映させる。
Mixer_DeviceOut = BassMix.CreateMixerStream( Mixer_DeviceOut = BassMix.CreateMixerStream(
freq, 2, flag); freq, 2, flag);
if (this.Mixer_DeviceOut == 0) if (this.Mixer_DeviceOut == 0) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
Bass.Free(); Bass.Free();
this.IsBASSSoundFree = true; this.IsBASSSoundFree = true;
@ -142,8 +119,7 @@ namespace FDK
} }
{ {
bool b1 = BassMix.MixerAddChannel(this.Mixer_DeviceOut, this.MixerHandle, BassFlags.Default); bool b1 = BassMix.MixerAddChannel(this.Mixer_DeviceOut, this.MixerHandle, BassFlags.Default);
if (!b1) if (!b1) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
Bass.Free(); Bass.Free();
this.IsBASSSoundFree = true; this.IsBASSSoundFree = true;
@ -161,9 +137,7 @@ namespace FDK
Bass.Free(); Bass.Free();
this.IsBASSSoundFree = true; this.IsBASSSoundFree = true;
throw new Exception("BASS デバイス出力開始に失敗しました。" + err.ToString()); throw new Exception("BASS デバイス出力開始に失敗しました。" + err.ToString());
} } else {
else
{
Bass.GetInfo(out var info); Bass.GetInfo(out var info);
this.BufferSize = this.OutputDelay = info.Latency + bufferSize;//求め方があっているのだろうか… this.BufferSize = this.OutputDelay = info.Latency + bufferSize;//求め方があっているのだろうか…
@ -176,15 +150,13 @@ namespace FDK
} }
#region [ tCreateSound() ] #region [ tCreateSound() ]
public CSound tCreateSound(string strFilename, ESoundGroup soundGroup) public CSound tCreateSound(string strFilename, ESoundGroup soundGroup) {
{
var sound = new CSound(soundGroup); var sound = new CSound(soundGroup);
sound.CreateBassSound(strFilename, this.MixerHandle); sound.CreateBassSound(strFilename, this.MixerHandle);
return sound; return sound;
} }
public void tCreateSound(string strFilename, CSound sound) public void tCreateSound(string strFilename, CSound sound) {
{
sound.CreateBassSound(strFilename, this.MixerHandle); sound.CreateBassSound(strFilename, this.MixerHandle);
} }
#endregion #endregion
@ -192,43 +164,35 @@ namespace FDK
#region [ Dispose-Finallizeパターン実装 ] #region [ Dispose-Finallizeパターン実装 ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{
this.Dispose(true); this.Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool bManagedDispose) protected void Dispose(bool bManagedDispose) {
{
this.SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) this.SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if (MainStreamHandle != -1) if (MainStreamHandle != -1) {
{
Bass.StreamFree(this.MainStreamHandle); Bass.StreamFree(this.MainStreamHandle);
} }
if (MixerHandle != -1) if (MixerHandle != -1) {
{
Bass.StreamFree(this.MixerHandle); Bass.StreamFree(this.MixerHandle);
} }
if (!this.IsBASSSoundFree) if (!this.IsBASSSoundFree) {
{
Bass.Stop(); Bass.Stop();
Bass.Free();// システムタイマより先に呼び出すこと。Stream処理() の中でシステムタイマを参照してるため) Bass.Free();// システムタイマより先に呼び出すこと。Stream処理() の中でシステムタイマを参照してるため)
} }
if (bManagedDispose) if (bManagedDispose) {
{
SystemTimer.Dispose(); SystemTimer.Dispose();
this.SystemTimer = null; this.SystemTimer = null;
} }
} }
~CSoundDeviceBASS() ~CSoundDeviceBASS() {
{
this.Dispose(false); this.Dispose(false);
} }
//----------------- //-----------------
#endregion #endregion
public int StreamProc(int handle, IntPtr buffer, int length, IntPtr user) public int StreamProc(int handle, IntPtr buffer, int length, IntPtr user) {
{
// BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。 // BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。
int num = Bass.ChannelGetData(this.Mixer_DeviceOut, buffer, length); // num = 実際に転送した長さ int num = Bass.ChannelGetData(this.Mixer_DeviceOut, buffer, length); // num = 実際に転送した長さ
@ -258,4 +222,4 @@ namespace FDK
//WASAPIとASIOはLinuxでは使えないので、ここだけで良し //WASAPIとASIOはLinuxでは使えないので、ここだけで良し
} }
} }

View File

@ -1,82 +1,65 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ManagedBass; using ManagedBass;
using ManagedBass.Wasapi;
using ManagedBass.Mix; using ManagedBass.Mix;
using ManagedBass.Wasapi;
namespace FDK namespace FDK {
{ internal class CSoundDeviceWASAPI : ISoundDevice {
internal class CSoundDeviceWASAPI : ISoundDevice
{
// プロパティ // プロパティ
public ESoundDeviceType SoundDeviceType public ESoundDeviceType SoundDeviceType {
{
get; get;
protected set; protected set;
} }
public long OutputDelay public long OutputDelay {
{
get; get;
protected set; protected set;
} }
public long BufferSize public long BufferSize {
{
get; get;
protected set; protected set;
} }
// CSoundTimer 用に公開しているプロパティ // CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs public long ElapsedTimeMs {
{
get; get;
protected set; protected set;
} }
public long UpdateSystemTimeMs public long UpdateSystemTimeMs {
{
get; get;
protected set; protected set;
} }
public CTimer SystemTimer public CTimer SystemTimer {
{
get; get;
protected set; protected set;
} }
public enum EWASAPIMode { Exclusion, Share } public enum EWASAPIMode { Exclusion, Share }
public int nMasterVolume public int nMasterVolume {
{ get {
get
{
float volume = 0.0f; float volume = 0.0f;
//if ( BassMix.BASS_Mixer_ChannelGetEnvelopePos( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, ref f音量 ) == -1 ) //if ( BassMix.BASS_Mixer_ChannelGetEnvelopePos( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, ref f音量 ) == -1 )
// return 100; // return 100;
//bool b = Bass.BASS_ChannelGetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, ref f音量 ); //bool b = Bass.BASS_ChannelGetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, ref f音量 );
bool b = Bass.ChannelGetAttribute( this.hMixer, ChannelAttribute.Volume, out volume ); bool b = Bass.ChannelGetAttribute(this.hMixer, ChannelAttribute.Volume, out volume);
if ( !b ) if (!b) {
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation( "WASAPI Master Volume Get Error: " + be.ToString() ); Trace.TraceInformation("WASAPI Master Volume Get Error: " + be.ToString());
} } else {
else Trace.TraceInformation("WASAPI Master Volume Get Success: " + (volume * 100));
{
Trace.TraceInformation( "WASAPI Master Volume Get Success: " + (volume * 100) );
} }
return (int) ( volume * 100 ); return (int)(volume * 100);
} }
set set {
{
// bool b = Bass.BASS_SetVolume( value / 100.0f ); // bool b = Bass.BASS_SetVolume( value / 100.0f );
// →Exclusiveモード時は無効 // →Exclusiveモード時は無効
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_VOL_SESSION, (float) ( value / 100 ) ); // bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_VOL_SESSION, (float) ( value / 100 ) );
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_CURVE_WINDOWS, (float) ( value / 100 ) ); // bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_CURVE_WINDOWS, (float) ( value / 100 ) );
bool b = Bass.ChannelSetAttribute( this.hMixer, ChannelAttribute.Volume, (float) ( value / 100.0 ) ); bool b = Bass.ChannelSetAttribute(this.hMixer, ChannelAttribute.Volume, (float)(value / 100.0));
// If you would like to have a volume control in exclusive mode too, and you're using the BASSmix add-on, // If you would like to have a volume control in exclusive mode too, and you're using the BASSmix add-on,
// you can adjust the source's BASS_ATTRIB_VOL setting via BASS_ChannelSetAttribute. // you can adjust the source's BASS_ATTRIB_VOL setting via BASS_ChannelSetAttribute.
// しかし、hMixerに対するBASS_ChannelSetAttribute()でBASS_ATTRIB_VOLを変更: なぜか出力音量に反映されず // しかし、hMixerに対するBASS_ChannelSetAttribute()でBASS_ATTRIB_VOLを変更: なぜか出力音量に反映されず
@ -88,13 +71,10 @@ namespace FDK
//var nodes = new BASS_MIXER_NODE[ 1 ] { new BASS_MIXER_NODE( 0, (float) value ) }; //var nodes = new BASS_MIXER_NODE[ 1 ] { new BASS_MIXER_NODE( 0, (float) value ) };
//bool b = BassMix.BASS_Mixer_ChannelSetEnvelope( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes ); //bool b = BassMix.BASS_Mixer_ChannelSetEnvelope( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes );
//bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, value / 100.0f ); //bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, value / 100.0f );
if ( !b ) if (!b) {
{
Errors be = Bass.LastError; Errors be = Bass.LastError;
Trace.TraceInformation( "WASAPI Master Volume Set Error: " + be.ToString() ); Trace.TraceInformation("WASAPI Master Volume Set Error: " + be.ToString());
} } else {
else
{
// int n = this.nMasterVolume; // int n = this.nMasterVolume;
// Trace.TraceInformation( "WASAPI Master Volume Set Success: " + value ); // Trace.TraceInformation( "WASAPI Master Volume Set Success: " + value );
@ -109,40 +89,39 @@ namespace FDK
/// <param name="mode"></param> /// <param name="mode"></param>
/// <param name="bufferSize">(未使用; 本メソッド内で自動設定する)</param> /// <param name="bufferSize">(未使用; 本メソッド内で自動設定する)</param>
/// <param name="interval">(未使用; 本メソッド内で自動設定する)</param> /// <param name="interval">(未使用; 本メソッド内で自動設定する)</param>
public CSoundDeviceWASAPI( EWASAPIMode mode, long bufferSize, long interval ) public CSoundDeviceWASAPI(EWASAPIMode mode, long bufferSize, long interval) {
{
// 初期化。 // 初期化。
Trace.TraceInformation( "BASS (WASAPI) の初期化を開始します。" ); Trace.TraceInformation("BASS (WASAPI) の初期化を開始します。");
this.SoundDeviceType = ESoundDeviceType.Unknown; this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0; this.OutputDelay = 0;
this.ElapsedTimeMs = 0; this.ElapsedTimeMs = 0;
this.UpdateSystemTimeMs = CTimer.UnusedNum; this.UpdateSystemTimeMs = CTimer.UnusedNum;
this.SystemTimer = new CTimer( CTimer.TimerType.MultiMedia ); this.SystemTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.b最初の実出力遅延算出 = true; this.b最初の実出力遅延算出 = true;
// BASS の設定。 // BASS の設定。
this.bIsBASSFree = true; this.bIsBASSFree = true;
if (!Bass.Configure( Configuration.UpdatePeriod, 0 )) // 0:BASSストリームの自動更新を行わない。 if (!Bass.Configure(Configuration.UpdatePeriod, 0)) // 0:BASSストリームの自動更新を行わない。
{ {
Trace.TraceWarning($"Configure({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]"); Trace.TraceWarning($"Configure({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]");
} }
if (!Bass.Configure( Configuration.UpdateThreads, 0 )) // 0:BASSストリームの自動更新を行わない。 if (!Bass.Configure(Configuration.UpdateThreads, 0)) // 0:BASSストリームの自動更新を行わない。
{ {
Trace.TraceWarning($"Configure({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]"); Trace.TraceWarning($"Configure({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]");
} }
// BASS の初期化。 // BASS の初期化。
int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。 int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
int n周波数 = 44100; // 仮決め。lデバイス≠ドライバがネイティブに対応している周波数であれば何でもいいようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。 int n周波数 = 44100; // 仮決め。lデバイス≠ドライバがネイティブに対応している周波数であれば何でもいいようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。
//if( !Bass.Init( nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero ) ) //if( !Bass.Init( nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero ) )
// throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString() ) ); // throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString() ) );
Bass.Configure(Configuration.LogarithmicVolumeCurve, true); Bass.Configure(Configuration.LogarithmicVolumeCurve, true);
#region [ : WASAPIデバイスのenumerateと ] #region [ : WASAPIデバイスのenumerateと ]
//(デバッグ用) //(デバッグ用)
@ -150,12 +129,10 @@ namespace FDK
int a; int a;
string strDefaultSoundDeviceName = null; string strDefaultSoundDeviceName = null;
DeviceInfo[] bassDevInfos = new DeviceInfo[Bass.DeviceCount]; DeviceInfo[] bassDevInfos = new DeviceInfo[Bass.DeviceCount];
for(int j = 0; j < bassDevInfos.Length; j++) for (int j = 0; j < bassDevInfos.Length; j++) {
{
bassDevInfos[j] = Bass.GetDeviceInfo(j); bassDevInfos[j] = Bass.GetDeviceInfo(j);
} }
for (a = 0; a < bassDevInfos.GetLength(0); a++) for (a = 0; a < bassDevInfos.GetLength(0); a++) {
{
{ {
Trace.TraceInformation("Sound Device #{0}: {1}: IsDefault={2}, isEnabled={3}", Trace.TraceInformation("Sound Device #{0}: {1}: IsDefault={2}, isEnabled={3}",
a, a,
@ -163,8 +140,7 @@ namespace FDK
bassDevInfos[a].IsDefault, bassDevInfos[a].IsDefault,
bassDevInfos[a].IsEnabled bassDevInfos[a].IsEnabled
); );
if (bassDevInfos[a].IsDefault) if (bassDevInfos[a].IsDefault) {
{
// これはOS標準のdefault device。後でWASAPIのdefault deviceと比較する。 // これはOS標準のdefault device。後でWASAPIのdefault deviceと比較する。
strDefaultSoundDeviceName = bassDevInfos[a].Name; strDefaultSoundDeviceName = bassDevInfos[a].Name;
} }
@ -175,9 +151,9 @@ namespace FDK
// BASS WASAPI の初期化。 // BASS WASAPI の初期化。
nデバイス = -1; nデバイス = -1;
n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate) n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate)
int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels) int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels)
this.tWasapiProc = new WasapiProcedure( this.tWASAPI処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。 this.tWasapiProc = new WasapiProcedure(this.tWASAPI処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
// WASAPIの更新間隔(period)は、バッファサイズにも影響を与える。 // WASAPIの更新間隔(period)は、バッファサイズにも影響を与える。
// 更新間隔を最小にするには、BassWasapi.BASS_WASAPI_GetDeviceInfo( ndevNo ).minperiod の値を使えばよい。 // 更新間隔を最小にするには、BassWasapi.BASS_WASAPI_GetDeviceInfo( ndevNo ).minperiod の値を使えばよい。
@ -185,8 +161,7 @@ namespace FDK
#region [ WASAPIデバイスを検索しmsを設定できる最小値にする ] #region [ WASAPIデバイスを検索しmsを設定できる最小値にする ]
int nDevNo = -1; int nDevNo = -1;
WasapiDeviceInfo deviceInfo; WasapiDeviceInfo deviceInfo;
for (int n = 0; BassWasapi.GetDeviceInfo(n, out deviceInfo); n++) for (int n = 0; BassWasapi.GetDeviceInfo(n, out deviceInfo); n++) {
{
// #37940 2018.2.15: BASS_DEVICEINFOとBASS_WASAPI_DEVICEINFOで、IsDefaultとなっているデバイスが異なる場合がある。 // #37940 2018.2.15: BASS_DEVICEINFOとBASS_WASAPI_DEVICEINFOで、IsDefaultとなっているデバイスが異なる場合がある。
// (WASAPIでIsDefaultとなっているデバイスが正しくない場合がある) // (WASAPIでIsDefaultとなっているデバイスが正しくない場合がある)
// そのため、BASS_DEVICEでIsDefaultとなっているものを探し、それと同じ名前のWASAPIデバイスを使用する。 // そのため、BASS_DEVICEでIsDefaultとなっているものを探し、それと同じ名前のWASAPIデバイスを使用する。
@ -195,8 +170,7 @@ namespace FDK
// (具体的には、defperiod, minperiod, mixchans, mixfreqがすべて0のデバイスは使用不可のため // (具体的には、defperiod, minperiod, mixchans, mixfreqがすべて0のデバイスは使用不可のため
// これらが0でないものを選択する) // これらが0でないものを選択する)
//if ( deviceInfo.IsDefault ) //if ( deviceInfo.IsDefault )
if (deviceInfo.Name == strDefaultSoundDeviceName && deviceInfo.MixFrequency > 0) if (deviceInfo.Name == strDefaultSoundDeviceName && deviceInfo.MixFrequency > 0) {
{
nDevNo = n; nDevNo = n;
#region [ ] #region [ ]
Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}", Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}",
@ -207,8 +181,7 @@ namespace FDK
break; break;
} }
} }
if (nDevNo != -1) if (nDevNo != -1) {
{
Trace.TraceInformation("Start Bass_Init(device=0(fixed value: no sound), deviceInfo.mixfreq=" + deviceInfo.MixFrequency + ", BASS_DEVICE_DEFAULT, Zero)"); Trace.TraceInformation("Start Bass_Init(device=0(fixed value: no sound), deviceInfo.mixfreq=" + deviceInfo.MixFrequency + ", BASS_DEVICE_DEFAULT, Zero)");
if (!Bass.Init(0, deviceInfo.MixFrequency, DeviceInitFlags.Default, IntPtr.Zero)) // device = 0:"no device": BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。 if (!Bass.Init(0, deviceInfo.MixFrequency, DeviceInitFlags.Default, IntPtr.Zero)) // device = 0:"no device": BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_Init)[{1}]", mode.ToString(), Bass.LastError.ToString())); throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_Init)[{1}]", mode.ToString(), Bass.LastError.ToString()));
@ -224,30 +197,26 @@ namespace FDK
//{ //{
// n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。 // n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。
//} //}
} } else {
else
{
Trace.TraceError("Error: Default WASAPI Device is not found."); Trace.TraceError("Error: Default WASAPI Device is not found.");
} }
#endregion #endregion
//Retry: //Retry:
var flags = ( mode == EWASAPIMode.Exclusion ) ? WasapiInitFlags.AutoFormat | WasapiInitFlags.Exclusive : WasapiInitFlags.Shared | WasapiInitFlags.AutoFormat; var flags = (mode == EWASAPIMode.Exclusion) ? WasapiInitFlags.AutoFormat | WasapiInitFlags.Exclusive : WasapiInitFlags.Shared | WasapiInitFlags.AutoFormat;
//var flags = ( mode == Eデバイスモード.排他 ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT; //var flags = ( mode == Eデバイスモード.排他 ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT;
if ( BassWasapi.Init( nデバイス, n周波数, nチャンネル数, flags, ( bufferSize / 1000.0f ), ( interval / 1000.0f ), this.tWasapiProc, IntPtr.Zero ) ) if (BassWasapi.Init(nデバイス, n周波数, nチャンネル数, flags, (bufferSize / 1000.0f), (interval / 1000.0f), this.tWasapiProc, IntPtr.Zero)) {
{ if (mode == EWASAPIMode.Exclusion) {
if( mode == EWASAPIMode.Exclusion )
{
#region [ ] #region [ ]
//----------------- //-----------------
this.SoundDeviceType = ESoundDeviceType.ExclusiveWASAPI; this.SoundDeviceType = ESoundDeviceType.ExclusiveWASAPI;
nDevNo = BassWasapi.CurrentDevice; nDevNo = BassWasapi.CurrentDevice;
deviceInfo = BassWasapi.GetDeviceInfo( nDevNo ); deviceInfo = BassWasapi.GetDeviceInfo(nDevNo);
BassWasapi.GetInfo(out var wasapiInfo); BassWasapi.GetInfo(out var wasapiInfo);
int n1サンプルのバイト数 = 2 * wasapiInfo.Channels; // default; int n1サンプルのバイト数 = 2 * wasapiInfo.Channels; // default;
switch( wasapiInfo.Format ) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。 switch (wasapiInfo.Format) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。
{ {
case WasapiFormat.Bit8: n1サンプルのバイト数 = 1 * wasapiInfo.Channels; break; case WasapiFormat.Bit8: n1サンプルのバイト数 = 1 * wasapiInfo.Channels; break;
case WasapiFormat.Bit16: n1サンプルのバイト数 = 2 * wasapiInfo.Channels; break; case WasapiFormat.Bit16: n1サンプルのバイト数 = 2 * wasapiInfo.Channels; break;
@ -257,33 +226,31 @@ namespace FDK
case WasapiFormat.Unknown: throw new ArgumentOutOfRangeException($"WASAPI format error ({wasapiInfo.ToString()})"); case WasapiFormat.Unknown: throw new ArgumentOutOfRangeException($"WASAPI format error ({wasapiInfo.ToString()})");
} }
int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.Frequency; int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.Frequency;
this.BufferSize = (long) ( wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数 ); this.BufferSize = (long)(wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数);
this.OutputDelay = 0; // 初期値はゼロ this.OutputDelay = 0; // 初期値はゼロ
Trace.TraceInformation( "使用デバイス: #" + nDevNo + " : " + deviceInfo.Name ); Trace.TraceInformation("使用デバイス: #" + nDevNo + " : " + deviceInfo.Name);
Trace.TraceInformation( "BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)", Trace.TraceInformation("BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
wasapiInfo.Frequency, wasapiInfo.Frequency,
wasapiInfo.Channels, wasapiInfo.Channels,
wasapiInfo.Format.ToString(), wasapiInfo.Format.ToString(),
wasapiInfo.BufferLength, wasapiInfo.BufferLength,
BufferSize.ToString(), BufferSize.ToString(),
bufferSize.ToString(), bufferSize.ToString(),
interval.ToString() ); interval.ToString());
Trace.TraceInformation( "デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.MinimumUpdatePeriod * 1000, deviceInfo.DefaultUpdatePeriod * 1000 ); Trace.TraceInformation("デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.MinimumUpdatePeriod * 1000, deviceInfo.DefaultUpdatePeriod * 1000);
this.bIsBASSFree = false; this.bIsBASSFree = false;
//----------------- //-----------------
#endregion #endregion
} } else {
else
{
#region [ ] #region [ ]
//----------------- //-----------------
this.SoundDeviceType = ESoundDeviceType.SharedWASAPI; this.SoundDeviceType = ESoundDeviceType.SharedWASAPI;
var devInfo = BassWasapi.GetDeviceInfo(BassWasapi.CurrentDevice); var devInfo = BassWasapi.GetDeviceInfo(BassWasapi.CurrentDevice);
BassWasapi.GetInfo(out var wasapiInfo); BassWasapi.GetInfo(out var wasapiInfo);
int n1サンプルのバイト数 = 2 * wasapiInfo.Channels; // default; int n1サンプルのバイト数 = 2 * wasapiInfo.Channels; // default;
switch (wasapiInfo.Format) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。 switch (wasapiInfo.Format) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。
{ {
case WasapiFormat.Bit8: n1サンプルのバイト数 = 1 * wasapiInfo.Channels; break; case WasapiFormat.Bit8: n1サンプルのバイト数 = 1 * wasapiInfo.Channels; break;
case WasapiFormat.Bit16: n1サンプルのバイト数 = 2 * wasapiInfo.Channels; break; case WasapiFormat.Bit16: n1サンプルのバイト数 = 2 * wasapiInfo.Channels; break;
case WasapiFormat.Bit24: n1サンプルのバイト数 = 3 * wasapiInfo.Channels; break; case WasapiFormat.Bit24: n1サンプルのバイト数 = 3 * wasapiInfo.Channels; break;
@ -291,12 +258,12 @@ namespace FDK
case WasapiFormat.Float: n1サンプルのバイト数 = 4 * wasapiInfo.Channels; break; case WasapiFormat.Float: n1サンプルのバイト数 = 4 * wasapiInfo.Channels; break;
case WasapiFormat.Unknown: throw new ArgumentOutOfRangeException($"WASAPI format error ({wasapiInfo.ToString()})"); case WasapiFormat.Unknown: throw new ArgumentOutOfRangeException($"WASAPI format error ({wasapiInfo.ToString()})");
} }
int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.Frequency; int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.Frequency;
this.BufferSize = (long)(wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数); this.BufferSize = (long)(wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数);
this.OutputDelay = 0; // 初期値はゼロ this.OutputDelay = 0; // 初期値はゼロ
Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", bufferSize, devInfo.DefaultUpdatePeriod * 1000.0f ); Trace.TraceInformation("BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", bufferSize, devInfo.DefaultUpdatePeriod * 1000.0f);
this.bIsBASSFree = false; this.bIsBASSFree = false;
//----------------- //-----------------
#endregion #endregion
@ -315,14 +282,13 @@ namespace FDK
// #endregion // #endregion
//} //}
#endregion #endregion
else else {
{
#region [ ] #region [ ]
//----------------- //-----------------
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode ) ); throw new Exception(string.Format("BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode));
//----------------- //-----------------
#endregion #endregion
} }
@ -334,21 +300,20 @@ namespace FDK
this.hMixer = BassMix.CreateMixerStream( this.hMixer = BassMix.CreateMixerStream(
info.Frequency, info.Frequency,
info.Channels, info.Channels,
BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode); // デコードのみ発声しない。WASAPIに出力されるだけ。 BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer == 0 ) if (this.hMixer == 0) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
BassWasapi.Free(); BassWasapi.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode ) ); throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode));
} }
// BASS ミキサーの1秒あたりのバイト数を算出。 // BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.ChannelGetInfo( this.hMixer ); var mixerInfo = Bass.ChannelGetInfo(this.hMixer);
long nミキサーの1サンプルあたりのバイト数 = mixerInfo.Channels * 4; // 4 = sizeof(FLOAT) long nミキサーの1サンプルあたりのバイト数 = mixerInfo.Channels * 4; // 4 = sizeof(FLOAT)
this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.Frequency; this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.Frequency;
@ -360,25 +325,23 @@ namespace FDK
this.hMixer_DeviceOut = BassMix.CreateMixerStream( this.hMixer_DeviceOut = BassMix.CreateMixerStream(
info.Frequency, info.Frequency,
info.Channels, info.Channels,
BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode ); // デコードのみ発声しない。WASAPIに出力されるだけ。 BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer_DeviceOut == 0 ) if (this.hMixer_DeviceOut == 0) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
BassWasapi.Free(); BassWasapi.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) ); throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode));
} }
{ {
bool b1 = BassMix.MixerAddChannel( this.hMixer_DeviceOut, this.hMixer, BassFlags.Default ); bool b1 = BassMix.MixerAddChannel(this.hMixer_DeviceOut, this.hMixer, BassFlags.Default);
if ( !b1 ) if (!b1) {
{
Errors errcode = Bass.LastError; Errors errcode = Bass.LastError;
BassWasapi.Free(); BassWasapi.Free();
Bass.Free(); Bass.Free();
this.bIsBASSFree = true; this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) ); throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode));
}; };
} }
@ -388,47 +351,39 @@ namespace FDK
BassWasapi.Start(); BassWasapi.Start();
} }
#region [ tサウンドを作成する() ] #region [ tサウンドを作成する() ]
public CSound tCreateSound( string strファイル名, ESoundGroup soundGroup ) public CSound tCreateSound(string strファイル名, ESoundGroup soundGroup) {
{
var sound = new CSound(soundGroup); var sound = new CSound(soundGroup);
sound.CreateWASAPISound( strファイル名, this.hMixer, this.SoundDeviceType ); sound.CreateWASAPISound(strファイル名, this.hMixer, this.SoundDeviceType);
return sound; return sound;
} }
public void tCreateSound( string strファイル名, CSound sound ) public void tCreateSound(string strファイル名, CSound sound) {
{ sound.CreateWASAPISound(strファイル名, this.hMixer, this.SoundDeviceType);
sound.CreateWASAPISound( strファイル名, this.hMixer, this.SoundDeviceType );
} }
#endregion #endregion
#region [ Dispose-Finallizeパターン実装 ] #region [ Dispose-Finallizeパターン実装 ]
//----------------- //-----------------
public void Dispose() public void Dispose() {
{ this.Dispose(true);
this.Dispose( true ); GC.SuppressFinalize(this);
GC.SuppressFinalize( this );
} }
protected void Dispose( bool bManagedDispose ) protected void Dispose(bool bManagedDispose) {
{ SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (hMixer != -1) {
if ( hMixer != -1 ) Bass.StreamFree(hMixer);
{
Bass.StreamFree( hMixer );
} }
if ( !bIsBASSFree ) if (!bIsBASSFree) {
{ BassWasapi.Free(); // システムタイマより先に呼び出すこと。tWasapi処理() の中でシステムタイマを参照してるため)
BassWasapi.Free(); // システムタイマより先に呼び出すこと。tWasapi処理() の中でシステムタイマを参照してるため)
Bass.Free(); Bass.Free();
} }
if( bManagedDispose ) if (bManagedDispose) {
{
SystemTimer.Dispose(); SystemTimer.Dispose();
SystemTimer = null; SystemTimer = null;
} }
} }
~CSoundDeviceWASAPI() ~CSoundDeviceWASAPI() {
{ this.Dispose(false);
this.Dispose( false );
} }
//----------------- //-----------------
#endregion #endregion
@ -437,31 +392,30 @@ namespace FDK
protected int hMixer_DeviceOut = -1; protected int hMixer_DeviceOut = -1;
protected WasapiProcedure tWasapiProc = null; protected WasapiProcedure tWasapiProc = null;
protected int tWASAPI処理( IntPtr buffer, int length, IntPtr user ) protected int tWASAPI処理(IntPtr buffer, int length, IntPtr user) {
{
// BASSミキサからの出力データをそのまま WASAPI buffer へ丸投げ。 // BASSミキサからの出力データをそのまま WASAPI buffer へ丸投げ。
int num = Bass.ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ int num = Bass.ChannelGetData(this.hMixer_DeviceOut, buffer, length); // num = 実際に転送した長さ
if ( num == -1 ) num = 0; if (num == -1) num = 0;
// 経過時間を更新。 // 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。 // データの転送差分ではなく累積転送バイト数から算出する。
int n未再生バイト数 = BassWasapi.GetData( null, (int) DataFlags.Available ); // 誤差削減のため、必要となるギリギリ直前に取得する。 int n未再生バイト数 = BassWasapi.GetData(null, (int)DataFlags.Available); // 誤差削減のため、必要となるギリギリ直前に取得する。
this.ElapsedTimeMs = ( this.n累積転送バイト数 - n未再生バイト数 ) * 1000 / this.nミキサーの1秒あたりのバイト数; this.ElapsedTimeMs = (this.n累積転送バイト数 - n未再生バイト数) * 1000 / this.nミキサーの1秒あたりのバイト数;
this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs; this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs;
// 実出力遅延を更新。 // 実出力遅延を更新。
// 未再生バイト数の平均値。 // 未再生バイト数の平均値。
long n今回の遅延ms = n未再生バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数; long n今回の遅延ms = n未再生バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数;
this.OutputDelay = ( this.b最初の実出力遅延算出 ) ? n今回の遅延ms : ( this.OutputDelay + n今回の遅延ms ) / 2; this.OutputDelay = (this.b最初の実出力遅延算出) ? n今回の遅延ms : (this.OutputDelay + n今回の遅延ms) / 2;
this.b最初の実出力遅延算出 = false; this.b最初の実出力遅延算出 = false;
// 経過時間を更新後に、今回分の累積転送バイト数を反映。 // 経過時間を更新後に、今回分の累積転送バイト数を反映。
this.n累積転送バイト数 += num; this.n累積転送バイト数 += num;
return num; return num;
} }

View File

@ -1,23 +1,13 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FDK namespace FDK {
{ public class CSoundTimer : CTimerBase {
public class CSoundTimer : CTimerBase public override long SystemTimeMs {
{ get {
public override long SystemTimeMs if (this.Device.SoundDeviceType == ESoundDeviceType.Bass ||
{ this.Device.SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI ||
get
{
if( this.Device.SoundDeviceType == ESoundDeviceType.Bass ||
this.Device.SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI ||
this.Device.SoundDeviceType == ESoundDeviceType.SharedWASAPI || this.Device.SoundDeviceType == ESoundDeviceType.SharedWASAPI ||
this.Device.SoundDeviceType == ESoundDeviceType.ASIO ) this.Device.SoundDeviceType == ESoundDeviceType.ASIO) {
{
// BASS 系の ISoundDevice.n経過時間ms はオーディオバッファの更新間隔ずつでしか更新されないため、単にこれを返すだけではとびとびの値になる。 // BASS 系の ISoundDevice.n経過時間ms はオーディオバッファの更新間隔ずつでしか更新されないため、単にこれを返すだけではとびとびの値になる。
// そこで、更新間隔の最中に呼ばれた場合は、システムタイマを使って補間する。 // そこで、更新間隔の最中に呼ばれた場合は、システムタイマを使って補間する。
// この場合の経過時間との誤差は更新間隔以内に収まるので問題ないと判断する。 // この場合の経過時間との誤差は更新間隔以内に収まるので問題ないと判断する。
@ -25,7 +15,7 @@ namespace FDK
// 動作がおかしくなる。(具体的には、ここで返すタイマー値の逆行が発生し、スクロールが巻き戻る) // 動作がおかしくなる。(具体的には、ここで返すタイマー値の逆行が発生し、スクロールが巻き戻る)
// この場合の対策は、ASIOのバッファ量を増やして、ASIOの音声合成処理の負荷を下げること。 // この場合の対策は、ASIOのバッファ量を増やして、ASIOの音声合成処理の負荷を下げること。
if ( this.Device.UpdateSystemTimeMs == CTimer.UnusedNum ) // #33890 2014.5.27 yyagi if (this.Device.UpdateSystemTimeMs == CTimer.UnusedNum) // #33890 2014.5.27 yyagi
{ {
// 環境によっては、ASIOベースの演奏タイマーが動作する前(つまりASIOのサウンド転送が始まる前)に // 環境によっては、ASIOベースの演奏タイマーが動作する前(つまりASIOのサウンド転送が始まる前)に
// DTXデータの演奏が始まる場合がある。 // DTXデータの演奏が始まる場合がある。
@ -39,18 +29,14 @@ namespace FDK
// 補正部分をゼロにして、n経過時間msだけを返すようにする。 // 補正部分をゼロにして、n経過時間msだけを返すようにする。
// こうすることで、演奏タイマが動作を始めても、破綻しなくなる。 // こうすることで、演奏タイマが動作を始めても、破綻しなくなる。
return this.Device.ElapsedTimeMs; return this.Device.ElapsedTimeMs;
} } else {
else if (FDK.SoundManager.bUseOSTimer)
{
if ( FDK.SoundManager.bUseOSTimer )
//if ( true ) //if ( true )
{ {
return ctDInputTimer.SystemTimeMs; // 仮にCSoundTimerをCTimer相当の動作にしてみた return ctDInputTimer.SystemTimeMs; // 仮にCSoundTimerをCTimer相当の動作にしてみた
} } else {
else
{
return this.Device.ElapsedTimeMs return this.Device.ElapsedTimeMs
+ ( this.Device.SystemTimer.SystemTimeMs - this.Device.UpdateSystemTimeMs ); + (this.Device.SystemTimer.SystemTimeMs - this.Device.UpdateSystemTimeMs);
} }
} }
} }
@ -58,67 +44,60 @@ namespace FDK
} }
} }
internal CSoundTimer( ISoundDevice device ) internal CSoundTimer(ISoundDevice device) {
{
this.Device = device; this.Device = device;
TimerCallback timerDelegate = new TimerCallback(SnapTimers); // CSoundTimerをシステム時刻に変換するために、 TimerCallback timerDelegate = new TimerCallback(SnapTimers); // CSoundTimerをシステム時刻に変換するために、
timer = new Timer(timerDelegate, null, 0, 1000); // CSoundTimerとCTimerを両方とも走らせておき、 timer = new Timer(timerDelegate, null, 0, 1000); // CSoundTimerとCTimerを両方とも走らせておき、
ctDInputTimer = new CTimer(CTimer.TimerType.MultiMedia); // 1秒に1回時差を測定するようにしておく ctDInputTimer = new CTimer(CTimer.TimerType.MultiMedia); // 1秒に1回時差を測定するようにしておく
} }
private void SnapTimers(object o) // 1秒に1回呼び出され、2つのタイマー間の現在値をそれぞれ保持する。 private void SnapTimers(object o) // 1秒に1回呼び出され、2つのタイマー間の現在値をそれぞれ保持する。
{ {
try try {
{
this.nDInputTimerCounter = this.ctDInputTimer.SystemTimeMs; this.nDInputTimerCounter = this.ctDInputTimer.SystemTimeMs;
this.nSoundTimerCounter = this.SystemTimeMs; this.nSoundTimerCounter = this.SystemTimeMs;
//Debug.WriteLine( "BaseCounter: " + nDInputTimerCounter + ", " + nSoundTimerCounter ); //Debug.WriteLine( "BaseCounter: " + nDInputTimerCounter + ", " + nSoundTimerCounter );
} } catch (Exception e)
catch (Exception e) // サウンド設定変更時に、timer.Dispose()した後、timerが実際に停止する前にここに来てしまう場合があり
// サウンド設定変更時に、timer.Dispose()した後、timerが実際に停止する前にここに来てしまう場合があり // その際にNullReferenceExceptionが発生する
// その際にNullReferenceExceptionが発生する // timerが実際に停止したことを検出してから次の設定をすべきだが、実装が難しいため、
// timerが実際に停止したことを検出してから次の設定をすべきだが、実装が難しいため、 // ここで単に例外破棄することで代替する
// ここで単に例外破棄することで代替する {
{
Trace.TraceInformation(e.ToString()); Trace.TraceInformation(e.ToString());
Trace.TraceInformation("FDK: CSoundTimer.SnapTimers(): 例外発生しましたが、継続します。"); Trace.TraceInformation("FDK: CSoundTimer.SnapTimers(): 例外発生しましたが、継続します。");
} }
} }
public long nサウンドタイマーのシステム時刻msへの変換( long nDInputのタイムスタンプ ) public long nサウンドタイマーのシステム時刻msへの変換(long nDInputのタイムスタンプ) {
{ return nDInputのタイムスタンプ - this.nDInputTimerCounter + this.nSoundTimerCounter; // Timer違いによる時差を補正する
return nDInputのタイムスタンプ - this.nDInputTimerCounter + this.nSoundTimerCounter; // Timer違いによる時差を補正する
} }
public override void Dispose() public override void Dispose() {
{
// 特になし; ISoundDevice の解放は呼び出し元で行うこと。 // 特になし; ISoundDevice の解放は呼び出し元で行うこと。
//sendinputスレッド削除 //sendinputスレッド削除
if ( timer != null ) if (timer != null) {
{ timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
timer.Change( System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite );
// ここで、実際にtimerが停止したことを確認するコードを追加すべきだが、やり方わからず。 // ここで、実際にtimerが停止したことを確認するコードを追加すべきだが、やり方わからず。
// 代替策として、SnapTimers()中で、例外発生を破棄している。 // 代替策として、SnapTimers()中で、例外発生を破棄している。
timer.Dispose(); timer.Dispose();
timer = null; timer = null;
} }
if ( ct != null ) if (ct != null) {
{
ct.Pause(); ct.Pause();
ct.Dispose(); ct.Dispose();
ct = null; ct = null;
} }
} }
internal ISoundDevice Device = null; // debugのため、一時的にprotectedをpublicにする。後で元に戻しておくこと。 internal ISoundDevice Device = null; // debugのため、一時的にprotectedをpublicにする。後で元に戻しておくこと。
//protected Thread thSendInput = null; //protected Thread thSendInput = null;
//protected Thread thSnapTimers = null; //protected Thread thSnapTimers = null;
private CTimer ctDInputTimer = null; private CTimer ctDInputTimer = null;
private long nDInputTimerCounter = 0; private long nDInputTimerCounter = 0;
private long nSoundTimerCounter = 0; private long nSoundTimerCounter = 0;
Timer timer = null; Timer timer = null;
private CTimer ct = null; // TESTCODE private CTimer ct = null; // TESTCODE
} }
} }

View File

@ -1,11 +1,5 @@
using System; namespace FDK {
using System.Collections.Generic; public enum ESoundDeviceType {
using System.Text;
namespace FDK
{
public enum ESoundDeviceType
{
Bass, Bass,
ExclusiveWASAPI, ExclusiveWASAPI,
SharedWASAPI, SharedWASAPI,

View File

@ -1,11 +1,9 @@
namespace FDK namespace FDK {
{ public enum ESoundGroup {
public enum ESoundGroup SoundEffect = 1,
{ Voice = 2,
SoundEffect = 1, SongPreview = 3,
Voice = 2, SongPlayback = 4,
SongPreview = 3, Unknown = 0
SongPlayback = 4, }
Unknown = 0
}
} }

View File

@ -1,26 +1,18 @@
using System; using ManagedBass;
using System.Collections.Generic;
using System.Text;
using ManagedBass;
using ManagedBass.Mix; using ManagedBass.Mix;
namespace FDK.BassMixExtension namespace FDK.BassMixExtension {
{ public static class BassMixExtensions {
public static class BassMixExtensions public static bool ChannelPlay(int hHandle) {
{ return BassMix.ChannelRemoveFlag(hHandle, BassFlags.MixerChanPause);
public static bool ChannelPlay(int hHandle) }
{
return BassMix.ChannelRemoveFlag(hHandle, BassFlags.MixerChanPause);
}
public static bool ChannelPause(int hHandle) public static bool ChannelPause(int hHandle) {
{ return BassMix.ChannelAddFlag(hHandle, BassFlags.MixerChanPause);
return BassMix.ChannelAddFlag(hHandle, BassFlags.MixerChanPause); }
}
public static bool ChannelIsPlaying(int hHandle) public static bool ChannelIsPlaying(int hHandle) {
{ return !BassMix.ChannelHasFlag(hHandle, BassFlags.MixerChanPause);
return !BassMix.ChannelHasFlag(hHandle, BassFlags.MixerChanPause); }
} }
} }
}

View File

@ -1,12 +1,5 @@
using System; namespace FDK {
using System.Collections.Generic; internal interface ISoundDevice : IDisposable {
using System.Text;
using System.Diagnostics;
namespace FDK
{
internal interface ISoundDevice : IDisposable
{
ESoundDeviceType SoundDeviceType { get; } ESoundDeviceType SoundDeviceType { get; }
int nMasterVolume { get; set; } int nMasterVolume { get; set; }
long OutputDelay { get; } long OutputDelay { get; }
@ -15,7 +8,7 @@ namespace FDK
long UpdateSystemTimeMs { get; } long UpdateSystemTimeMs { get; }
CTimer SystemTimer { get; } CTimer SystemTimer { get; }
CSound tCreateSound( string strファイル名, ESoundGroup soundGroup ); CSound tCreateSound(string strファイル名, ESoundGroup soundGroup);
void tCreateSound( string strファイル名, CSound sound ); void tCreateSound(string strファイル名, CSound sound);
} }
} }

View File

@ -1,22 +1,17 @@
using System; namespace FDK {
/// <summary>
/// The LoudnessMetadata structure is used to carry, and assist with
/// calculations related to, integrated loudness and true peak
/// loudness.
/// </summary>
[Serializable]
public struct LoudnessMetadata {
public readonly Lufs Integrated;
public readonly Lufs? TruePeak;
namespace FDK public LoudnessMetadata(Lufs integrated, Lufs? truePeak) {
{ Integrated = integrated;
/// <summary> TruePeak = truePeak;
/// The LoudnessMetadata structure is used to carry, and assist with }
/// calculations related to, integrated loudness and true peak }
/// loudness. }
/// </summary>
[Serializable]
public struct LoudnessMetadata
{
public readonly Lufs Integrated;
public readonly Lufs? TruePeak;
public LoudnessMetadata(Lufs integrated, Lufs? truePeak)
{
Integrated = integrated;
TruePeak = truePeak;
}
}
}

View File

@ -1,357 +1,296 @@
using System; using System.ComponentModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.XPath; using System.Xml.XPath;
namespace FDK namespace FDK {
{ /// <summary>
/// <summary> /// The LoudnessMetadataScanner plays two roles:
/// The LoudnessMetadataScanner plays two roles: /// 1. Scanning of song audio files using BS1770GAIN (http://bs1770gain.sourceforge.net/)
/// 1. Scanning of song audio files using BS1770GAIN (http://bs1770gain.sourceforge.net/) /// to determine their perceived loudness. Running on a background thread while not
/// to determine their perceived loudness. Running on a background thread while not /// in song gameplay, songs without existing loudness metadata files (e.g. *.bs1770gain.xml)
/// in song gameplay, songs without existing loudness metadata files (e.g. *.bs1770gain.xml) /// have their perceived loudness determined and saved into an associated metadata file
/// have their perceived loudness determined and saved into an associated metadata file /// without modifying the original audio file. This scanning process begins running
/// without modifying the original audio file. This scanning process begins running /// with scanning jobs ordered based on the order in which songs are enumerated when
/// with scanning jobs ordered based on the order in which songs are enumerated when /// the application starts, but shifts to prioritize songs which are browsed and previewed
/// the application starts, but shifts to prioritize songs which are browsed and previewed /// while on the song select screen.
/// while on the song select screen. /// 2. Loading of loudness metadata from the BS1770GAIN metadata file alongside each audio file.
/// 2. Loading of loudness metadata from the BS1770GAIN metadata file alongside each audio file. /// This occurs when parsing .tja files, when song preview begins, and when song playback
/// This occurs when parsing .tja files, when song preview begins, and when song playback /// begins. When no file is available on disk, a scanning job is passed to the background
/// begins. When no file is available on disk, a scanning job is passed to the background /// scanning thread for processing. The loaded metadata is then passed into the
/// scanning thread for processing. The loaded metadata is then passed into the /// SongGainController for combination with a configured target loudness, resulting in a
/// SongGainController for combination with a configured target loudness, resulting in a /// gain value assigned to the sound object just before playback begins.
/// gain value assigned to the sound object just before playback begins. /// </summary>
/// </summary> public static class LoudnessMetadataScanner {
public static class LoudnessMetadataScanner private const string Bs1770GainExeFileName = "bs1770gain.exe";
{
private const string Bs1770GainExeFileName = "bs1770gain.exe";
private static readonly Stack<string> Jobs = new Stack<string>(); private static readonly Stack<string> Jobs = new Stack<string>();
private static readonly object LockObject = new object(); private static readonly object LockObject = new object();
private static readonly Queue<double> RecentFileScanDurations = new Queue<double>(); private static readonly Queue<double> RecentFileScanDurations = new Queue<double>();
private static Thread ScanningThread; private static Thread ScanningThread;
private static Semaphore Semaphore; private static Semaphore Semaphore;
public static void StartBackgroundScanning() public static void StartBackgroundScanning() {
{ var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StartBackgroundScanning)}";
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StartBackgroundScanning)}";
if (!IsBs1770GainAvailable()) if (!IsBs1770GainAvailable()) {
{ Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is not available. A background scanning thread will not be started.");
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is not available. A background scanning thread will not be started."); return;
return; }
}
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is available. Starting background scanning thread..."); Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is available. Starting background scanning thread...");
lock (LockObject) lock (LockObject) {
{ Semaphore = new Semaphore(Jobs.Count, int.MaxValue);
Semaphore = new Semaphore(Jobs.Count, int.MaxValue); ScanningThread = new Thread(Scan) {
ScanningThread = new Thread(Scan) IsBackground = true,
{ Name = "LoudnessMetadataScanner background scanning thread.",
IsBackground = true, Priority = ThreadPriority.Lowest
Name = "LoudnessMetadataScanner background scanning thread.", };
Priority = ThreadPriority.Lowest ScanningThread.Start();
}; }
ScanningThread.Start();
}
Trace.TraceInformation($"{tracePrefix}: Background scanning thread started."); Trace.TraceInformation($"{tracePrefix}: Background scanning thread started.");
} }
public static void StopBackgroundScanning(bool joinImmediately) public static void StopBackgroundScanning(bool joinImmediately) {
{ var scanningThread = ScanningThread;
var scanningThread = ScanningThread;
if (scanningThread == null) if (scanningThread == null) {
{ return;
return; }
}
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StopBackgroundScanning)}"; var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StopBackgroundScanning)}";
Trace.TraceInformation($"{tracePrefix}: Stopping background scanning thread..."); Trace.TraceInformation($"{tracePrefix}: Stopping background scanning thread...");
lock (LockObject) lock (LockObject) {
{ ScanningThread = null;
ScanningThread = null; Semaphore.Release();
Semaphore.Release(); Semaphore = null;
Semaphore = null; }
}
if (joinImmediately) if (joinImmediately) {
{ scanningThread.Join();
scanningThread.Join(); }
}
Trace.TraceInformation($"{tracePrefix}: Background scanning thread stopped."); Trace.TraceInformation($"{tracePrefix}: Background scanning thread stopped.");
} }
public static LoudnessMetadata? LoadForAudioPath(string absoluteBgmPath) public static LoudnessMetadata? LoadForAudioPath(string absoluteBgmPath) {
{ try {
try var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
{
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath)) if (File.Exists(loudnessMetadataPath)) {
{ return LoadFromMetadataPath(loudnessMetadataPath);
return LoadFromMetadataPath(loudnessMetadataPath); }
}
SubmitForBackgroundScanning(absoluteBgmPath); SubmitForBackgroundScanning(absoluteBgmPath);
} } catch (Exception e) {
catch (Exception e) var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadForAudioPath)}";
{ Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to load {absoluteBgmPath}");
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadForAudioPath)}"; Trace.TraceError(e.ToString());
Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to load {absoluteBgmPath}"); }
Trace.TraceError(e.ToString());
}
return null; return null;
} }
private static string GetLoudnessMetadataPath(string absoluteBgmPath) private static string GetLoudnessMetadataPath(string absoluteBgmPath) {
{ return Path.Combine(
return Path.Combine( Path.GetDirectoryName(absoluteBgmPath),
Path.GetDirectoryName(absoluteBgmPath), Path.GetFileNameWithoutExtension(absoluteBgmPath) + ".bs1770gain.xml");
Path.GetFileNameWithoutExtension(absoluteBgmPath) + ".bs1770gain.xml"); }
}
private static LoudnessMetadata? LoadFromMetadataPath(string loudnessMetadataPath) private static LoudnessMetadata? LoadFromMetadataPath(string loudnessMetadataPath) {
{ XPathDocument xPathDocument;
XPathDocument xPathDocument; try {
try xPathDocument = new XPathDocument(loudnessMetadataPath);
{ } catch (IOException) {
xPathDocument = new XPathDocument(loudnessMetadataPath); var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
} Trace.TraceWarning($"{tracePrefix}: Encountered IOException while attempting to read {loudnessMetadataPath}. This can occur when attempting to load while scanning the same file. Returning null...");
catch (IOException) return null;
{ }
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered IOException while attempting to read {loudnessMetadataPath}. This can occur when attempting to load while scanning the same file. Returning null...");
return null;
}
var trackNavigator = xPathDocument.CreateNavigator() var trackNavigator = xPathDocument.CreateNavigator()
.SelectSingleNode(@"//bs1770gain/track[@ToTal=""1"" and @Number=""1""]"); .SelectSingleNode(@"//bs1770gain/track[@ToTal=""1"" and @Number=""1""]");
var integratedLufsNode = trackNavigator?.SelectSingleNode(@"integrated/@lufs"); var integratedLufsNode = trackNavigator?.SelectSingleNode(@"integrated/@lufs");
var truePeakTpfsNode = trackNavigator?.SelectSingleNode(@"true-peak/@tpfs"); var truePeakTpfsNode = trackNavigator?.SelectSingleNode(@"true-peak/@tpfs");
if (trackNavigator == null || integratedLufsNode == null || truePeakTpfsNode == null) if (trackNavigator == null || integratedLufsNode == null || truePeakTpfsNode == null) {
{ var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}"; Trace.TraceWarning($"{tracePrefix}: Encountered incorrect xml element structure while parsing {loudnessMetadataPath}. Returning null...");
Trace.TraceWarning($"{tracePrefix}: Encountered incorrect xml element structure while parsing {loudnessMetadataPath}. Returning null..."); return null;
return null; }
}
var integrated = integratedLufsNode.ValueAsDouble; var integrated = integratedLufsNode.ValueAsDouble;
var truePeak = truePeakTpfsNode.ValueAsDouble; var truePeak = truePeakTpfsNode.ValueAsDouble;
if (integrated <= -70.0 || truePeak >= 12.04) if (integrated <= -70.0 || truePeak >= 12.04) {
{ var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}"; Trace.TraceWarning($"{tracePrefix}: Encountered evidence of extreme clipping while parsing {loudnessMetadataPath}. Returning null...");
Trace.TraceWarning($"{tracePrefix}: Encountered evidence of extreme clipping while parsing {loudnessMetadataPath}. Returning null..."); return null;
return null; }
}
return new LoudnessMetadata(new Lufs(integrated), new Lufs(truePeak)); return new LoudnessMetadata(new Lufs(integrated), new Lufs(truePeak));
} }
private static void SubmitForBackgroundScanning(string absoluteBgmPath) private static void SubmitForBackgroundScanning(string absoluteBgmPath) {
{ lock (LockObject) {
lock (LockObject) // Quite often, the loading process will cause the same job to be submitted many times.
{ // As such, we'll do a quick check as when this happens an equivalent job will often
// Quite often, the loading process will cause the same job to be submitted many times. // already be at the top of the stack and we need not add it again.
// As such, we'll do a quick check as when this happens an equivalent job will often //
// already be at the top of the stack and we need not add it again. // Note that we will not scan the whole stack as that is an O(n) operation on the main
// // thread, whereas redundant file existence checks on the background thread are not harmful.
// Note that we will not scan the whole stack as that is an O(n) operation on the main //
// thread, whereas redundant file existence checks on the background thread are not harmful. // We also do not want to scan the whole stack, for example to skip pushing a new item onto it,
// // because we want to re-submit jobs as the user interacts with their data, usually by
// We also do not want to scan the whole stack, for example to skip pushing a new item onto it, // scrolling through songs and previewing them. Their current interests should drive
// because we want to re-submit jobs as the user interacts with their data, usually by // scanning priorities, and it is for this reason that a stack is used instead of a queue.
// scrolling through songs and previewing them. Their current interests should drive var semaphore = Semaphore;
// scanning priorities, and it is for this reason that a stack is used instead of a queue. if (semaphore != null && (Jobs.Count == 0 || Jobs.Peek() != absoluteBgmPath)) {
var semaphore = Semaphore; Jobs.Push(absoluteBgmPath);
if (semaphore != null && (Jobs.Count == 0 || Jobs.Peek() != absoluteBgmPath)) semaphore.Release();
{ }
Jobs.Push(absoluteBgmPath); }
semaphore.Release(); }
}
}
}
private static void Scan() private static void Scan() {
{ try {
try while (true) {
{ RaiseScanningStateChanged(false);
while (true)
{
RaiseScanningStateChanged(false);
Semaphore?.WaitOne(); Semaphore?.WaitOne();
if (ScanningThread == null) if (ScanningThread == null) {
{ return;
return; }
}
RaiseScanningStateChanged(true); RaiseScanningStateChanged(true);
int jobCount; int jobCount;
string absoluteBgmPath; string absoluteBgmPath;
lock (LockObject) lock (LockObject) {
{ jobCount = Jobs.Count;
jobCount = Jobs.Count; absoluteBgmPath = Jobs.Pop();
absoluteBgmPath = Jobs.Pop(); }
}
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}"; var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
try try {
{ if (!File.Exists(absoluteBgmPath)) {
if (!File.Exists(absoluteBgmPath)) Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Missing audio file. Skipping {absoluteBgmPath}...");
{ continue;
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Missing audio file. Skipping {absoluteBgmPath}..."); }
continue;
}
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath); var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath)) if (File.Exists(loudnessMetadataPath)) {
{ Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Pre-existing metadata. Skipping {absoluteBgmPath}...");
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Pre-existing metadata. Skipping {absoluteBgmPath}..."); continue;
continue; }
}
Trace.TraceInformation($"{tracePrefix}: Scanning jobs outstanding: {jobCount}. Scanning {absoluteBgmPath}..."); Trace.TraceInformation($"{tracePrefix}: Scanning jobs outstanding: {jobCount}. Scanning {absoluteBgmPath}...");
var stopwatch = Stopwatch.StartNew(); var stopwatch = Stopwatch.StartNew();
File.Delete(loudnessMetadataPath); File.Delete(loudnessMetadataPath);
var arguments = $"-it --xml -f \"{Path.GetFileName(loudnessMetadataPath)}\" \"{Path.GetFileName(absoluteBgmPath)}\""; var arguments = $"-it --xml -f \"{Path.GetFileName(loudnessMetadataPath)}\" \"{Path.GetFileName(absoluteBgmPath)}\"";
Execute(Path.GetDirectoryName(absoluteBgmPath), Bs1770GainExeFileName, arguments, true); Execute(Path.GetDirectoryName(absoluteBgmPath), Bs1770GainExeFileName, arguments, true);
var seconds = stopwatch.Elapsed.TotalSeconds; var seconds = stopwatch.Elapsed.TotalSeconds;
RecentFileScanDurations.Enqueue(seconds); RecentFileScanDurations.Enqueue(seconds);
while (RecentFileScanDurations.Count > 20) while (RecentFileScanDurations.Count > 20) {
{ RecentFileScanDurations.Dequeue();
RecentFileScanDurations.Dequeue(); }
} var averageSeconds = RecentFileScanDurations.Average();
var averageSeconds = RecentFileScanDurations.Average(); Trace.TraceInformation($"{tracePrefix}: Scanned in {seconds}s. Estimated remaining: {(int)(averageSeconds * (jobCount - 1))}s.");
Trace.TraceInformation($"{tracePrefix}: Scanned in {seconds}s. Estimated remaining: {(int)(averageSeconds * (jobCount - 1))}s."); } catch (Exception e) {
} Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to scan {absoluteBgmPath}");
catch (Exception e) Trace.TraceError(e.ToString());
{ }
Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to scan {absoluteBgmPath}"); }
Trace.TraceError(e.ToString()); } catch (Exception e) {
} var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
} Trace.TraceError($"{tracePrefix}: caught an exception at the level of the thread method. The background scanning thread will now terminate.");
} Trace.TraceError(e.ToString());
catch (Exception e) }
{ }
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
Trace.TraceError($"{tracePrefix}: caught an exception at the level of the thread method. The background scanning thread will now terminate.");
Trace.TraceError(e.ToString());
}
}
private static bool IsBs1770GainAvailable() private static bool IsBs1770GainAvailable() {
{ try {
try Execute(null, Bs1770GainExeFileName, "-h");
{ return true;
Execute(null, Bs1770GainExeFileName, "-h"); } catch (Win32Exception) {
return true; return false;
} } catch (Exception e) {
catch (Win32Exception) var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(IsBs1770GainAvailable)}";
{ Trace.TraceError($"{tracePrefix}: Encountered an exception. Returning false...");
return false; Trace.TraceError(e.ToString());
}
catch (Exception e)
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(IsBs1770GainAvailable)}";
Trace.TraceError($"{tracePrefix}: Encountered an exception. Returning false...");
Trace.TraceError(e.ToString());
return false; return false;
} }
} }
private static string Execute( private static string Execute(
string workingDirectory, string fileName, string arguments, bool shouldFailOnStdErrDataReceived = false) string workingDirectory, string fileName, string arguments, bool shouldFailOnStdErrDataReceived = false) {
{ var processStartInfo = new ProcessStartInfo(fileName, arguments) {
var processStartInfo = new ProcessStartInfo(fileName, arguments) CreateNoWindow = true,
{ RedirectStandardError = true,
CreateNoWindow = true, RedirectStandardOutput = true,
RedirectStandardError = true, UseShellExecute = false,
RedirectStandardOutput = true, WorkingDirectory = workingDirectory ?? ""
UseShellExecute = false, };
WorkingDirectory = workingDirectory ?? ""
};
var stdoutWriter = new StringWriter(); var stdoutWriter = new StringWriter();
var stderrWriter = new StringWriter(); var stderrWriter = new StringWriter();
using (var process = Process.Start(processStartInfo)) using (var process = Process.Start(processStartInfo)) {
{ process.OutputDataReceived += (s, e) => {
process.OutputDataReceived += (s, e) => if (e.Data != null) {
{ stdoutWriter.Write(e.Data);
if (e.Data != null) stdoutWriter.Write(Environment.NewLine);
{ }
stdoutWriter.Write(e.Data); };
stdoutWriter.Write(Environment.NewLine);
}
};
var errorDataReceived = false; var errorDataReceived = false;
process.ErrorDataReceived += (s, e) => process.ErrorDataReceived += (s, e) => {
{ if (e.Data != null) {
if (e.Data != null) errorDataReceived = true;
{ stderrWriter.Write(e.Data);
errorDataReceived = true; stderrWriter.Write(Environment.NewLine);
stderrWriter.Write(e.Data); }
stderrWriter.Write(Environment.NewLine); };
}
};
process.BeginOutputReadLine(); process.BeginOutputReadLine();
process.BeginErrorReadLine(); process.BeginErrorReadLine();
process.WaitForExit(); process.WaitForExit();
if ((shouldFailOnStdErrDataReceived && errorDataReceived) || process.ExitCode != 0) if ((shouldFailOnStdErrDataReceived && errorDataReceived) || process.ExitCode != 0) {
{ var stderr = stderrWriter.ToString();
var stderr = stderrWriter.ToString(); if (string.IsNullOrEmpty(stderr)) {
if (string.IsNullOrEmpty(stderr)) stderr = stdoutWriter.ToString();
{ }
stderr = stdoutWriter.ToString();
}
throw new Exception( throw new Exception(
$"Execution of {processStartInfo.FileName} with arguments {processStartInfo.Arguments} failed with exit code {process.ExitCode}: {stderr}"); $"Execution of {processStartInfo.FileName} with arguments {processStartInfo.Arguments} failed with exit code {process.ExitCode}: {stderr}");
} }
return stdoutWriter.ToString(); return stdoutWriter.ToString();
} }
} }
private static void RaiseScanningStateChanged(bool isActivelyScanning) private static void RaiseScanningStateChanged(bool isActivelyScanning) {
{ ScanningStateChanged?.Invoke(null, new ScanningStateChangedEventArgs(isActivelyScanning));
ScanningStateChanged?.Invoke(null, new ScanningStateChangedEventArgs(isActivelyScanning)); }
}
public class ScanningStateChangedEventArgs : EventArgs public class ScanningStateChangedEventArgs : EventArgs {
{ public ScanningStateChangedEventArgs(bool isActivelyScanning) {
public ScanningStateChangedEventArgs(bool isActivelyScanning) IsActivelyScanning = isActivelyScanning;
{ }
IsActivelyScanning = isActivelyScanning;
}
public bool IsActivelyScanning { get; private set; } public bool IsActivelyScanning { get; private set; }
} }
public static event EventHandler<ScanningStateChangedEventArgs> ScanningStateChanged; public static event EventHandler<ScanningStateChangedEventArgs> ScanningStateChanged;
} }
} }

View File

@ -1,47 +1,37 @@
using System; namespace FDK {
/// <summary>
/// The Lufs structure is used to carry, and assist with calculations related to,
/// Loudness Units relative to Full Scale. LUFS are measured in absolute scale
/// and whole values represent one decibel.
/// </summary>
[Serializable]
public struct Lufs {
private readonly double _value;
namespace FDK public Lufs(double value) {
{ _value = value;
/// <summary> }
/// The Lufs structure is used to carry, and assist with calculations related to,
/// Loudness Units relative to Full Scale. LUFS are measured in absolute scale
/// and whole values represent one decibel.
/// </summary>
[Serializable]
public struct Lufs
{
private readonly double _value;
public Lufs(double value) public double ToDouble() => _value;
{
_value = value;
}
public double ToDouble() => _value; public Lufs Min(Lufs lufs) {
return new Lufs(Math.Min(_value, lufs._value));
}
public Lufs Min(Lufs lufs) public Lufs Negate() {
{ return new Lufs(-_value);
return new Lufs(Math.Min(_value, lufs._value)); }
}
public Lufs Negate() public override string ToString() {
{ return _value.ToString();
return new Lufs(-_value); }
}
public override string ToString() public static Lufs operator -(Lufs left, Lufs right) {
{ return new Lufs(left._value - right._value);
return _value.ToString(); }
}
public static Lufs operator- (Lufs left, Lufs right) public static Lufs operator +(Lufs left, Lufs right) {
{ return new Lufs(left._value + right._value);
return new Lufs(left._value - right._value); }
} }
public static Lufs operator+ (Lufs left, Lufs right)
{
return new Lufs(left._value + right._value);
}
}
} }

View File

@ -1,32 +1,26 @@
namespace FDK namespace FDK {
{ /// <summary>
/// <summary> /// SongGainController provides a central place through which song preview
/// SongGainController provides a central place through which song preview /// and song playback attempt to apply BS1770GAIN-based loudness metadata
/// and song playback attempt to apply BS1770GAIN-based loudness metadata /// or .tja SONGVOL as the Gain of a song sound.
/// or .tja SONGVOL as the Gain of a song sound. ///
/// /// By doing so through SongGainController instead of directly against the
/// By doing so through SongGainController instead of directly against the /// song (preview) CSound object, SongGainController can override the Gain
/// song (preview) CSound object, SongGainController can override the Gain /// value based on configuration or other information.
/// value based on configuration or other information. /// </summary>
/// </summary> public sealed class SongGainController {
public sealed class SongGainController public bool ApplyLoudnessMetadata { private get; set; }
{ public Lufs TargetLoudness { private get; set; }
public bool ApplyLoudnessMetadata { private get; set; } public bool ApplySongVol { private get; set; }
public Lufs TargetLoudness { private get; set; }
public bool ApplySongVol { private get; set; }
public void Set(int songVol, LoudnessMetadata? songLoudnessMetadata, CSound sound) public void Set(int songVol, LoudnessMetadata? songLoudnessMetadata, CSound sound) {
{ if (ApplyLoudnessMetadata && songLoudnessMetadata.HasValue) {
if (ApplyLoudnessMetadata && songLoudnessMetadata.HasValue) var gain = TargetLoudness - songLoudnessMetadata.Value.Integrated;
{
var gain = TargetLoudness - songLoudnessMetadata.Value.Integrated;
sound.SetGain(gain, songLoudnessMetadata.Value.TruePeak); sound.SetGain(gain, songLoudnessMetadata.Value.TruePeak);
} } else {
else sound.SetGain(ApplySongVol ? songVol : CSound.DefaultSongVol);
{ }
sound.SetGain(ApplySongVol ? songVol : CSound.DefaultSongVol); }
} }
}
}
} }

View File

@ -1,132 +1,113 @@
using System; using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using FDK.ExtensionMethods; using FDK.ExtensionMethods;
namespace FDK namespace FDK {
{ /// <summary>
/// <summary> /// SoundGroupLevelController holds the current sound level value for each
/// SoundGroupLevelController holds the current sound level value for each /// of the unique sound groups, along with an increment by which they can
/// of the unique sound groups, along with an increment by which they can /// easily be adjusted.
/// easily be adjusted. ///
/// /// Configuration changes to the sound group levels are provided to the
/// Configuration changes to the sound group levels are provided to the /// controller via binding code which allows CConfigIni and
/// controller via binding code which allows CConfigIni and /// SoundGroupLevelController to be unaware of one another.
/// SoundGroupLevelController to be unaware of one another. /// See ConfigIniToSoundGroupLevelControllerBinder for more details.
/// See ConfigIniToSoundGroupLevelControllerBinder for more details. ///
/// /// Dynamic adjustment of sound group levels during song selection and song
/// Dynamic adjustment of sound group levels during song selection and song /// playback are managed via a small dependency taken by the respective
/// playback are managed via a small dependency taken by the respective /// stage classes. See KeyboardSoundGroupLevelControlHandler and its usages
/// stage classes. See KeyboardSoundGroupLevelControlHandler and its usages /// for more details.
/// for more details. ///
/// /// As new sound objects are created, including when reloading sounds due
/// As new sound objects are created, including when reloading sounds due /// to a changer in audio output device, SoundGroupLevelController ensures
/// to a changer in audio output device, SoundGroupLevelController ensures /// that they are provided with the current level for their associated
/// that they are provided with the current level for their associated /// sound group by subscribing to notifications regarding changes to a
/// sound group by subscribing to notifications regarding changes to a /// collection of sound objects provided during construction. This
/// collection of sound objects provided during construction. This /// observable collection comes from the sound manager, but without either
/// observable collection comes from the sound manager, but without either /// it or this class being directly aware of one another.
/// it or this class being directly aware of one another. ///
/// /// As sound group levels are changed, SoundGroupLevelController updates
/// As sound group levels are changed, SoundGroupLevelController updates /// all existing sound objects group levels by iterating that same
/// all existing sound objects group levels by iterating that same /// observable collection.
/// observable collection. /// </summary>
/// </summary> public sealed class SoundGroupLevelController {
public sealed class SoundGroupLevelController private readonly Dictionary<ESoundGroup, int> _levelBySoundGroup = new Dictionary<ESoundGroup, int> {
{ [ESoundGroup.SoundEffect] = CSound.MaximumGroupLevel,
private readonly Dictionary<ESoundGroup, int> _levelBySoundGroup = new Dictionary<ESoundGroup, int> [ESoundGroup.Voice] = CSound.MaximumGroupLevel,
{ [ESoundGroup.SongPreview] = CSound.MaximumGroupLevel,
[ESoundGroup.SoundEffect] = CSound.MaximumGroupLevel, [ESoundGroup.SongPlayback] = CSound.MaximumGroupLevel,
[ESoundGroup.Voice] = CSound.MaximumGroupLevel, [ESoundGroup.Unknown] = CSound.MaximumGroupLevel
[ESoundGroup.SongPreview] = CSound.MaximumGroupLevel, };
[ESoundGroup.SongPlayback] = CSound.MaximumGroupLevel,
[ESoundGroup.Unknown] = CSound.MaximumGroupLevel
};
private readonly ObservableCollection<CSound> _sounds; private readonly ObservableCollection<CSound> _sounds;
private int _keyboardSoundLevelIncrement; private int _keyboardSoundLevelIncrement;
public SoundGroupLevelController(ObservableCollection<CSound> sounds) public SoundGroupLevelController(ObservableCollection<CSound> sounds) {
{ _sounds = sounds;
_sounds = sounds;
_sounds.CollectionChanged += SoundsOnCollectionChanged; _sounds.CollectionChanged += SoundsOnCollectionChanged;
} }
public void SetLevel(ESoundGroup soundGroup, int level) public void SetLevel(ESoundGroup soundGroup, int level) {
{ var clampedLevel = level.Clamp(CSound.MinimumGroupLevel, CSound.MaximumGroupLevel);
var clampedLevel = level.Clamp(CSound.MinimumGroupLevel, CSound.MaximumGroupLevel);
if (_levelBySoundGroup[soundGroup] == clampedLevel) if (_levelBySoundGroup[soundGroup] == clampedLevel) {
{ return;
return; }
}
_levelBySoundGroup[soundGroup] = clampedLevel; _levelBySoundGroup[soundGroup] = clampedLevel;
foreach (var sound in _sounds) foreach (var sound in _sounds) {
{ if (sound.SoundGroup == soundGroup) {
if (sound.SoundGroup == soundGroup) SetLevel(sound);
{ }
SetLevel(sound); }
}
}
RaiseLevelChanged(soundGroup, clampedLevel); RaiseLevelChanged(soundGroup, clampedLevel);
} }
public void SetKeyboardSoundLevelIncrement(int keyboardSoundLevelIncrement) public void SetKeyboardSoundLevelIncrement(int keyboardSoundLevelIncrement) {
{ _keyboardSoundLevelIncrement = keyboardSoundLevelIncrement;
_keyboardSoundLevelIncrement = keyboardSoundLevelIncrement; }
}
public void AdjustLevel(ESoundGroup soundGroup, bool isAdjustmentPositive) public void AdjustLevel(ESoundGroup soundGroup, bool isAdjustmentPositive) {
{ var adjustmentIncrement = isAdjustmentPositive
var adjustmentIncrement = isAdjustmentPositive ? _keyboardSoundLevelIncrement
? _keyboardSoundLevelIncrement : -_keyboardSoundLevelIncrement;
: -_keyboardSoundLevelIncrement;
SetLevel(soundGroup, _levelBySoundGroup[soundGroup] + adjustmentIncrement); SetLevel(soundGroup, _levelBySoundGroup[soundGroup] + adjustmentIncrement);
} }
private void SetLevel(CSound sound) private void SetLevel(CSound sound) {
{ sound.GroupLevel = _levelBySoundGroup[sound.SoundGroup];
sound.GroupLevel = _levelBySoundGroup[sound.SoundGroup]; }
}
private void SoundsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void SoundsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
{ switch (e.Action) {
switch (e.Action) case NotifyCollectionChangedAction.Add:
{ case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Add: foreach (CSound sound in e.NewItems) {
case NotifyCollectionChangedAction.Replace: SetLevel(sound);
foreach (CSound sound in e.NewItems) }
{ break;
SetLevel(sound); }
} }
break;
}
}
private void RaiseLevelChanged(ESoundGroup soundGroup, int level) private void RaiseLevelChanged(ESoundGroup soundGroup, int level) {
{ LevelChanged?.Invoke(this, new LevelChangedEventArgs(soundGroup, level));
LevelChanged?.Invoke(this, new LevelChangedEventArgs(soundGroup, level)); }
}
public class LevelChangedEventArgs : EventArgs public class LevelChangedEventArgs : EventArgs {
{ public LevelChangedEventArgs(ESoundGroup soundGroup, int level) {
public LevelChangedEventArgs(ESoundGroup soundGroup, int level) SoundGroup = soundGroup;
{ Level = level;
SoundGroup = soundGroup; }
Level = level;
}
public ESoundGroup SoundGroup { get; private set; } public ESoundGroup SoundGroup { get; private set; }
public int Level { get; private set; } public int Level { get; private set; }
} }
public event EventHandler<LevelChangedEventArgs> LevelChanged; public event EventHandler<LevelChangedEventArgs> LevelChanged;
} }
} }

View File

@ -1,49 +1,32 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Linq;
using System.Threading;
using FDK.ExtensionMethods;
using ManagedBass; using ManagedBass;
using ManagedBass.Asio;
using ManagedBass.Wasapi;
using ManagedBass.Mix;
using ManagedBass.Fx;
using Silk.NET.Windowing; using Silk.NET.Windowing;
using FDK.BassMixExtension;
namespace FDK namespace FDK {
{ public class SoundManager // : CSound
public class SoundManager // : CSound
{ {
private static ISoundDevice SoundDevice private static ISoundDevice SoundDevice {
{
get; set; get; set;
} }
private static ESoundDeviceType SoundDeviceType private static ESoundDeviceType SoundDeviceType {
{
get; set; get; set;
} }
public static CSoundTimer PlayTimer = null; public static CSoundTimer PlayTimer = null;
public static bool bUseOSTimer = false; // OSのタイマーを使うか、CSoundTimerを使うか。DTXCではfalse, DTXManiaではtrue。 public static bool bUseOSTimer = false; // OSのタイマーを使うか、CSoundTimerを使うか。DTXCではfalse, DTXManiaではtrue。
// DTXC(DirectSound)でCSoundTimerを使うと、内部で無音のループサウンドを再生するため // DTXC(DirectSound)でCSoundTimerを使うと、内部で無音のループサウンドを再生するため
// サウンドデバイスを占有してしまい、Viewerとして呼び出されるDTXManiaで、ASIOが使えなくなる。 // サウンドデバイスを占有してしまい、Viewerとして呼び出されるDTXManiaで、ASIOが使えなくなる。
// DTXMania単体でこれをtrueにすると、WASAPI/ASIO時に演奏タイマーとしてFDKタイマーではなく // DTXMania単体でこれをtrueにすると、WASAPI/ASIO時に演奏タイマーとしてFDKタイマーではなく
// システムのタイマーを使うようになる。こうするとスクロールは滑らかになるが、音ズレが出るかもしれない。 // システムのタイマーを使うようになる。こうするとスクロールは滑らかになるが、音ズレが出るかもしれない。
public static bool bIsTimeStretch = false; public static bool bIsTimeStretch = false;
private static IWindow Window_; private static IWindow Window_;
private static int _nMasterVolume; private static int _nMasterVolume;
public int nMasterVolume public int nMasterVolume {
{ get {
get
{
return _nMasterVolume; return _nMasterVolume;
} }
//get //get
@ -90,8 +73,7 @@ namespace FDK
// BassMix.BASS_Mixer_ChannelSetEnvelope( SoundDevice.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes ); // BassMix.BASS_Mixer_ChannelSetEnvelope( SoundDevice.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes );
// } // }
//} //}
set set {
{
SoundDevice.nMasterVolume = value; SoundDevice.nMasterVolume = value;
_nMasterVolume = value; _nMasterVolume = value;
} }
@ -105,13 +87,11 @@ namespace FDK
//public static bool bIsMP3DecodeByWindowsCodec = false; //public static bool bIsMP3DecodeByWindowsCodec = false;
public static int nMixing = 0; public static int nMixing = 0;
public int GetMixingStreams() public int GetMixingStreams() {
{
return nMixing; return nMixing;
} }
public static int nStreams = 0; public static int nStreams = 0;
public int GetStreams() public int GetStreams() {
{
return nStreams; return nStreams;
} }
#region [ WASAPI/ASIO/DirectSound設定値 ] #region [ WASAPI/ASIO/DirectSound設定値 ]
@ -119,13 +99,11 @@ namespace FDK
/// <para>WASAPI 排他モード出力における再生遅延[ms](の希望値)。最終的にはこの数値を基にドライバが決定する)。</para> /// <para>WASAPI 排他モード出力における再生遅延[ms](の希望値)。最終的にはこの数値を基にドライバが決定する)。</para>
/// <para>0以下の値を指定すると、この数値はWASAPI初期化時に自動設定する。正数を指定すると、その値を設定しようと試みる。</para> /// <para>0以下の値を指定すると、この数値はWASAPI初期化時に自動設定する。正数を指定すると、その値を設定しようと試みる。</para>
/// </summary> /// </summary>
public static int SoundDelayExclusiveWASAPI = 0; // SSTでは、50ms public static int SoundDelayExclusiveWASAPI = 0; // SSTでは、50ms
public int GetSoundExclusiveWASAPI() public int GetSoundExclusiveWASAPI() {
{
return SoundDelayExclusiveWASAPI; return SoundDelayExclusiveWASAPI;
} }
public void SetSoundDelayExclusiveWASAPI( int value ) public void SetSoundDelayExclusiveWASAPI(int value) {
{
SoundDelayExclusiveWASAPI = value; SoundDelayExclusiveWASAPI = value;
} }
/// <summary> /// <summary>
@ -157,22 +135,18 @@ namespace FDK
/// <summary> /// <summary>
/// <para>ASIO 出力におけるバッファサイズ。</para> /// <para>ASIO 出力におけるバッファサイズ。</para>
/// </summary> /// </summary>
public static int SoundDelayASIO = 0; // 0にすると、デバイスの設定値をそのまま使う。 public static int SoundDelayASIO = 0; // 0にすると、デバイスの設定値をそのまま使う。
public int GetSoundDelayASIO() public int GetSoundDelayASIO() {
{
return SoundDelayASIO; return SoundDelayASIO;
} }
public void SetSoundDelayASIO(int value) public void SetSoundDelayASIO(int value) {
{
SoundDelayASIO = value; SoundDelayASIO = value;
} }
public static int ASIODevice = 0; public static int ASIODevice = 0;
public int GetASIODevice() public int GetASIODevice() {
{
return ASIODevice; return ASIODevice;
} }
public void SetASIODevice(int value) public void SetASIODevice(int value) {
{
ASIODevice = value; ASIODevice = value;
} }
/// <summary> /// <summary>
@ -180,14 +154,10 @@ namespace FDK
/// </summary> /// </summary>
public static int SoundDelayDirectSound = 100; public static int SoundDelayDirectSound = 100;
public long GetSoundDelay() public long GetSoundDelay() {
{ if (SoundDevice != null) {
if ( SoundDevice != null )
{
return SoundDevice.BufferSize; return SoundDevice.BufferSize;
} } else {
else
{
return -1; return -1;
} }
} }
@ -203,15 +173,13 @@ namespace FDK
/// <param name="nSoundDelayExclusiveWASAPI"></param> /// <param name="nSoundDelayExclusiveWASAPI"></param>
/// <param name="nSoundDelayASIO"></param> /// <param name="nSoundDelayASIO"></param>
/// <param name="nASIODevice"></param> /// <param name="nASIODevice"></param>
public SoundManager( IWindow window, ESoundDeviceType soundDeviceType, int nSoundDelayBASS, int nSoundDelayExclusiveWASAPI, int nSoundDelayASIO, int nASIODevice, bool _bUseOSTimer ) public SoundManager(IWindow window, ESoundDeviceType soundDeviceType, int nSoundDelayBASS, int nSoundDelayExclusiveWASAPI, int nSoundDelayASIO, int nASIODevice, bool _bUseOSTimer) {
{
Window_ = window; Window_ = window;
SoundDevice = null; SoundDevice = null;
//bUseOSTimer = false; //bUseOSTimer = false;
tInitialize( soundDeviceType, nSoundDelayBASS, nSoundDelayExclusiveWASAPI, nSoundDelayASIO, nASIODevice, _bUseOSTimer ); tInitialize(soundDeviceType, nSoundDelayBASS, nSoundDelayExclusiveWASAPI, nSoundDelayASIO, nASIODevice, _bUseOSTimer);
} }
public void Dispose() public void Dispose() {
{
t終了(); t終了();
} }
@ -220,29 +188,26 @@ namespace FDK
// t初期化( ESoundDeviceType.DirectSound, 0, 0, 0 ); // t初期化( ESoundDeviceType.DirectSound, 0, 0, 0 );
//} //}
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, IntPtr handle ) public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, IntPtr handle) {
{
//if ( !bInitialized ) //if ( !bInitialized )
{ {
tInitialize( soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice ); tInitialize(soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice);
//bInitialized = true; //bInitialized = true;
} }
} }
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice ) public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice) {
{ tInitialize(soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice, false);
tInitialize( soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice, false );
} }
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, bool _bUseOSTimer ) public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, bool _bUseOSTimer) {
{
//SoundDevice = null; // 後で再初期化することがあるので、null初期化はコンストラクタに回す //SoundDevice = null; // 後で再初期化することがあるので、null初期化はコンストラクタに回す
PlayTimer = null; // Global.Bass 依存(つまりユーザ依存) PlayTimer = null; // Global.Bass 依存(つまりユーザ依存)
nMixing = 0; nMixing = 0;
SoundDelayBASS = _nSoundDelayBASS; SoundDelayBASS = _nSoundDelayBASS;
SoundDelayExclusiveWASAPI = _nSoundDelayExclusiveWASAPI; SoundDelayExclusiveWASAPI = _nSoundDelayExclusiveWASAPI;
SoundDelaySharedWASAPI = _nSoundDelayExclusiveWASAPI; SoundDelaySharedWASAPI = _nSoundDelayExclusiveWASAPI;
SoundDelayASIO = _nSoundDelayASIO; SoundDelayASIO = _nSoundDelayASIO;
ASIODevice = _nASIODevice; ASIODevice = _nASIODevice;
bUseOSTimer = _bUseOSTimer; bUseOSTimer = _bUseOSTimer;
@ -256,8 +221,7 @@ namespace FDK
}; };
int initialDevice; int initialDevice;
switch ( soundDeviceType ) switch (soundDeviceType) {
{
case ESoundDeviceType.Bass: case ESoundDeviceType.Bass:
initialDevice = 0; initialDevice = 0;
break; break;
@ -274,39 +238,32 @@ namespace FDK
initialDevice = 4; initialDevice = 4;
break; break;
} }
for ( SoundDeviceType = ESoundDeviceTypes[ initialDevice ]; ; SoundDeviceType = ESoundDeviceTypes[ ++initialDevice ] ) for (SoundDeviceType = ESoundDeviceTypes[initialDevice]; ; SoundDeviceType = ESoundDeviceTypes[++initialDevice]) {
{ try {
try
{
tReloadSoundDeviceAndSound(); tReloadSoundDeviceAndSound();
break; break;
} } catch (Exception e) {
catch ( Exception e ) Trace.TraceError(e.ToString());
{ Trace.TraceError("例外が発生しましたが処理を継続します。 (2609806d-23e8-45c2-9389-b427e80915bc)");
Trace.TraceError( e.ToString() ); if (ESoundDeviceTypes[initialDevice] == ESoundDeviceType.Unknown) {
Trace.TraceError( "例外が発生しましたが処理を継続します。 (2609806d-23e8-45c2-9389-b427e80915bc)" ); Trace.TraceError(string.Format("サウンドデバイスの初期化に失敗しました。"));
if ( ESoundDeviceTypes[ initialDevice ] == ESoundDeviceType.Unknown )
{
Trace.TraceError( string.Format( "サウンドデバイスの初期化に失敗しました。" ) );
break; break;
} }
} }
} }
if ( soundDeviceType == ESoundDeviceType.Bass if (soundDeviceType == ESoundDeviceType.Bass
|| soundDeviceType == ESoundDeviceType.ExclusiveWASAPI || soundDeviceType == ESoundDeviceType.ExclusiveWASAPI
|| soundDeviceType == ESoundDeviceType.SharedWASAPI || soundDeviceType == ESoundDeviceType.SharedWASAPI
|| soundDeviceType == ESoundDeviceType.ASIO ) || soundDeviceType == ESoundDeviceType.ASIO) {
{
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 4 ); //Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 4 );
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ); //Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 );
Trace.TraceInformation( "BASS_CONFIG_UpdatePeriod=" + Bass.GetConfig( Configuration.UpdatePeriod ) ); Trace.TraceInformation("BASS_CONFIG_UpdatePeriod=" + Bass.GetConfig(Configuration.UpdatePeriod));
Trace.TraceInformation( "BASS_CONFIG_UpdateThreads=" + Bass.GetConfig( Configuration.UpdateThreads ) ); Trace.TraceInformation("BASS_CONFIG_UpdateThreads=" + Bass.GetConfig(Configuration.UpdateThreads));
} }
} }
public void tDisableUpdateBufferAutomatically() public void tDisableUpdateBufferAutomatically() {
{
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 0 ); //Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 0 );
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ); //Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 );
@ -315,93 +272,83 @@ namespace FDK
} }
public static void t終了() public static void t終了() {
{
SoundDevice.Dispose(); SoundDevice.Dispose();
PlayTimer.Dispose(); // Global.Bass を解放した後に解放すること。Global.Bass で参照されているため) PlayTimer.Dispose(); // Global.Bass を解放した後に解放すること。Global.Bass で参照されているため)
} }
public static void tReloadSoundDeviceAndSound() public static void tReloadSoundDeviceAndSound() {
{
#region [ ] #region [ ]
//----------------- //-----------------
if ( SoundDevice != null ) if (SoundDevice != null) {
{
// すでに生成済みのサウンドがあれば初期状態に戻す。 // すでに生成済みのサウンドがあれば初期状態に戻す。
CSound.tResetAllSound(); // リソースは解放するが、CSoundのインスタンスは残す。 CSound.tResetAllSound(); // リソースは解放するが、CSoundのインスタンスは残す。
// サウンドデバイスと演奏タイマを解放する。 // サウンドデバイスと演奏タイマを解放する。
SoundDevice.Dispose(); SoundDevice.Dispose();
PlayTimer?.Dispose(); // Global.SoundDevice を解放した後に解放すること。Global.SoundDevice で参照されているため) PlayTimer?.Dispose(); // Global.SoundDevice を解放した後に解放すること。Global.SoundDevice で参照されているため)
} }
//----------------- //-----------------
#endregion #endregion
#region [ ] #region [ ]
//----------------- //-----------------
switch ( SoundDeviceType ) switch (SoundDeviceType) {
{
case ESoundDeviceType.Bass: case ESoundDeviceType.Bass:
SoundDevice = new CSoundDeviceBASS( SoundDelayBASS, SoundUpdatePeriodBASS ); SoundDevice = new CSoundDeviceBASS(SoundDelayBASS, SoundUpdatePeriodBASS);
break; break;
case ESoundDeviceType.ExclusiveWASAPI: case ESoundDeviceType.ExclusiveWASAPI:
SoundDevice = new CSoundDeviceWASAPI( CSoundDeviceWASAPI.EWASAPIMode.Exclusion, SoundDelayExclusiveWASAPI, SoundUpdatePeriodExclusiveWASAPI ); SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.EWASAPIMode.Exclusion, SoundDelayExclusiveWASAPI, SoundUpdatePeriodExclusiveWASAPI);
break; break;
case ESoundDeviceType.SharedWASAPI: case ESoundDeviceType.SharedWASAPI:
SoundDevice = new CSoundDeviceWASAPI( CSoundDeviceWASAPI.EWASAPIMode.Share, SoundDelaySharedWASAPI, SoundUpdatePeriodSharedWASAPI ); SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.EWASAPIMode.Share, SoundDelaySharedWASAPI, SoundUpdatePeriodSharedWASAPI);
break; break;
case ESoundDeviceType.ASIO: case ESoundDeviceType.ASIO:
SoundDevice = new CSoundDeviceASIO( SoundDelayASIO, ASIODevice ); SoundDevice = new CSoundDeviceASIO(SoundDelayASIO, ASIODevice);
break; break;
default: default:
throw new Exception( string.Format( "未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString() ) ); throw new Exception(string.Format("未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString()));
} }
//----------------- //-----------------
#endregion #endregion
#region [ ] #region [ ]
//----------------- //-----------------
PlayTimer = new CSoundTimer( SoundDevice ); PlayTimer = new CSoundTimer(SoundDevice);
//----------------- //-----------------
#endregion #endregion
SoundDevice.nMasterVolume = _nMasterVolume; // サウンドデバイスに対して、マスターボリュームを再設定する SoundDevice.nMasterVolume = _nMasterVolume; // サウンドデバイスに対して、マスターボリュームを再設定する
CSound.tReloadSound( SoundDevice ); // すでに生成済みのサウンドがあれば作り直す。 CSound.tReloadSound(SoundDevice); // すでに生成済みのサウンドがあれば作り直す。
} }
public CSound tCreateSound( string filename, ESoundGroup soundGroup ) public CSound tCreateSound(string filename, ESoundGroup soundGroup) {
{ if (!File.Exists(filename)) {
if( !File.Exists( filename ) ) Trace.TraceWarning($"[i18n] File does not exist: {filename}");
{ return null;
Trace.TraceWarning($"[i18n] File does not exist: {filename}");
return null;
}
if ( SoundDeviceType == ESoundDeviceType.Unknown )
{
throw new Exception( string.Format( "未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString() ) );
} }
return SoundDevice.tCreateSound( filename, soundGroup );
if (SoundDeviceType == ESoundDeviceType.Unknown) {
throw new Exception(string.Format("未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString()));
}
return SoundDevice.tCreateSound(filename, soundGroup);
} }
private static DateTime lastUpdateTime = DateTime.MinValue; private static DateTime lastUpdateTime = DateTime.MinValue;
public void tDisposeSound( CSound csound ) public void tDisposeSound(CSound csound) {
{ csound?.tDispose(true); // インスタンスは存続→破棄にする。
csound?.tDispose( true ); // インスタンスは存続→破棄にする。
} }
public string GetCurrentSoundDeviceType() public string GetCurrentSoundDeviceType() {
{ switch (SoundDeviceType) {
switch ( SoundDeviceType )
{
case ESoundDeviceType.Bass: case ESoundDeviceType.Bass:
return "Bass"; return "Bass";
case ESoundDeviceType.ExclusiveWASAPI: case ESoundDeviceType.ExclusiveWASAPI:
@ -415,24 +362,20 @@ namespace FDK
} }
} }
public void AddMixer( CSound cs, double db再生速度, bool _b演奏終了後も再生が続くチップである ) public void AddMixer(CSound cs, double db再生速度, bool _b演奏終了後も再生が続くチップである) {
{
cs.b演奏終了後も再生が続くチップである = _b演奏終了後も再生が続くチップである; cs.b演奏終了後も再生が続くチップである = _b演奏終了後も再生が続くチップである;
cs.PlaySpeed = db再生速度; cs.PlaySpeed = db再生速度;
cs.AddBassSoundFromMixer(); cs.AddBassSoundFromMixer();
} }
public void AddMixer( CSound cs, double db再生速度 ) public void AddMixer(CSound cs, double db再生速度) {
{
cs.PlaySpeed = db再生速度; cs.PlaySpeed = db再生速度;
cs.AddBassSoundFromMixer(); cs.AddBassSoundFromMixer();
} }
public void AddMixer( CSound cs ) public void AddMixer(CSound cs) {
{
cs.AddBassSoundFromMixer(); cs.AddBassSoundFromMixer();
} }
public void RemoveMixer( CSound cs ) public void RemoveMixer(CSound cs) {
{
cs.tRemoveSoundFromMixer(); cs.tRemoveSoundFromMixer();
} }
} }
} }

View File

@ -1,15 +1,8 @@
using System; using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using SkiaSharp; using SkiaSharp;
namespace FDK namespace FDK {
{ public static class BitmapUtil {
public static class BitmapUtil
{
// 定数 // 定数
public const uint DIB_PAL_COLORS = 1; public const uint DIB_PAL_COLORS = 1;
@ -18,9 +11,8 @@ namespace FDK
// 構造体 // 構造体
[StructLayout( LayoutKind.Sequential, Pack = 1 )] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPFILEHEADER public struct BITMAPFILEHEADER {
{
public ushort bfType; public ushort bfType;
public uint bfSize; public uint bfSize;
public ushort bfReserved1; public ushort bfReserved1;
@ -28,9 +20,8 @@ namespace FDK
public uint bfOffBits; public uint bfOffBits;
} }
[StructLayout( LayoutKind.Sequential, Pack = 1 )] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPINFOHEADER public struct BITMAPINFOHEADER {
{
public const int BI_RGB = 0; public const int BI_RGB = 0;
public uint biSize構造体のサイズ; public uint biSize構造体のサイズ;
public int biWidthビットマップの幅dot; public int biWidthビットマップの幅dot;
@ -48,25 +39,24 @@ namespace FDK
// メソッド // メソッド
public static unsafe SKBitmap ToBitmap( IntPtr pBITMAPINFOHEADER ) public static unsafe SKBitmap ToBitmap(IntPtr pBITMAPINFOHEADER) {
{
BITMAPFILEHEADER bitmapfileheader; BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER* bitmapinfoheaderPtr = (BITMAPINFOHEADER*) pBITMAPINFOHEADER; BITMAPINFOHEADER* bitmapinfoheaderPtr = (BITMAPINFOHEADER*)pBITMAPINFOHEADER;
bitmapfileheader.bfType = 0x4d42; bitmapfileheader.bfType = 0x4d42;
bitmapfileheader.bfOffBits = (uint) ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) ); bitmapfileheader.bfOffBits = (uint)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ; bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ;
MemoryStream output = new MemoryStream(); MemoryStream output = new MemoryStream();
BinaryWriter writer = new BinaryWriter( output ); BinaryWriter writer = new BinaryWriter(output);
byte[] destination = new byte[ sizeof( BITMAPFILEHEADER ) ]; byte[] destination = new byte[sizeof(BITMAPFILEHEADER)];
Marshal.Copy( (IntPtr) ( &bitmapfileheader ), destination, 0, destination.Length ); Marshal.Copy((IntPtr)(&bitmapfileheader), destination, 0, destination.Length);
writer.Write( destination ); writer.Write(destination);
destination = new byte[ sizeof( BITMAPINFOHEADER ) ]; destination = new byte[sizeof(BITMAPINFOHEADER)];
Marshal.Copy( pBITMAPINFOHEADER, destination, 0, destination.Length ); Marshal.Copy(pBITMAPINFOHEADER, destination, 0, destination.Length);
writer.Write( destination ); writer.Write(destination);
destination = new byte[ bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ ]; destination = new byte[bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ];
bitmapinfoheaderPtr++; bitmapinfoheaderPtr++;
Marshal.Copy( (IntPtr) bitmapinfoheaderPtr, destination, 0, destination.Length ); Marshal.Copy((IntPtr)bitmapinfoheaderPtr, destination, 0, destination.Length);
writer.Write( destination ); writer.Write(destination);
writer.Flush(); writer.Flush();
writer.BaseStream.Position = 0L; writer.BaseStream.Position = 0L;
return null; return null;

View File

@ -1,61 +1,46 @@
using System; using System.Drawing;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using FFmpeg.AutoGen; using FFmpeg.AutoGen;
namespace FDK namespace FDK {
{ public class CDecodedFrame : IDisposable {
public class CDecodedFrame : IDisposable public CDecodedFrame(Size texsize) {
{
public CDecodedFrame(Size texsize)
{
this.Using = false; this.Using = false;
this.TexSize = texsize; this.TexSize = texsize;
this.TexPointer = Marshal.AllocHGlobal(texsize.Width * TexSize.Height * 4); this.TexPointer = Marshal.AllocHGlobal(texsize.Width * TexSize.Height * 4);
} }
public bool Using public bool Using {
{
get; get;
private set; private set;
} }
public double Time public double Time {
{
get; get;
private set; private set;
} }
public IntPtr TexPointer public IntPtr TexPointer {
{
get; get;
private set; private set;
} }
public Size TexSize public Size TexSize {
{
get; get;
private set; private set;
} }
public unsafe CDecodedFrame UpdateFrame(double time, AVFrame* frame) public unsafe CDecodedFrame UpdateFrame(double time, AVFrame* frame) {
{
this.Time = time; this.Time = time;
Buffer.MemoryCopy(frame->data[0], (void*)this.TexPointer, frame->linesize[0] * frame->height, frame->linesize[0] * frame->height); Buffer.MemoryCopy(frame->data[0], (void*)this.TexPointer, frame->linesize[0] * frame->height, frame->linesize[0] * frame->height);
this.Using = true; this.Using = true;
return this; return this;
} }
public void RemoveFrame() public void RemoveFrame() {
{
this.Using = false; this.Using = false;
} }
public void Dispose() public void Dispose() {
{
this.Using = false; this.Using = false;
Marshal.FreeHGlobal(this.TexPointer); Marshal.FreeHGlobal(this.TexPointer);
} }
} }
} }

View File

@ -1,75 +1,63 @@
using System; using System.Drawing;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using FFmpeg.AutoGen; using FFmpeg.AutoGen;
namespace FDK namespace FDK {
{ public unsafe class CFrameConverter : IDisposable {
public unsafe class CFrameConverter : IDisposable public CFrameConverter(Size FrameSize, AVPixelFormat pix_fmt) {
{ this.FrameSize = FrameSize;
public CFrameConverter(Size FrameSize, AVPixelFormat pix_fmt) if (pix_fmt != CVPxfmt) {
{ convert_context = ffmpeg.sws_getContext(
this.FrameSize = FrameSize; FrameSize.Width,
if (pix_fmt != CVPxfmt) FrameSize.Height,
{ pix_fmt,
convert_context = ffmpeg.sws_getContext( FrameSize.Width,
FrameSize.Width, FrameSize.Height,
FrameSize.Height, CVPxfmt,
pix_fmt, ffmpeg.SWS_FAST_BILINEAR, null, null, null);
FrameSize.Width, this.IsConvert = true;
FrameSize.Height, if (convert_context == null) throw new ApplicationException("Could not initialize the conversion context.\n");
CVPxfmt, }
ffmpeg.SWS_FAST_BILINEAR, null, null, null); _convertedFrameBufferPtr = Marshal.AllocHGlobal(ffmpeg.av_image_get_buffer_size(CVPxfmt, FrameSize.Width, FrameSize.Height, 1));
this.IsConvert = true;
if (convert_context == null) throw new ApplicationException("Could not initialize the conversion context.\n");
}
_convertedFrameBufferPtr = Marshal.AllocHGlobal(ffmpeg.av_image_get_buffer_size(CVPxfmt, FrameSize.Width, FrameSize.Height, 1));
_dstData = new byte_ptrArray4(); _dstData = new byte_ptrArray4();
_dstLinesize = new int_array4(); _dstLinesize = new int_array4();
ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize, (byte*)_convertedFrameBufferPtr, CVPxfmt, FrameSize.Width, FrameSize.Height, 1); ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize, (byte*)_convertedFrameBufferPtr, CVPxfmt, FrameSize.Width, FrameSize.Height, 1);
} }
public AVFrame* Convert(AVFrame* framep) public AVFrame* Convert(AVFrame* framep) {
{ if (this.IsConvert) {
if (this.IsConvert) ffmpeg.sws_scale(convert_context, framep->data, framep->linesize, 0, framep->height, _dstData, _dstLinesize);
{
ffmpeg.sws_scale(convert_context, framep->data, framep->linesize, 0, framep->height, _dstData, _dstLinesize);
AVFrame* tmp = ffmpeg.av_frame_alloc(); AVFrame* tmp = ffmpeg.av_frame_alloc();
tmp = ffmpeg.av_frame_alloc(); tmp = ffmpeg.av_frame_alloc();
tmp->best_effort_timestamp = framep->best_effort_timestamp; tmp->best_effort_timestamp = framep->best_effort_timestamp;
tmp->width = FrameSize.Width; tmp->width = FrameSize.Width;
tmp->height = FrameSize.Height; tmp->height = FrameSize.Height;
tmp->data = new byte_ptrArray8(); tmp->data = new byte_ptrArray8();
tmp->data.UpdateFrom(_dstData); tmp->data.UpdateFrom(_dstData);
tmp->linesize = new int_array8(); tmp->linesize = new int_array8();
tmp->linesize.UpdateFrom(_dstLinesize); tmp->linesize.UpdateFrom(_dstLinesize);
ffmpeg.av_frame_unref(framep); ffmpeg.av_frame_unref(framep);
return tmp; return tmp;
} } else {
else return framep;
{ }
return framep; }
}
}
public void Dispose() public void Dispose() {
{ Marshal.FreeHGlobal(_convertedFrameBufferPtr);
Marshal.FreeHGlobal(_convertedFrameBufferPtr); ffmpeg.sws_freeContext(convert_context);
ffmpeg.sws_freeContext(convert_context); }
}
private SwsContext* convert_context; private SwsContext* convert_context;
private readonly byte_ptrArray4 _dstData; private readonly byte_ptrArray4 _dstData;
private readonly int_array4 _dstLinesize; private readonly int_array4 _dstLinesize;
private readonly IntPtr _convertedFrameBufferPtr; private readonly IntPtr _convertedFrameBufferPtr;
private const AVPixelFormat CVPxfmt = AVPixelFormat.AV_PIX_FMT_RGBA; private const AVPixelFormat CVPxfmt = AVPixelFormat.AV_PIX_FMT_RGBA;
private bool IsConvert = false; private bool IsConvert = false;
private Size FrameSize; private Size FrameSize;
} }
} }

View File

@ -1065,4 +1065,4 @@ namespace FDK
//----------------- //-----------------
#endregion #endregion
} }
} }

View File

@ -1,18 +1,6 @@
using System; using Rectangle = System.Drawing.Rectangle;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Diagnostics;
using Silk.NET.Maths;
using Rectangle = System.Drawing.Rectangle; namespace FDK {
using Point = System.Drawing.Point;
using Color = System.Drawing.Color;
namespace FDK
{
/// <summary> /// <summary>
/// 縦長_横長の画像を自動で折りたたんでテクスチャ化するCTexture。 /// 縦長_横長の画像を自動で折りたたんでテクスチャ化するCTexture。
/// 例えば、768x30 のテクスチャファイルが入力されたら、 /// 例えば、768x30 のテクスチャファイルが入力されたら、
@ -20,8 +8,7 @@ namespace FDK
/// 必要に応じて、正方形テクスチャにもする。 /// 必要に応じて、正方形テクスチャにもする。
/// また、t2D描画は、その折り返しを加味して実行する。 /// また、t2D描画は、その折り返しを加味して実行する。
/// </summary> /// </summary>
public class CTextureAf : CTexture, IDisposable public class CTextureAf : CTexture, IDisposable {
{
/// <summary> /// <summary>
/// <para>画像ファイルからテクスチャを生成する。</para> /// <para>画像ファイルからテクスチャを生成する。</para>
@ -36,18 +23,16 @@ namespace FDK
/// <param name="b黒を透過する">画像の黒0xFFFFFFFFを透過させるなら true。</param> /// <param name="b黒を透過する">画像の黒0xFFFFFFFFを透過させるなら true。</param>
/// <param name="pool">テクスチャの管理方法。</param> /// <param name="pool">テクスチャの管理方法。</param>
/// <exception cref="CTextureCreateFailedException">テクスチャの作成に失敗しました。</exception> /// <exception cref="CTextureCreateFailedException">テクスチャの作成に失敗しました。</exception>
public CTextureAf( string strファイル名, bool b黒を透過する ) public CTextureAf(string strファイル名, bool b黒を透過する) {
{ MakeTexture(strファイル名, b黒を透過する);
MakeTexture( strファイル名, b黒を透過する );
} }
public new void MakeTexture( string strファイル名, bool b黒を透過する ) public new void MakeTexture(string strファイル名, bool b黒を透過する) {
{ if (!File.Exists(strファイル名)) // #27122 2012.1.13 from: ImageInformation では FileNotFound 例外は返ってこないので、ここで自分でチェックする。わかりやすいログのために。
if ( !File.Exists( strファイル名 ) ) // #27122 2012.1.13 from: ImageInformation では FileNotFound 例外は返ってこないので、ここで自分でチェックする。わかりやすいログのために。 throw new FileNotFoundException(string.Format("ファイルが存在しません。\n[{0}]", strファイル名));
throw new FileNotFoundException( string.Format( "ファイルが存在しません。\n[{0}]", strファイル名 ) );
base.MakeTexture(strファイル名, b黒を透過する); base.MakeTexture(strファイル名, b黒を透過する);
} }
@ -60,43 +45,39 @@ namespace FDK
/// <param name="height"></param> /// <param name="height"></param>
/// <param name="foldtimes"></param> /// <param name="foldtimes"></param>
/// <returns></returns> /// <returns></returns>
private bool GetFoldedTextureSize( ref int width, ref int height, out int foldtimes ) private bool GetFoldedTextureSize(ref int width, ref int height, out int foldtimes) {
{
int orgWidth = width, orgHeight = height; int orgWidth = width, orgHeight = height;
#region [ widthが2 ] #region [ widthが2 ]
int pow = 1; int pow = 1;
while ( orgWidth >= pow ) while (orgWidth >= pow) {
{
pow *= 2; pow *= 2;
} }
pow /= 2; pow /= 2;
#endregion #endregion
#region [ 22 ] #region [ 22 ]
foldtimes = ( orgWidth == pow ) ? 0 : 1; // 2のべき乗からの溢れがあれば、まずその溢れ分で1回折り畳む foldtimes = (orgWidth == pow) ? 0 : 1; // 2のべき乗からの溢れがあれば、まずその溢れ分で1回折り畳む
if ( foldtimes != 0 ) if (foldtimes != 0) {
{ //Debug.WriteLine( "powちょうどではないので、溢れあり。まずは1回折りたたむ。" );
//Debug.WriteLine( "powちょうどではないので、溢れあり。まずは1回折りたたむ。" );
// 試しに、widthをpowに切り詰め、1回折り返してみる。 // 試しに、widthをpowに切り詰め、1回折り返してみる。
// width>heightを維持しているなら、テクスチャサイズはより最適な状態になったということになる。 // width>heightを維持しているなら、テクスチャサイズはより最適な状態になったということになる。
if ( pow <= orgHeight * 2 ) // 新width > 新heightを維持できなくなったなら if (pow <= orgHeight * 2) // 新width > 新heightを維持できなくなったなら
{ // 最適化不可とみなし、baseの処理に委ねる { // 最適化不可とみなし、baseの処理に委ねる
return false; return false;
} }
} }
#endregion #endregion
#region [ width > height ] #region [ width > height ]
width = pow; width = pow;
height = orgHeight * 2; // 初期値1回折りたたんだ状態 height = orgHeight * 2; // 初期値1回折りたたんだ状態
do do {
{
width /= 2; width /= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1; foldtimes = (orgWidth / width) + ((orgWidth % width > 0) ? 1 : 0) - 1;
height = orgHeight * ( foldtimes + 1 ); height = orgHeight * (foldtimes + 1);
} while ( width > height ); } while (width > height);
width *= 2; width *= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1; foldtimes = (orgWidth / width) + ((orgWidth % width > 0) ? 1 : 0) - 1;
height = orgHeight * ( foldtimes + 1 ); height = orgHeight * (foldtimes + 1);
#endregion #endregion
return true; return true;
@ -110,69 +91,58 @@ namespace FDK
/// <param name="device">Direct3D9 デバイス。</param> /// <param name="device">Direct3D9 デバイス。</param>
/// <param name="x">描画位置(テクスチャの左上位置の X 座標[dot])。</param> /// <param name="x">描画位置(テクスチャの左上位置の X 座標[dot])。</param>
/// <param name="y">描画位置(テクスチャの左上位置の Y 座標[dot])。</param> /// <param name="y">描画位置(テクスチャの左上位置の Y 座標[dot])。</param>
public new void t2D描画( int x, int y ) public new void t2D描画(int x, int y) {
{
#if TEST_FOLDTEXTURE #if TEST_FOLDTEXTURE
base.t2D描画( x, y, 1f, rc全画像 ); base.t2D描画( x, y, 1f, rc全画像 );
#else #else
for ( int n = 0; n <= _foldtimes; n++ ) for (int n = 0; n <= _foldtimes; n++) {
{
Rectangle r; Rectangle r;
if ( b横長のテクスチャである ) if (b横長のテクスチャである) {
{
int currentHeight = n * _orgHeight; int currentHeight = n * _orgHeight;
r = new Rectangle( 0, currentHeight, this.rc全画像.Width, _orgHeight ); r = new Rectangle(0, currentHeight, this.rc全画像.Width, _orgHeight);
base.t2D描画( x + n * this.rc全画像.Width, y, 1f, r ); base.t2D描画(x + n * this.rc全画像.Width, y, 1f, r);
} } else {
else
{
int currentWidth = n * _orgWidth; int currentWidth = n * _orgWidth;
r = new Rectangle( currentWidth, 0, _orgWidth, this.rc全画像.Height ); r = new Rectangle(currentWidth, 0, _orgWidth, this.rc全画像.Height);
base.t2D描画( x, y + n * this.rc全画像.Height, 1f, r ); base.t2D描画(x, y + n * this.rc全画像.Height, 1f, r);
} }
} }
#endif #endif
} }
public new void t2D描画( int x, int y, Rectangle rc ) public new void t2D描画(int x, int y, Rectangle rc) {
{
Rectangle r; Rectangle r;
if ( b横長のテクスチャである ) if (b横長のテクスチャである) {
{
int beginFold = rc.X / this.rc全画像.Width; int beginFold = rc.X / this.rc全画像.Width;
int endFold = ( rc.X + rc.Width ) / rc全画像.Width; int endFold = (rc.X + rc.Width) / rc全画像.Width;
for ( int i = beginFold; i <= endFold; i++ ) for (int i = beginFold; i <= endFold; i++) {
{ if (i > _foldtimes) break;
if ( i > _foldtimes ) break;
int newRcY = i * _orgHeight + rc.Y; int newRcY = i * _orgHeight + rc.Y;
int newRcX = ( i == beginFold ) ? ( rc.X % this.rc全画像.Width ) : 0; int newRcX = (i == beginFold) ? (rc.X % this.rc全画像.Width) : 0;
int newRcWidth = ( newRcX + rc.Width > rc全画像.Width ) ? rc全画像.Width - newRcX : rc.Width; int newRcWidth = (newRcX + rc.Width > rc全画像.Width) ? rc全画像.Width - newRcX : rc.Width;
r = new Rectangle( newRcX, newRcY, newRcWidth, rc.Height ); r = new Rectangle(newRcX, newRcY, newRcWidth, rc.Height);
base.t2D描画( x, y, 1f, r ); base.t2D描画(x, y, 1f, r);
int deltaX = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Width - rc.X : rc全画像.Width; int deltaX = (i == beginFold) ? (i + 1) * rc全画像.Width - rc.X : rc全画像.Width;
int newWidth = rc.Width - deltaX; int newWidth = rc.Width - deltaX;
x += deltaX; x += deltaX;
rc.Width = newWidth; rc.Width = newWidth;
} }
} } else {
else
{
int beginFold = rc.Y / this.rc全画像.Height; int beginFold = rc.Y / this.rc全画像.Height;
int endFold = ( rc.Y + rc.Height ) / rc全画像.Height; int endFold = (rc.Y + rc.Height) / rc全画像.Height;
for ( int i = beginFold; i <= endFold; i++ ) for (int i = beginFold; i <= endFold; i++) {
{ if (i > _foldtimes) break;
if ( i > _foldtimes ) break;
int newRcX = i * _orgWidth + rc.X; int newRcX = i * _orgWidth + rc.X;
int newRcY = ( i == beginFold ) ? ( rc.Y % this.rc全画像.Height ) : 0; int newRcY = (i == beginFold) ? (rc.Y % this.rc全画像.Height) : 0;
int newRcHeight = ( newRcY + rc.Height > rc全画像.Height ) ? rc全画像.Height - newRcY : rc.Height; int newRcHeight = (newRcY + rc.Height > rc全画像.Height) ? rc全画像.Height - newRcY : rc.Height;
r = new Rectangle( newRcX, newRcY, rc.Width, newRcHeight ); r = new Rectangle(newRcX, newRcY, rc.Width, newRcHeight);
base.t2D描画( x, y, 1f, r ); base.t2D描画(x, y, 1f, r);
int deltaY = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Height - rc.Y : rc全画像.Height; int deltaY = (i == beginFold) ? (i + 1) * rc全画像.Height - rc.Y : rc全画像.Height;
int newHeight = rc.Height - deltaY; int newHeight = rc.Height - deltaY;
y += deltaY; y += deltaY;
rc.Height = newHeight; rc.Height = newHeight;
@ -180,13 +150,11 @@ namespace FDK
} }
} }
public new void t2D描画( float x, float y ) public new void t2D描画(float x, float y) {
{ t2D描画((int)x, (int)y);
t2D描画( (int) x, (int) y );
} }
public void t2D描画( float x, float y, Rectangle rc ) public void t2D描画(float x, float y, Rectangle rc) {
{ t2D描画((int)x, (int)y, rc);
t2D描画( (int) x, (int) y, rc );
} }
#region [ private ] #region [ private ]

View File

@ -1,29 +1,20 @@
using System; using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace FDK namespace FDK {
{
/// <summary> /// <summary>
/// テクスチャの作成に失敗しました。 /// テクスチャの作成に失敗しました。
/// </summary> /// </summary>
public class CTextureCreateFailedException : Exception public class CTextureCreateFailedException : Exception {
{ public CTextureCreateFailedException() {
public CTextureCreateFailedException()
{
} }
public CTextureCreateFailedException( string message ) public CTextureCreateFailedException(string message)
: base( message ) : base(message) {
{
} }
public CTextureCreateFailedException( SerializationInfo info, StreamingContext context ) public CTextureCreateFailedException(SerializationInfo info, StreamingContext context)
: base( info, context ) : base(info, context) {
{
} }
public CTextureCreateFailedException( string message, Exception innerException ) public CTextureCreateFailedException(string message, Exception innerException)
: base( message, innerException ) : base(message, innerException) {
{
} }
} }
} }

View File

@ -1,35 +1,21 @@
using System; using System.Collections.Concurrent;
using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FFmpeg.AutoGen; using FFmpeg.AutoGen;
using System.Threading;
using Size = System.Drawing.Size; using Size = System.Drawing.Size;
namespace FDK namespace FDK {
{
/// <summary> /// <summary>
/// ビデオのデコードをするクラス /// ビデオのデコードをするクラス
/// ファイル名・nullのCTextureをもらえれば、勝手に、CTextureに映像を格納して返す。 /// ファイル名・nullのCTextureをもらえれば、勝手に、CTextureに映像を格納して返す。
/// 演奏とは別のタイマーを使用しているので、ずれる可能性がある。 /// 演奏とは別のタイマーを使用しているので、ずれる可能性がある。
/// </summary> /// </summary>
public unsafe class CVideoDecoder : IDisposable public unsafe class CVideoDecoder : IDisposable {
{ public CVideoDecoder(string filename) {
public CVideoDecoder(string filename)
{
if (!File.Exists(filename)) if (!File.Exists(filename))
throw new FileNotFoundException(filename + " not found..."); throw new FileNotFoundException(filename + " not found...");
format_context = ffmpeg.avformat_alloc_context(); format_context = ffmpeg.avformat_alloc_context();
fixed (AVFormatContext** format_contexttmp = &format_context) fixed (AVFormatContext** format_contexttmp = &format_context) {
{
if (ffmpeg.avformat_open_input(format_contexttmp, filename, null, null) != 0) if (ffmpeg.avformat_open_input(format_contexttmp, filename, null, null) != 0)
throw new FileLoadException("avformat_open_input failed\n"); throw new FileLoadException("avformat_open_input failed\n");
@ -37,10 +23,8 @@ namespace FDK
throw new FileLoadException("avformat_find_stream_info failed\n"); throw new FileLoadException("avformat_find_stream_info failed\n");
// find audio stream // find audio stream
for (int i = 0; i < (int)format_context->nb_streams; i++) for (int i = 0; i < (int)format_context->nb_streams; i++) {
{ if (format_context->streams[i]->codecpar->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO) {
if (format_context->streams[i]->codecpar->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
{
video_stream = format_context->streams[i]; video_stream = format_context->streams[i];
break; break;
} }
@ -76,10 +60,9 @@ namespace FDK
} }
} }
public void Dispose() public void Dispose() {
{
bDrawing = false; bDrawing = false;
close = true; close = true;
cts?.Cancel(); cts?.Cancel();
while (DS != DecodingState.Stopped) ; while (DS != DecodingState.Stopped) ;
frameconv.Dispose(); frameconv.Dispose();
@ -88,8 +71,7 @@ namespace FDK
if (ffmpeg.avcodec_close(codec_context) < 0) if (ffmpeg.avcodec_close(codec_context) < 0)
Trace.TraceError("codec context close error."); Trace.TraceError("codec context close error.");
video_stream = null; video_stream = null;
fixed (AVFormatContext** format_contexttmp = &format_context) fixed (AVFormatContext** format_contexttmp = &format_context) {
{
ffmpeg.avformat_close_input(format_contexttmp); ffmpeg.avformat_close_input(format_contexttmp);
} }
if (lastTexture != null) if (lastTexture != null)
@ -98,49 +80,39 @@ namespace FDK
frame.Dispose(); frame.Dispose();
} }
public void Start() public void Start() {
{
CTimer.Reset(); CTimer.Reset();
CTimer.Resume(); CTimer.Resume();
this.bPlaying = true; this.bPlaying = true;
bDrawing = true; bDrawing = true;
} }
public void PauseControl() public void PauseControl() {
{ if (this.bPlaying) {
if (this.bPlaying)
{
CTimer.Pause(); CTimer.Pause();
this.bPlaying = false; this.bPlaying = false;
} } else {
else
{
CTimer.Resume(); CTimer.Resume();
this.bPlaying = true; this.bPlaying = true;
} }
} }
public void Stop() public void Stop() {
{
CTimer.Pause(); CTimer.Pause();
this.bPlaying = false; this.bPlaying = false;
bDrawing = false; bDrawing = false;
} }
public void InitRead() public void InitRead() {
{ if (!bqueueinitialized) {
if (!bqueueinitialized)
{
this.Seek(0); this.Seek(0);
bqueueinitialized = true; bqueueinitialized = true;
} } else
else
Trace.TraceError("The class has already been initialized.\n"); Trace.TraceError("The class has already been initialized.\n");
} }
public void Seek(long timestampms) public void Seek(long timestampms) {
{
cts?.Cancel(); cts?.Cancel();
while (DS != DecodingState.Stopped) ; while (DS != DecodingState.Stopped) ;
if (ffmpeg.av_seek_frame(format_context, video_stream->index, timestampms, ffmpeg.AVSEEK_FLAG_BACKWARD) < 0) if (ffmpeg.av_seek_frame(format_context, video_stream->index, timestampms, ffmpeg.AVSEEK_FLAG_BACKWARD) < 0)
@ -156,21 +128,16 @@ namespace FDK
lastTexture = new CTexture(FrameSize.Width, FrameSize.Height); lastTexture = new CTexture(FrameSize.Width, FrameSize.Height);
} }
public void GetNowFrame(ref CTexture Texture) public void GetNowFrame(ref CTexture Texture) {
{ if (this.bPlaying && decodedframes.Count != 0) {
if (this.bPlaying && decodedframes.Count != 0)
{
CTimer.Update(); CTimer.Update();
if (decodedframes.TryPeek(out CDecodedFrame frame)) if (decodedframes.TryPeek(out CDecodedFrame frame)) {
{ while (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed)) {
while (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed))
{
if (decodedframes.TryDequeue(out CDecodedFrame cdecodedframe)) { if (decodedframes.TryDequeue(out CDecodedFrame cdecodedframe)) {
if (decodedframes.Count != 0) if (decodedframes.Count != 0)
if (decodedframes.TryPeek(out frame)) if (decodedframes.TryPeek(out frame))
if (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed)) if (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed)) {
{
cdecodedframe.RemoveFrame(); cdecodedframe.RemoveFrame();
continue; continue;
} }
@ -197,24 +164,19 @@ namespace FDK
} }
private void EnqueueFrames() private void EnqueueFrames() {
{ if (DS != DecodingState.Running && !close) {
if (DS != DecodingState.Running && !close)
{
cts = new CancellationTokenSource(); cts = new CancellationTokenSource();
Task.Factory.StartNew(() => EnqueueOneFrame()); Task.Factory.StartNew(() => EnqueueOneFrame());
} }
} }
private void EnqueueOneFrame() private void EnqueueOneFrame() {
{
DS = DecodingState.Running; DS = DecodingState.Running;
AVFrame* frame = ffmpeg.av_frame_alloc(); AVFrame* frame = ffmpeg.av_frame_alloc();
AVPacket* packet = ffmpeg.av_packet_alloc(); AVPacket* packet = ffmpeg.av_packet_alloc();
try try {
{ while (true) {
while (true)
{
if (cts.IsCancellationRequested || close) if (cts.IsCancellationRequested || close)
return; return;
@ -223,14 +185,10 @@ namespace FDK
{ {
int error = ffmpeg.av_read_frame(format_context, packet); int error = ffmpeg.av_read_frame(format_context, packet);
if (error >= 0) if (error >= 0) {
{ if (packet->stream_index == video_stream->index) {
if (packet->stream_index == video_stream->index) if (ffmpeg.avcodec_send_packet(codec_context, packet) >= 0) {
{ if (ffmpeg.avcodec_receive_frame(codec_context, frame) == 0) {
if (ffmpeg.avcodec_send_packet(codec_context, packet) >= 0)
{
if (ffmpeg.avcodec_receive_frame(codec_context, frame) == 0)
{
AVFrame* outframe = null; AVFrame* outframe = null;
outframe = frameconv.Convert(frame); outframe = frameconv.Convert(frame);
@ -246,26 +204,18 @@ namespace FDK
//2020/10/27 Mr-Ojii packetが解放されない周回があった問題を修正。 //2020/10/27 Mr-Ojii packetが解放されない周回があった問題を修正。
ffmpeg.av_packet_unref(packet); ffmpeg.av_packet_unref(packet);
} } else if (error == ffmpeg.AVERROR_EOF) {
else if (error == ffmpeg.AVERROR_EOF)
{
return; return;
} }
} } else {
else
{
//ポーズ中に無限ループに入り、CPU使用率が異常に高くなってしまうため、1ms待つ。 //ポーズ中に無限ループに入り、CPU使用率が異常に高くなってしまうため、1ms待つ。
//ネットを調べると、await Task.Delay()を使えというお話が出てくるが、unsafeなので、使えない //ネットを調べると、await Task.Delay()を使えというお話が出てくるが、unsafeなので、使えない
Thread.Sleep(1); Thread.Sleep(1);
} }
} }
} } catch (Exception e) {
catch (Exception e)
{
Trace.TraceError(e.ToString()); Trace.TraceError(e.ToString());
} } finally {
finally
{
ffmpeg.av_packet_free(&packet); ffmpeg.av_packet_free(&packet);
ffmpeg.av_frame_unref(frame); ffmpeg.av_frame_unref(frame);
ffmpeg.av_free(frame); ffmpeg.av_free(frame);
@ -273,42 +223,32 @@ namespace FDK
} }
} }
public CDecodedFrame PickUnusedDcodedFrame() public CDecodedFrame PickUnusedDcodedFrame() {
{
for (int i = 0; i < framelist.Length; i++) { for (int i = 0; i < framelist.Length; i++) {
if (framelist[i].Using == false) if (framelist[i].Using == false) {
{
return framelist[i]; return framelist[i];
} }
} }
return null; return null;
} }
public Size FrameSize public Size FrameSize {
{
get; get;
private set; private set;
} }
public double Duration public double Duration {
{
get; get;
private set; private set;
} }
public double dbPlaySpeed public double dbPlaySpeed {
{ get {
get
{
return this._dbPlaySpeed; return this._dbPlaySpeed;
} }
set set {
{ if (value > 0) {
if (value > 0)
{
this._dbPlaySpeed = value; this._dbPlaySpeed = value;
} } else {
else
{
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
} }
@ -325,16 +265,15 @@ namespace FDK
private CancellationTokenSource cts; private CancellationTokenSource cts;
private CDecodedFrame[] framelist = new CDecodedFrame[6]; private CDecodedFrame[] framelist = new CDecodedFrame[6];
private DecodingState DS = DecodingState.Stopped; private DecodingState DS = DecodingState.Stopped;
private enum DecodingState private enum DecodingState {
{
Stopped, Stopped,
Running Running
} }
//for play //for play
public bool bPlaying { get; private set; } = false; public bool bPlaying { get; private set; } = false;
public bool bDrawing { get; private set; } = false; public bool bDrawing { get; private set; } = false;
private CTimer CTimer; private CTimer CTimer;
private AVRational Framerate; private AVRational Framerate;
private CTexture lastTexture; private CTexture lastTexture;
private bool bqueueinitialized = false; private bool bqueueinitialized = false;
@ -343,4 +282,4 @@ namespace FDK
private CFrameConverter frameconv; private CFrameConverter frameconv;
#endregion #endregion
} }
} }

View File

@ -1,34 +1,27 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics;
using SkiaSharp; using SkiaSharp;
using Color = System.Drawing.Color; using Color = System.Drawing.Color;
namespace FDK namespace FDK {
{
/// <summary> /// <summary>
/// 高速描画版のCFontRendererクラス。 /// 高速描画版のCFontRendererクラス。
/// といっても、一度レンダリングした結果をキャッシュして使いまわしているだけ。 /// といっても、一度レンダリングした結果をキャッシュして使いまわしているだけ。
/// </summary> /// </summary>
public class CCachedFontRenderer : CFontRenderer public class CCachedFontRenderer : CFontRenderer {
{
#region [ ] #region [ ]
public CCachedFontRenderer( string fontpath, int pt, CFontRenderer.FontStyle style ) public CCachedFontRenderer(string fontpath, int pt, CFontRenderer.FontStyle style) {
{ Initialize(fontpath, pt, style);
Initialize( fontpath, pt, style );
} }
public CCachedFontRenderer( string fontpath, int pt ) public CCachedFontRenderer(string fontpath, int pt) {
{ Initialize(fontpath, pt, CFontRenderer.FontStyle.Regular);
Initialize( fontpath, pt, CFontRenderer.FontStyle.Regular );
} }
#endregion #endregion
#region [ ] #region [ ]
protected new void Initialize( string fontpath, int pt, CFontRenderer.FontStyle style ) protected new void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style) {
{
this.bDisposed_CCachedFontRenderer = false; this.bDisposed_CCachedFontRenderer = false;
this.listFontCache = new List<FontCache>(); this.listFontCache = new List<FontCache>();
base.Initialize( fontpath, pt, style ); base.Initialize(fontpath, pt, style);
} }
#endregion #endregion
@ -41,9 +34,8 @@ namespace FDK
/// <param name="fontColor">描画色</param> /// <param name="fontColor">描画色</param>
/// <param name="edgeColor">縁取色</param> /// <param name="edgeColor">縁取色</param>
/// <returns>描画済テクスチャ</returns> /// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) public new SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
{ return DrawText(drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
return DrawText( drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter );
} }
/// <summary> /// <summary>
@ -53,9 +45,8 @@ namespace FDK
/// <param name="fontColor">描画色</param> /// <param name="fontColor">描画色</param>
/// <param name="edgeColor">縁取色</param> /// <param name="edgeColor">縁取色</param>
/// <returns>描画済テクスチャ</returns> /// <returns>描画済テクスチャ</returns>
public SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, DrawMode dMode, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, DrawMode dMode, int edge_Ratio, bool keepCenter = false) {
{ return DrawText(drawstr, dMode, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
return DrawText( drawstr, dMode, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter );
} }
/// <summary> /// <summary>
@ -67,9 +58,8 @@ namespace FDK
/// <param name="gradationTopColor">グラデーション 上側の色</param> /// <param name="gradationTopColor">グラデーション 上側の色</param>
/// <param name="gradationBottomColor">グラデーション 下側の色</param> /// <param name="gradationBottomColor">グラデーション 下側の色</param>
/// <returns>描画済テクスチャ</returns> /// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false ) public new SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
{ return DrawText(drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
return DrawText( drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter );
} }
/// <summary> /// <summary>
@ -81,19 +71,16 @@ namespace FDK
/// <param name="gradationTopColor">グラデーション 上側の色</param> /// <param name="gradationTopColor">グラデーション 上側の色</param>
/// <param name="gradationBottomColor">グラデーション 下側の色</param> /// <param name="gradationBottomColor">グラデーション 下側の色</param>
/// <returns>描画済テクスチャ</returns> /// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText_V( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false ) public new SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText_V(drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.Black, Color.Black, edge_Ratio, keepCenter); return DrawText_V(drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.Black, Color.Black, edge_Ratio, keepCenter);
} }
#endregion #endregion
protected new SKBitmap DrawText( string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false ) protected new SKBitmap DrawText(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
{
#region [ /? (?) ] #region [ /? (?) ]
int index = listFontCache.FindIndex( int index = listFontCache.FindIndex(
delegate( FontCache fontcache ) delegate (FontCache fontcache) {
{
return ( return (
drawstr == fontcache.drawstr && drawstr == fontcache.drawstr &&
drawmode == fontcache.drawmode && drawmode == fontcache.drawmode &&
@ -108,12 +95,11 @@ namespace FDK
} }
); );
#endregion #endregion
if ( index < 0 ) if (index < 0) {
{
// キャッシュにヒットせず。 // キャッシュにヒットせず。
#region [ ] #region [ ]
FontCache fc = new FontCache(); FontCache fc = new FontCache();
fc.bmp = base.DrawText( drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter); fc.bmp = base.DrawText(drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter);
fc.drawstr = drawstr; fc.drawstr = drawstr;
fc.drawmode = drawmode; fc.drawmode = drawmode;
fc.fontColor = fontColor; fc.fontColor = fontColor;
@ -123,40 +109,34 @@ namespace FDK
fc.gradationBottomColor = gradationBottomColor; fc.gradationBottomColor = gradationBottomColor;
fc.Vertical = false; fc.Vertical = false;
fc.KeepCenter = keepCenter; fc.KeepCenter = keepCenter;
listFontCache.Add( fc ); listFontCache.Add(fc);
Debug.WriteLine( drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")" ); Debug.WriteLine(drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")");
#endregion #endregion
#region [ ] #region [ ]
if ( listFontCache.Count > MAXCACHESIZE ) if (listFontCache.Count > MAXCACHESIZE) {
{ Debug.WriteLine("Cache溢れ。" + listFontCache[0].drawstr + " を解放します。");
Debug.WriteLine( "Cache溢れ。" + listFontCache[ 0 ].drawstr + " を解放します。" ); if (listFontCache[0].bmp != null) {
if ( listFontCache[ 0 ].bmp != null ) listFontCache[0].bmp.Dispose();
{
listFontCache[ 0 ].bmp.Dispose();
} }
listFontCache.RemoveAt( 0 ); listFontCache.RemoveAt(0);
} }
#endregion #endregion
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。 // 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ listFontCache.Count - 1 ].bmp.Copy(); return listFontCache[listFontCache.Count - 1].bmp.Copy();
} } else {
else Debug.WriteLine(drawstr + ": Cacheにヒット!! index=" + index);
{
Debug.WriteLine( drawstr + ": Cacheにヒット!! index=" + index );
#region [ ] #region [ ]
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。 // 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ index ].bmp.Copy(); return listFontCache[index].bmp.Copy();
#endregion #endregion
} }
} }
protected new SKBitmap DrawText_V(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) protected new SKBitmap DrawText_V(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
{
#region [ /? (?) ] #region [ /? (?) ]
int index = listFontCache.FindIndex( int index = listFontCache.FindIndex(
delegate (FontCache fontcache) delegate (FontCache fontcache) {
{
return ( return (
drawstr == fontcache.drawstr && drawstr == fontcache.drawstr &&
drawmode == fontcache.drawmode && drawmode == fontcache.drawmode &&
@ -171,8 +151,7 @@ namespace FDK
} }
); );
#endregion #endregion
if ( index < 0 ) if (index < 0) {
{
// キャッシュにヒットせず。 // キャッシュにヒットせず。
#region [ ] #region [ ]
FontCache fc = new FontCache(); FontCache fc = new FontCache();
@ -185,48 +164,39 @@ namespace FDK
fc.gradationBottomColor = gradationBottomColor; fc.gradationBottomColor = gradationBottomColor;
fc.Vertical = true; fc.Vertical = true;
fc.KeepCenter = keepCenter; fc.KeepCenter = keepCenter;
listFontCache.Add( fc ); listFontCache.Add(fc);
Debug.WriteLine( drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")" ); Debug.WriteLine(drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")");
#endregion #endregion
#region [ ] #region [ ]
if ( listFontCache.Count > MAXCACHESIZE ) if (listFontCache.Count > MAXCACHESIZE) {
{ Debug.WriteLine("Cache溢れ。" + listFontCache[0].drawstr + " を解放します。");
Debug.WriteLine( "Cache溢れ。" + listFontCache[ 0 ].drawstr + " を解放します。" ); if (listFontCache[0].bmp != null) {
if ( listFontCache[ 0 ].bmp != null ) listFontCache[0].bmp.Dispose();
{
listFontCache[ 0 ].bmp.Dispose();
} }
listFontCache.RemoveAt( 0 ); listFontCache.RemoveAt(0);
} }
#endregion #endregion
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。 // 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ listFontCache.Count - 1 ].bmp.Copy(); return listFontCache[listFontCache.Count - 1].bmp.Copy();
} } else {
else Debug.WriteLine(drawstr + ": Cacheにヒット!! index=" + index);
{
Debug.WriteLine( drawstr + ": Cacheにヒット!! index=" + index );
#region [ ] #region [ ]
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。 // 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ index ].bmp.Copy(); return listFontCache[index].bmp.Copy();
#endregion #endregion
} }
} }
#region [ IDisposable ] #region [ IDisposable ]
//----------------- //-----------------
public new void Dispose() public new void Dispose() {
{ if (!this.bDisposed_CCachedFontRenderer) {
if (!this.bDisposed_CCachedFontRenderer) if (listFontCache != null) {
{
if (listFontCache != null)
{
//Debug.WriteLine( "Disposing CCachedFontRenderer()" ); //Debug.WriteLine( "Disposing CCachedFontRenderer()" );
#region [ ] #region [ ]
foreach (FontCache bc in listFontCache) foreach (FontCache bc in listFontCache) {
{ if (bc.bmp != null) {
if (bc.bmp != null)
{
bc.bmp.Dispose(); bc.bmp.Dispose();
} }
} }
@ -248,8 +218,7 @@ namespace FDK
/// </summary> /// </summary>
private const int MAXCACHESIZE = 256; private const int MAXCACHESIZE = 256;
private struct FontCache private struct FontCache {
{
// public Font font; // public Font font;
public string drawstr; public string drawstr;
public DrawMode drawmode; public DrawMode drawmode;
@ -268,4 +237,4 @@ namespace FDK
//----------------- //-----------------
#endregion #endregion
} }
} }

View File

@ -1,40 +1,31 @@
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SkiaSharp; using SkiaSharp;
using Color = System.Drawing.Color; using Color = System.Drawing.Color;
namespace FDK namespace FDK {
{
public class CFontRenderer : IDisposable public class CFontRenderer : IDisposable {
{
#region[static系] #region[static系]
public static void SetTextCorrectionX_Chara_List_Vertical(string[] list) public static void SetTextCorrectionX_Chara_List_Vertical(string[] list) {
{
if (list != null) if (list != null)
CorrectionX_Chara_List_Vertical = list.Where(c => c != null).ToArray(); CorrectionX_Chara_List_Vertical = list.Where(c => c != null).ToArray();
} }
public static void SetTextCorrectionX_Chara_List_Value_Vertical(int[] list) public static void SetTextCorrectionX_Chara_List_Value_Vertical(int[] list) {
{
if (list != null) if (list != null)
CorrectionX_Chara_List_Value_Vertical = list; CorrectionX_Chara_List_Value_Vertical = list;
} }
public static void SetTextCorrectionY_Chara_List_Vertical(string[] list) public static void SetTextCorrectionY_Chara_List_Vertical(string[] list) {
{
if (list != null) if (list != null)
CorrectionY_Chara_List_Vertical = list.Where(c => c != null).ToArray(); CorrectionY_Chara_List_Vertical = list.Where(c => c != null).ToArray();
} }
public static void SetTextCorrectionY_Chara_List_Value_Vertical(int[] list) public static void SetTextCorrectionY_Chara_List_Value_Vertical(int[] list) {
{
if (list != null) if (list != null)
CorrectionY_Chara_List_Value_Vertical = list; CorrectionY_Chara_List_Value_Vertical = list;
} }
public static void SetRotate_Chara_List_Vertical(string[] list) public static void SetRotate_Chara_List_Vertical(string[] list) {
{
if (list != null) if (list != null)
Rotate_Chara_List_Vertical = list.Where(c => c != null).ToArray(); Rotate_Chara_List_Vertical = list.Where(c => c != null).ToArray();
} }
@ -49,16 +40,14 @@ namespace FDK
[Flags] [Flags]
public enum DrawMode public enum DrawMode {
{
Normal = 0, Normal = 0,
Edge, Edge,
Gradation Gradation
} }
[Flags] [Flags]
public enum FontStyle public enum FontStyle {
{
Regular = 0, Regular = 0,
Bold, Bold,
Italic, Italic,
@ -66,10 +55,8 @@ namespace FDK
Strikeout Strikeout
} }
public static string DefaultFontName public static string DefaultFontName {
{ get {
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "MS UI Gothic"; return "MS UI Gothic";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@ -79,100 +66,78 @@ namespace FDK
} }
} }
public static bool FontExists(string fontpath) public static bool FontExists(string fontpath) {
{
return SKFontManager.Default.FontFamilies.Contains(fontpath) || File.Exists(fontpath); return SKFontManager.Default.FontFamilies.Contains(fontpath) || File.Exists(fontpath);
} }
#region [ ] #region [ ]
public CFontRenderer(string fontpath, int pt, FontStyle style) public CFontRenderer(string fontpath, int pt, FontStyle style) {
{
Initialize(fontpath, pt, style); Initialize(fontpath, pt, style);
} }
public CFontRenderer(string fontpath, int pt) public CFontRenderer(string fontpath, int pt) {
{
Initialize(fontpath, pt, FontStyle.Regular); Initialize(fontpath, pt, FontStyle.Regular);
} }
public CFontRenderer() public CFontRenderer() {
{
//throw new ArgumentException("CFontRenderer: 引数があるコンストラクタを使用してください。"); //throw new ArgumentException("CFontRenderer: 引数があるコンストラクタを使用してください。");
} }
#endregion #endregion
protected void Initialize(string fontpath, int pt, FontStyle style) protected void Initialize(string fontpath, int pt, FontStyle style) {
{ try {
try
{
this.textRenderer = new CSkiaSharpTextRenderer(fontpath, pt, style); this.textRenderer = new CSkiaSharpTextRenderer(fontpath, pt, style);
return; return;
} catch (Exception e) {
Trace.TraceWarning("SkiaSharpでのフォント生成に失敗しました。" + e.ToString());
this.textRenderer?.Dispose();
} }
catch(Exception e)
{
Trace.TraceWarning("SkiaSharpでのフォント生成に失敗しました。" + e.ToString());
this.textRenderer?.Dispose();
}
try try {
{
this.textRenderer = new CSkiaSharpTextRenderer(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"FDK.mplus-1p-medium.ttf"), pt, style); this.textRenderer = new CSkiaSharpTextRenderer(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"FDK.mplus-1p-medium.ttf"), pt, style);
} } catch (Exception e) {
catch (Exception e)
{
Trace.TraceWarning("ビルトインフォントを使用してのフォント生成に失敗しました。" + e.ToString()); Trace.TraceWarning("ビルトインフォントを使用してのフォント生成に失敗しました。" + e.ToString());
this.textRenderer?.Dispose(); this.textRenderer?.Dispose();
throw; throw;
} }
} }
public SKBitmap DrawText(string drawstr, Color fontColor, bool keepCenter = false) public SKBitmap DrawText(string drawstr, Color fontColor, bool keepCenter = false) {
{
return DrawText(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter); return DrawText(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter);
} }
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter); return DrawText(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
} }
public SKBitmap DrawText(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter); return DrawText(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
} }
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter); return DrawText(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
} }
protected SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) protected SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
{
//横書きに対してのCorrectionは廃止 //横書きに対してのCorrectionは廃止
return this.textRenderer.DrawText(drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter); return this.textRenderer.DrawText(drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter);
} }
public SKBitmap DrawText_V(string drawstr, Color fontColor, bool keepCenter = false) public SKBitmap DrawText_V(string drawstr, Color fontColor, bool keepCenter = false) {
{
return DrawText_V(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter); return DrawText_V(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter);
} }
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter); return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
} }
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText_V(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText_V(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter); return DrawText_V(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
} }
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
{
return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter); return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
} }
protected SKBitmap DrawText_V(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) protected SKBitmap DrawText_V(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
{ if (string.IsNullOrEmpty(drawstr)) {
if (string.IsNullOrEmpty(drawstr))
{
//nullか""だったら、1x1を返す //nullか""だったら、1x1を返す
return new SKBitmap(1, 1); return new SKBitmap(1, 1);
} }
@ -187,15 +152,12 @@ namespace FDK
//レンダリング,大きさ計測 //レンダリング,大きさ計測
int nWidth = 0; int nWidth = 0;
int nHeight = 0; int nHeight = 0;
for (int i = 0; i < strImageList.Length; i++) for (int i = 0; i < strImageList.Length; i++) {
{
strImageList[i] = this.textRenderer.DrawText(strList[i], drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, false); strImageList[i] = this.textRenderer.DrawText(strList[i], drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, false);
//回転する文字 //回転する文字
if(Rotate_Chara_List_Vertical.Contains(strList[i])) if (Rotate_Chara_List_Vertical.Contains(strList[i])) {
{ using (var surface = new SKCanvas(strImageList[i])) {
using (var surface = new SKCanvas(strImageList[i]))
{
surface.RotateDegrees(90, strImageList[i].Width / 2, strImageList[i].Height / 2); surface.RotateDegrees(90, strImageList[i].Width / 2, strImageList[i].Height / 2);
surface.DrawBitmap(strImageList[i], 0, 0); surface.DrawBitmap(strImageList[i], 0, 0);
} }
@ -212,44 +174,29 @@ namespace FDK
//1文字ずつ描画したやつを全体キャンバスに描画していく //1文字ずつ描画したやつを全体キャンバスに描画していく
int nowHeightPos = 0; int nowHeightPos = 0;
for (int i = 0; i < strImageList.Length; i++) for (int i = 0; i < strImageList.Length; i++) {
{
int Correction_X = 0, Correction_Y = 0; int Correction_X = 0, Correction_Y = 0;
if (CorrectionX_Chara_List_Vertical != null && CorrectionX_Chara_List_Value_Vertical != null) if (CorrectionX_Chara_List_Vertical != null && CorrectionX_Chara_List_Value_Vertical != null) {
{
int Xindex = Array.IndexOf(CorrectionX_Chara_List_Vertical, strList[i]); int Xindex = Array.IndexOf(CorrectionX_Chara_List_Vertical, strList[i]);
if (-1 < Xindex && Xindex < CorrectionX_Chara_List_Value_Vertical.Length && CorrectionX_Chara_List_Vertical.Contains(strList[i])) if (-1 < Xindex && Xindex < CorrectionX_Chara_List_Value_Vertical.Length && CorrectionX_Chara_List_Vertical.Contains(strList[i])) {
{
Correction_X = CorrectionX_Chara_List_Value_Vertical[Xindex]; Correction_X = CorrectionX_Chara_List_Value_Vertical[Xindex];
} } else {
else if (-1 < Xindex && CorrectionX_Chara_List_Value_Vertical.Length <= Xindex && CorrectionX_Chara_List_Vertical.Contains(strList[i])) {
{
if (-1 < Xindex && CorrectionX_Chara_List_Value_Vertical.Length <= Xindex && CorrectionX_Chara_List_Vertical.Contains(strList[i]))
{
Correction_X = CorrectionX_Chara_List_Value_Vertical[0]; Correction_X = CorrectionX_Chara_List_Value_Vertical[0];
} } else {
else
{
Correction_X = 0; Correction_X = 0;
} }
} }
} }
if (CorrectionY_Chara_List_Vertical != null && CorrectionY_Chara_List_Value_Vertical != null) if (CorrectionY_Chara_List_Vertical != null && CorrectionY_Chara_List_Value_Vertical != null) {
{
int Yindex = Array.IndexOf(CorrectionY_Chara_List_Vertical, strList[i]); int Yindex = Array.IndexOf(CorrectionY_Chara_List_Vertical, strList[i]);
if (-1 < Yindex && Yindex < CorrectionY_Chara_List_Value_Vertical.Length && CorrectionY_Chara_List_Vertical.Contains(strList[i])) if (-1 < Yindex && Yindex < CorrectionY_Chara_List_Value_Vertical.Length && CorrectionY_Chara_List_Vertical.Contains(strList[i])) {
{
Correction_Y = CorrectionY_Chara_List_Value_Vertical[Yindex]; Correction_Y = CorrectionY_Chara_List_Value_Vertical[Yindex];
} } else {
else if (-1 < Yindex && CorrectionY_Chara_List_Value_Vertical.Length <= Yindex && CorrectionY_Chara_List_Vertical.Contains(strList[i])) {
{
if (-1 < Yindex && CorrectionY_Chara_List_Value_Vertical.Length <= Yindex && CorrectionY_Chara_List_Vertical.Contains(strList[i]))
{
Correction_Y = CorrectionY_Chara_List_Value_Vertical[0]; Correction_Y = CorrectionY_Chara_List_Value_Vertical[0];
} } else {
else
{
Correction_Y = 0; Correction_Y = 0;
} }
} }
@ -259,22 +206,20 @@ namespace FDK
} }
//1文字ずつ描画したやつの解放 //1文字ずつ描画したやつの解放
for (int i = 0; i < strImageList.Length; i++) for (int i = 0; i < strImageList.Length; i++) {
{
strImageList[i].Dispose(); strImageList[i].Dispose();
} }
SKImage image = skSurface.Snapshot(); SKImage image = skSurface.Snapshot();
//返します //返します
return SKBitmap.FromImage(image); return SKBitmap.FromImage(image);
} }
public void Dispose() public void Dispose() {
{
this.textRenderer.Dispose(); this.textRenderer.Dispose();
} }
private ITextRenderer textRenderer; private ITextRenderer textRenderer;
} }
} }

View File

@ -1,318 +1,268 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SkiaSharp;
using System.Text.RegularExpressions;
using Color = System.Drawing.Color;
using Rectangle = System.Drawing.Rectangle;
using System.Drawing; using System.Drawing;
using static FDK.CSkiaSharpTextRenderer; using System.Text.RegularExpressions;
using SkiaSharp;
using Color = System.Drawing.Color;
namespace FDK namespace FDK {
{ internal class CSkiaSharpTextRenderer : ITextRenderer {
internal class CSkiaSharpTextRenderer : ITextRenderer //https://monobook.org/wiki/SkiaSharp%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E6%8F%8F%E7%94%BB%E3%81%99%E3%82%8B
{ public CSkiaSharpTextRenderer(string fontpath, int pt) {
//https://monobook.org/wiki/SkiaSharp%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E6%8F%8F%E7%94%BB%E3%81%99%E3%82%8B Initialize(fontpath, pt, CFontRenderer.FontStyle.Regular);
public CSkiaSharpTextRenderer(string fontpath, int pt) }
{
Initialize(fontpath, pt, CFontRenderer.FontStyle.Regular);
}
public CSkiaSharpTextRenderer(string fontpath, int pt, CFontRenderer.FontStyle style) public CSkiaSharpTextRenderer(string fontpath, int pt, CFontRenderer.FontStyle style) {
{ Initialize(fontpath, pt, style);
Initialize(fontpath, pt, style); }
}
public CSkiaSharpTextRenderer(Stream fontstream, int pt, CFontRenderer.FontStyle style) public CSkiaSharpTextRenderer(Stream fontstream, int pt, CFontRenderer.FontStyle style) {
{ Initialize(fontstream, pt, style);
Initialize(fontstream, pt, style); }
}
protected void Initialize(Stream fontstream, int pt, CFontRenderer.FontStyle style) protected void Initialize(Stream fontstream, int pt, CFontRenderer.FontStyle style) {
{ paint = new SKPaint();
paint = new SKPaint();
//stream・filepathから生成した場合に、style設定をどうすればいいのかがわからない //stream・filepathから生成した場合に、style設定をどうすればいいのかがわからない
paint.Typeface = SKFontManager.Default.CreateTypeface(fontstream); paint.Typeface = SKFontManager.Default.CreateTypeface(fontstream);
paint.TextSize = (pt * 1.3f); paint.TextSize = (pt * 1.3f);
paint.IsAntialias = true; paint.IsAntialias = true;
} }
protected void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style) protected void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style) {
{ paint = new SKPaint();
paint = new SKPaint();
SKFontStyleWeight weight = SKFontStyleWeight.Normal; SKFontStyleWeight weight = SKFontStyleWeight.Normal;
SKFontStyleWidth width = SKFontStyleWidth.Normal; SKFontStyleWidth width = SKFontStyleWidth.Normal;
SKFontStyleSlant slant = SKFontStyleSlant.Upright; SKFontStyleSlant slant = SKFontStyleSlant.Upright;
if (style.HasFlag(CFontRenderer.FontStyle.Bold)) if (style.HasFlag(CFontRenderer.FontStyle.Bold)) {
{ weight = SKFontStyleWeight.Bold;
weight = SKFontStyleWeight.Bold; }
} if (style.HasFlag(CFontRenderer.FontStyle.Italic)) {
if (style.HasFlag(CFontRenderer.FontStyle.Italic)) slant = SKFontStyleSlant.Italic;
{ }
slant = SKFontStyleSlant.Italic; if (style.HasFlag(CFontRenderer.FontStyle.Strikeout)) {
} paint.Style = SKPaintStyle.Stroke;
if (style.HasFlag(CFontRenderer.FontStyle.Strikeout)) }
{ if (style.HasFlag(CFontRenderer.FontStyle.Underline)) {
paint.Style = SKPaintStyle.Stroke; //????
} //paint.FontMetrics.UnderlinePosition;
if (style.HasFlag(CFontRenderer.FontStyle.Underline)) }
{
//????
//paint.FontMetrics.UnderlinePosition;
}
if (SKFontManager.Default.FontFamilies.Contains(fontpath)) if (SKFontManager.Default.FontFamilies.Contains(fontpath))
paint.Typeface = SKTypeface.FromFamilyName(fontpath, weight, width, slant); paint.Typeface = SKTypeface.FromFamilyName(fontpath, weight, width, slant);
//stream・filepathから生成した場合に、style設定をどうすればいいのかがわからない //stream・filepathから生成した場合に、style設定をどうすればいいのかがわからない
if (File.Exists(fontpath)) if (File.Exists(fontpath))
paint.Typeface = SKTypeface.FromFile(fontpath, 0); paint.Typeface = SKTypeface.FromFile(fontpath, 0);
if (paint.Typeface == null) if (paint.Typeface == null)
throw new FileNotFoundException(fontpath); throw new FileNotFoundException(fontpath);
paint.TextSize = (pt * 1.3f); paint.TextSize = (pt * 1.3f);
paint.IsAntialias = true; paint.IsAntialias = true;
} }
internal struct SStringToken internal struct SStringToken {
{ public string s;
public string s; public Color TextColor;
public Color TextColor; public bool UseGradiant;
public bool UseGradiant; public Color GradiantTop;
public Color GradiantTop; public Color GradiantBottom;
public Color GradiantBottom; public bool UseOutline;
public bool UseOutline; public Color OutlineColor;
public Color OutlineColor; }
}
// Purify is equivalent to RemoveTags on ObjectExtensions.cs, update both if changing TagRegex // Purify is equivalent to RemoveTags on ObjectExtensions.cs, update both if changing TagRegex
private const string TagRegex = @"<(/?)([gc](?:\.#[0-9a-fA-F]{6})*?)>"; private const string TagRegex = @"<(/?)([gc](?:\.#[0-9a-fA-F]{6})*?)>";
private string Purify(string input) private string Purify(string input) {
{ return Regex.Replace(input, TagRegex, "");
return Regex.Replace(input, TagRegex, ""); }
}
private List<SStringToken> Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor) private List<SStringToken> Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor) {
{ List<SStringToken> tokens = new List<SStringToken>();
List<SStringToken> tokens = new List<SStringToken>(); Stack<string> tags = new Stack<string>();
Stack<string> tags = new Stack<string>(); Stack<SStringToken> tokenStack = new Stack<SStringToken>();
Stack<SStringToken> tokenStack = new Stack<SStringToken>(); int lastPos = 0;
int lastPos = 0;
var tagRegex = new Regex(TagRegex); var tagRegex = new Regex(TagRegex);
var matches = tagRegex.Matches(input); var matches = tagRegex.Matches(input);
foreach (Match match in matches) foreach (Match match in matches) {
{ int pos = match.Index;
int pos = match.Index; string text = input.Substring(lastPos, pos - lastPos);
string text = input.Substring(lastPos, pos - lastPos);
// First // First
if (text.Length > 0) if (text.Length > 0) {
{ SStringToken token = new SStringToken {
SStringToken token = new SStringToken s = text,
{ UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant,
s = text, GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant, GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop, TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor,
GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom, UseOutline = tokenStack.Count > 0 && tokenStack.Peek().UseOutline,
TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor, OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor,
UseOutline = tokenStack.Count > 0 && tokenStack.Peek().UseOutline, };
OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor, tokens.Add(token);
}; }
tokens.Add(token);
}
lastPos = pos + match.Length; lastPos = pos + match.Length;
if (match.Groups[1].Value == "/") if (match.Groups[1].Value == "/") {
{ if (tags.Count > 0) tags.Pop();
if (tags.Count > 0) tags.Pop(); if (tokenStack.Count > 0) tokenStack.Pop();
if (tokenStack.Count > 0) tokenStack.Pop(); } else {
} tags.Push(match.Groups[2].Value);
else SStringToken newToken = new SStringToken {
{ UseGradiant = tokenStack.Count > 0 ? tokenStack.Peek().UseGradiant : false,
tags.Push(match.Groups[2].Value); GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
SStringToken newToken = new SStringToken GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom,
{ TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor,
UseGradiant = tokenStack.Count > 0 ? tokenStack.Peek().UseGradiant : false, UseOutline = tokenStack.Count > 0 ? tokenStack.Peek().UseOutline : false,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop, OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor,
GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom, };
TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor,
UseOutline = tokenStack.Count > 0 ? tokenStack.Peek().UseOutline : false,
OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor,
};
string[] _varSplit = match.Groups[2].Value.Split("."); string[] _varSplit = match.Groups[2].Value.Split(".");
if (_varSplit.Length > 0) if (_varSplit.Length > 0) {
{ switch (_varSplit[0]) {
switch (_varSplit[0]) case "g": {
{ if (_varSplit.Length > 2) {
case "g": newToken.UseGradiant = true;
{ newToken.GradiantTop = ColorTranslator.FromHtml(_varSplit[1]);
if (_varSplit.Length > 2) newToken.GradiantBottom = ColorTranslator.FromHtml(_varSplit[2]);
{ }
newToken.UseGradiant = true; break;
newToken.GradiantTop = ColorTranslator.FromHtml(_varSplit[1]); }
newToken.GradiantBottom = ColorTranslator.FromHtml(_varSplit[2]); case "c": {
} if (_varSplit.Length > 1) {
break; newToken.TextColor = ColorTranslator.FromHtml(_varSplit[1]);
} }
case "c": if (_varSplit.Length > 2) {
{ newToken.UseOutline = true;
if (_varSplit.Length > 1) newToken.OutlineColor = ColorTranslator.FromHtml(_varSplit[2]);
{ }
newToken.TextColor = ColorTranslator.FromHtml(_varSplit[1]); break;
} }
if (_varSplit.Length > 2)
{
newToken.UseOutline = true;
newToken.OutlineColor = ColorTranslator.FromHtml(_varSplit[2]);
}
break;
}
} }
} }
tokenStack.Push(newToken); tokenStack.Push(newToken);
} }
} }
// Last // Last
if (lastPos < input.Length) if (lastPos < input.Length) {
{ SStringToken token = new SStringToken {
SStringToken token = new SStringToken s = input.Substring(lastPos),
{ UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant,
s = input.Substring(lastPos), GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant, GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop, TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor,
GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom, UseOutline = tokenStack.Count > 0 && tokenStack.Peek().UseOutline,
TextColor = (tokenStack.Count == 0) ? fontColor : tokenStack.Peek().TextColor, OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor,
UseOutline = tokenStack.Count > 0 && tokenStack.Peek().UseOutline, };
OutlineColor = (tokenStack.Count == 0) ? edgeColor : tokenStack.Peek().OutlineColor, tokens.Add(token);
}; }
tokens.Add(token);
}
return tokens; return tokens;
} }
public SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawMode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter) public SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawMode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter) {
{ if (string.IsNullOrEmpty(drawstr)) {
if (string.IsNullOrEmpty(drawstr)) //nullか""だったら、1x1を返す
{ return new SKBitmap(1, 1);
//nullか""だったら、1x1を返す }
return new SKBitmap(1, 1);
}
string[] strs = drawstr.Split("\n"); string[] strs = drawstr.Split("\n");
List<SStringToken>[] tokens = new List<SStringToken>[strs.Length]; List<SStringToken>[] tokens = new List<SStringToken>[strs.Length];
for (int i = 0; i < strs.Length; i++) for (int i = 0; i < strs.Length; i++) {
{ tokens[i] = Tokenize(strs[i], fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor);
tokens[i] = Tokenize(strs[i], fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor); }
}
SKBitmap[] images = new SKBitmap[strs.Length]; SKBitmap[] images = new SKBitmap[strs.Length];
for (int i = 0; i < strs.Length; i++) { for (int i = 0; i < strs.Length; i++) {
SKRect bounds = new SKRect(); SKRect bounds = new SKRect();
int width = (int)Math.Ceiling(paint.MeasureText(Purify(strs[i]), ref bounds)) + 50; int width = (int)Math.Ceiling(paint.MeasureText(Purify(strs[i]), ref bounds)) + 50;
int height = (int)Math.Ceiling(paint.FontMetrics.Descent - paint.FontMetrics.Ascent) + 50; int height = (int)Math.Ceiling(paint.FontMetrics.Descent - paint.FontMetrics.Ascent) + 50;
//少し大きめにとる(定数じゃない方法を考えましょう) //少し大きめにとる(定数じゃない方法を考えましょう)
SKBitmap bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); SKBitmap bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
SKCanvas canvas = new SKCanvas(bitmap); SKCanvas canvas = new SKCanvas(bitmap);
int x_offset = 0; int x_offset = 0;
foreach (SStringToken tok in tokens[i]) foreach (SStringToken tok in tokens[i]) {
{ int token_width = (int)Math.Ceiling(paint.MeasureText(tok.s, ref bounds));
int token_width = (int)Math.Ceiling(paint.MeasureText(tok.s, ref bounds));
if (drawMode.HasFlag(CFontRenderer.DrawMode.Edge) || tok.UseOutline) if (drawMode.HasFlag(CFontRenderer.DrawMode.Edge) || tok.UseOutline) {
{
SKPath path = paint.GetTextPath(tok.s, 25 + x_offset, -paint.FontMetrics.Ascent + 25); SKPath path = paint.GetTextPath(tok.s, 25 + x_offset, -paint.FontMetrics.Ascent + 25);
if (secondEdgeColor != null) if (secondEdgeColor != null) {
{ SKPaint secondEdgePaint = new SKPaint();
SKPaint secondEdgePaint = new SKPaint(); secondEdgePaint.StrokeWidth = paint.TextSize * 8 / edge_Ratio;
secondEdgePaint.StrokeWidth = paint.TextSize * 8 / edge_Ratio; secondEdgePaint.StrokeJoin = SKStrokeJoin.Round;
secondEdgePaint.StrokeJoin = SKStrokeJoin.Round; secondEdgePaint.Color = new SKColor(secondEdgeColor.Value.R, secondEdgeColor.Value.G, secondEdgeColor.Value.B, secondEdgeColor.Value.A);
secondEdgePaint.Color = new SKColor(secondEdgeColor.Value.R, secondEdgeColor.Value.G, secondEdgeColor.Value.B, secondEdgeColor.Value.A); secondEdgePaint.Style = SKPaintStyle.Stroke;
secondEdgePaint.Style = SKPaintStyle.Stroke; secondEdgePaint.IsAntialias = true;
secondEdgePaint.IsAntialias = true; canvas.DrawPath(path, secondEdgePaint);
canvas.DrawPath(path, secondEdgePaint); }
}
SKPaint edgePaint = new SKPaint(); SKPaint edgePaint = new SKPaint();
edgePaint.StrokeWidth = paint.TextSize * (secondEdgeColor == null ? 8 : 4) / edge_Ratio; edgePaint.StrokeWidth = paint.TextSize * (secondEdgeColor == null ? 8 : 4) / edge_Ratio;
edgePaint.StrokeJoin = SKStrokeJoin.Round; edgePaint.StrokeJoin = SKStrokeJoin.Round;
edgePaint.Color = new SKColor(tok.OutlineColor.R, tok.OutlineColor.G, tok.OutlineColor.B, tok.OutlineColor.A); edgePaint.Color = new SKColor(tok.OutlineColor.R, tok.OutlineColor.G, tok.OutlineColor.B, tok.OutlineColor.A);
edgePaint.Style = SKPaintStyle.Stroke; edgePaint.Style = SKPaintStyle.Stroke;
edgePaint.IsAntialias = true; edgePaint.IsAntialias = true;
canvas.DrawPath(path, edgePaint); canvas.DrawPath(path, edgePaint);
} }
if (tok.UseGradiant) if (tok.UseGradiant) {
{ //https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/shaders/linear-gradient
//https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/shaders/linear-gradient paint.Shader = SKShader.CreateLinearGradient(
paint.Shader = SKShader.CreateLinearGradient( new SKPoint(0, 25),
new SKPoint(0, 25), new SKPoint(0, height - 25),
new SKPoint(0, height - 25), new SKColor[] {
new SKColor[] { new SKColor(tok.GradiantTop.R, tok.GradiantTop.G, tok.GradiantTop.B, tok.GradiantTop.A),
new SKColor(tok.GradiantTop.R, tok.GradiantTop.G, tok.GradiantTop.B, tok.GradiantTop.A), new SKColor(tok.GradiantBottom.R, tok.GradiantBottom.G, tok.GradiantBottom.B, tok.GradiantBottom.A) },
new SKColor(tok.GradiantBottom.R, tok.GradiantBottom.G, tok.GradiantBottom.B, tok.GradiantBottom.A) }, new float[] { 0, 1 },
new float[] { 0, 1 }, SKShaderTileMode.Clamp);
SKShaderTileMode.Clamp); paint.Color = new SKColor(0xffffffff);
paint.Color = new SKColor(0xffffffff); } else {
} paint.Shader = null;
else paint.Color = new SKColor(tok.TextColor.R, tok.TextColor.G, tok.TextColor.B);
{ }
paint.Shader = null;
paint.Color = new SKColor(tok.TextColor.R, tok.TextColor.G, tok.TextColor.B);
}
canvas.DrawText(tok.s, 25 + x_offset, -paint.FontMetrics.Ascent + 25, paint); canvas.DrawText(tok.s, 25 + x_offset, -paint.FontMetrics.Ascent + 25, paint);
x_offset += token_width;
}
canvas.Flush();
images[i] = bitmap;
}
int ret_width = 0;
int ret_height = 0;
for (int i = 0; i < images.Length; i++) {
ret_width = Math.Max(ret_width, images[i].Width);
ret_height += images[i].Height - 25;
}
x_offset += token_width;
}
canvas.Flush();
images[i] = bitmap;
}
int ret_width = 0;
int ret_height = 0;
for(int i = 0; i < images.Length; i++)
{
ret_width = Math.Max(ret_width, images[i].Width);
ret_height += images[i].Height - 25;
}
SKImageInfo skImageInfo = new SKImageInfo(ret_width, ret_height); SKImageInfo skImageInfo = new SKImageInfo(ret_width, ret_height);
using var skSurface = SKSurface.Create(skImageInfo); using var skSurface = SKSurface.Create(skImageInfo);
@ -321,33 +271,28 @@ namespace FDK
int height_i = -25; int height_i = -25;
for (int i = 0; i < images.Length; i++) for (int i = 0; i < images.Length; i++) {
{ if (keepCenter) {
if (keepCenter) skCanvas.DrawBitmap(images[i], new SKPoint((ret_width / 2) - (images[i].Width / 2.0f), height_i));
{ } else {
skCanvas.DrawBitmap(images[i], new SKPoint((ret_width / 2) - (images[i].Width / 2.0f), height_i)); skCanvas.DrawBitmap(images[i], new SKPoint(0, height_i));
} }
else height_i += images[i].Height - 50;
{ images[i].Dispose();
skCanvas.DrawBitmap(images[i], new SKPoint(0, height_i)); }
}
height_i += images[i].Height - 50;
images[i].Dispose();
}
SKImage image = skSurface.Snapshot(); SKImage image = skSurface.Snapshot();
//返します //返します
return SKBitmap.FromImage(image); return SKBitmap.FromImage(image);
} }
public void Dispose() public void Dispose() {
{ paint.Dispose();
paint.Dispose(); }
}
private SKPaint paint = null; private SKPaint paint = null;
} }
} }

View File

@ -1,11 +1,8 @@
using System;
using SkiaSharp; using SkiaSharp;
using Color = System.Drawing.Color; using Color = System.Drawing.Color;
namespace FDK namespace FDK {
{ internal interface ITextRenderer : IDisposable {
internal interface ITextRenderer : IDisposable SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter);
{ }
SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter); }
}
}

View File

@ -192,4 +192,4 @@ namespace FDK
private List<stBeatPos> listBeatPositions = null; private List<stBeatPos> listBeatPositions = null;
} }
} }
*/ */

View File

@ -1,119 +1,96 @@
using System; using FDK;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TJAPlayer3;
using FDK;
namespace TJAPlayer3.Animations namespace TJAPlayer3.Animations {
{ class Animator : IAnimatable {
class Animator : IAnimatable public Animator(int startValue, int endValue, int tickInterval, bool isLoop) {
{ Type = CounterType.Normal;
public Animator(int startValue, int endValue, int tickInterval, bool isLoop) StartValue = startValue;
{ EndValue = endValue;
Type = CounterType.Normal; TickInterval = tickInterval;
StartValue = startValue; IsLoop = isLoop;
EndValue = endValue; Counter = new CCounter();
TickInterval = tickInterval; }
IsLoop = isLoop; public Animator(double startValue, double endValue, double tickInterval, bool isLoop) {
Counter = new CCounter(); Type = CounterType.Double;
} StartValue = startValue;
public Animator(double startValue, double endValue, double tickInterval, bool isLoop) EndValue = endValue;
{ TickInterval = tickInterval;
Type = CounterType.Double; IsLoop = isLoop;
StartValue = startValue; Counter = new CCounter();
EndValue = endValue; }
TickInterval = tickInterval; public void Start() {
IsLoop = isLoop; if (Counter == null) throw new NullReferenceException();
Counter = new CCounter(); switch (Type) {
} case CounterType.Normal:
public void Start() Counter.Start((int)StartValue, (int)EndValue, (int)TickInterval, TJAPlayer3.Timer);
{ break;
if (Counter == null) throw new NullReferenceException(); case CounterType.Double:
switch (Type) Counter.Start((double)StartValue, (double)EndValue, (double)TickInterval, SoundManager.PlayTimer);
{ break;
case CounterType.Normal: default:
Counter.Start((int)StartValue, (int)EndValue, (int)TickInterval, TJAPlayer3.Timer); break;
break; }
case CounterType.Double: }
Counter.Start((double)StartValue, (double)EndValue, (double)TickInterval, SoundManager.PlayTimer); public void Stop() {
break; if (Counter == null) throw new NullReferenceException();
default: Counter.Stop();
break; }
} public void Reset() {
} if (Counter == null) throw new NullReferenceException();
public void Stop() Start();
{ }
if (Counter == null) throw new NullReferenceException();
Counter.Stop();
}
public void Reset()
{
if (Counter == null) throw new NullReferenceException();
Start();
}
public void Tick() public void Tick() {
{ if (Counter == null) throw new NullReferenceException();
if (Counter == null) throw new NullReferenceException(); switch (Type) {
switch (Type) case CounterType.Normal:
{ if (IsLoop) Counter.TickLoop(); else Counter.Tick();
case CounterType.Normal: if (!IsLoop && Counter.IsEnded) Stop();
if (IsLoop) Counter.TickLoop(); else Counter.Tick(); break;
if (!IsLoop && Counter.IsEnded) Stop(); case CounterType.Double:
break; if (IsLoop) Counter.TickLoopDB(); else Counter.TickDB();
case CounterType.Double: if (!IsLoop && Counter.IsEnded) Stop();
if (IsLoop) Counter.TickLoopDB(); else Counter.TickDB(); break;
if (!IsLoop && Counter.IsEnded) Stop(); default:
break; break;
default: }
break; }
}
}
public virtual object GetAnimation() public virtual object GetAnimation() {
{ throw new NotImplementedException();
throw new NotImplementedException(); }
}
// プロパティ // プロパティ
public CCounter Counter public CCounter Counter {
{ get;
get; private set;
private set; }
} public CounterType Type {
public CounterType Type get;
{ private set;
get; }
private set; public object StartValue {
} get;
public object StartValue private set;
{ }
get; public object EndValue {
private set; get;
} private set;
public object EndValue }
{ public object TickInterval {
get; get;
private set; private set;
} }
public object TickInterval public bool IsLoop {
{ get;
get; private set;
private set; }
} }
public bool IsLoop
{
get;
private set;
}
}
enum CounterType enum CounterType {
{ Normal,
Normal, Double
Double }
}
} }

View File

@ -1,38 +1,29 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// イーズインを行うクラス。
using System.Text; /// </summary>
class EaseIn : Animator {
/// <summary>
/// イーズインを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseIn(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
namespace TJAPlayer3.Animations public override object GetAnimation() {
{ var persent = Counter.CurrentValue / (double)TimeMs;
/// <summary> return ((double)Sa * persent * persent * persent) + StartPoint;
/// イーズインを行うクラス。 }
/// </summary>
class EaseIn : Animator
{
/// <summary>
/// イーズインを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseIn(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation() private readonly int StartPoint;
{ private readonly int EndPoint;
var persent = Counter.CurrentValue / (double)TimeMs; private readonly int Sa;
return ((double)Sa * persent * persent * persent) + StartPoint; private readonly int TimeMs;
} }
private readonly int StartPoint;
private readonly int EndPoint;
private readonly int Sa;
private readonly int TimeMs;
}
} }

View File

@ -1,46 +1,34 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// イーズイン・アウトを行うクラス。
using System.Text; /// </summary>
class EaseInOut : Animator {
/// <summary>
/// イーズイン・アウトを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseInOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
namespace TJAPlayer3.Animations public override object GetAnimation() {
{ var persent = Counter.CurrentValue / (double)TimeMs * 2.0;
/// <summary> if (persent < 1) {
/// イーズイン・アウトを行うクラス。 return ((double)Sa / 2.0 * persent * persent * persent) + StartPoint;
/// </summary> } else {
class EaseInOut : Animator persent -= 2;
{ return ((double)Sa / 2.0 * ((persent * persent * persent) + 2)) + StartPoint;
/// <summary> }
/// イーズイン・アウトを初期化します。 }
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseInOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation() private readonly int StartPoint;
{ private readonly int EndPoint;
var persent = Counter.CurrentValue / (double)TimeMs * 2.0; private readonly int Sa;
if (persent < 1) private readonly int TimeMs;
{ }
return ((double)Sa / 2.0 * persent * persent * persent) + StartPoint;
}
else
{
persent -= 2;
return ((double)Sa / 2.0 * ((persent * persent * persent) + 2)) + StartPoint;
}
}
private readonly int StartPoint;
private readonly int EndPoint;
private readonly int Sa;
private readonly int TimeMs;
}
} }

View File

@ -1,39 +1,30 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// イーズアウトを行うクラス。
using System.Text; /// </summary>
class EaseOut : Animator {
/// <summary>
/// イーズアウトを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
namespace TJAPlayer3.Animations public override object GetAnimation() {
{ var persent = Counter.CurrentValue / (double)TimeMs;
/// <summary> persent -= 1;
/// イーズアウトを行うクラス。 return (double)Sa * (persent * persent * persent + 1) + StartPoint;
/// </summary> }
class EaseOut : Animator
{
/// <summary>
/// イーズアウトを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation() private readonly int StartPoint;
{ private readonly int EndPoint;
var persent = Counter.CurrentValue / (double)TimeMs; private readonly int Sa;
persent -= 1; private readonly int TimeMs;
return (double)Sa * (persent * persent * persent + 1) + StartPoint; }
}
private readonly int StartPoint;
private readonly int EndPoint;
private readonly int Sa;
private readonly int TimeMs;
}
} }

View File

@ -1,34 +1,25 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// フェードインを行うクラス。
using System.Text; /// </summary>
internal class FadeIn : Animator {
/// <summary>
/// フェードインを初期化します。
/// </summary>
/// <param name="timems">フェードインに掛ける秒数(ミリ秒)</param>
public FadeIn(int timems) : base(0, timems - 1, 1, false) {
TimeMs = timems;
}
namespace TJAPlayer3.Animations /// <summary>
{ /// フェードインの不透明度を255段階で返します。
/// <summary> /// </summary>
/// フェードインを行うクラス。 /// <returns>不透明度。</returns>
/// </summary> public override object GetAnimation() {
internal class FadeIn : Animator var opacity = base.Counter.CurrentValue * 255 / TimeMs;
{ return opacity;
/// <summary> }
/// フェードインを初期化します。
/// </summary>
/// <param name="timems">フェードインに掛ける秒数(ミリ秒)</param>
public FadeIn(int timems) : base(0, timems - 1, 1, false)
{
TimeMs = timems;
}
/// <summary> private readonly int TimeMs;
/// フェードインの不透明度を255段階で返します。 }
/// </summary>
/// <returns>不透明度。</returns>
public override object GetAnimation()
{
var opacity = base.Counter.CurrentValue * 255 / TimeMs;
return opacity;
}
private readonly int TimeMs;
}
} }

View File

@ -1,34 +1,25 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// フェードアウトを行うクラス。
using System.Text; /// </summary>
internal class FadeOut : Animator {
/// <summary>
/// フェードアウトを初期化します。
/// </summary>
/// <param name="timems">フェードアウトに掛ける秒数(ミリ秒)</param>
public FadeOut(int timems) : base(0, timems - 1, 1, false) {
TimeMs = timems;
}
namespace TJAPlayer3.Animations /// <summary>
{ /// フェードアウトの不透明度を255段階で返します。
/// <summary> /// </summary>
/// フェードアウトを行うクラス。 /// <returns>不透明度。</returns>
/// </summary> public override object GetAnimation() {
internal class FadeOut : Animator var opacity = (TimeMs - base.Counter.CurrentValue) * 255 / TimeMs;
{ return opacity;
/// <summary> }
/// フェードアウトを初期化します。
/// </summary>
/// <param name="timems">フェードアウトに掛ける秒数(ミリ秒)</param>
public FadeOut(int timems) : base(0, timems - 1, 1, false)
{
TimeMs = timems;
}
/// <summary> private readonly int TimeMs;
/// フェードアウトの不透明度を255段階で返します。 }
/// </summary>
/// <returns>不透明度。</returns>
public override object GetAnimation()
{
var opacity = (TimeMs - base.Counter.CurrentValue) * 255 / TimeMs;
return opacity;
}
private readonly int TimeMs;
}
} }

View File

@ -1,35 +1,28 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// アニメーション インターフェイス。
using System.Text; /// </summary>
interface IAnimatable {
namespace TJAPlayer3.Animations /// <summary>
{ /// アニメーションを開始します。
/// <summary> /// </summary>
/// アニメーション インターフェイス。 void Start();
/// </summary> /// <summary>
interface IAnimatable /// アニメーションを停止します。
{ /// </summary>
/// <summary> void Stop();
/// アニメーションを開始します。 /// <summary>
/// </summary> /// アニメーションをリセットします。
void Start(); /// </summary>
/// <summary> void Reset();
/// アニメーションを停止します。 /// <summary>
/// </summary> /// アニメーションの進行を行います。
void Stop(); /// </summary>
/// <summary> void Tick();
/// アニメーションをリセットします。 /// <summary>
/// </summary> /// アニメーションのパラメータを返します。
void Reset(); /// </summary>
/// <summary> /// <returns>アニメーションのパラメータを返します。</returns>
/// アニメーションの進行を行います。 object GetAnimation();
/// </summary> }
void Tick();
/// <summary>
/// アニメーションのパラメータを返します。
/// </summary>
/// <returns>アニメーションのパラメータを返します。</returns>
object GetAnimation();
}
} }

View File

@ -1,38 +1,29 @@
using System; namespace TJAPlayer3.Animations {
using System.Collections.Generic; /// <summary>
using System.Linq; /// リニア移動を行うクラス。
using System.Text; /// </summary>
class Linear : Animator {
/// <summary>
/// リニア移動を初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">移動にかける時間。</param>
public Linear(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
namespace TJAPlayer3.Animations public override object GetAnimation() {
{ var persent = Counter.CurrentValue / (double)TimeMs;
/// <summary> return (Sa * persent) + StartPoint;
/// リニア移動を行うクラス。 }
/// </summary>
class Linear : Animator
{
/// <summary>
/// リニア移動を初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">移動にかける時間。</param>
public Linear(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation() private readonly int StartPoint;
{ private readonly int EndPoint;
var persent = Counter.CurrentValue / (double)TimeMs; private readonly int Sa;
return (Sa * persent) + StartPoint; private readonly int TimeMs;
} }
private readonly int StartPoint;
private readonly int EndPoint;
private readonly int Sa;
private readonly int TimeMs;
}
} }

View File

@ -1,347 +1,288 @@
using System; using FDK;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ class CMenuCharacter {
class CMenuCharacter private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
{ private static CCounter[] ctCharacterSelect = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterStart = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterSelect = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterWait = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterStart = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterEntry = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterWait = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterEntryNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterEntry = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterEntryNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
public enum ECharacterAnimation public enum ECharacterAnimation {
{ // Song select
// Song select NORMAL,
NORMAL, START,
START, SELECT,
SELECT, WAIT,
WAIT, // Main menu
// Main menu ENTRY,
ENTRY, ENTRY_NORMAL,
ENTRY_NORMAL, }
}
private static bool _usesSubstituteTexture(int player, ECharacterAnimation eca) private static bool _usesSubstituteTexture(int player, ECharacterAnimation eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
{ switch (eca) {
switch (eca) case (ECharacterAnimation.NORMAL): {
{ if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
case (ECharacterAnimation.NORMAL): return false;
{ break;
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0) }
return false; case (ECharacterAnimation.START): {
break; if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0)
} return false;
case (ECharacterAnimation.START): break;
{ }
if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0) case (ECharacterAnimation.SELECT): {
return false; if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0)
break; return false;
} break;
case (ECharacterAnimation.SELECT): }
{ case (ECharacterAnimation.WAIT): {
if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0)
return false; return false;
break; break;
} }
case (ECharacterAnimation.WAIT): case (ECharacterAnimation.ENTRY): {
{ if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0)
if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0) return false;
return false; break;
break; }
} case (ECharacterAnimation.ENTRY_NORMAL): {
case (ECharacterAnimation.ENTRY): if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
{ return false;
if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0) break;
return false; }
break; }
} }
case (ECharacterAnimation.ENTRY_NORMAL):
{
if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
return false;
break;
}
}
}
return true; return true;
} }
public static CTexture[] _getReferenceArray(int player, ECharacterAnimation eca) public static CTexture[] _getReferenceArray(int player, ECharacterAnimation eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
{ switch (eca) {
switch (eca) case (ECharacterAnimation.NORMAL): {
{ if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
case (ECharacterAnimation.NORMAL): return TJAPlayer3.Tx.Characters_Menu_Loop[_charaId];
{ if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0) return TJAPlayer3.Tx.Characters_Normal[_charaId];
return TJAPlayer3.Tx.Characters_Menu_Loop[_charaId]; break;
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0) }
return TJAPlayer3.Tx.Characters_Normal[_charaId]; case (ECharacterAnimation.START): {
break; if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0)
} return TJAPlayer3.Tx.Characters_Menu_Start[_charaId];
case (ECharacterAnimation.START): if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
{ return TJAPlayer3.Tx.Characters_10Combo[_charaId];
if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0) break;
return TJAPlayer3.Tx.Characters_Menu_Start[_charaId]; }
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0) case (ECharacterAnimation.SELECT): {
return TJAPlayer3.Tx.Characters_10Combo[_charaId]; if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0)
break; return TJAPlayer3.Tx.Characters_Menu_Select[_charaId];
} if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
case (ECharacterAnimation.SELECT): return TJAPlayer3.Tx.Characters_10Combo[_charaId];
{ break;
if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0) }
return TJAPlayer3.Tx.Characters_Menu_Select[_charaId]; case (ECharacterAnimation.WAIT): {
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId]; return TJAPlayer3.Tx.Characters_Menu_Wait[_charaId];
break; if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
} return TJAPlayer3.Tx.Characters_Menu_Loop[_charaId];
case (ECharacterAnimation.WAIT): if (TJAPlayer3.Tx.Characters_GoGoTime[_charaId].Length > 0)
{ return TJAPlayer3.Tx.Characters_GoGoTime[_charaId];
if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0) break;
return TJAPlayer3.Tx.Characters_Menu_Wait[_charaId]; }
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0) case (ECharacterAnimation.ENTRY): {
return TJAPlayer3.Tx.Characters_Menu_Loop[_charaId]; if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0)
if (TJAPlayer3.Tx.Characters_GoGoTime[_charaId].Length > 0) return TJAPlayer3.Tx.Characters_Title_Entry[_charaId];
return TJAPlayer3.Tx.Characters_GoGoTime[_charaId]; if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
break; return TJAPlayer3.Tx.Characters_10Combo[_charaId];
} break;
case (ECharacterAnimation.ENTRY): }
{ case (ECharacterAnimation.ENTRY_NORMAL): {
if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Title_Entry[_charaId]; return TJAPlayer3.Tx.Characters_Title_Normal[_charaId];
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId]; return TJAPlayer3.Tx.Characters_Normal[_charaId];
break; break;
} }
case (ECharacterAnimation.ENTRY_NORMAL): }
{ }
if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Title_Normal[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId];
break;
}
}
}
return null;
}
public static CCounter[] _getReferenceCounter(ECharacterAnimation eca)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
return ctCharacterNormal;
}
case (ECharacterAnimation.START):
{
return ctCharacterStart;
}
case (ECharacterAnimation.SELECT):
{
return ctCharacterSelect;
}
case (ECharacterAnimation.WAIT):
{
return ctCharacterWait;
}
case (ECharacterAnimation.ENTRY):
{
return ctCharacterEntry;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
return ctCharacterEntryNormal;
}
}
return null;
}
public static int _getReferenceAnimationDuration(int player, ECharacterAnimation eca)
{
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
return TJAPlayer3.Skin.Characters_Menu_Loop_AnimationDuration[_charaId];
}
case (ECharacterAnimation.START):
{
return TJAPlayer3.Skin.Characters_Menu_Start_AnimationDuration[_charaId];
}
case (ECharacterAnimation.SELECT):
{
return TJAPlayer3.Skin.Characters_Menu_Select_AnimationDuration[_charaId];
}
case (ECharacterAnimation.WAIT):
{
return TJAPlayer3.Skin.Characters_Menu_Wait_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY):
{
return TJAPlayer3.Skin.Characters_Title_Entry_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
return TJAPlayer3.Skin.Characters_Title_Normal_AnimationDuration[_charaId];
}
}
return 1000;
}
public static void tDisableCounter(ECharacterAnimation eca)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
for (int i = 0; i < 5; i++)
ctCharacterNormal[i] = new CCounter();
break;
}
case (ECharacterAnimation.START):
{
for (int i = 0; i < 5; i++)
ctCharacterStart[i] = new CCounter();
break;
}
case (ECharacterAnimation.SELECT):
{
for (int i = 0; i < 5; i++)
ctCharacterSelect[i] = new CCounter();
break;
}
case (ECharacterAnimation.WAIT):
{
for (int i = 0; i < 5; i++)
ctCharacterWait[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY):
{
for (int i = 0; i < 5; i++)
ctCharacterEntry[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
for (int i = 0; i < 5; i++)
ctCharacterEntryNormal[i] = new CCounter();
break;
}
}
}
public static void tMenuResetTimer(int player, ECharacterAnimation eca) return null;
{ }
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
int _animeref = _getReferenceAnimationDuration(player, eca);
if (_ref != null && _ref.Length > 0 && _ctref != null) public static CCounter[] _getReferenceCounter(ECharacterAnimation eca) {
{ switch (eca) {
_ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer); case (ECharacterAnimation.NORMAL): {
} return ctCharacterNormal;
} }
case (ECharacterAnimation.START): {
return ctCharacterStart;
}
case (ECharacterAnimation.SELECT): {
return ctCharacterSelect;
}
case (ECharacterAnimation.WAIT): {
return ctCharacterWait;
}
case (ECharacterAnimation.ENTRY): {
return ctCharacterEntry;
}
case (ECharacterAnimation.ENTRY_NORMAL): {
return ctCharacterEntryNormal;
}
}
return null;
}
public static void tMenuResetTimer(ECharacterAnimation eca) public static int _getReferenceAnimationDuration(int player, ECharacterAnimation eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
for (int i = 0; i < 5; i++)
{
tMenuResetTimer(i, eca);
}
}
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterAnimation eca, int opacity = 255) switch (eca) {
{ case (ECharacterAnimation.NORMAL): {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character; return TJAPlayer3.Skin.Characters_Menu_Loop_AnimationDuration[_charaId];
CTexture[] _ref = _getReferenceArray(player, eca); }
CCounter[] _ctref = _getReferenceCounter(eca); case (ECharacterAnimation.START): {
bool _substitute = _usesSubstituteTexture(player, eca); return TJAPlayer3.Skin.Characters_Menu_Start_AnimationDuration[_charaId];
}
case (ECharacterAnimation.SELECT): {
return TJAPlayer3.Skin.Characters_Menu_Select_AnimationDuration[_charaId];
}
case (ECharacterAnimation.WAIT): {
return TJAPlayer3.Skin.Characters_Menu_Wait_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY): {
return TJAPlayer3.Skin.Characters_Title_Entry_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY_NORMAL): {
return TJAPlayer3.Skin.Characters_Title_Normal_AnimationDuration[_charaId];
}
}
return 1000;
}
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) public static void tDisableCounter(ECharacterAnimation eca) {
{ switch (eca) {
if (eca == ECharacterAnimation.NORMAL case (ECharacterAnimation.NORMAL): {
|| eca == ECharacterAnimation.WAIT for (int i = 0; i < 5; i++)
|| eca == ECharacterAnimation.ENTRY ctCharacterNormal[i] = new CCounter();
|| eca == ECharacterAnimation.ENTRY_NORMAL) break;
_ctref[player].TickLoop(); }
else case (ECharacterAnimation.START): {
_ctref[player].Tick(); for (int i = 0; i < 5; i++)
ctCharacterStart[i] = new CCounter();
break;
}
case (ECharacterAnimation.SELECT): {
for (int i = 0; i < 5; i++)
ctCharacterSelect[i] = new CCounter();
break;
}
case (ECharacterAnimation.WAIT): {
for (int i = 0; i < 5; i++)
ctCharacterWait[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY): {
for (int i = 0; i < 5; i++)
ctCharacterEntry[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY_NORMAL): {
for (int i = 0; i < 5; i++)
ctCharacterEntryNormal[i] = new CCounter();
break;
}
}
// Quick fix }
if (_ctref[player].CurrentValue >= _ref.Length) return;
var _tex = _ref[_ctref[player].CurrentValue];
_tex.Opacity = opacity; public static void tMenuResetTimer(int player, ECharacterAnimation eca) {
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
int _animeref = _getReferenceAnimationDuration(player, eca);
float resolutionRatioX = TJAPlayer3.Skin.Resolution[0] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][0]; if (_ref != null && _ref.Length > 0 && _ctref != null) {
float resolutionRatioY = TJAPlayer3.Skin.Resolution[1] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][1]; _ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer);
}
}
//float _x = (x + (150.0f * (TJAPlayer3.Skin.Characters_Resolution[_charaId][0] / 1280.0f))) * resolutionRatioX; public static void tMenuResetTimer(ECharacterAnimation eca) {
//float _y = (y + (((_substitute == true) ? 290 : _ref[_ctref[player].n現在の値].szテクスチャサイズ.Height)) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][1] / 720.0f)) * resolutionRatioY; for (int i = 0; i < 5; i++) {
tMenuResetTimer(i, eca);
}
}
_tex.vcScaleRatio.X *= resolutionRatioX; public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterAnimation eca, int opacity = 255) {
_tex.vcScaleRatio.Y *= resolutionRatioY; int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
bool _substitute = _usesSubstituteTexture(player, eca);
float _x = x; if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) {
float _y = y; if (eca == ECharacterAnimation.NORMAL
|| eca == ECharacterAnimation.WAIT
|| eca == ECharacterAnimation.ENTRY
|| eca == ECharacterAnimation.ENTRY_NORMAL)
_ctref[player].TickLoop();
else
_ctref[player].Tick();
if (player % 2 == 0) // Quick fix
{ if (_ctref[player].CurrentValue >= _ref.Length) return;
//_ref[_ctref[player].n現在の値].t2D描画(x, y);
//_ref[_ctref[player].n現在の値].t2D中心基準描画(x + 150, y + 156);
_tex.t2D拡大率考慮下中心基準描画( var _tex = _ref[_ctref[player].CurrentValue];
_x,
_y // 312 _tex.Opacity = opacity;
);
float resolutionRatioX = TJAPlayer3.Skin.Resolution[0] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][0];
float resolutionRatioY = TJAPlayer3.Skin.Resolution[1] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][1];
//float _x = (x + (150.0f * (TJAPlayer3.Skin.Characters_Resolution[_charaId][0] / 1280.0f))) * resolutionRatioX;
//float _y = (y + (((_substitute == true) ? 290 : _ref[_ctref[player].n現在の値].szテクスチャサイズ.Height)) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][1] / 720.0f)) * resolutionRatioY;
_tex.vcScaleRatio.X *= resolutionRatioX;
_tex.vcScaleRatio.Y *= resolutionRatioY;
float _x = x;
float _y = y;
if (player % 2 == 0) {
//_ref[_ctref[player].n現在の値].t2D描画(x, y);
//_ref[_ctref[player].n現在の値].t2D中心基準描画(x + 150, y + 156);
_tex.t2D拡大率考慮下中心基準描画(
_x,
_y // 312
);
} } else {
else //_ref[_ctref[player].n現在の値].t2D左右反転描画(x, y);
{ //_ref[_ctref[player].n現在の値].t2D中心基準描画Mirrored(x + 150, y + 156);
//_ref[_ctref[player].n現在の値].t2D左右反転描画(x, y);
//_ref[_ctref[player].n現在の値].t2D中心基準描画Mirrored(x + 150, y + 156);
_tex.t2D拡大率考慮下中心基準描画Mirrored( _tex.t2D拡大率考慮下中心基準描画Mirrored(
_x, _x,
_y // 312 _y // 312
); );
} }
_tex.vcScaleRatio.X = 1f; _tex.vcScaleRatio.X = 1f;
_tex.vcScaleRatio.Y = 1f; _tex.vcScaleRatio.Y = 1f;
_tex.Opacity = 255; _tex.Opacity = 255;
} }
} }
} }
} }

View File

@ -1,296 +1,245 @@
using System; using FDK;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ class CResultCharacter {
class CResultCharacter private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
{ private static CCounter[] ctCharacterClear = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterFailed = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterClear = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() }; private static CCounter[] ctCharacterFailedIn = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterFailed = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterFailedIn = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
public enum ECharacterResult public enum ECharacterResult {
{ // Song select
// Song select NORMAL,
NORMAL, CLEAR,
CLEAR, FAILED,
FAILED, FAILED_IN,
FAILED_IN, }
}
public static bool tIsCounterProcessing(int player, ECharacterResult eca) public static bool tIsCounterProcessing(int player, ECharacterResult eca) {
{ CCounter[] _ctref = _getReferenceCounter(eca);
CCounter[] _ctref = _getReferenceCounter(eca);
if (_ctref[player] != null) if (_ctref[player] != null)
return _ctref[player].IsTicked; return _ctref[player].IsTicked;
return false; return false;
} }
public static bool tIsCounterEnded(int player, ECharacterResult eca) public static bool tIsCounterEnded(int player, ECharacterResult eca) {
{ CCounter[] _ctref = _getReferenceCounter(eca);
CCounter[] _ctref = _getReferenceCounter(eca);
if (_ctref[player] != null) if (_ctref[player] != null)
return _ctref[player].IsEnded; return _ctref[player].IsEnded;
return false; return false;
} }
private static bool _usesSubstituteTexture(int player, ECharacterResult eca) private static bool _usesSubstituteTexture(int player, ECharacterResult eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
{ switch (eca) {
switch (eca) case (ECharacterResult.NORMAL): {
{ if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0)
case (ECharacterResult.NORMAL): return false;
{ break;
if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0) }
return false; case (ECharacterResult.CLEAR): {
break; if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0)
} return false;
case (ECharacterResult.CLEAR): break;
{ }
if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0) case (ECharacterResult.FAILED): {
return false; if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0)
break; return false;
} break;
case (ECharacterResult.FAILED): }
{ case (ECharacterResult.FAILED_IN): {
if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0)
return false; return false;
break; break;
} }
case (ECharacterResult.FAILED_IN): }
{ }
if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0)
return false;
break;
}
}
}
return true; return true;
} }
public static CTexture[] _getReferenceArray(int player, ECharacterResult eca) public static CTexture[] _getReferenceArray(int player, ECharacterResult eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
{ switch (eca) {
switch (eca) case (ECharacterResult.NORMAL): {
{ if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0)
case (ECharacterResult.NORMAL): return TJAPlayer3.Tx.Characters_Result_Normal[_charaId];
{ if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0) return TJAPlayer3.Tx.Characters_Normal[_charaId];
return TJAPlayer3.Tx.Characters_Result_Normal[_charaId]; break;
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0) }
return TJAPlayer3.Tx.Characters_Normal[_charaId]; case (ECharacterResult.CLEAR): {
break; if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0)
} return TJAPlayer3.Tx.Characters_Result_Clear[_charaId];
case (ECharacterResult.CLEAR): if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
{ return TJAPlayer3.Tx.Characters_10Combo[_charaId];
if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0) break;
return TJAPlayer3.Tx.Characters_Result_Clear[_charaId]; }
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0) case (ECharacterResult.FAILED): {
return TJAPlayer3.Tx.Characters_10Combo[_charaId]; if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0)
break; return TJAPlayer3.Tx.Characters_Result_Failed[_charaId];
} if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
case (ECharacterResult.FAILED): return TJAPlayer3.Tx.Characters_Normal[_charaId];
{ break;
if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0) }
return TJAPlayer3.Tx.Characters_Result_Failed[_charaId]; case (ECharacterResult.FAILED_IN): {
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0) if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId]; return TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId];
break; if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
} return TJAPlayer3.Tx.Characters_Normal[_charaId];
case (ECharacterResult.FAILED_IN): break;
{ }
if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0) }
return TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId]; }
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId];
break;
}
}
}
return null; return null;
} }
public static CCounter[] _getReferenceCounter(ECharacterResult eca) public static CCounter[] _getReferenceCounter(ECharacterResult eca) {
{ switch (eca) {
switch (eca) case (ECharacterResult.NORMAL): {
{ return ctCharacterNormal;
case (ECharacterResult.NORMAL): }
{ case (ECharacterResult.CLEAR): {
return ctCharacterNormal; return ctCharacterClear;
} }
case (ECharacterResult.CLEAR): case (ECharacterResult.FAILED): {
{ return ctCharacterFailed;
return ctCharacterClear; }
} case (ECharacterResult.FAILED_IN): {
case (ECharacterResult.FAILED): return ctCharacterFailedIn;
{ }
return ctCharacterFailed; }
} return null;
case (ECharacterResult.FAILED_IN): }
{
return ctCharacterFailedIn;
}
}
return null;
}
public static int _getReferenceAnimationDuration(int player, ECharacterResult eca) public static int _getReferenceAnimationDuration(int player, ECharacterResult eca) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
switch (eca) switch (eca) {
{ case (ECharacterResult.NORMAL): {
case (ECharacterResult.NORMAL): return TJAPlayer3.Skin.Characters_Result_Normal_AnimationDuration[_charaId];
{ }
return TJAPlayer3.Skin.Characters_Result_Normal_AnimationDuration[_charaId]; case (ECharacterResult.CLEAR): {
} return TJAPlayer3.Skin.Characters_Result_Clear_AnimationDuration[_charaId];
case (ECharacterResult.CLEAR): }
{ case (ECharacterResult.FAILED): {
return TJAPlayer3.Skin.Characters_Result_Clear_AnimationDuration[_charaId]; return TJAPlayer3.Skin.Characters_Result_Failed_AnimationDuration[_charaId];
} }
case (ECharacterResult.FAILED): case (ECharacterResult.FAILED_IN): {
{ return TJAPlayer3.Skin.Characters_Result_Failed_In_AnimationDuration[_charaId];
return TJAPlayer3.Skin.Characters_Result_Failed_AnimationDuration[_charaId]; }
} }
case (ECharacterResult.FAILED_IN): return 1000;
{ }
return TJAPlayer3.Skin.Characters_Result_Failed_In_AnimationDuration[_charaId];
}
}
return 1000;
}
public static void tDisableCounter(ECharacterResult eca) public static void tDisableCounter(ECharacterResult eca) {
{ switch (eca) {
switch (eca) case (ECharacterResult.NORMAL): {
{ for (int i = 0; i < 5; i++)
case (ECharacterResult.NORMAL): ctCharacterNormal[i] = new CCounter();
{ break;
for (int i = 0; i < 5; i++) }
ctCharacterNormal[i] = new CCounter(); case (ECharacterResult.CLEAR): {
break; for (int i = 0; i < 5; i++)
} ctCharacterClear[i] = new CCounter();
case (ECharacterResult.CLEAR): break;
{ }
for (int i = 0; i < 5; i++) case (ECharacterResult.FAILED): {
ctCharacterClear[i] = new CCounter(); for (int i = 0; i < 5; i++)
break; ctCharacterFailed[i] = new CCounter();
} break;
case (ECharacterResult.FAILED): }
{ case (ECharacterResult.FAILED_IN): {
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
ctCharacterFailed[i] = new CCounter(); ctCharacterFailedIn[i] = new CCounter();
break; break;
} }
case (ECharacterResult.FAILED_IN): }
{
for (int i = 0; i < 5; i++)
ctCharacterFailedIn[i] = new CCounter();
break;
}
}
} }
public static void tMenuResetTimer(int player, ECharacterResult eca) public static void tMenuResetTimer(int player, ECharacterResult eca) {
{ CTexture[] _ref = _getReferenceArray(player, eca);
CTexture[] _ref = _getReferenceArray(player, eca); CCounter[] _ctref = _getReferenceCounter(eca);
CCounter[] _ctref = _getReferenceCounter(eca); int _animeref = _getReferenceAnimationDuration(player, eca);
int _animeref = _getReferenceAnimationDuration(player, eca);
if (_ref != null && _ref.Length > 0 && _ctref != null) if (_ref != null && _ref.Length > 0 && _ctref != null) {
{ _ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer);
_ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer); }
} }
}
public static void tMenuResetTimer(ECharacterResult eca) public static void tMenuResetTimer(ECharacterResult eca) {
{ for (int i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++) tMenuResetTimer(i, eca);
{ }
tMenuResetTimer(i, eca); }
}
}
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterResult eca, int pos = 0, int opacity = 255) public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterResult eca, int pos = 0, int opacity = 255) {
{ int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character; CTexture[] _ref = _getReferenceArray(player, eca);
CTexture[] _ref = _getReferenceArray(player, eca); CCounter[] _ctref = _getReferenceCounter(eca);
CCounter[] _ctref = _getReferenceCounter(eca); bool _substitute = _usesSubstituteTexture(player, eca);
bool _substitute = _usesSubstituteTexture(player, eca);
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) {
{ if (eca == ECharacterResult.NORMAL
if (eca == ECharacterResult.NORMAL || eca == ECharacterResult.CLEAR
|| eca == ECharacterResult.CLEAR || eca == ECharacterResult.FAILED)
|| eca == ECharacterResult.FAILED) _ctref[player].TickLoop();
_ctref[player].TickLoop(); else
else _ctref[player].Tick();
_ctref[player].Tick();
// Quick fix // Quick fix
if (_ctref[player].CurrentValue >= _ref.Length) return; if (_ctref[player].CurrentValue >= _ref.Length) return;
var _tex = _ref[_ctref[player].CurrentValue]; var _tex = _ref[_ctref[player].CurrentValue];
_tex.Opacity = opacity; _tex.Opacity = opacity;
float resolutionRatioX = TJAPlayer3.Skin.Resolution[0] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][0]; float resolutionRatioX = TJAPlayer3.Skin.Resolution[0] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][0];
float resolutionRatioY = TJAPlayer3.Skin.Resolution[1] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][1]; float resolutionRatioY = TJAPlayer3.Skin.Resolution[1] / (float)TJAPlayer3.Skin.Characters_Resolution[_charaId][1];
//202 //202
//float _x = (x - (((_substitute == true) ? 20 : 40) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][0] / 1280.0f))) * resolutionRatioX; //float _x = (x - (((_substitute == true) ? 20 : 40) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][0] / 1280.0f))) * resolutionRatioX;
//532 //532
//float _y = (y - (((_substitute == true) ? 20 : 40) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][1] / 720.0f))) * resolutionRatioY; //float _y = (y - (((_substitute == true) ? 20 : 40) * (TJAPlayer3.Skin.Characters_Resolution[_charaId][1] / 720.0f))) * resolutionRatioY;
float _x = x; float _x = x;
float _y = y; float _y = y;
_tex.vcScaleRatio.X *= resolutionRatioX; _tex.vcScaleRatio.X *= resolutionRatioX;
_tex.vcScaleRatio.Y *= resolutionRatioY; _tex.vcScaleRatio.Y *= resolutionRatioY;
if (pos % 2 == 0 || TJAPlayer3.ConfigIni.nPlayerCount > 2) if (pos % 2 == 0 || TJAPlayer3.ConfigIni.nPlayerCount > 2) {
{ _tex.t2D拡大率考慮下中心基準描画(
_tex.t2D拡大率考慮下中心基準描画( _x,
_x, _y
_y );
); } else {
} _tex.t2D拡大率考慮下中心基準描画Mirrored(
else _x,
{ _y
_tex.t2D拡大率考慮下中心基準描画Mirrored( );
_x, }
_y
);
}
_tex.vcScaleRatio.X = 1f; _tex.vcScaleRatio.X = 1f;
_tex.vcScaleRatio.Y = 1f; _tex.vcScaleRatio.Y = 1f;
_tex.Opacity = 255; _tex.Opacity = 255;
} }
} }
} }
} }

View File

@ -1,133 +1,116 @@
using TJAPlayer3; using FDK;
using FDK;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Silk.NET.Maths; using Silk.NET.Maths;
using Rectangle = System.Drawing.Rectangle; using Rectangle = System.Drawing.Rectangle;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ class PuchiChara : CActivity {
class PuchiChara : CActivity public PuchiChara() {
{ base.IsDeActivated = true;
public PuchiChara() }
{
base.IsDeActivated = true;
}
public override void Activate() public override void Activate() {
{ Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, TJAPlayer3.Skin.Game_PuchiChara_Timer * 0.5f, TJAPlayer3.Timer);
Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, TJAPlayer3.Skin.Game_PuchiChara_Timer * 0.5f, TJAPlayer3.Timer); SineCounter = new CCounter(0, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer, SoundManager.PlayTimer);
SineCounter = new CCounter(0, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer, SoundManager.PlayTimer); SineCounterIdle = new CCounter(1, 360, (float)TJAPlayer3.Skin.Game_PuchiChara_SineTimer * 2f, TJAPlayer3.Timer);
SineCounterIdle = new CCounter(1, 360, (float)TJAPlayer3.Skin.Game_PuchiChara_SineTimer * 2f, TJAPlayer3.Timer); this.inGame = false;
this.inGame = false; base.Activate();
base.Activate(); }
} public override void DeActivate() {
public override void DeActivate() Counter = null;
{ SineCounter = null;
Counter = null; SineCounterIdle = null;
SineCounter = null; base.DeActivate();
SineCounterIdle = null; }
base.DeActivate();
}
public static int tGetPuchiCharaIndexByName(int p) public static int tGetPuchiCharaIndexByName(int p) {
{ var _pc = TJAPlayer3.SaveFileInstances[p].data.PuchiChara;
var _pc = TJAPlayer3.SaveFileInstances[p].data.PuchiChara; var _pcs = TJAPlayer3.Skin.Puchicharas_Name;
var _pcs = TJAPlayer3.Skin.Puchicharas_Name; int puriChar = 0;
int puriChar = 0; if (_pcs.Contains(_pc))
if (_pcs.Contains(_pc)) puriChar = _pcs.ToList().IndexOf(_pc);
puriChar = _pcs.ToList().IndexOf(_pc);
return puriChar; return puriChar;
} }
public void ChangeBPM(double bpm)
{
Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, (int)(TJAPlayer3.Skin.Game_PuchiChara_Timer * bpm / TJAPlayer3.Skin.Game_PuchiChara[2]), TJAPlayer3.Timer);
SineCounter = new CCounter(1, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer * bpm / 180, SoundManager.PlayTimer);
this.inGame = true;
}
public void IdleAnimation() public void ChangeBPM(double bpm) {
{ Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, (int)(TJAPlayer3.Skin.Game_PuchiChara_Timer * bpm / TJAPlayer3.Skin.Game_PuchiChara[2]), TJAPlayer3.Timer);
this.inGame = false; SineCounter = new CCounter(1, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer * bpm / 180, SoundManager.PlayTimer);
} this.inGame = true;
}
/// <summary> public void IdleAnimation() {
/// ぷちキャラを描画する。(オーバーライドじゃないよ) this.inGame = false;
/// </summary> }
/// <param name="x">X座標(中央)</param>
/// <param name="y">Y座標(中央)</param>
/// <param name="alpha">不透明度</param>
/// <returns></returns>
public int On進行描画(int x, int y, bool isGrowing, int alpha = 255, bool isBalloon = false, int player = 0, float scale = 1.0f)
{
if (!TJAPlayer3.ConfigIni.ShowPuchiChara) return base.Draw();
if (Counter == null || SineCounter == null || TJAPlayer3.Tx.Puchichara == null) return base.Draw();
Counter.TickLoop();
SineCounter.TickLoopDB();
SineCounterIdle.TickLoop();
int p = TJAPlayer3.GetActualPlayer(player); /// <summary>
/// ぷちキャラを描画する。(オーバーライドじゃないよ)
/// </summary>
/// <param name="x">X座標(中央)</param>
/// <param name="y">Y座標(中央)</param>
/// <param name="alpha">不透明度</param>
/// <returns></returns>
public int On進行描画(int x, int y, bool isGrowing, int alpha = 255, bool isBalloon = false, int player = 0, float scale = 1.0f) {
if (!TJAPlayer3.ConfigIni.ShowPuchiChara) return base.Draw();
if (Counter == null || SineCounter == null || TJAPlayer3.Tx.Puchichara == null) return base.Draw();
Counter.TickLoop();
SineCounter.TickLoopDB();
SineCounterIdle.TickLoop();
/* int p = TJAPlayer3.GetActualPlayer(player);
/*
TJAPlayer3.act文字コンソール.tPrint(700, 500, C文字コンソール.Eフォント種別., Counter.n現在の値.ToString()); TJAPlayer3.act文字コンソール.tPrint(700, 500, C文字コンソール.Eフォント種別., Counter.n現在の値.ToString());
TJAPlayer3.act文字コンソール.tPrint(700, 520, C文字コンソール.Eフォント種別., SineCounter.n現在の値.ToString()); TJAPlayer3.act文字コンソール.tPrint(700, 520, C文字コンソール.Eフォント種別., SineCounter.n現在の値.ToString());
TJAPlayer3.act文字コンソール.tPrint(700, 540, C文字コンソール.Eフォント種別., SineCounterIdle.n現在の値.ToString()); TJAPlayer3.act文字コンソール.tPrint(700, 540, C文字コンソール.Eフォント種別., SineCounterIdle.n現在の値.ToString());
*/ */
if (inGame) if (inGame)
sineY = (double)SineCounter.CurrentValue; sineY = (double)SineCounter.CurrentValue;
else else
sineY = (double)SineCounterIdle.CurrentValue; sineY = (double)SineCounterIdle.CurrentValue;
// TJAPlayer3.act文字コンソール.tPrint(700, 560, C文字コンソール.Eフォント種別.白, sineY.ToString()); // TJAPlayer3.act文字コンソール.tPrint(700, 560, C文字コンソール.Eフォント種別.白, sineY.ToString());
sineY = Math.Sin(sineY * (Math.PI / 180)) * (TJAPlayer3.Skin.Game_PuchiChara_Sine * (isBalloon ? TJAPlayer3.Skin.Game_PuchiChara_Scale[1] : TJAPlayer3.Skin.Game_PuchiChara_Scale[0])); sineY = Math.Sin(sineY * (Math.PI / 180)) * (TJAPlayer3.Skin.Game_PuchiChara_Sine * (isBalloon ? TJAPlayer3.Skin.Game_PuchiChara_Scale[1] : TJAPlayer3.Skin.Game_PuchiChara_Scale[0]));
// TJAPlayer3.act文字コンソール.tPrint(700, 580, C文字コンソール.Eフォント種別.白, sineY.ToString()); // TJAPlayer3.act文字コンソール.tPrint(700, 580, C文字コンソール.Eフォント種別.白, sineY.ToString());
//int puriChar = Math.Max(0, Math.Min(TJAPlayer3.Skin.Puchichara_Ptn - 1, TJAPlayer3.NamePlateConfig.data.PuchiChara[p])); //int puriChar = Math.Max(0, Math.Min(TJAPlayer3.Skin.Puchichara_Ptn - 1, TJAPlayer3.NamePlateConfig.data.PuchiChara[p]));
int puriChar = PuchiChara.tGetPuchiCharaIndexByName(p); int puriChar = PuchiChara.tGetPuchiCharaIndexByName(p);
var chara = TJAPlayer3.Tx.Puchichara[puriChar].tx; var chara = TJAPlayer3.Tx.Puchichara[puriChar].tx;
//TJAPlayer3.Tx.PuchiChara[puriChar]; //TJAPlayer3.Tx.PuchiChara[puriChar];
if (chara != null) if (chara != null) {
{ float puchiScale = TJAPlayer3.Skin.Resolution[1] / 720.0f;
float puchiScale = TJAPlayer3.Skin.Resolution[1] / 720.0f;
chara.vcScaleRatio = new Vector3D<float>((isBalloon ? TJAPlayer3.Skin.Game_PuchiChara_Scale[1] * puchiScale : TJAPlayer3.Skin.Game_PuchiChara_Scale[0] * puchiScale)); chara.vcScaleRatio = new Vector3D<float>((isBalloon ? TJAPlayer3.Skin.Game_PuchiChara_Scale[1] * puchiScale : TJAPlayer3.Skin.Game_PuchiChara_Scale[0] * puchiScale));
chara.vcScaleRatio.X *= scale; chara.vcScaleRatio.X *= scale;
chara.vcScaleRatio.Y *= scale; chara.vcScaleRatio.Y *= scale;
chara.Opacity = alpha; chara.Opacity = alpha;
// (isGrowing ? TJAPlayer3.Skin.Game_PuchiChara[1] : 0) => Height // (isGrowing ? TJAPlayer3.Skin.Game_PuchiChara[1] : 0) => Height
/* To do : /* To do :
** **
** - Yellow light color filter when isGrowing is true ** - Yellow light color filter when isGrowing is true
*/ */
int adjustedX = x - 32; int adjustedX = x - 32;
int adjustedY = y - 32; int adjustedY = y - 32;
chara.t2D拡大率考慮中央基準描画(adjustedX, adjustedY + (int)sineY, new Rectangle((Counter.CurrentValue + 2) * TJAPlayer3.Skin.Game_PuchiChara[0], 0, TJAPlayer3.Skin.Game_PuchiChara[0], TJAPlayer3.Skin.Game_PuchiChara[1])); chara.t2D拡大率考慮中央基準描画(adjustedX, adjustedY + (int)sineY, new Rectangle((Counter.CurrentValue + 2) * TJAPlayer3.Skin.Game_PuchiChara[0], 0, TJAPlayer3.Skin.Game_PuchiChara[0], TJAPlayer3.Skin.Game_PuchiChara[1]));
} }
return base.Draw(); return base.Draw();
} }
public double sineY; public double sineY;
public CCounter Counter; public CCounter Counter;
private CCounter SineCounter; private CCounter SineCounter;
private CCounter SineCounterIdle; private CCounter SineCounterIdle;
private bool inGame; private bool inGame;
} }
} }

View File

@ -1,225 +1,198 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; internal class BestPlayRecords {
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3 public enum EClearStatus {
{ NONE = 0,
internal class BestPlayRecords ASSISTED_CLEAR = 1,
{ CLEAR = 2,
FC = 3,
PERFECT = 4,
TOTAL = 5
}
public enum EClearStatus public enum EDanClearStatus {
{ NONE = 0,
NONE = 0, ASSISTED_CLEAR_RED = 1,
ASSISTED_CLEAR = 1, ASSISTED_CLEAR_GOLD = 2,
CLEAR = 2, CLEAR_RED = 3,
FC = 3, CLEAR_GOLD = 4,
PERFECT = 4, FC_RED = 5,
TOTAL = 5 FC_GOLD = 6,
} PERFECT_RED = 7,
PERFECT_GOLD = 8,
TOTAL = 9
}
public enum EDanClearStatus public enum ETowerClearStatus {
{ NONE = 0,
NONE = 0, ASSISTED_CLEAR = 1,
ASSISTED_CLEAR_RED = 1, PROGRESS_10 = 2,
ASSISTED_CLEAR_GOLD = 2, PROGRESS_25 = 3,
CLEAR_RED = 3, PROGRESS_50 = 4,
CLEAR_GOLD = 4, PROGRESS_75 = 5,
FC_RED = 5, CLEAR = 6,
FC_GOLD = 6, FC = 7,
PERFECT_RED = 7, PERFECT = 8,
PERFECT_GOLD = 8, TOTAL = 9
TOTAL = 9 }
}
public enum ETowerClearStatus public class CSongSelectTableEntry {
{ public int ScoreRankDifficulty = 0;
NONE = 0, public int ScoreRank = -1;
ASSISTED_CLEAR = 1, public int ClearStatusDifficulty = 0;
PROGRESS_10 = 2, public int ClearStatus = -1;
PROGRESS_25 = 3, public int TowerReachedFloor = 0;
PROGRESS_50 = 4, public int[] ClearStatuses = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 };
PROGRESS_75 = 5, public int[] ScoreRanks = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 };
CLEAR = 6, public int[] HighScore = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 };
FC = 7, }
PERFECT = 8,
TOTAL = 9
}
public class CSongSelectTableEntry public class CBestPlayRecord {
{ public string ChartUniqueId = "none";
public int ScoreRankDifficulty = 0; public string ChartGenre = "none";
public int ScoreRank = -1; public string Charter = "none";
public int ClearStatusDifficulty = 0; public string Artist = "none";
public int ClearStatus = -1; public Int64 PlayMods = 0;
public int TowerReachedFloor = 0; public Int64 ChartDifficulty = 3;
public int[] ClearStatuses = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 }; public Int64 ChartLevel = 8;
public int[] ScoreRanks = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 }; public Int64 ClearStatus = -1;
public int[] HighScore = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 }; public Int64 ScoreRank = -1;
} public Int64 HighScore = 0;
public Int64 TowerBestFloor = 0;
public List<int> DanExam1 = new List<int> { -1 };
public List<int> DanExam2 = new List<int> { -1 };
public List<int> DanExam3 = new List<int> { -1 };
public List<int> DanExam4 = new List<int> { -1 };
public List<int> DanExam5 = new List<int> { -1 };
public List<int> DanExam6 = new List<int> { -1 };
public List<int> DanExam7 = new List<int> { -1 };
public Int64 PlayCount = 1;
public Int64 HighScoreGoodCount = 0;
public Int64 HighScoreOkCount = 0;
public Int64 HighScoreBadCount = 0;
public Int64 HighScoreMaxCombo = 0;
public Int64 HighScoreRollCount = 0;
public Int64 HighScoreADLibCount = 0;
public Int64 HighScoreBoomCount = 0;
}
public class CBestPlayRecord public class CBestPlayStats {
{ public int DistinctPlays = 0;
public string ChartUniqueId = "none"; public int DistinctClears = 0;
public string ChartGenre = "none"; public int DistinctFCs = 0;
public string Charter = "none"; public int DistinctPerfects = 0;
public string Artist = "none"; public int SongDistinctPlays = 0;
public Int64 PlayMods = 0; public int SongDistinctClears = 0;
public Int64 ChartDifficulty = 3; public int SongDistinctFCs = 0;
public Int64 ChartLevel = 8; public int SongDistinctPerfects = 0;
public Int64 ClearStatus = -1; public int[][] ClearStatuses = new int[(int)Difficulty.Total][];
public Int64 ScoreRank = -1; public int[][] ScoreRanks = new int[(int)Difficulty.Total][];
public Int64 HighScore = 0; public Dictionary<int, int> LevelPlays = new Dictionary<int, int>();
public Int64 TowerBestFloor = 0; public Dictionary<int, int> LevelClears = new Dictionary<int, int>();
public List<int> DanExam1 = new List<int> { -1 }; public Dictionary<int, int> LevelFCs = new Dictionary<int, int>();
public List<int> DanExam2 = new List<int> { -1 }; public Dictionary<int, int> LevelPerfects = new Dictionary<int, int>();
public List<int> DanExam3 = new List<int> { -1 }; public Dictionary<string, int> GenrePlays = new Dictionary<string, int>();
public List<int> DanExam4 = new List<int> { -1 }; public Dictionary<string, int> GenreClears = new Dictionary<string, int>();
public List<int> DanExam5 = new List<int> { -1 }; public Dictionary<string, int> GenreFCs = new Dictionary<string, int>();
public List<int> DanExam6 = new List<int> { -1 }; public Dictionary<string, int> GenrePerfects = new Dictionary<string, int>();
public List<int> DanExam7 = new List<int> { -1 }; public Dictionary<string, int> SongGenrePlays = new Dictionary<string, int>();
public Int64 PlayCount = 1; public Dictionary<string, int> SongGenreClears = new Dictionary<string, int>();
public Int64 HighScoreGoodCount = 0; public Dictionary<string, int> SongGenreFCs = new Dictionary<string, int>();
public Int64 HighScoreOkCount = 0; public Dictionary<string, int> SongGenrePerfects = new Dictionary<string, int>();
public Int64 HighScoreBadCount = 0; public Dictionary<string, int> CharterPlays = new Dictionary<string, int>();
public Int64 HighScoreMaxCombo = 0; public Dictionary<string, int> CharterClears = new Dictionary<string, int>();
public Int64 HighScoreRollCount = 0; public Dictionary<string, int> CharterFCs = new Dictionary<string, int>();
public Int64 HighScoreADLibCount = 0; public Dictionary<string, int> CharterPerfects = new Dictionary<string, int>();
public Int64 HighScoreBoomCount = 0;
}
public class CBestPlayStats public CBestPlayStats() {
{ // 0 : Not clear, 1 : Assisted clear, 2 : Clear, 3 : FC, 4 : Perfect
public int DistinctPlays = 0; ClearStatuses[0] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
public int DistinctClears = 0; ClearStatuses[1] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
public int DistinctFCs = 0; ClearStatuses[2] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
public int DistinctPerfects = 0; ClearStatuses[3] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
public int SongDistinctPlays = 0; ClearStatuses[4] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
public int SongDistinctClears = 0; ClearStatuses[5] = new int[(int)ETowerClearStatus.TOTAL] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public int SongDistinctFCs = 0; ClearStatuses[6] = new int[(int)EDanClearStatus.TOTAL] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public int SongDistinctPerfects = 0;
public int[][] ClearStatuses = new int[(int)Difficulty.Total][];
public int[][] ScoreRanks = new int[(int)Difficulty.Total][];
public Dictionary<int, int> LevelPlays = new Dictionary<int, int>();
public Dictionary<int, int> LevelClears = new Dictionary<int, int>();
public Dictionary<int, int> LevelFCs = new Dictionary<int, int>();
public Dictionary<int, int> LevelPerfects = new Dictionary<int, int>();
public Dictionary<string, int> GenrePlays = new Dictionary<string, int>();
public Dictionary<string, int> GenreClears = new Dictionary<string, int>();
public Dictionary<string, int> GenreFCs = new Dictionary<string, int>();
public Dictionary<string, int> GenrePerfects = new Dictionary<string, int>();
public Dictionary<string, int> SongGenrePlays = new Dictionary<string, int>();
public Dictionary<string, int> SongGenreClears = new Dictionary<string, int>();
public Dictionary<string, int> SongGenreFCs = new Dictionary<string, int>();
public Dictionary<string, int> SongGenrePerfects = new Dictionary<string, int>();
public Dictionary<string, int> CharterPlays = new Dictionary<string, int>();
public Dictionary<string, int> CharterClears = new Dictionary<string, int>();
public Dictionary<string, int> CharterFCs = new Dictionary<string, int>();
public Dictionary<string, int> CharterPerfects = new Dictionary<string, int>();
public CBestPlayStats() // 0 : None, 1 : E, 2 : D, 3 : C, 4 : B, 5 : A, 6 : S, 7 : Omega
{ ScoreRanks[0] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
// 0 : Not clear, 1 : Assisted clear, 2 : Clear, 3 : FC, 4 : Perfect ScoreRanks[1] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
ClearStatuses[0] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 }; ScoreRanks[2] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
ClearStatuses[1] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 }; ScoreRanks[3] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
ClearStatuses[2] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 }; ScoreRanks[4] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
ClearStatuses[3] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 }; }
ClearStatuses[4] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 }; }
ClearStatuses[5] = new int[(int)ETowerClearStatus.TOTAL] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ClearStatuses[6] = new int[(int)EDanClearStatus.TOTAL] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// 0 : None, 1 : E, 2 : D, 3 : C, 4 : B, 5 : A, 6 : S, 7 : Omega static private void InitOrAddDict<T>(Dictionary<T, int> dict, T entry) where T : notnull {
ScoreRanks[0] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; if (!dict.ContainsKey(entry))
ScoreRanks[1] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; dict[entry] = 0;
ScoreRanks[2] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; dict[entry]++;
ScoreRanks[3] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; }
ScoreRanks[4] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
}
}
static private void InitOrAddDict<T>(Dictionary<T, int> dict, T entry) where T : notnull static public CBestPlayStats tGenerateBestPlayStats(
{ Dictionary<string, CBestPlayRecord>.ValueCollection uniqueChartBestPlays,
if (!dict.ContainsKey(entry)) Dictionary<string, CBestPlayRecord>.ValueCollection uniqueSongBestPlays
dict[entry] = 0; ) {
dict[entry]++; CBestPlayStats stats = new CBestPlayStats();
}
static public CBestPlayStats tGenerateBestPlayStats( // Individual charts
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueChartBestPlays, foreach (CBestPlayRecord record in uniqueChartBestPlays) {
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueSongBestPlays Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
) if (roundedDifficulty <= (int)Difficulty.Edit) {
{ string[] ChartersArr = record.Charter.SplitByCommas();
CBestPlayStats stats = new CBestPlayStats(); Int64 roundedScoreRank = Math.Max(0, Math.Min(7, record.ScoreRank + 1));
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
// Individual charts stats.ScoreRanks[roundedDifficulty][roundedScoreRank]++;
foreach (CBestPlayRecord record in uniqueChartBestPlays) stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
{ foreach (string Charter in ChartersArr) {
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty)); InitOrAddDict(stats.CharterPlays, Charter);
if (roundedDifficulty <= (int)Difficulty.Edit) if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.CharterClears, Charter);
{ if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.CharterFCs, Charter);
string[] ChartersArr = record.Charter.SplitByCommas(); if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.CharterPerfects, Charter);
Int64 roundedScoreRank = Math.Max(0, Math.Min(7, record.ScoreRank + 1)); }
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1)); InitOrAddDict(stats.GenrePlays, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.GenreClears, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.GenreFCs, record.ChartGenre);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.GenrePerfects, record.ChartGenre);
InitOrAddDict(stats.LevelPlays, (int)record.ChartLevel);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.LevelClears, (int)record.ChartLevel);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.LevelFCs, (int)record.ChartLevel);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.LevelPerfects, (int)record.ChartLevel);
stats.DistinctPlays++;
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.DistinctClears++;
if (roundedClearStatus >= (int)EClearStatus.FC) stats.DistinctFCs++;
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.DistinctPerfects++;
} else if (roundedDifficulty == (int)Difficulty.Tower) {
Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)ETowerClearStatus.NONE, (int)ETowerClearStatus.TOTAL);
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
stats.ScoreRanks[roundedDifficulty][roundedScoreRank]++; } else if (roundedDifficulty == (int)Difficulty.Dan) {
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++; Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)EDanClearStatus.NONE, (int)EDanClearStatus.TOTAL);
foreach (string Charter in ChartersArr) stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
{
InitOrAddDict(stats.CharterPlays, Charter);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.CharterClears, Charter);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.CharterFCs, Charter);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.CharterPerfects, Charter);
}
InitOrAddDict(stats.GenrePlays, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.GenreClears, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.GenreFCs, record.ChartGenre);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.GenrePerfects, record.ChartGenre);
InitOrAddDict(stats.LevelPlays, (int)record.ChartLevel);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.LevelClears, (int)record.ChartLevel);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.LevelFCs, (int)record.ChartLevel);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.LevelPerfects, (int)record.ChartLevel);
stats.DistinctPlays++;
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.DistinctClears++;
if (roundedClearStatus >= (int)EClearStatus.FC) stats.DistinctFCs++;
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.DistinctPerfects++;
}
else if (roundedDifficulty == (int)Difficulty.Tower)
{
Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)ETowerClearStatus.NONE, (int)ETowerClearStatus.TOTAL);
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
} }
else if (roundedDifficulty == (int)Difficulty.Dan) }
{
Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)EDanClearStatus.NONE, (int)EDanClearStatus.TOTAL);
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
} // Individual songs
} foreach (CBestPlayRecord record in uniqueSongBestPlays) {
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
// Individual songs if (roundedDifficulty <= (int)Difficulty.Edit) {
foreach (CBestPlayRecord record in uniqueSongBestPlays) Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
{
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
if (roundedDifficulty <= (int)Difficulty.Edit)
{
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
InitOrAddDict(stats.SongGenrePlays, record.ChartGenre); InitOrAddDict(stats.SongGenrePlays, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.SongGenreClears, record.ChartGenre); if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.SongGenreClears, record.ChartGenre);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.SongGenreFCs, record.ChartGenre); if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.SongGenreFCs, record.ChartGenre);
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.SongGenrePerfects, record.ChartGenre); if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.SongGenrePerfects, record.ChartGenre);
stats.SongDistinctPlays++; stats.SongDistinctPlays++;
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.SongDistinctClears++; if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.SongDistinctClears++;
if (roundedClearStatus >= (int)EClearStatus.FC) stats.SongDistinctFCs++; if (roundedClearStatus >= (int)EClearStatus.FC) stats.SongDistinctFCs++;
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.SongDistinctPerfects++; if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.SongDistinctPerfects++;
} }
} }
return stats; return stats;
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +1,25 @@
using System; using System.Security.Cryptography;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class CCrypto {
internal class CCrypto internal static readonly char[] chars =
{ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
internal static readonly char[] chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
public static string GetUniqueKey(int size) public static string GetUniqueKey(int size) {
{ byte[] data = new byte[4 * size];
byte[] data = new byte[4 * size]; using (var crypto = RandomNumberGenerator.Create()) {
using (var crypto = RandomNumberGenerator.Create()) crypto.GetBytes(data);
{ }
crypto.GetBytes(data); StringBuilder result = new StringBuilder(size);
} for (int i = 0; i < size; i++) {
StringBuilder result = new StringBuilder(size); var rnd = BitConverter.ToUInt32(data, i * 4);
for (int i = 0; i < size; i++) var idx = rnd % chars.Length;
{
var rnd = BitConverter.ToUInt32(data, i * 4);
var idx = rnd % chars.Length;
result.Append(chars[idx]); result.Append(chars[idx]);
} }
return result.ToString(); return result.ToString();
} }
} }
} }

View File

@ -1,23 +1,18 @@
using System; using System.Text;
using System.Collections.Generic;
using System.Text;
namespace TJAPlayer3 namespace TJAPlayer3 {
{
/// <summary> /// <summary>
/// <para>DTXMania のバージョン。</para> /// <para>DTXMania のバージョン。</para>
/// <para>例1"078b" → 整数部=078, 小数部=2000000 ('英字'+'yymmdd') </para> /// <para>例1"078b" → 整数部=078, 小数部=2000000 ('英字'+'yymmdd') </para>
/// <para>例2"078a(100124)" → 整数部=078, 小数部=1100124 ('英字'+'yymmdd')</para> /// <para>例2"078a(100124)" → 整数部=078, 小数部=1100124 ('英字'+'yymmdd')</para>
/// </summary> /// </summary>
public class CDTXVersion public class CDTXVersion {
{
// プロパティ // プロパティ
/// <summary> /// <summary>
/// <para>バージョンが未知のときに true になる。</para> /// <para>バージョンが未知のときに true になる。</para>
/// </summary> /// </summary>
public bool Unknown public bool Unknown {
{
get; get;
private set; private set;
} }
@ -40,159 +35,129 @@ namespace TJAPlayer3
// コンストラクタ // コンストラクタ
public CDTXVersion() public CDTXVersion() {
{
this.n整数部 = 0; this.n整数部 = 0;
this.n小数部 = 0; this.n小数部 = 0;
this.Unknown = true; this.Unknown = true;
} }
public CDTXVersion( int n整数部 ) public CDTXVersion(int n整数部) {
{
this.n整数部 = n整数部; this.n整数部 = n整数部;
this.n小数部 = 0; this.n小数部 = 0;
this.Unknown = false; this.Unknown = false;
} }
public CDTXVersion( string Version ) public CDTXVersion(string Version) {
{
this.n整数部 = 0; this.n整数部 = 0;
this.n小数部 = 0; this.n小数部 = 0;
this.Unknown = true; this.Unknown = true;
if( Version.ToLower().Equals( "unknown" ) ) if (Version.ToLower().Equals("unknown")) {
{
this.Unknown = true; this.Unknown = true;
} } else {
else
{
int num = 0; int num = 0;
int length = Version.Length; int length = Version.Length;
if( ( num < length ) && char.IsDigit( Version[ num ] ) ) if ((num < length) && char.IsDigit(Version[num])) {
{
// 整数部 取得 // 整数部 取得
while( ( num < length ) && char.IsDigit( Version[ num ] ) ) while ((num < length) && char.IsDigit(Version[num])) {
{ this.n整数部 = (this.n整数部 * 10) + CDTXVersion.DIG10.IndexOf(Version[num++]);
this.n整数部 = ( this.n整数部 * 10 ) + CDTXVersion.DIG10.IndexOf( Version[ num++ ] );
} }
// 小数部(1)英字部分 取得 // 小数部(1)英字部分 取得
while( ( num < length ) && ( ( Version[ num ] == ' ' ) || ( Version[ num ] == '(' ) ) ) while ((num < length) && ((Version[num] == ' ') || (Version[num] == '('))) {
{
num++; num++;
} }
if( ( num < length ) && ( CDTXVersion.DIG36.IndexOf( Version[ num ] ) >= 10 ) ) if ((num < length) && (CDTXVersion.DIG36.IndexOf(Version[num]) >= 10)) {
{ this.n小数部 = CDTXVersion.DIG36.IndexOf(Version[num++]) - 10;
this.n小数部 = CDTXVersion.DIG36.IndexOf( Version[ num++ ] ) - 10; if (this.n小数部 >= 0x1a) {
if( this.n小数部 >= 0x1a )
{
this.n小数部 -= 0x1a; this.n小数部 -= 0x1a;
} }
this.n小数部++; this.n小数部++;
} }
// 小数部(2)日付部分(yymmdd) 取得 // 小数部(2)日付部分(yymmdd) 取得
while( ( num < length ) && ( ( Version[ num ] == ' ' ) || ( Version[ num ] == '(' ) ) ) while ((num < length) && ((Version[num] == ' ') || (Version[num] == '('))) {
{
num++; num++;
} }
for( int i = 0; i < 6; i++ ) for (int i = 0; i < 6; i++) {
{
this.n小数部 *= 10; this.n小数部 *= 10;
if( ( num < length ) && char.IsDigit( Version[ num ] ) ) if ((num < length) && char.IsDigit(Version[num])) {
{ this.n小数部 += CDTXVersion.DIG10.IndexOf(Version[num]);
this.n小数部 += CDTXVersion.DIG10.IndexOf( Version[ num ] );
} }
num++; num++;
} }
this.Unknown = false; this.Unknown = false;
} } else {
else
{
this.Unknown = true; this.Unknown = true;
} }
} }
} }
public CDTXVersion( int n整数部, int n小数部 ) public CDTXVersion(int n整数部, int n小数部) {
{
this.n整数部 = n整数部; this.n整数部 = n整数部;
this.n小数部 = n小数部; this.n小数部 = n小数部;
this.Unknown = false; this.Unknown = false;
} }
// メソッド // メソッド
public string toString() public string toString() {
{ var result = new StringBuilder(32);
var result = new StringBuilder( 32 );
// 整数部 // 整数部
result.Append( this.n整数部.ToString( "000" ) ); result.Append(this.n整数部.ToString("000"));
// 英字部分(あれば) // 英字部分(あれば)
if( this.n小数部 >= 1000000 ) if (this.n小数部 >= 1000000) {
{ int n英字 = Math.Min(this.n小数部 / 1000000, 26); // 126
int n英字 = Math.Min( this.n小数部 / 1000000, 26 ); // 126 result.Append(CDTXVersion.DIG36[10 + (n英字 - 1)]);
result.Append( CDTXVersion.DIG36[ 10 + ( n英字 - 1 ) ] );
} }
// 日付部分(あれば) // 日付部分(あれば)
int n日付 = this.n小数部 % 1000000; int n日付 = this.n小数部 % 1000000;
if( n日付 > 0 ) if (n日付 > 0) {
{ result.Append('(');
result.Append( '(' ); result.Append(n日付.ToString("000000"));
result.Append( n日付.ToString( "000000" ) ); result.Append(')');
result.Append( ')' );
} }
return result.ToString(); return result.ToString();
} }
public static bool operator ==( CDTXVersion x, CDTXVersion y ) public static bool operator ==(CDTXVersion x, CDTXVersion y) {
{ return (((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部)) && (x.Unknown == y.Unknown));
return ( ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 == y.n小数部 ) ) && ( x.Unknown == y.Unknown ) );
} }
public static bool operator >( CDTXVersion x, CDTXVersion y ) public static bool operator >(CDTXVersion x, CDTXVersion y) {
{ return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 > y.n小数部)));
return ( ( x.n整数部 > y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 > y.n小数部 ) ) );
} }
public static bool operator >=( CDTXVersion x, CDTXVersion y ) public static bool operator >=(CDTXVersion x, CDTXVersion y) {
{ return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 >= y.n小数部)));
return ( ( x.n整数部 > y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 >= y.n小数部 ) ) );
} }
public static bool operator !=( CDTXVersion x, CDTXVersion y ) public static bool operator !=(CDTXVersion x, CDTXVersion y) {
{ if ((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部)) {
if( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 == y.n小数部 ) ) return (x.Unknown != y.Unknown);
{
return ( x.Unknown != y.Unknown );
} }
return true; return true;
} }
public static bool operator <( CDTXVersion x, CDTXVersion y ) public static bool operator <(CDTXVersion x, CDTXVersion y) {
{ return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 < y.n小数部)));
return ( ( x.n整数部 < y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 < y.n小数部 ) ) );
} }
public static bool operator <=( CDTXVersion x, CDTXVersion y ) public static bool operator <=(CDTXVersion x, CDTXVersion y) {
{ return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 <= y.n小数部)));
return ( ( x.n整数部 < y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 <= y.n小数部 ) ) );
} }
public override bool Equals(object obj) // 2011.1.3 yyagi: warningを無くすために追加 public override bool Equals(object obj) // 2011.1.3 yyagi: warningを無くすために追加
{ {
if (obj == null) if (obj == null) {
{
return false; return false;
} }
if (this.GetType() != obj.GetType()) if (this.GetType() != obj.GetType()) {
{
return false; return false;
} }
CDTXVersion objCDTXVersion = (CDTXVersion)obj; CDTXVersion objCDTXVersion = (CDTXVersion)obj;
if (!int.Equals(this.n整数部, objCDTXVersion.n整数部) || !int.Equals(this.n小数部, objCDTXVersion.n小数部)) if (!int.Equals(this.n整数部, objCDTXVersion.n整数部) || !int.Equals(this.n小数部, objCDTXVersion.n小数部)) {
{
return false; return false;
} }
return true; return true;
} }
public override int GetHashCode() // 2011.1.3 yyagi: warningを無くすために追加 public override int GetHashCode() // 2011.1.3 yyagi: warningを無くすために追加
{ {
string v = this.toString(); string v = this.toString();
return v.GetHashCode(); return v.GetHashCode();

View File

@ -1,73 +1,59 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; class CHitSounds {
using System.Linq; public CHitSounds(string path) {
using System.Text; tLoadFile(path);
using System.Threading.Tasks; for (int i = 0; i < 5; i++) {
tReloadHitSounds(TJAPlayer3.ConfigIni.nHitSounds[i], i);
}
}
namespace TJAPlayer3 public bool tReloadHitSounds(int id, int player) {
{ if (id >= names.Length || id >= data.Length)
class CHitSounds return false;
{
public CHitSounds(string path)
{
tLoadFile(path);
for (int i = 0; i < 5; i++)
{
tReloadHitSounds(TJAPlayer3.ConfigIni.nHitSounds[i], i);
}
}
public bool tReloadHitSounds(int id, int player) string ext = "";
{
if (id >= names.Length || id >= data.Length)
return false;
string ext = ""; if (data[id].format == "WAV")
ext = ".wav";
else if (data[id].format == "OGG")
ext = ".ogg";
if (data[id].format == "WAV") don[player] = data[id].path + "dong" + ext;
ext = ".wav"; ka[player] = data[id].path + "ka" + ext;
else if (data[id].format == "OGG") adlib[player] = data[id].path + "Adlib" + ext;
ext = ".ogg"; clap[player] = data[id].path + "clap" + ext;
don[player] = data[id].path + "dong" + ext; return true;
ka[player] = data[id].path + "ka" + ext; }
adlib[player] = data[id].path + "Adlib" + ext;
clap[player] = data[id].path + "clap" + ext;
return true; public string[] names;
}
public string[] names; public string[] don = new string[5];
public string[] ka = new string[5];
public string[] adlib = new string[5];
public string[] clap = new string[5];
public string[] don = new string[5]; #region [private]
public string[] ka = new string[5];
public string[] adlib = new string[5];
public string[] clap = new string[5];
#region [private] private class HitSoundsData {
public string name;
public string path;
public string format;
}
private class HitSoundsData private HitSoundsData[] data;
{
public string name;
public string path;
public string format;
}
private HitSoundsData[] data; private void tLoadFile(string path) {
data = ConfigManager.GetConfig<List<HitSoundsData>>(path).ToArray();
private void tLoadFile(string path) names = new string[data.Length];
{
data = ConfigManager.GetConfig<List<HitSoundsData>>(path).ToArray();
names = new string[data.Length]; for (int i = 0; i < data.Length; i++) {
names[i] = data[i].name;
}
}
for (int i = 0; i < data.Length; i++) #endregion
{
names[i] = data[i].name;
}
}
#endregion }
}
} }

View File

@ -1,26 +1,19 @@
using System; using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using FDK; using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ public class CPad {
public class CPad
{
// プロパティ // プロパティ
internal STHIT st検知したデバイス; internal STHIT st検知したデバイス;
[StructLayout( LayoutKind.Sequential )] [StructLayout(LayoutKind.Sequential)]
internal struct STHIT internal struct STHIT {
{
public bool Keyboard; public bool Keyboard;
public bool MIDIIN; public bool MIDIIN;
public bool Joypad; public bool Joypad;
public bool Gamepad; public bool Gamepad;
public bool Mouse; public bool Mouse;
public void Clear() public void Clear() {
{
this.Keyboard = false; this.Keyboard = false;
this.MIDIIN = false; this.MIDIIN = false;
this.Joypad = false; this.Joypad = false;
@ -31,8 +24,7 @@ namespace TJAPlayer3
// コンストラクタ // コンストラクタ
internal CPad( CConfigIni configIni, CInputManager mgrInput ) internal CPad(CConfigIni configIni, CInputManager mgrInput) {
{
this.rConfigIni = configIni; this.rConfigIni = configIni;
this.rInput管理 = mgrInput; this.rInput管理 = mgrInput;
this.st検知したデバイス.Clear(); this.st検知したデバイス.Clear();
@ -41,58 +33,47 @@ namespace TJAPlayer3
// メソッド // メソッド
public List<STInputEvent> GetEvents( EInstrumentPad part, EPad pad ) public List<STInputEvent> GetEvents(EInstrumentPad part, EPad pad) {
{ CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ];
List<STInputEvent> list = new List<STInputEvent>(); List<STInputEvent> list = new List<STInputEvent>();
// すべての入力デバイスについて… // すべての入力デバイスについて…
foreach( IInputDevice device in this.rInput管理.InputDevices ) foreach (IInputDevice device in this.rInput管理.InputDevices) {
{ if ((device.InputEvents != null) && (device.InputEvents.Count != 0)) {
if( ( device.InputEvents != null ) && ( device.InputEvents.Count != 0 ) ) foreach (STInputEvent event2 in device.InputEvents) {
{ for (int i = 0; i < stkeyassignArray.Length; i++) {
foreach( STInputEvent event2 in device.InputEvents ) switch (stkeyassignArray[i].) {
{
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
case EInputDevice.Keyboard: case EInputDevice.Keyboard:
if( ( device.CurrentType == InputDeviceType.Keyboard ) && ( event2.nKey == stkeyassignArray[ i ]. ) ) if ((device.CurrentType == InputDeviceType.Keyboard) && (event2.nKey == stkeyassignArray[i].)) {
{ list.Add(event2);
list.Add( event2 );
this.st検知したデバイス.Keyboard = true; this.st検知したデバイス.Keyboard = true;
} }
break; break;
case EInputDevice.MIDIInput: case EInputDevice.MIDIInput:
if( ( ( device.CurrentType == InputDeviceType.MidiIn ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) ) if (((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
{ list.Add(event2);
list.Add( event2 );
this.st検知したデバイス.MIDIIN = true; this.st検知したデバイス.MIDIIN = true;
} }
break; break;
case EInputDevice.Joypad: case EInputDevice.Joypad:
if( ( ( device.CurrentType == InputDeviceType.Joystick ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) ) if (((device.CurrentType == InputDeviceType.Joystick) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
{ list.Add(event2);
list.Add( event2 );
this.st検知したデバイス.Joypad = true; this.st検知したデバイス.Joypad = true;
} }
break; break;
case EInputDevice.Gamepad: case EInputDevice.Gamepad:
if( ( ( device.CurrentType == InputDeviceType.Gamepad ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) ) if (((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
{ list.Add(event2);
list.Add( event2 );
this.st検知したデバイス.Gamepad = true; this.st検知したデバイス.Gamepad = true;
} }
break; break;
case EInputDevice.Mouse: case EInputDevice.Mouse:
if( ( device.CurrentType == InputDeviceType.Mouse ) && ( event2.nKey == stkeyassignArray[ i ]. ) ) if ((device.CurrentType == InputDeviceType.Mouse) && (event2.nKey == stkeyassignArray[i].)) {
{ list.Add(event2);
list.Add( event2 );
this.st検知したデバイス.Mouse = true; this.st検知したデバイス.Mouse = true;
} }
break; break;
@ -104,58 +85,51 @@ namespace TJAPlayer3
} }
return list; return list;
} }
public bool bPressed( EInstrumentPad part, EPad pad ) public bool bPressed(EInstrumentPad part, EPad pad) {
{ if (part != EInstrumentPad.UNKNOWN) {
if( part != EInstrumentPad.UNKNOWN )
{ CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
for (int i = 0; i < stkeyassignArray.Length; i++) {
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ]; switch (stkeyassignArray[i].) {
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
case EInputDevice.Keyboard: case EInputDevice.Keyboard:
if( !this.rInput管理.Keyboard.KeyPressed( stkeyassignArray[ i ]. ) ) if (!this.rInput管理.Keyboard.KeyPressed(stkeyassignArray[i].))
break; break;
this.st検知したデバイス.Keyboard = true; this.st検知したデバイス.Keyboard = true;
return true; return true;
case EInputDevice.MIDIInput: case EInputDevice.MIDIInput: {
{ IInputDevice device2 = this.rInput管理.MidiIn(stkeyassignArray[i].ID);
IInputDevice device2 = this.rInput管理.MidiIn( stkeyassignArray[ i ].ID ); if ((device2 == null) || !device2.KeyPressed(stkeyassignArray[i].))
if( ( device2 == null ) || !device2.KeyPressed( stkeyassignArray[ i ]. ) )
break; break;
this.st検知したデバイス.MIDIIN = true; this.st検知したデバイス.MIDIIN = true;
return true; return true;
} }
case EInputDevice.Joypad: case EInputDevice.Joypad: {
{ if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID))
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
break; break;
IInputDevice device = this.rInput管理.Joystick( stkeyassignArray[ i ].ID ); IInputDevice device = this.rInput管理.Joystick(stkeyassignArray[i].ID);
if( ( device == null ) || !device.KeyPressed( stkeyassignArray[ i ]. ) ) if ((device == null) || !device.KeyPressed(stkeyassignArray[i].))
break; break;
this.st検知したデバイス.Joypad = true; this.st検知したデバイス.Joypad = true;
return true; return true;
} }
case EInputDevice.Gamepad: case EInputDevice.Gamepad: {
{ if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID))
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
break; break;
IInputDevice device = this.rInput管理.Gamepad( stkeyassignArray[ i ].ID ); IInputDevice device = this.rInput管理.Gamepad(stkeyassignArray[i].ID);
if( ( device == null ) || !device.KeyPressed( stkeyassignArray[ i ]. ) ) if ((device == null) || !device.KeyPressed(stkeyassignArray[i].))
break; break;
this.st検知したデバイス.Gamepad = true; this.st検知したデバイス.Gamepad = true;
return true; return true;
} }
case EInputDevice.Mouse: case EInputDevice.Mouse:
if( !this.rInput管理.Mouse.KeyPressed( stkeyassignArray[ i ]. ) ) if (!this.rInput管理.Mouse.KeyPressed(stkeyassignArray[i].))
break; break;
this.st検知したデバイス.Mouse = true; this.st検知したデバイス.Mouse = true;
@ -165,71 +139,55 @@ namespace TJAPlayer3
} }
return false; return false;
} }
public bool bPressedDGB( EPad pad ) public bool bPressedDGB(EPad pad) {
{ if (!this.bPressed(EInstrumentPad.DRUMS, pad) && !this.bPressed(EInstrumentPad.GUITAR, pad)) {
if( !this.bPressed( EInstrumentPad.DRUMS, pad ) && !this.bPressed( EInstrumentPad.GUITAR, pad ) ) return this.bPressed(EInstrumentPad.BASS, pad);
{
return this.bPressed( EInstrumentPad.BASS, pad );
} }
return true; return true;
} }
public bool bPressedGB( EPad pad ) public bool bPressedGB(EPad pad) {
{ if (!this.bPressed(EInstrumentPad.GUITAR, pad)) {
if( !this.bPressed( EInstrumentPad.GUITAR, pad ) ) return this.bPressed(EInstrumentPad.BASS, pad);
{
return this.bPressed( EInstrumentPad.BASS, pad );
} }
return true; return true;
} }
public bool b押されている( EInstrumentPad part, EPad pad ) public bool b押されている(EInstrumentPad part, EPad pad) {
{ if (part != EInstrumentPad.UNKNOWN) {
if( part != EInstrumentPad.UNKNOWN ) CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
{ for (int i = 0; i < stkeyassignArray.Length; i++) {
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ]; switch (stkeyassignArray[i].) {
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
case EInputDevice.Keyboard: case EInputDevice.Keyboard:
if( !this.rInput管理.Keyboard.KeyPressing( stkeyassignArray[ i ]. ) ) if (!this.rInput管理.Keyboard.KeyPressing(stkeyassignArray[i].)) {
{
break; break;
} }
this.st検知したデバイス.Keyboard = true; this.st検知したデバイス.Keyboard = true;
return true; return true;
case EInputDevice.Joypad: case EInputDevice.Joypad: {
{ if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID)) {
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
{
break; break;
} }
IInputDevice device = this.rInput管理.Joystick( stkeyassignArray[ i ].ID ); IInputDevice device = this.rInput管理.Joystick(stkeyassignArray[i].ID);
if( ( device == null ) || !device.KeyPressing( stkeyassignArray[ i ]. ) ) if ((device == null) || !device.KeyPressing(stkeyassignArray[i].)) {
{
break; break;
} }
this.st検知したデバイス.Joypad = true; this.st検知したデバイス.Joypad = true;
return true; return true;
} }
case EInputDevice.Gamepad: case EInputDevice.Gamepad: {
{ if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID)) {
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
{
break; break;
} }
IInputDevice device = this.rInput管理.Gamepad( stkeyassignArray[ i ].ID ); IInputDevice device = this.rInput管理.Gamepad(stkeyassignArray[i].ID);
if( ( device == null ) || !device.KeyPressing( stkeyassignArray[ i ]. ) ) if ((device == null) || !device.KeyPressing(stkeyassignArray[i].)) {
{
break; break;
} }
this.st検知したデバイス.Gamepad = true; this.st検知したデバイス.Gamepad = true;
return true; return true;
} }
case EInputDevice.Mouse: case EInputDevice.Mouse:
if( !this.rInput管理.Mouse.KeyPressing( stkeyassignArray[ i ]. ) ) if (!this.rInput管理.Mouse.KeyPressing(stkeyassignArray[i].)) {
{
break; break;
} }
this.st検知したデバイス.Mouse = true; this.st検知したデバイス.Mouse = true;
@ -239,11 +197,9 @@ namespace TJAPlayer3
} }
return false; return false;
} }
public bool b押されているGB( EPad pad ) public bool b押されているGB(EPad pad) {
{ if (!this.b押されている(EInstrumentPad.GUITAR, pad)) {
if( !this.b押されている( EInstrumentPad.GUITAR, pad ) ) return this.b押されている(EInstrumentPad.BASS, pad);
{
return this.b押されている( EInstrumentPad.BASS, pad );
} }
return true; return true;
} }

View File

@ -1,43 +1,29 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; class CSavableT<T> where T : new() {
using System.Linq; public virtual string _fn {
using System.Text; get;
using System.Threading.Tasks; protected set;
using System.IO; }
public void tDBInitSavable() {
if (!File.Exists(_fn))
tSaveFile();
tLoadFile();
}
namespace TJAPlayer3 public T data = new T();
{
class CSavableT<T> where T : new()
{
public virtual string _fn
{
get;
protected set;
}
public void tDBInitSavable()
{
if (!File.Exists(_fn))
tSaveFile();
tLoadFile(); #region [private]
}
public T data = new T(); private void tSaveFile() {
ConfigManager.SaveConfig(data, _fn);
}
#region [private] private void tLoadFile() {
data = ConfigManager.GetConfig<T>(_fn);
}
private void tSaveFile() #endregion
{
ConfigManager.SaveConfig(data, _fn);
}
private void tLoadFile() }
{
data = ConfigManager.GetConfig<T>(_fn);
}
#endregion
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,309 +1,269 @@
using System; using System.Drawing;
using System.Collections.Generic;
using System.Linq; namespace TJAPlayer3 {
using System.Text; internal class CSongDict {
using System.Threading.Tasks; private static Dictionary<string, CSongListNode> nodes = new Dictionary<string, CSongListNode>();
using System.Drawing; private static HashSet<string> urls = new HashSet<string>();
namespace TJAPlayer3 public static CActSelect曲リスト.CScorePad[][] ScorePads = new CActSelect曲リスト.CScorePad[5][]
{ {
internal class CSongDict new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() },
{ new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() },
private static Dictionary<string, CSongListNode> nodes = new Dictionary<string, CSongListNode>(); new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() },
private static HashSet<string> urls = new HashSet<string>(); new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() },
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() }
public static CActSelect曲リスト.CScorePad[][] ScorePads = new CActSelect曲リスト.CScorePad[5][] };
{
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() }, public static int tGetNodesCount() {
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() }, return nodes.Count();
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() }, }
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() },
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() } public static string[] tGetNodesByGenreName(string genreName) {
}; return nodes.Where(_nd => _nd.Value.strジャンル == genreName).Select(_nd => _nd.Key).ToArray();
}
public static int tGetNodesCount()
{ #region [General song dict methods]
return nodes.Count();
} public static CSongListNode tGetNodeFromID(string id) {
if (nodes.ContainsKey(id))
public static string[] tGetNodesByGenreName(string genreName) return nodes[id].Clone();
{ return null;
return nodes.Where(_nd => _nd.Value.strジャンル == genreName).Select(_nd => _nd.Key).ToArray(); }
}
public static void tAddSongNode(CSongUniqueID sid, CSongListNode node) {
#region [General song dict methods] if (sid != null && sid.data.id != null && sid.data.id != "" && !nodes.ContainsKey(sid.data.id))
nodes.Add(sid.data.id, node.Clone());
public static CSongListNode tGetNodeFromID(string id) tAddSongUrl(sid);
{ }
if (nodes.ContainsKey(id))
return nodes[id].Clone(); public static bool tContainsSongUrl(string url) {
return null; return urls.Contains(url);
} }
public static void tAddSongNode(CSongUniqueID sid, CSongListNode node) public static void tAddSongUrl(CSongUniqueID sid) {
{ var url = sid.data.url;
if (sid != null && sid.data.id != null && sid.data.id != "" && !nodes.ContainsKey(sid.data.id))
nodes.Add(sid.data.id, node.Clone()); if (url != null && url != "" && !urls.Contains(url))
tAddSongUrl(sid); urls.Add(url);
} }
public static bool tContainsSongUrl(string url) public static void tRemoveSongUrl(CSongUniqueID sid) {
{ var url = sid.data.url;
return urls.Contains(url);
} if (url != null && url != "" && urls.Contains(url))
urls.Remove(url);
public static void tAddSongUrl(CSongUniqueID sid) }
{
var url = sid.data.url; public static void tRemoveSongNode(CSongUniqueID sid) {
if (sid != null && nodes.ContainsKey(sid.data.id)) {
if (url != null && url != "" && !urls.Contains(url)) tRemoveSongUrl(sid);
urls.Add(url); nodes.Remove(sid.data.id);
} }
}
public static void tRemoveSongUrl(CSongUniqueID sid)
{ public static void tClearSongNodes() {
var url = sid.data.url; nodes.Clear();
urls.Clear();
if (url != null && url != "" && urls.Contains(url)) }
urls.Remove(url);
} #endregion
public static void tRemoveSongNode(CSongUniqueID sid) #region [Extra methods]
{
if (sid != null && nodes.ContainsKey(sid.data.id)) // Generate a back button
{ public static CSongListNode tGenerateBackButton(CSongListNode parent, string path = "/", List<string> listStrBoxDef = null) {
tRemoveSongUrl(sid); CSongListNode itemBack = new CSongListNode();
nodes.Remove(sid.data.id); itemBack.eード種別 = CSongListNode.ENodeType.BACKBOX;
}
}
// とじる
public static void tClearSongNodes() itemBack.ldTitle = CLangManager.GetAllStringsAsLocalizationDataWithArgs("SONGSELECT_RETURN_PATH", path, path);
{
nodes.Clear(); itemBack.BackColor = ColorTranslator.FromHtml("#513009");
urls.Clear(); itemBack.BoxColor = Color.White;
}
itemBack.BgColor = parent.BgColor;
#endregion itemBack.isChangedBgColor = parent.isChangedBgColor;
itemBack.BgType = parent.BgType;
#region [Extra methods] itemBack.isChangedBgType = parent.isChangedBgType;
// Generate a back button itemBack.strジャンル = parent.strジャンル;
public static CSongListNode tGenerateBackButton(CSongListNode parent, string path = "/", List<string> listStrBoxDef = null) itemBack.strSelectBGPath = parent.strSelectBGPath;
{ itemBack.nスコア数 = 1;
CSongListNode itemBack = new CSongListNode(); itemBack.rParentNode = parent;
itemBack.eード種別 = CSongListNode.ENodeType.BACKBOX; itemBack.strSkinPath = (parent.rParentNode == null) ?
"" : parent.rParentNode.strSkinPath;
// とじる // I guess this is used to count the number of box.def instances and only at startup, which makes using it here pretty weird
itemBack.ldTitle = CLangManager.GetAllStringsAsLocalizationDataWithArgs("SONGSELECT_RETURN_PATH", path, path); if (listStrBoxDef != null && itemBack.strSkinPath != "" && !listStrBoxDef.Contains(itemBack.strSkinPath)) {
listStrBoxDef.Add(itemBack.strSkinPath);
itemBack.BackColor = ColorTranslator.FromHtml("#513009"); }
itemBack.BoxColor = Color.White;
itemBack.strBreadcrumbs = (itemBack.rParentNode == null) ?
itemBack.BgColor = parent.BgColor; itemBack.ldTitle.GetString("") : itemBack.rParentNode.strBreadcrumbs + " > " + itemBack.ldTitle.GetString("");
itemBack.isChangedBgColor = parent.isChangedBgColor;
itemBack.BgType = parent.BgType; itemBack.arスコア[0] = new Cスコア();
itemBack.isChangedBgType = parent.isChangedBgType; itemBack.arスコア[0].. = "";
itemBack.arスコア[0].. = itemBack.ldTitle.GetString("");
itemBack.strジャンル = parent.strジャンル; itemBack.arスコア[0].. = "";
itemBack.strSelectBGPath = parent.strSelectBGPath;
itemBack.nスコア数 = 1; return (itemBack);
itemBack.rParentNode = parent; }
itemBack.strSkinPath = (parent.rParentNode == null) ?
"" : parent.rParentNode.strSkinPath; public static CSongListNode tGenerateRandomButton(CSongListNode parent, string path = "/") {
CSongListNode itemRandom = new CSongListNode();
// I guess this is used to count the number of box.def instances and only at startup, which makes using it here pretty weird itemRandom.eード種別 = CSongListNode.ENodeType.RANDOM;
if (listStrBoxDef != null && itemBack.strSkinPath != "" && !listStrBoxDef.Contains(itemBack.strSkinPath))
{ itemRandom.ldTitle = CLangManager.GetAllStringsAsLocalizationDataWithArgs("SONGSELECT_RANDOM_PATH", path, path);
listStrBoxDef.Add(itemBack.strSkinPath);
} itemRandom.nスコア数 = (int)Difficulty.Total;
itemRandom.rParentNode = parent;
itemBack.strBreadcrumbs = (itemBack.rParentNode == null) ?
itemBack.ldTitle.GetString("") : itemBack.rParentNode.strBreadcrumbs + " > " + itemBack.ldTitle.GetString(""); itemRandom.strBreadcrumbs = (itemRandom.rParentNode == null) ?
itemRandom.ldTitle.GetString("") : itemRandom.rParentNode.strBreadcrumbs + " > " + itemRandom.ldTitle.GetString("");
itemBack.arスコア[0] = new Cスコア();
itemBack.arスコア[0].. = ""; itemRandom.arスコア[0] = new Cスコア();
itemBack.arスコア[0].. = itemBack.ldTitle.GetString("");
itemBack.arスコア[0].. = ""; return itemRandom;
}
return (itemBack);
} // Reset the position of all back buttons, also adds a random button at the end
public static List<CSongListNode> tReinsertBackButtons(CSongListNode parent, List<CSongListNode> songList, string path = "/", List<string> listStrBoxDef = null) {
public static CSongListNode tGenerateRandomButton(CSongListNode parent, string path = "/") // Remove all the existing back boxes currently existing
{ songList.RemoveAll(e => e.eード種別 == CSongListNode.ENodeType.BACKBOX || e.eード種別 == CSongListNode.ENodeType.RANDOM);
CSongListNode itemRandom = new CSongListNode();
itemRandom.eード種別 = CSongListNode.ENodeType.RANDOM; int songCount = songList.Count;
itemRandom.ldTitle = CLangManager.GetAllStringsAsLocalizationDataWithArgs("SONGSELECT_RANDOM_PATH", path, path); for (int index = 0; index < (songCount / 7) + 1; index++) {
var backBox = tGenerateBackButton(parent, path, listStrBoxDef);
itemRandom.nスコア数 = (int)Difficulty.Total; songList.Insert(Math.Min(index * (7 + 1), songList.Count), backBox);
itemRandom.rParentNode = parent; }
itemRandom.strBreadcrumbs = (itemRandom.rParentNode == null) ? if (songCount > 0)
itemRandom.ldTitle.GetString("") : itemRandom.rParentNode.strBreadcrumbs + " > " + itemRandom.ldTitle.GetString(""); songList.Add(tGenerateRandomButton(parent, path));
itemRandom.arスコア[0] = new Cスコア(); // Return the reference in case of
return songList;
return itemRandom; }
}
// Reset the position of all back buttons, also adds a random button at the end private static CSongListNode tReadaptChildNote(CSongListNode parent, CSongListNode node) {
public static List<CSongListNode> tReinsertBackButtons(CSongListNode parent, List<CSongListNode> songList, string path = "/", List<string> listStrBoxDef = null) if (node != null) {
{ node.rParentNode = parent;
// Remove all the existing back boxes currently existing node.isChangedBgType = parent.isChangedBgType;
songList.RemoveAll(e => e.eード種別 == CSongListNode.ENodeType.BACKBOX || e.eード種別 == CSongListNode.ENodeType.RANDOM); node.isChangedBgColor = parent.isChangedBgColor;
node.isChangedBoxType = parent.isChangedBoxType;
int songCount = songList.Count; node.isChangedBoxColor = parent.isChangedBoxColor;
for (int index = 0; index < (songCount / 7) + 1; index++) node.ForeColor = parent.ForeColor;
{ node.BackColor = parent.BackColor;
var backBox = tGenerateBackButton(parent, path, listStrBoxDef); node.BoxColor = parent.BoxColor;
songList.Insert(Math.Min(index * (7 + 1), songList.Count), backBox); node.BgColor = parent.BgColor;
} node.BgType = parent.BgType;
node.BoxType = parent.BoxType;
if (songCount > 0)
songList.Add(tGenerateRandomButton(parent, path)); return node;
}
// Return the reference in case of return null;
return songList; }
}
// Generate the favorite folder content
public static List<CSongListNode> tFetchFavoriteFolder(CSongListNode parent) {
private static CSongListNode tReadaptChildNote(CSongListNode parent, CSongListNode node) List<CSongListNode> childList = new List<CSongListNode>();
{
if (node != null) foreach (string id in TJAPlayer3.Favorites.data.favorites[TJAPlayer3.SaveFile]) {
{ var node = tReadaptChildNote(parent, tGetNodeFromID(id));
node.rParentNode = parent; if (node != null) {
node.isChangedBgType = parent.isChangedBgType; childList.Add(node);
node.isChangedBgColor = parent.isChangedBgColor; }
node.isChangedBoxType = parent.isChangedBoxType;
node.isChangedBoxColor = parent.isChangedBoxColor; }
node.ForeColor = parent.ForeColor; // Generate back buttons
node.BackColor = parent.BackColor;
node.BoxColor = parent.BoxColor; string favPath = "./" + parent.ldTitle.GetString("") + "/";
node.BgColor = parent.BgColor;
node.BgType = parent.BgType; tReinsertBackButtons(parent, childList, favPath);
node.BoxType = parent.BoxType;
return childList;
return node; }
}
return null; // Generate recently played songs folder
} public static List<CSongListNode> tFetchRecentlyPlayedSongsFolder(CSongListNode parent) {
List<CSongListNode> childList = new List<CSongListNode>();
// Generate the favorite folder content
public static List<CSongListNode> tFetchFavoriteFolder(CSongListNode parent) foreach (string id in TJAPlayer3.RecentlyPlayedSongs.data.recentlyplayedsongs[TJAPlayer3.SaveFile].Reverse()) {
{ var node = tReadaptChildNote(parent, tGetNodeFromID(id));
List<CSongListNode> childList = new List<CSongListNode>(); if (node != null) {
childList.Add(node);
foreach (string id in TJAPlayer3.Favorites.data.favorites[TJAPlayer3.SaveFile]) }
{
var node = tReadaptChildNote(parent, tGetNodeFromID(id)); }
if (node != null)
{ // Generate back buttons
childList.Add(node);
} string favPath = "./" + parent.ldTitle.GetString("") + "/";
} tReinsertBackButtons(parent, childList, favPath);
// Generate back buttons return childList;
}
string favPath = "./" + parent.ldTitle.GetString("") + "/";
// 13 includes any higher difficulty
tReinsertBackButtons(parent, childList, favPath); private static bool tLevelMatches(int check, int level) {
if (level == 13)
return childList; return check >= level;
} return check == level;
}
// Generate recently played songs folder
public static List<CSongListNode> tFetchRecentlyPlayedSongsFolder(CSongListNode parent) // Generate search by difficulty folder
{ public static List<CSongListNode> tFetchSongsByDifficulty(CSongListNode parent, int difficulty = (int)Difficulty.Oni, int level = 8) {
List<CSongListNode> childList = new List<CSongListNode>(); List<CSongListNode> childList = new List<CSongListNode>();
foreach (string id in TJAPlayer3.RecentlyPlayedSongs.data.recentlyplayedsongs[TJAPlayer3.SaveFile].Reverse()) foreach (CSongListNode nodeT in nodes.Values) {
{ var score = nodeT.nLevel;
var node = tReadaptChildNote(parent, tGetNodeFromID(id)); if (tLevelMatches(score[difficulty], level)
if (node != null) || (difficulty == (int)Difficulty.Oni && tLevelMatches(score[(int)Difficulty.Edit], level))) // Oni includes Ura
{ {
childList.Add(node); var node = tReadaptChildNote(parent, nodeT);
} if (node != null) {
childList.Add(node);
} }
}
// Generate back buttons }
string favPath = "./" + parent.ldTitle.GetString("") + "/"; // Generate back buttons
tReinsertBackButtons(parent, childList, favPath); string favPath = "./" + parent.ldTitle.GetString("") + "/";
return childList; tReinsertBackButtons(parent, childList, favPath);
}
return childList;
// 13 includes any higher difficulty }
private static bool tLevelMatches(int check, int level)
{ #endregion
if (level == 13)
return check >= level; #region [Score tables methods]
return check == level;
} public static void tRefreshScoreTables() {
for (int pl = 0; pl < 5; pl++) {
// Generate search by difficulty folder CActSelect曲リスト.CScorePad[] SPArrRef = ScorePads[pl];
public static List<CSongListNode> tFetchSongsByDifficulty(CSongListNode parent, int difficulty = (int)Difficulty.Oni, int level = 8) var BestPlayStats = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(pl)].data.bestPlaysStats;
{
List<CSongListNode> childList = new List<CSongListNode>(); for (int s = 0; s <= (int)Difficulty.Edit + 1; s++) {
CActSelect曲リスト.CScorePad SPRef = SPArrRef[s];
foreach (CSongListNode nodeT in nodes.Values)
{ if (s <= (int)Difficulty.Edit) {
var score = nodeT.nLevel; SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[s].Skip(1).ToArray(); ;
if (tLevelMatches(score[difficulty], level) SPRef.CrownCount = BestPlayStats.ClearStatuses[s].Skip(1).ToArray(); ;
|| (difficulty == (int)Difficulty.Oni && tLevelMatches(score[(int)Difficulty.Edit], level))) // Oni includes Ura } else {
{ SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ScoreRanks[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
var node = tReadaptChildNote(parent, nodeT); SPRef.CrownCount = BestPlayStats.ClearStatuses[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ClearStatuses[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
if (node != null) }
{ }
childList.Add(node); }
} }
}
} #endregion
}
// Generate back buttons
string favPath = "./" + parent.ldTitle.GetString("") + "/";
tReinsertBackButtons(parent, childList, favPath);
return childList;
}
#endregion
#region [Score tables methods]
public static void tRefreshScoreTables()
{
for (int pl = 0; pl < 5; pl++)
{
CActSelect曲リスト.CScorePad[] SPArrRef = ScorePads[pl];
var BestPlayStats = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(pl)].data.bestPlaysStats;
for (int s = 0; s <= (int)Difficulty.Edit + 1; s++)
{
CActSelect曲リスト.CScorePad SPRef = SPArrRef[s];
if (s <= (int)Difficulty.Edit)
{
SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[s].Skip(1).ToArray(); ;
SPRef.CrownCount= BestPlayStats.ClearStatuses[s].Skip(1).ToArray(); ;
}
else
{
SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ScoreRanks[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
SPRef.CrownCount = BestPlayStats.ClearStatuses[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ClearStatuses[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
}
}
}
}
#endregion
}
} }

View File

@ -1,17 +1,11 @@
using System; using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using FDK; using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class CTextConsole : CActivity {
internal class CTextConsole : CActivity
{
// 定数 // 定数
public enum EFontType public enum EFontType {
{
White, White,
Cyan, Cyan,
Gray, Gray,
@ -22,31 +16,21 @@ namespace TJAPlayer3
// メソッド // メソッド
public void tPrint( int x, int y, EFontType font, string strAlphanumericString ) public void tPrint(int x, int y, EFontType font, string strAlphanumericString) {
{ if (!base.IsDeActivated && !string.IsNullOrEmpty(strAlphanumericString)) {
if( !base.IsDeActivated && !string.IsNullOrEmpty( strAlphanumericString ) )
{
int BOL = x; int BOL = x;
for( int i = 0; i < strAlphanumericString.Length; i++ ) for (int i = 0; i < strAlphanumericString.Length; i++) {
{ char ch = strAlphanumericString[i];
char ch = strAlphanumericString[ i ]; if (ch == '\n') {
if( ch == '\n' )
{
x = BOL; x = BOL;
y += nFontHeight; y += nFontHeight;
} } else {
else int index = str表記可能文字.IndexOf(ch);
{ if (index < 0) {
int index = str表記可能文字.IndexOf( ch );
if( index < 0 )
{
x += nFontWidth; x += nFontWidth;
} } else {
else if (this.txフォント8x16[(int)((int)font / (int)EFontType.WhiteSlim)] != null) {
{ this.txフォント8x16[(int)((int)font / (int)EFontType.WhiteSlim)].t2D描画(x, y, this.rc文字の矩形領域[(int)((int)font % (int)EFontType.WhiteSlim), index]);
if( this.txフォント8x16[ (int) ( (int) font / (int) EFontType.WhiteSlim ) ] != null )
{
this.txフォント8x16[ (int) ( (int) font / (int) EFontType.WhiteSlim ) ].t2D描画( x, y, this.rc文字の矩形領域[ (int) ( (int) font % (int) EFontType.WhiteSlim ), index ] );
} }
x += nFontWidth; x += nFontWidth;
} }
@ -58,32 +42,26 @@ namespace TJAPlayer3
// CActivity 実装 // CActivity 実装
public override void Activate() public override void Activate() {
{
base.Activate(); base.Activate();
} }
public override void DeActivate() public override void DeActivate() {
{ if (this.rc文字の矩形領域 != null)
if( this.rc文字の矩形領域 != null )
this.rc文字の矩形領域 = null; this.rc文字の矩形領域 = null;
base.DeActivate(); base.DeActivate();
} }
public override void CreateManagedResource() public override void CreateManagedResource() {
{ if (!base.IsDeActivated) {
if( !base.IsDeActivated ) this.txフォント8x16[0] = TJAPlayer3.Tx.TxC(@"Console_Font.png");
{ this.txフォント8x16[1] = TJAPlayer3.Tx.TxC(@"Console_Font_Small.png");
this.txフォント8x16[ 0 ] = TJAPlayer3.Tx.TxC(@"Console_Font.png");
this.txフォント8x16[ 1 ] = TJAPlayer3.Tx.TxC(@"Console_Font_Small.png");
nFontWidth = this.txフォント8x16[0].szTextureSize.Width / 32; nFontWidth = this.txフォント8x16[0].szTextureSize.Width / 32;
nFontHeight = this.txフォント8x16[0].szTextureSize.Height / 16; nFontHeight = this.txフォント8x16[0].szTextureSize.Height / 16;
this.rc文字の矩形領域 = new Rectangle[3, str表記可能文字.Length]; this.rc文字の矩形領域 = new Rectangle[3, str表記可能文字.Length];
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++) {
{ for (int j = 0; j < str表記可能文字.Length; j++) {
for (int j = 0; j < str表記可能文字.Length; j++)
{
int regionX = nFontWidth * 16, regionY = nFontHeight * 8; int regionX = nFontWidth * 16, regionY = nFontHeight * 8;
this.rc文字の矩形領域[i, j].X = ((i / 2) * regionX) + ((j % 16) * nFontWidth); this.rc文字の矩形領域[i, j].X = ((i / 2) * regionX) + ((j % 16) * nFontWidth);
this.rc文字の矩形領域[i, j].Y = ((i % 2) * regionY) + ((j / 16) * nFontHeight); this.rc文字の矩形領域[i, j].Y = ((i % 2) * regionY) + ((j / 16) * nFontHeight);
@ -95,16 +73,12 @@ namespace TJAPlayer3
base.CreateManagedResource(); base.CreateManagedResource();
} }
} }
public override void ReleaseManagedResource() public override void ReleaseManagedResource() {
{ if (!base.IsDeActivated) {
if( !base.IsDeActivated ) for (int i = 0; i < 2; i++) {
{ if (this.txフォント8x16[i] != null) {
for( int i = 0; i < 2; i++ ) this.txフォント8x16[i].Dispose();
{ this.txフォント8x16[i] = null;
if( this.txフォント8x16[ i ] != null )
{
this.txフォント8x16[ i ].Dispose();
this.txフォント8x16[ i ] = null;
} }
} }
base.ReleaseManagedResource(); base.ReleaseManagedResource();
@ -119,7 +93,7 @@ namespace TJAPlayer3
private Rectangle[,] rc文字の矩形領域; private Rectangle[,] rc文字の矩形領域;
private const string str表記可能文字 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "; private const string str表記可能文字 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ";
public int nFontWidth = 8, nFontHeight = 16; public int nFontWidth = 8, nFontHeight = 16;
private CTexture[] txフォント8x16 = new CTexture[ 2 ]; private CTexture[] txフォント8x16 = new CTexture[2];
//----------------- //-----------------
#endregion #endregion
} }

View File

@ -1,38 +1,30 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; class CVersionList {
using System.Linq; public static string[] VersionList = {
using System.Text; "0.1.0",
using System.Threading.Tasks; "0.2.0",
"0.3.0",
namespace TJAPlayer3 "0.3.1",
{ "0.3.2",
class CVersionList "0.3.3",
{ "0.3.4",
public static string[] VersionList = { "0.3.4.1",
"0.1.0", "0.3.4.2",
"0.2.0", "0.4.0",
"0.3.0", "0.4.1",
"0.3.1", "0.4.2",
"0.3.2", "0.4.3",
"0.3.3", "0.5.0",
"0.3.4", "0.5.1",
"0.3.4.1", "0.5.2",
"0.3.4.2", "0.5.2.1",
"0.4.0", "Pre 0.5.3",
"0.4.1", "0.5.3",
"0.4.2", "0.5.3.1",
"0.4.3", "0.5.3.2",
"0.5.0", "0.5.4",
"0.5.1", "Pre 0.6.0 b1",
"0.5.2", "Pre 0.6.0 b2",
"0.5.2.1", };
"Pre 0.5.3", }
"0.5.3",
"0.5.3.1",
"0.5.3.2",
"0.5.4",
"Pre 0.6.0 b1",
"Pre 0.6.0 b2",
};
}
} }

View File

@ -1,38 +1,33 @@
using FDK; using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ /// <summary>
/// <summary> /// The ConfigIniToSongGainControllerBinder allows for SONGVOL and/or other
/// The ConfigIniToSongGainControllerBinder allows for SONGVOL and/or other /// properties related to the Gain levels applied to song preview and
/// properties related to the Gain levels applied to song preview and /// playback, to be applied conditionally based on settings flowing from
/// playback, to be applied conditionally based on settings flowing from /// ConfigIni. This binder class allows that to take place without either
/// ConfigIni. This binder class allows that to take place without either /// ConfigIni or SongGainController having awareness of one another.
/// ConfigIni or SongGainController having awareness of one another. /// See those classes properties, methods, and events for more details.
/// See those classes properties, methods, and events for more details. /// </summary>
/// </summary> internal static class ConfigIniToSongGainControllerBinder {
internal static class ConfigIniToSongGainControllerBinder internal static void Bind(CConfigIni configIni, SongGainController songGainController) {
{ songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata;
internal static void Bind(CConfigIni configIni, SongGainController songGainController) songGainController.TargetLoudness = new Lufs(configIni.TargetLoudness);
{ songGainController.ApplySongVol = configIni.ApplySongVol;
songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata;
songGainController.TargetLoudness = new Lufs(configIni.TargetLoudness);
songGainController.ApplySongVol = configIni.ApplySongVol;
configIni.PropertyChanged += (sender, args) => configIni.PropertyChanged += (sender, args) => {
{ switch (args.PropertyName) {
switch (args.PropertyName) case nameof(CConfigIni.ApplyLoudnessMetadata):
{ songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata;
case nameof(CConfigIni.ApplyLoudnessMetadata): break;
songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata; case nameof(CConfigIni.TargetLoudness):
break; songGainController.TargetLoudness = new Lufs(configIni.TargetLoudness);
case nameof(CConfigIni.TargetLoudness): break;
songGainController.TargetLoudness = new Lufs(configIni.TargetLoudness); case nameof(CConfigIni.ApplySongVol):
break; songGainController.ApplySongVol = configIni.ApplySongVol;
case nameof(CConfigIni.ApplySongVol): break;
songGainController.ApplySongVol = configIni.ApplySongVol; }
break; };
} }
}; }
} }
}
}

View File

@ -1,67 +1,59 @@
using System; using FDK;
using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ /// <summary>
/// <summary> /// The ConfigIniToSoundGroupLevelControllerBinder allows for updated sound
/// The ConfigIniToSoundGroupLevelControllerBinder allows for updated sound /// group level values, and keyboard sound level adjustment increment
/// group level values, and keyboard sound level adjustment increment /// values, to flow between CConfigIni and the SoundGroupLevelController
/// values, to flow between CConfigIni and the SoundGroupLevelController /// without either of those two classes being aware of one another.
/// without either of those two classes being aware of one another. /// See those classes properties, methods, and events for more details.
/// See those classes properties, methods, and events for more details. /// </summary>
/// </summary> internal static class ConfigIniToSoundGroupLevelControllerBinder {
internal static class ConfigIniToSoundGroupLevelControllerBinder internal static void Bind(CConfigIni configIni, SoundGroupLevelController soundGroupLevelController) {
{ soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel);
internal static void Bind(CConfigIni configIni, SoundGroupLevelController soundGroupLevelController) soundGroupLevelController.SetLevel(ESoundGroup.Voice, configIni.VoiceLevel);
{ soundGroupLevelController.SetLevel(ESoundGroup.SongPreview, configIni.SongPreviewLevel);
soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel); soundGroupLevelController.SetLevel(ESoundGroup.SongPlayback, configIni.SongPlaybackLevel);
soundGroupLevelController.SetLevel(ESoundGroup.Voice, configIni.VoiceLevel); soundGroupLevelController.SetKeyboardSoundLevelIncrement(configIni.KeyboardSoundLevelIncrement);
soundGroupLevelController.SetLevel(ESoundGroup.SongPreview, configIni.SongPreviewLevel);
soundGroupLevelController.SetLevel(ESoundGroup.SongPlayback, configIni.SongPlaybackLevel);
soundGroupLevelController.SetKeyboardSoundLevelIncrement(configIni.KeyboardSoundLevelIncrement);
configIni.PropertyChanged += (sender, args) => configIni.PropertyChanged += (sender, args) => {
{ switch (args.PropertyName) {
switch (args.PropertyName) case nameof(CConfigIni.SoundEffectLevel):
{ soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel);
case nameof(CConfigIni.SoundEffectLevel): break;
soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel); case nameof(CConfigIni.VoiceLevel):
break; soundGroupLevelController.SetLevel(ESoundGroup.Voice, configIni.VoiceLevel);
case nameof(CConfigIni.VoiceLevel): break;
soundGroupLevelController.SetLevel(ESoundGroup.Voice, configIni.VoiceLevel); case nameof(CConfigIni.SongPreviewLevel):
break; soundGroupLevelController.SetLevel(ESoundGroup.SongPreview, configIni.SongPreviewLevel);
case nameof(CConfigIni.SongPreviewLevel): break;
soundGroupLevelController.SetLevel(ESoundGroup.SongPreview, configIni.SongPreviewLevel); case nameof(CConfigIni.SongPlaybackLevel):
break; soundGroupLevelController.SetLevel(ESoundGroup.SongPlayback, configIni.SongPlaybackLevel);
case nameof(CConfigIni.SongPlaybackLevel): break;
soundGroupLevelController.SetLevel(ESoundGroup.SongPlayback, configIni.SongPlaybackLevel); case nameof(CConfigIni.KeyboardSoundLevelIncrement):
break; soundGroupLevelController.SetKeyboardSoundLevelIncrement(configIni.KeyboardSoundLevelIncrement);
case nameof(CConfigIni.KeyboardSoundLevelIncrement): break;
soundGroupLevelController.SetKeyboardSoundLevelIncrement(configIni.KeyboardSoundLevelIncrement); }
break; };
}
};
soundGroupLevelController.LevelChanged += (sender, args) => soundGroupLevelController.LevelChanged += (sender, args) => {
{ switch (args.SoundGroup) {
switch (args.SoundGroup) case ESoundGroup.SoundEffect:
{ configIni.SoundEffectLevel = args.Level;
case ESoundGroup.SoundEffect: break;
configIni.SoundEffectLevel = args.Level; case ESoundGroup.Voice:
break; configIni.VoiceLevel = args.Level;
case ESoundGroup.Voice: break;
configIni.VoiceLevel = args.Level; case ESoundGroup.SongPreview:
break; configIni.SongPreviewLevel = args.Level;
case ESoundGroup.SongPreview: break;
configIni.SongPreviewLevel = args.Level; case ESoundGroup.SongPlayback:
break; configIni.SongPlaybackLevel = args.Level;
case ESoundGroup.SongPlayback: break;
configIni.SongPlaybackLevel = args.Level; default:
break; throw new ArgumentOutOfRangeException();
default: }
throw new ArgumentOutOfRangeException(); };
} }
}; }
}
}
} }

View File

@ -1,60 +1,50 @@
using System.IO; using System.Text;
using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ /// <summary>
/// <summary> /// 設定ファイル入出力クラス。
/// 設定ファイル入出力クラス。 /// </summary>
/// </summary> public static class ConfigManager {
public static class ConfigManager private static readonly JsonSerializerSettings Settings =
{ new JsonSerializerSettings() {
private static readonly JsonSerializerSettings Settings = ObjectCreationHandling = ObjectCreationHandling.Auto,
new JsonSerializerSettings() DefaultValueHandling = DefaultValueHandling.Include,
{ // ContractResolver = new CamelCasePropertyNamesContractResolver(),
ObjectCreationHandling = ObjectCreationHandling.Auto, NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Include, MissingMemberHandling = MissingMemberHandling.Ignore,
// ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = new StringEnumConverter[] { new StringEnumConverter() }
NullValueHandling = NullValueHandling.Ignore, };
MissingMemberHandling = MissingMemberHandling.Ignore,
Converters = new StringEnumConverter[] { new StringEnumConverter() }
};
/// <summary> /// <summary>
/// 設定ファイルの読み込みを行います。ファイルが存在しなかった場合、そのクラスの新規インスタンスを返します。 /// 設定ファイルの読み込みを行います。ファイルが存在しなかった場合、そのクラスの新規インスタンスを返します。
/// </summary> /// </summary>
/// <typeparam name="T">シリアライズしたクラス。</typeparam> /// <typeparam name="T">シリアライズしたクラス。</typeparam>
/// <param name="filePath">ファイル名。</param> /// <param name="filePath">ファイル名。</param>
/// <returns>デシリアライズ結果。</returns> /// <returns>デシリアライズ結果。</returns>
public static T GetConfig<T>(string filePath) where T : new() public static T GetConfig<T>(string filePath) where T : new() {
{ var json = "";
var json = ""; if (!System.IO.File.Exists(filePath)) {
if (!System.IO.File.Exists(filePath)) // ファイルが存在しないので
{ SaveConfig(new T(), filePath);
// ファイルが存在しないので }
SaveConfig(new T(), filePath); using (var stream = new System.IO.StreamReader(filePath, Encoding.UTF8)) {
} json = stream.ReadToEnd();
using (var stream = new System.IO.StreamReader(filePath, Encoding.UTF8)) }
{ return JsonConvert.DeserializeObject<T>(json, Settings);
json = stream.ReadToEnd(); }
}
return JsonConvert.DeserializeObject<T>(json, Settings);
}
/// <summary> /// <summary>
/// 設定ファイルの書き込みを行います。 /// 設定ファイルの書き込みを行います。
/// </summary> /// </summary>
/// <param name="obj">シリアライズするインスタンス。</param> /// <param name="obj">シリアライズするインスタンス。</param>
/// <param name="filePath">ファイル名。</param> /// <param name="filePath">ファイル名。</param>
public static void SaveConfig(object obj, string filePath) public static void SaveConfig(object obj, string filePath) {
{ (new FileInfo(filePath)).Directory.Create();
(new FileInfo(filePath)).Directory.Create(); using (var stream = new System.IO.StreamWriter(filePath, false, Encoding.UTF8)) {
using (var stream = new System.IO.StreamWriter(filePath, false, Encoding.UTF8)) stream.Write(JsonConvert.SerializeObject(obj, Formatting.None, Settings));
{ }
stream.Write(JsonConvert.SerializeObject(obj, Formatting.None, Settings)); }
} }
}
}
} }

View File

@ -1,77 +1,69 @@
using System; using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace TJAPlayer3 namespace TJAPlayer3 {
{
/// <summary> /// <summary>
/// 難易度。 /// 難易度。
/// </summary> /// </summary>
public enum Difficulty public enum Difficulty {
{ Easy,
Easy, Normal,
Normal, Hard,
Hard, Oni,
Oni, Edit,
Edit, Tower,
Tower, Dan,
Dan, Total
Total }
}
public enum EScrollMode public enum EScrollMode {
{ Normal,
Normal, BMSCROLL,
BMSCROLL, HBSCROLL
HBSCROLL }
}
public enum EGame public enum EGame {
{ OFF = 0,
OFF = 0, = 1,
= 1, = 2
= 2 }
} public enum E難易度表示タイプ {
public enum E難易度表示タイプ OFF = 0,
{ n曲目に表示 = 1,
OFF = 0, mtaikoに画像で表示 = 2,
n曲目に表示 = 1, }
mtaikoに画像で表示 = 2,
}
public enum EPad // 演奏用のenum。ここを修正するときは、次に出てくる EKeyConfigPad と EパッドFlag もセットで修正すること。 public enum EPad // 演奏用のenum。ここを修正するときは、次に出てくる EKeyConfigPad と EパッドFlag もセットで修正すること。
{ {
HH = 0, HH = 0,
R = 0, R = 0,
SD = 1, SD = 1,
G = 1, G = 1,
BD = 2, BD = 2,
B = 2, B = 2,
HT = 3, HT = 3,
Pick = 3, Pick = 3,
LT = 4, LT = 4,
Wail = 4, Wail = 4,
FT = 5, FT = 5,
Cancel = 5, Cancel = 5,
CY = 6, CY = 6,
Decide = 6, Decide = 6,
HHO = 7, HHO = 7,
RD = 8, RD = 8,
LC = 9, LC = 9,
LP = 10, // #27029 2012.1.4 from LP = 10, // #27029 2012.1.4 from
LBD = 11, LBD = 11,
LRed = 12, LRed = 12,
RRed = 13, RRed = 13,
LBlue = 14, LBlue = 14,
RBlue = 15, RBlue = 15,
LRed2P = 16, LRed2P = 16,
RRed2P = 17, RRed2P = 17,
LBlue2P = 18, LBlue2P = 18,
RBlue2P = 19, RBlue2P = 19,
LRed3P = 20, LRed3P = 20,
RRed3P = 21, RRed3P = 21,
@ -88,48 +80,48 @@ namespace TJAPlayer3
LBlue5P = 30, LBlue5P = 30,
RBlue5P = 31, RBlue5P = 31,
CLAP = 32, CLAP = 32,
CLAP2P = 33, CLAP2P = 33,
CLAP3P = 34, CLAP3P = 34,
CLAP4P = 35, CLAP4P = 35,
CLAP5P = 36, CLAP5P = 36,
LeftChange = 37, LeftChange = 37,
RightChange = 38, RightChange = 38,
MAX, // 門番用として定義 MAX, // 門番用として定義
UNKNOWN = 99 UNKNOWN = 99
} }
public enum EKeyConfigPad // #24609 キーコンフィグで使うenum。capture要素あり。 public enum EKeyConfigPad // #24609 キーコンフィグで使うenum。capture要素あり。
{ {
HH = EPad.HH, HH = EPad.HH,
R = EPad.R, R = EPad.R,
SD = EPad.SD, SD = EPad.SD,
G = EPad.G, G = EPad.G,
BD = EPad.BD, BD = EPad.BD,
B = EPad.B, B = EPad.B,
HT = EPad.HT, HT = EPad.HT,
Pick = EPad.Pick, Pick = EPad.Pick,
LT = EPad.LT, LT = EPad.LT,
Wail = EPad.Wail, Wail = EPad.Wail,
FT = EPad.FT, FT = EPad.FT,
Cancel = EPad.Cancel, Cancel = EPad.Cancel,
CY = EPad.CY, CY = EPad.CY,
Decide = EPad.Decide, Decide = EPad.Decide,
HHO = EPad.HHO, HHO = EPad.HHO,
RD = EPad.RD, RD = EPad.RD,
LC = EPad.LC, LC = EPad.LC,
LP = EPad.LP, // #27029 2012.1.4 from LP = EPad.LP, // #27029 2012.1.4 from
LBD = EPad.LBD, LBD = EPad.LBD,
#region [Gameplay Keys] #region [Gameplay Keys]
LRed = EPad.LRed, LRed = EPad.LRed,
RRed = EPad.RRed, RRed = EPad.RRed,
LBlue = EPad.LBlue, LBlue = EPad.LBlue,
RBlue = EPad.RBlue, RBlue = EPad.RBlue,
LRed2P = EPad.LRed2P, LRed2P = EPad.LRed2P,
RRed2P = EPad.RRed2P, RRed2P = EPad.RRed2P,
LBlue2P = EPad.LBlue2P, LBlue2P = EPad.LBlue2P,
RBlue2P = EPad.RBlue2P, RBlue2P = EPad.RBlue2P,
LRed3P = EPad.LRed3P, LRed3P = EPad.LRed3P,
RRed3P = EPad.RRed3P, RRed3P = EPad.RRed3P,
@ -146,7 +138,7 @@ namespace TJAPlayer3
LBlue5P = EPad.LBlue5P, LBlue5P = EPad.LBlue5P,
RBlue5P = EPad.RBlue5P, RBlue5P = EPad.RBlue5P,
Clap = EPad.CLAP, Clap = EPad.CLAP,
Clap2P = EPad.CLAP2P, Clap2P = EPad.CLAP2P,
Clap3P = EPad.CLAP3P, Clap3P = EPad.CLAP3P,
Clap4P = EPad.CLAP4P, Clap4P = EPad.CLAP4P,
@ -170,9 +162,9 @@ namespace TJAPlayer3
#endregion #endregion
#region [Gameplay/Training only] #region [Gameplay/Training only]
CycleVideoDisplayMode, CycleVideoDisplayMode,
#endregion #endregion
#endregion #endregion
#region [Training Keys] #region [Training Keys]
TrainingIncreaseScrollSpeed, TrainingIncreaseScrollSpeed,
TrainingDecreaseScrollSpeed, TrainingDecreaseScrollSpeed,
TrainingIncreaseSongSpeed, TrainingIncreaseSongSpeed,
@ -189,121 +181,113 @@ namespace TJAPlayer3
TrainingSkipBackMeasure, TrainingSkipBackMeasure,
TrainingJumpToFirstMeasure, TrainingJumpToFirstMeasure,
TrainingJumpToLastMeasure, TrainingJumpToLastMeasure,
#endregion #endregion
MAX, MAX,
UNKNOWN = EPad.UNKNOWN UNKNOWN = EPad.UNKNOWN
} }
[Flags] [Flags]
public enum EPadFlag // #24063 2011.1.16 yyagi コマンド入力用 パッド入力のフラグ化 public enum EPadFlag // #24063 2011.1.16 yyagi コマンド入力用 パッド入力のフラグ化
{ {
None = 0, None = 0,
HH = 1, HH = 1,
R = 1, R = 1,
SD = 2, SD = 2,
G = 2, G = 2,
B = 4, B = 4,
BD = 4, BD = 4,
HT = 8, HT = 8,
Pick = 8, Pick = 8,
LT = 16, LT = 16,
Wail = 16, Wail = 16,
FT = 32, FT = 32,
Cancel = 32, Cancel = 32,
CY = 64, CY = 64,
Decide = 128, Decide = 128,
HHO = 128, HHO = 128,
RD = 256, RD = 256,
LC = 512, LC = 512,
LP = 1024, // #27029 LP = 1024, // #27029
LBD = 2048, LBD = 2048,
LRed = 0, LRed = 0,
RRed = 1, RRed = 1,
LBlue = 2, LBlue = 2,
RBlue = 4, RBlue = 4,
LRed2P = 8, LRed2P = 8,
RRed2P = 16, RRed2P = 16,
LBlue2P = 32, LBlue2P = 32,
RBlue2P = 64, RBlue2P = 64,
UNKNOWN = 4096 UNKNOWN = 4096
} }
public enum ERandomMode public enum ERandomMode {
{
OFF, OFF,
RANDOM, RANDOM,
MIRROR, MIRROR,
SUPERRANDOM, SUPERRANDOM,
MIRRORRANDOM MIRRORRANDOM
} }
public enum EFunMods public enum EFunMods {
{
NONE, NONE,
AVALANCHE, AVALANCHE,
MINESWEEPER, MINESWEEPER,
TOTAL, TOTAL,
} }
public enum EGameType public enum EGameType {
{
TAIKO = 0, TAIKO = 0,
KONGA = 1, KONGA = 1,
}
public enum EInstrumentPad // ここを修正するときは、セットで次の EKeyConfigPart も修正すること。
{
DRUMS = 0,
GUITAR = 1,
BASS = 2,
TAIKO = 3,
UNKNOWN = 99
} }
public enum EKeyConfigPart // : E楽器パート
public enum EInstrumentPad // ここを修正するときは、セットで次の EKeyConfigPart も修正すること。
{ {
DRUMS = EInstrumentPad.DRUMS, DRUMS = 0,
GUITAR = EInstrumentPad.GUITAR, GUITAR = 1,
BASS = EInstrumentPad.BASS, BASS = 2,
TAIKO = EInstrumentPad.TAIKO, TAIKO = 3,
UNKNOWN = 99
}
public enum EKeyConfigPart // : E楽器パート
{
DRUMS = EInstrumentPad.DRUMS,
GUITAR = EInstrumentPad.GUITAR,
BASS = EInstrumentPad.BASS,
TAIKO = EInstrumentPad.TAIKO,
SYSTEM, SYSTEM,
UNKNOWN = EInstrumentPad.UNKNOWN UNKNOWN = EInstrumentPad.UNKNOWN
} }
internal enum EInputDevice internal enum EInputDevice {
{ Keyboard = 0,
Keyboard = 0, MIDIInput = 1,
MIDIInput = 1, Joypad = 2,
Joypad = 2, Mouse = 3,
Mouse = 3,
Gamepad = 4, Gamepad = 4,
Unknown = -1 Unknown = -1
} }
public enum ENoteJudge public enum ENoteJudge {
{ Perfect = 0,
Perfect = 0, Great = 1,
Great = 1, Good = 2,
Good = 2, Poor = 3,
Poor = 3, Miss = 4,
Miss = 4, Bad = 5,
Bad = 5, Auto = 6,
Auto = 6, ADLIB = 7,
ADLIB = 7, Mine = 8,
Mine = 8,
} }
internal enum E判定文字表示位置 internal enum E判定文字表示位置 {
{
OFF, OFF,
, ,
, ,
} }
internal enum EFIFOモード internal enum EFIFOモード {
{
, ,
} }
internal enum E演奏画面の戻り値 internal enum E演奏画面の戻り値 {
{
, ,
, ,
, ,
@ -311,46 +295,41 @@ namespace TJAPlayer3
_再演奏, _再演奏,
} }
internal enum E曲読込画面の戻り値 internal enum E曲読込画面の戻り値 {
{
= 0, = 0,
, ,
} }
public enum ENoteState public enum ENoteState {
{ none,
none, wait,
wait, perfect,
perfect, grade,
grade, bad
bad }
}
public enum E連打State public enum E連打State {
{ none,
none, roll,
roll, rollB,
rollB, balloon,
balloon, potato
potato }
}
public enum EStealthMode public enum EStealthMode {
{ OFF = 0,
OFF = 0, DORON = 1,
DORON = 1, STEALTH = 2
STEALTH = 2 }
}
/// <summary> /// <summary>
/// 透明チップの種類 /// 透明チップの種類
/// </summary> /// </summary>
public enum EInvisible public enum EInvisible {
{ OFF, // チップを透明化しない
OFF, // チップを透明化しない SEMI, // Poor/Miss時だけ、一時的に透明解除する
SEMI, // Poor/Miss時だけ、一時的に透明解除する FULL // チップを常に透明化する
FULL // チップを常に透明化する
} }
/// <summary> /// <summary>
@ -358,58 +337,53 @@ namespace TJAPlayer3
/// </summary> /// </summary>
/// <typeparam name="T">値の型。</typeparam> /// <typeparam name="T">値の型。</typeparam>
[Serializable] [Serializable]
[StructLayout( LayoutKind.Sequential )] [StructLayout(LayoutKind.Sequential)]
public struct STDGBVALUE<T> // indexはE楽器パートと一致させること public struct STDGBVALUE<T> // indexはE楽器パートと一致させること
{ {
public T Drums; public T Drums;
public T Guitar; public T Guitar;
public T Bass; public T Bass;
public T Taiko; public T Taiko;
public T Unknown; public T Unknown;
public T this[ int index ] public T this[int index] {
{ get {
get switch (index) {
{ case (int)EInstrumentPad.DRUMS:
switch( index )
{
case (int) EInstrumentPad.DRUMS:
return this.Drums; return this.Drums;
case (int) EInstrumentPad.GUITAR: case (int)EInstrumentPad.GUITAR:
return this.Guitar; return this.Guitar;
case (int) EInstrumentPad.BASS: case (int)EInstrumentPad.BASS:
return this.Bass; return this.Bass;
case (int) EInstrumentPad.TAIKO: case (int)EInstrumentPad.TAIKO:
return this.Taiko; return this.Taiko;
case (int) EInstrumentPad.UNKNOWN: case (int)EInstrumentPad.UNKNOWN:
return this.Unknown; return this.Unknown;
} }
throw new IndexOutOfRangeException(); throw new IndexOutOfRangeException();
} }
set set {
{ switch (index) {
switch( index ) case (int)EInstrumentPad.DRUMS:
{
case (int) EInstrumentPad.DRUMS:
this.Drums = value; this.Drums = value;
return; return;
case (int) EInstrumentPad.GUITAR: case (int)EInstrumentPad.GUITAR:
this.Guitar = value; this.Guitar = value;
return; return;
case (int) EInstrumentPad.BASS: case (int)EInstrumentPad.BASS:
this.Bass = value; this.Bass = value;
return; return;
case (int) EInstrumentPad.TAIKO: case (int)EInstrumentPad.TAIKO:
this.Taiko = value; this.Taiko = value;
return; return;
case (int) EInstrumentPad.UNKNOWN: case (int)EInstrumentPad.UNKNOWN:
this.Unknown = value; this.Unknown = value;
return; return;
} }
@ -418,34 +392,30 @@ namespace TJAPlayer3
} }
} }
public enum EReturnValue : int public enum EReturnValue : int {
{
Continuation, Continuation,
ReturnToTitle, ReturnToTitle,
SongChoosen SongChoosen
} }
#region[Ver.K追加] #region[Ver.K追加]
public enum Eレーンタイプ public enum Eレーンタイプ {
{ TypeA,
TypeA, TypeB,
TypeB, TypeC,
TypeC, TypeD
TypeD }
} public enum Eミラー {
public enum Eミラー TypeA,
{ TypeB
TypeA, }
TypeB public enum EClipDispType {
} = 1,
public enum EClipDispType = 2,
{ = 3,
= 1, OFF = 0
= 2, }
= 3, #endregion
OFF = 0
}
#endregion
} }

View File

@ -1,208 +1,188 @@
using System; using FDK;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TJAPlayer3;
using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ class Easing {
class Easing public int EaseIn(CCounter counter, float startPoint, float endPoint, CalcType type) {
{ StartPoint = startPoint;
public int EaseIn(CCounter counter, float startPoint, float endPoint, CalcType type) EndPoint = endPoint;
{ Sa = EndPoint - StartPoint;
StartPoint = startPoint; TimeMs = (int)counter.EndValue;
EndPoint = endPoint; Type = type;
Sa = EndPoint - StartPoint; CounterValue = counter.CurrentValue;
TimeMs = (int)counter.EndValue;
Type = type;
CounterValue = counter.CurrentValue;
switch (Type) switch (Type) {
{ case CalcType.Quadratic: //Quadratic
case CalcType.Quadratic: //Quadratic CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = Sa * CounterValue * CounterValue + StartPoint;
Value = Sa * CounterValue * CounterValue + StartPoint; break;
break; case CalcType.Cubic: //Cubic
case CalcType.Cubic: //Cubic CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = Sa * CounterValue * CounterValue * CounterValue + StartPoint;
Value = Sa * CounterValue * CounterValue * CounterValue + StartPoint; break;
break; case CalcType.Quartic: //Quartic
case CalcType.Quartic: //Quartic CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = Sa * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
Value = Sa * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; break;
break; case CalcType.Quintic: //Quintic
case CalcType.Quintic: //Quintic CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = Sa * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
Value = Sa * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; break;
break; case CalcType.Sinusoidal: //Sinusoidal
case CalcType.Sinusoidal: //Sinusoidal Value = -Sa * Math.Cos(CounterValue / TimeMs * (Math.PI / 2)) + Sa + StartPoint;
Value = -Sa * Math.Cos(CounterValue / TimeMs * (Math.PI / 2)) + Sa + StartPoint; break;
break; case CalcType.Exponential: //Exponential
case CalcType.Exponential: //Exponential Value = Sa * Math.Pow(2, 10 * (CounterValue / TimeMs - 1)) + StartPoint;
Value = Sa * Math.Pow(2, 10 * (CounterValue / TimeMs - 1)) + StartPoint; break;
break; case CalcType.Circular: //Circular
case CalcType.Circular: //Circular CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = -Sa * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint;
Value = -Sa * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint; break;
break; case CalcType.Linear: //Linear
case CalcType.Linear: //Linear Value = Sa * (CounterValue / TimeMs) + StartPoint;
Value = Sa * (CounterValue / TimeMs) + StartPoint; break;
break; }
}
return (int)Value; return (int)Value;
} }
public int EaseOut(CCounter counter, float startPoint, float endPoint, CalcType type) public int EaseOut(CCounter counter, float startPoint, float endPoint, CalcType type) {
{ StartPoint = startPoint;
StartPoint = startPoint; EndPoint = endPoint;
EndPoint = endPoint; Sa = EndPoint - StartPoint;
Sa = EndPoint - StartPoint; TimeMs = (int)counter.EndValue;
TimeMs = (int)counter.EndValue; Type = type;
Type = type; CounterValue = counter.CurrentValue;
CounterValue = counter.CurrentValue;
switch (Type) switch (Type) {
{ case CalcType.Quadratic: //Quadratic
case CalcType.Quadratic: //Quadratic CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = -Sa * CounterValue * (CounterValue - 2) + StartPoint;
Value = -Sa * CounterValue * (CounterValue - 2) + StartPoint; break;
break; case CalcType.Cubic: //Cubic
case CalcType.Cubic: //Cubic CounterValue /= TimeMs;
CounterValue /= TimeMs; CounterValue--;
CounterValue--; Value = Sa * (CounterValue * CounterValue * CounterValue + 1) + StartPoint;
Value = Sa * (CounterValue * CounterValue * CounterValue + 1) + StartPoint; break;
break; case CalcType.Quartic: //Quartic
case CalcType.Quartic: //Quartic CounterValue /= TimeMs;
CounterValue /= TimeMs; CounterValue--;
CounterValue--; Value = -Sa * (CounterValue * CounterValue * CounterValue * CounterValue - 1) + StartPoint;
Value = -Sa * (CounterValue * CounterValue * CounterValue * CounterValue - 1) + StartPoint; break;
break; case CalcType.Quintic: //Quintic
case CalcType.Quintic: //Quintic CounterValue /= TimeMs;
CounterValue /= TimeMs; CounterValue--;
CounterValue--; Value = Sa * (CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + 1) + StartPoint;
Value = Sa * (CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + 1) + StartPoint; break;
break; case CalcType.Sinusoidal: //Sinusoidal
case CalcType.Sinusoidal: //Sinusoidal Value = Sa * Math.Sin(CounterValue / TimeMs * (Math.PI / 2)) + StartPoint;
Value = Sa * Math.Sin(CounterValue / TimeMs * (Math.PI / 2)) + StartPoint; break;
break; case CalcType.Exponential: //Exponential
case CalcType.Exponential: //Exponential Value = Sa * (-Math.Pow(2, -10 * CounterValue / TimeMs) + 1) + StartPoint;
Value = Sa * (-Math.Pow(2, -10 * CounterValue / TimeMs) + 1) + StartPoint; break;
break; case CalcType.Circular: //Circular
case CalcType.Circular: //Circular CounterValue /= TimeMs;
CounterValue /= TimeMs; CounterValue--;
CounterValue--; Value = Sa * Math.Sqrt(1 - CounterValue * CounterValue) + StartPoint;
Value = Sa * Math.Sqrt(1 - CounterValue * CounterValue) + StartPoint; break;
break; case CalcType.Linear: //Linear
case CalcType.Linear: //Linear CounterValue /= TimeMs;
CounterValue /= TimeMs; Value = Sa * CounterValue + StartPoint;
Value = Sa * CounterValue + StartPoint; break;
break; }
}
return (int)Value; return (int)Value;
} }
public float EaseInOut(CCounter counter, float startPoint, float endPoint, CalcType type) public float EaseInOut(CCounter counter, float startPoint, float endPoint, CalcType type) {
{ StartPoint = startPoint;
StartPoint = startPoint; EndPoint = endPoint;
EndPoint = endPoint; Sa = EndPoint - StartPoint;
Sa = EndPoint - StartPoint; TimeMs = counter.EndValue;
TimeMs = counter.EndValue; Type = type;
Type = type; CounterValue = counter.CurrentValue;
CounterValue = counter.CurrentValue;
switch (Type) switch (Type) {
{ case CalcType.Quadratic: //Quadratic
case CalcType.Quadratic: //Quadratic CounterValue /= TimeMs / 2;
CounterValue /= TimeMs / 2; if (CounterValue < 1) {
if (CounterValue < 1) Value = Sa / 2 * CounterValue * CounterValue + StartPoint;
{ break;
Value = Sa / 2 * CounterValue * CounterValue + StartPoint; }
break; CounterValue--;
} Value = -Sa / 2 * (CounterValue * (CounterValue - 2) - 1) + StartPoint;
CounterValue--; break;
Value = -Sa / 2 * (CounterValue * (CounterValue - 2) - 1) + StartPoint; case CalcType.Cubic: //Cubic
break; CounterValue /= TimeMs / 2;
case CalcType.Cubic: //Cubic if (CounterValue < 1) {
CounterValue /= TimeMs / 2; Value = Sa / 2 * CounterValue * CounterValue * CounterValue + StartPoint;
if (CounterValue < 1) break;
{ }
Value = Sa / 2 * CounterValue * CounterValue * CounterValue + StartPoint; CounterValue -= 2;
break; Value = Sa / 2 * (CounterValue * CounterValue * CounterValue + 2) + StartPoint;
} break;
CounterValue -= 2; case CalcType.Quartic: //Quartic
Value = Sa / 2 * (CounterValue * CounterValue * CounterValue + 2) + StartPoint; CounterValue /= TimeMs / 2;
break; if (CounterValue < 1) {
case CalcType.Quartic: //Quartic Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
CounterValue /= TimeMs / 2; break;
if (CounterValue < 1) }
{ CounterValue -= 2;
Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; Value = -Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue - 2) + StartPoint;
break; break;
} case CalcType.Quintic: //Quintic
CounterValue -= 2; CounterValue /= TimeMs;
Value = -Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue - 2) + StartPoint; CounterValue /= TimeMs / 2;
break; if (CounterValue < 1) {
case CalcType.Quintic: //Quintic Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
CounterValue /= TimeMs; break;
CounterValue /= TimeMs / 2; }
if (CounterValue < 1) CounterValue -= 2;
{ Value = Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + 2) + StartPoint;
Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; break;
break; case CalcType.Sinusoidal: //Sinusoidal
} Value = -Sa / 2 * (Math.Cos(Math.PI * CounterValue / TimeMs) - 1) + StartPoint;
CounterValue -= 2; break;
Value = Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + 2) + StartPoint; case CalcType.Exponential: //Exponential
break; CounterValue /= TimeMs / 2;
case CalcType.Sinusoidal: //Sinusoidal if (CounterValue < 1) {
Value = -Sa / 2 * (Math.Cos(Math.PI * CounterValue / TimeMs) - 1) + StartPoint; Value = Sa / 2 * Math.Pow(2, 10 * (CounterValue - 1)) + StartPoint;
break; break;
case CalcType.Exponential: //Exponential }
CounterValue /= TimeMs / 2; CounterValue--;
if (CounterValue < 1) Value = Sa / 2 * (-Math.Pow(2, -10 * CounterValue) + 2) + StartPoint;
{ break;
Value = Sa / 2 * Math.Pow(2, 10 * (CounterValue - 1)) + StartPoint; case CalcType.Circular: //Circular
break; CounterValue /= TimeMs / 2;
} if (CounterValue < 1) {
CounterValue--; Value = -Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint;
Value = Sa / 2 * (-Math.Pow(2, -10 * CounterValue) + 2) + StartPoint; break;
break; }
case CalcType.Circular: //Circular CounterValue -= 2;
CounterValue /= TimeMs / 2; Value = Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) + 1) + StartPoint;
if (CounterValue < 1) break;
{ case CalcType.Linear: //Linear
Value = -Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint; CounterValue /= TimeMs;
break; Value = Sa * CounterValue + StartPoint;
} break;
CounterValue -= 2; }
Value = Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) + 1) + StartPoint;
break;
case CalcType.Linear: //Linear
CounterValue /= TimeMs;
Value = Sa * CounterValue + StartPoint;
break;
}
return (float)Value; return (float)Value;
} }
private float StartPoint; private float StartPoint;
private float EndPoint; private float EndPoint;
private float Sa; private float Sa;
private double TimeMs; private double TimeMs;
private CalcType Type; private CalcType Type;
private double CounterValue; private double CounterValue;
private double Value; private double Value;
public enum CalcType public enum CalcType {
{ Quadratic,
Quadratic, Cubic,
Cubic, Quartic,
Quartic, Quintic,
Quintic, Sinusoidal,
Sinusoidal, Exponential,
Exponential, Circular,
Circular, Linear
Linear }
} }
} }
}

View File

@ -1,62 +1,47 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; internal class Favorites {
using System.IO; public void tFavorites() {
using System.Linq; if (!File.Exists("Favorite.json"))
using System.Text; tSaveFile();
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3 tLoadFile();
{ }
internal class Favorites
{
public void tFavorites() {
if (!File.Exists("Favorite.json"))
tSaveFile();
tLoadFile(); #region [Auxiliary methods]
}
#region [Auxiliary methods] public void tToggleFavorite(string chartID) {
if (tIsFavorite(chartID))
data.favorites[TJAPlayer3.SaveFile].Remove(chartID);
else
data.favorites[TJAPlayer3.SaveFile].Add(chartID);
public void tToggleFavorite(string chartID) tSaveFile();
{ }
if (tIsFavorite(chartID))
data.favorites[TJAPlayer3.SaveFile].Remove(chartID);
else
data.favorites[TJAPlayer3.SaveFile].Add(chartID);
tSaveFile(); public bool tIsFavorite(string chartID) {
} return (data.favorites[TJAPlayer3.SaveFile].Contains(chartID));
}
public bool tIsFavorite(string chartID)
{
return (data.favorites[TJAPlayer3.SaveFile].Contains(chartID));
}
#endregion #endregion
public class Data public class Data {
{ public HashSet<string>[] favorites = new HashSet<string>[2] { new HashSet<string>(), new HashSet<string>() };
public HashSet<string>[] favorites = new HashSet<string>[2] { new HashSet<string>(), new HashSet<string>() }; }
}
public Data data = new Data(); public Data data = new Data();
#region [private] #region [private]
private void tSaveFile() private void tSaveFile() {
{ ConfigManager.SaveConfig(data, "Favorite.json");
ConfigManager.SaveConfig(data, "Favorite.json"); }
}
private void tLoadFile() private void tLoadFile() {
{ data = ConfigManager.GetConfig<Data>(@"Favorite.json");
data = ConfigManager.GetConfig<Data>(@"Favorite.json"); }
}
#endregion #endregion
} }
} }

View File

@ -1,58 +1,50 @@
using FDK; using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ /// <summary>
/// <summary> /// KeyboardSoundGroupLevelControlHandler is called by the song selection
/// KeyboardSoundGroupLevelControlHandler is called by the song selection /// and song play stages when handling keyboard input. By delegating to
/// and song play stages when handling keyboard input. By delegating to /// this class they are able to support a centrally-managed and consistent
/// this class they are able to support a centrally-managed and consistent /// set of keyboard shortcuts for dynamically adjusting four sound group
/// set of keyboard shortcuts for dynamically adjusting four sound group /// levels:
/// levels: /// - sound effect level, via Ctrl and either of the Minus or Equals keys
/// - sound effect level, via Ctrl and either of the Minus or Equals keys /// - voice level, via Shift and either of the Minus or Equals keys
/// - voice level, via Shift and either of the Minus or Equals keys /// - song preview and song playback level, via the Minus or Equals key
/// - song preview and song playback level, via the Minus or Equals key ///
/// /// When the sound group levels are adjusted in this manner, the
/// When the sound group levels are adjusted in this manner, the /// SoundGroupLevelController (and handlers bound to its events) ensure
/// SoundGroupLevelController (and handlers bound to its events) ensure /// that both the sound object group levels are updated and the application
/// that both the sound object group levels are updated and the application /// configuration is updated. See ConfigIniToSoundGroupLevelControllerBinder
/// configuration is updated. See ConfigIniToSoundGroupLevelControllerBinder /// for more details on the latter.
/// for more details on the latter. /// </summary>
/// </summary> internal static class KeyboardSoundGroupLevelControlHandler {
internal static class KeyboardSoundGroupLevelControlHandler internal static void Handle(
{ IInputDevice keyboard,
internal static void Handle( SoundGroupLevelController soundGroupLevelController,
IInputDevice keyboard, CSkin skin,
SoundGroupLevelController soundGroupLevelController, bool isSongPreview) {
CSkin skin, bool isAdjustmentPositive = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolIncrease);
bool isSongPreview) bool isAdjustmentNegative = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolDecrease);
{
bool isAdjustmentPositive = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolIncrease);
bool isAdjustmentNegative = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolDecrease);
if (!(isAdjustmentPositive || isAdjustmentNegative)) return; if (!(isAdjustmentPositive || isAdjustmentNegative)) return;
ESoundGroup soundGroup; ESoundGroup soundGroup;
CSkin.CSystemSound = null; CSkin.CSystemSound = null;
if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftControl) || if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftControl) ||
keyboard.KeyPressing((int)SlimDXKeys.Key.RightControl)) keyboard.KeyPressing((int)SlimDXKeys.Key.RightControl)) {
{ soundGroup = ESoundGroup.SoundEffect;
soundGroup = ESoundGroup.SoundEffect; = skin.soundDecideSFX;
= skin.soundDecideSFX; } else if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftShift) ||
} keyboard.KeyPressing((int)SlimDXKeys.Key.RightShift)) {
else if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftShift) || soundGroup = ESoundGroup.Voice;
keyboard.KeyPressing((int)SlimDXKeys.Key.RightShift)) = skin.soundゲーム開始音;
{ } else {
soundGroup = ESoundGroup.Voice; soundGroup = ESoundGroup.SongPlayback;
= skin.soundゲーム開始音; }
}
else
{
soundGroup = ESoundGroup.SongPlayback;
}
soundGroupLevelController.AdjustLevel(soundGroup, isAdjustmentPositive); soundGroupLevelController.AdjustLevel(soundGroup, isAdjustmentPositive);
?.tPlay(); ?.tPlay();
} }
} }
} }

View File

@ -1,67 +1,52 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK; using FDK;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class LogNotification {
internal class LogNotification private static Queue<CLogNotification> Notifications = new Queue<CLogNotification>();
{
private static Queue<CLogNotification> Notifications = new Queue<CLogNotification>();
public enum ENotificationType public enum ENotificationType {
{ EINFO,
EINFO, ESUCCESS,
ESUCCESS, EWARNING,
EWARNING, EERROR,
EERROR, }
}
public class CLogNotification public class CLogNotification {
{ public CLogNotification(ENotificationType nt, string msg) {
public CLogNotification(ENotificationType nt, string msg) NotificationType = nt;
{ Message = msg;
NotificationType = nt; }
Message = msg;
}
public ENotificationType NotificationType = ENotificationType.EINFO; public ENotificationType NotificationType = ENotificationType.EINFO;
public string Message = ""; public string Message = "";
public CCounter LifeTime = new CCounter(0, 1000, 1, TJAPlayer3.Timer); public CCounter LifeTime = new CCounter(0, 1000, 1, TJAPlayer3.Timer);
} }
public static void PopError(string message) public static void PopError(string message) {
{ Notifications.Enqueue(new CLogNotification(ENotificationType.EERROR, message));
Notifications.Enqueue(new CLogNotification(ENotificationType.EERROR, message)); Trace.TraceError("<Runtime Error>: " + message);
Trace.TraceError("<Runtime Error>: " + message); }
}
public static void PopWarning(string message) public static void PopWarning(string message) {
{ Notifications.Enqueue(new CLogNotification(ENotificationType.EWARNING, message));
Notifications.Enqueue(new CLogNotification(ENotificationType.EWARNING, message)); Trace.TraceWarning("<Runtime Warning>: " + message);
Trace.TraceWarning("<Runtime Warning>: " + message); }
}
public static void PopSuccess(string message) public static void PopSuccess(string message) {
{ Notifications.Enqueue(new CLogNotification(ENotificationType.ESUCCESS, message));
Notifications.Enqueue(new CLogNotification(ENotificationType.ESUCCESS, message)); Trace.TraceInformation("<Runtime Success>: " + message);
Trace.TraceInformation("<Runtime Success>: " + message); }
}
public static void PopInfo(string message) public static void PopInfo(string message) {
{ Notifications.Enqueue(new CLogNotification(ENotificationType.EINFO, message));
Notifications.Enqueue(new CLogNotification(ENotificationType.EINFO, message)); Trace.TraceInformation("<Runtime Info>: " + message);
Trace.TraceInformation("<Runtime Info>: " + message); }
}
public static void Display() public static void Display() {
{ while (Notifications.Count > 0 && Notifications.Peek().LifeTime.IsEnded) Notifications.Dequeue();
while (Notifications.Count > 0 && Notifications.Peek().LifeTime.IsEnded) Notifications.Dequeue(); // Add an optimized method to display the notifications here
// Add an optimized method to display the notifications here }
} }
}
} }

View File

@ -1,47 +1,37 @@
using System; using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK; using FDK;
using System.Drawing;
using static TJAPlayer3.CActSelect曲リスト; using static TJAPlayer3.CActSelect曲リスト;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class Modal {
internal class Modal public Modal(EModalType mt, int ra, params object[] re) {
{ modalType = mt;
public Modal(EModalType mt, int ra, params object[] re) rarity = ra;
{ reference = re;
modalType = mt; _isSet = false;
rarity = ra; // TODO: Add an int (?) or string to find the Puchichara/Character/Song asset to display it
reference = re; }
_isSet = false;
// TODO: Add an int (?) or string to find the Puchichara/Character/Song asset to display it
}
public void tSetupModal() public void tSetupModal() {
{ CTexture[] arrRef;
CTexture[] arrRef;
if (modalFormat == EModalFormat.Half) if (modalFormat == EModalFormat.Half)
arrRef = TJAPlayer3.Tx.Modal_Half; arrRef = TJAPlayer3.Tx.Modal_Half;
else if (modalFormat == EModalFormat.Half_4P) else if (modalFormat == EModalFormat.Half_4P)
arrRef = TJAPlayer3.Tx.Modal_Half_4P; arrRef = TJAPlayer3.Tx.Modal_Half_4P;
else if (modalFormat == EModalFormat.Half_5P) else if (modalFormat == EModalFormat.Half_5P)
arrRef = TJAPlayer3.Tx.Modal_Half_5P; arrRef = TJAPlayer3.Tx.Modal_Half_5P;
else else
arrRef = TJAPlayer3.Tx.Modal_Full; arrRef = TJAPlayer3.Tx.Modal_Full;
if (modalType == EModalType.Coin) if (modalType == EModalType.Coin)
_box = arrRef[arrRef.Length - 1]; _box = arrRef[arrRef.Length - 1];
else else {
{ int usedTex = Math.Max(0, Math.Min(arrRef.Length - 2, rarity));
int usedTex = Math.Max(0, Math.Min(arrRef.Length - 2, rarity)); _box = arrRef[usedTex];
_box = arrRef[usedTex]; }
}
/* /*
_boxRect = new Rectangle( _boxRect = new Rectangle(
(modalFormat == EModalFormat.Full || player == 0) (modalFormat == EModalFormat.Full || player == 0)
? 0 ? 0
@ -53,76 +43,68 @@ namespace TJAPlayer3
_box.szテクスチャサイズ.Height); _box.szテクスチャサイズ.Height);
*/ */
_boxRect = new Rectangle( _boxRect = new Rectangle(
(modalFormat == EModalFormat.Full || player == 0) ? 0 : _box.szTextureSize.Width / 2, (modalFormat == EModalFormat.Full || player == 0) ? 0 : _box.szTextureSize.Width / 2,
0, 0,
(modalFormat == EModalFormat.Full) ? _box.szTextureSize.Width : _box.szTextureSize.Width / 2, (modalFormat == EModalFormat.Full) ? _box.szTextureSize.Width : _box.szTextureSize.Width / 2,
_box.szTextureSize.Height / (((TJAPlayer3.ConfigIni.nPlayerCount - 1) / 2) + 1)); _box.szTextureSize.Height / (((TJAPlayer3.ConfigIni.nPlayerCount - 1) / 2) + 1));
tGenerateTextures(); tGenerateTextures();
_isSet = true; _isSet = true;
} }
public void tDisplayModal() public void tDisplayModal() {
{ if (_isSet == true) {
if (_isSet == true) _box?.t2D描画(_boxRect.Width * (player % 2), _boxRect.Height * (player / 2), _boxRect);
{
_box?.t2D描画(_boxRect.Width * (player % 2), _boxRect.Height * (player / 2), _boxRect);
int[] title_x; int[] title_x;
int[] title_y; int[] title_y;
int[] text_x; int[] text_x;
int[] text_y; int[] text_y;
int moveX; int moveX;
int moveY; int moveY;
if (modalFormat == EModalFormat.Full) if (modalFormat == EModalFormat.Full) {
{ title_x = new int[] { TJAPlayer3.Skin.Modal_Title_Full[0] };
title_x = new int[] { TJAPlayer3.Skin.Modal_Title_Full[0] }; title_y = new int[] { TJAPlayer3.Skin.Modal_Title_Full[1] };
title_y = new int[] { TJAPlayer3.Skin.Modal_Title_Full[1] };
text_x = new int[] { TJAPlayer3.Skin.Modal_Text_Full[0] }; text_x = new int[] { TJAPlayer3.Skin.Modal_Text_Full[0] };
text_y = new int[] { TJAPlayer3.Skin.Modal_Text_Full[1] }; text_y = new int[] { TJAPlayer3.Skin.Modal_Text_Full[1] };
moveX = TJAPlayer3.Skin.Modal_Text_Full_Move[0]; moveX = TJAPlayer3.Skin.Modal_Text_Full_Move[0];
moveY = TJAPlayer3.Skin.Modal_Text_Full_Move[1]; moveY = TJAPlayer3.Skin.Modal_Text_Full_Move[1];
} } else if (modalFormat == EModalFormat.Half) {
else if (modalFormat == EModalFormat.Half) title_x = TJAPlayer3.Skin.Modal_Title_Half_X;
{ title_y = TJAPlayer3.Skin.Modal_Title_Half_Y;
title_x = TJAPlayer3.Skin.Modal_Title_Half_X;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y;
text_x = TJAPlayer3.Skin.Modal_Text_Half_X; text_x = TJAPlayer3.Skin.Modal_Text_Half_X;
text_y = TJAPlayer3.Skin.Modal_Text_Half_Y; text_y = TJAPlayer3.Skin.Modal_Text_Half_Y;
moveX = TJAPlayer3.Skin.Modal_Text_Half_Move[0]; moveX = TJAPlayer3.Skin.Modal_Text_Half_Move[0];
moveY = TJAPlayer3.Skin.Modal_Text_Half_Move[1]; moveY = TJAPlayer3.Skin.Modal_Text_Half_Move[1];
} } else if (modalFormat == EModalFormat.Half_4P) {
else if (modalFormat == EModalFormat.Half_4P) title_x = TJAPlayer3.Skin.Modal_Title_Half_X_4P;
{ title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_4P;
title_x = TJAPlayer3.Skin.Modal_Title_Half_X_4P;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_4P;
text_x = TJAPlayer3.Skin.Modal_Text_Half_X_4P; text_x = TJAPlayer3.Skin.Modal_Text_Half_X_4P;
text_y = TJAPlayer3.Skin.Modal_Text_Half_Y_4P; text_y = TJAPlayer3.Skin.Modal_Text_Half_Y_4P;
moveX = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[0]; moveX = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[0];
moveY = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[1]; moveY = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[1];
} } else// 5P
else// 5P {
{ title_x = TJAPlayer3.Skin.Modal_Title_Half_X_5P;
title_x = TJAPlayer3.Skin.Modal_Title_Half_X_5P; title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_5P;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_5P;
text_x = TJAPlayer3.Skin.Modal_Text_Half_X_5P; text_x = TJAPlayer3.Skin.Modal_Text_Half_X_5P;
text_y = TJAPlayer3.Skin.Modal_Text_Half_Y_5P; text_y = TJAPlayer3.Skin.Modal_Text_Half_Y_5P;
moveX = TJAPlayer3.Skin.Modal_Text_Half_Move_5P[0]; moveX = TJAPlayer3.Skin.Modal_Text_Half_Move_5P[0];
moveY = TJAPlayer3.Skin.Modal_Text_Half_Move_5P[1]; moveY = TJAPlayer3.Skin.Modal_Text_Half_Move_5P[1];
} }
/* /*
Point[] Pos = new Point[] Point[] Pos = new Point[]
{ {
(modalFormat == EModalFormat.Full) ? new Point(TJAPlayer3.Skin.Modal_Title_Full[0], TJAPlayer3.Skin.Modal_Title_Full[1]) : new Point(TJAPlayer3.Skin.Modal_Title_Half_X[player], TJAPlayer3.Skin.Modal_Title_Half_Y[player]), // title (modalFormat == EModalFormat.Full) ? new Point(TJAPlayer3.Skin.Modal_Title_Full[0], TJAPlayer3.Skin.Modal_Title_Full[1]) : new Point(TJAPlayer3.Skin.Modal_Title_Half_X[player], TJAPlayer3.Skin.Modal_Title_Half_Y[player]), // title
@ -135,172 +117,156 @@ namespace TJAPlayer3
}; };
*/ */
Point[] Pos = new Point[] Point[] Pos = new Point[]
{ {
new Point(title_x[player], title_y[player]), new Point(title_x[player], title_y[player]),
new Point(text_x[player] + (tTextCentered () ? moveX : 0), new Point(text_x[player] + (tTextCentered () ? moveX : 0),
text_y[player] + (tTextCentered () ? moveY : 0)), // content text_y[player] + (tTextCentered () ? moveY : 0)), // content
}; };
_ModalTitle?.t2D中心基準描画(Pos[0].X, Pos[0].Y); _ModalTitle?.t2D中心基準描画(Pos[0].X, Pos[0].Y);
_ModalText?.t2D中心基準描画(Pos[1].X, Pos[1].Y); _ModalText?.t2D中心基準描画(Pos[1].X, Pos[1].Y);
// Extra texture for Puchichara, Character and Titles next // Extra texture for Puchichara, Character and Titles next
} }
} }
public void tPlayModalSfx() public void tPlayModalSfx() {
{ if (modalType == EModalType.Coin)
if (modalType == EModalType.Coin) TJAPlayer3.Skin.soundModal[TJAPlayer3.Skin.soundModal.Length - 1].tPlay();
TJAPlayer3.Skin.soundModal[TJAPlayer3.Skin.soundModal.Length - 1].tPlay(); else
else TJAPlayer3.Skin.soundModal[Math.Max(0, Math.Min(TJAPlayer3.Skin.soundModal.Length - 2, rarity))].tPlay();
TJAPlayer3.Skin.soundModal[Math.Max(0, Math.Min(TJAPlayer3.Skin.soundModal.Length - 2, rarity))].tPlay(); }
}
public static void tInitModalFonts() public static void tInitModalFonts() {
{ if (_pfModalContentHalf != null
if (_pfModalContentHalf != null && _pfModalTitleHalf != null
&& _pfModalTitleHalf != null && _pfModalContentFull != null
&& _pfModalContentFull != null && _pfModalTitleFull != null)
&& _pfModalTitleFull != null) return;
return;
_pfModalContentHalf = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalContentHalf_Size); _pfModalContentHalf = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalContentHalf_Size);
_pfModalTitleHalf = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalTitleHalf_Size); _pfModalTitleHalf = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalTitleHalf_Size);
_pfModalContentFull = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalContentFull_Size); _pfModalContentFull = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalContentFull_Size);
_pfModalTitleFull = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalTitleFull_Size); _pfModalTitleFull = HPrivateFastFont.tInstantiateMainFont(TJAPlayer3.Skin.Modal_Font_ModalTitleFull_Size);
} }
#region [Enum definitions] #region [Enum definitions]
public enum EModalType public enum EModalType {
{ Coin = 0,
Coin = 0, Character = 1,
Character = 1, Puchichara = 2,
Puchichara = 2, Title = 3,
Title = 3, Song = 4,
Song = 4, Total = 5,
Total = 5, }
}
// Full : 1P standard modal, Half : Splitted screen modal // Full : 1P standard modal, Half : Splitted screen modal
public enum EModalFormat public enum EModalFormat {
{ Full,
Full, Half,
Half, Half_4P,
Half_4P, Half_5P,
Half_5P, }
}
#endregion #endregion
#region [Public variables] #region [Public variables]
// Coin number for coin; database/unlockable asset for puchichara, character and title; no effect on text, confirm // Coin number for coin; database/unlockable asset for puchichara, character and title; no effect on text, confirm
public object[] reference; public object[] reference;
public int rarity; public int rarity;
public EModalType modalType; public EModalType modalType;
public EModalFormat modalFormat; public EModalFormat modalFormat;
// For modalFormat = Half only // For modalFormat = Half only
public int player; public int player;
#endregion #endregion
#region [private] #region [private]
// Check if the text is vertically centered or slightly up (to let enough space for the unlocked unit texture) // Check if the text is vertically centered or slightly up (to let enough space for the unlocked unit texture)
private bool tTextCentered() private bool tTextCentered() {
{ if (modalType == EModalType.Coin)
if (modalType == EModalType.Coin) return true;
return true; return false;
return false; }
}
// Generate the modal title and content text textures // Generate the modal title and content text textures
private void tGenerateTextures() private void tGenerateTextures() {
{ string modalKey = "MODAL_TITLE_COIN";
string modalKey = "MODAL_TITLE_COIN"; switch (modalType) {
switch (modalType) case EModalType.Character:
{ modalKey = "MODAL_TITLE_CHARA";
case EModalType.Character: break;
modalKey = "MODAL_TITLE_CHARA"; case EModalType.Puchichara:
break; modalKey = "MODAL_TITLE_PUCHI";
case EModalType.Puchichara: break;
modalKey = "MODAL_TITLE_PUCHI"; case EModalType.Title:
break; modalKey = "MODAL_TITLE_NAMEPLATE";
case EModalType.Title: break;
modalKey = "MODAL_TITLE_NAMEPLATE"; case EModalType.Song:
break; modalKey = "MODAL_TITLE_SONG";
case EModalType.Song: break;
modalKey = "MODAL_TITLE_SONG"; }
break; TitleTextureKey _title = new TitleTextureKey(
} CLangManager.LangInstance.GetString(modalKey),
TitleTextureKey _title = new TitleTextureKey( (modalFormat == EModalFormat.Full)
CLangManager.LangInstance.GetString(modalKey), ? _pfModalTitleFull
(modalFormat == EModalFormat.Full) : _pfModalTitleHalf,
? _pfModalTitleFull Color.White,
: _pfModalTitleHalf, Color.Black,
Color.White, 1800);
Color.Black,
1800);
string content = ""; string content = "";
if (modalType == EModalType.Coin) if (modalType == EModalType.Coin) {
{ content = CLangManager.LangInstance.GetString("MODAL_MESSAGE_COIN", reference[0].ToString(), TJAPlayer3.SaveFileInstances[player].data.Medals.ToString());
content = CLangManager.LangInstance.GetString("MODAL_MESSAGE_COIN", reference[0].ToString(), TJAPlayer3.SaveFileInstances[player].data.Medals.ToString()); //content = String.Format("+{0} {1} ({2}: {3})",
//content = String.Format("+{0} {1} ({2}: {3})", // (int)reference[0],
// (int)reference[0], // CLangManager.LangInstance.GetString(306),
// CLangManager.LangInstance.GetString(306), // CLangManager.LangInstance.GetString(307),
// CLangManager.LangInstance.GetString(307), // TJAPlayer3.SaveFileInstances[player].data.Medals
// TJAPlayer3.SaveFileInstances[player].data.Medals // );
// ); } else if (modalType == EModalType.Title) {
} content = ((string)reference[0]).RemoveTags();
else if (modalType == EModalType.Title) } else if (modalType == EModalType.Character) {
{ content = ((string)reference[0]).RemoveTags();
content = ((string)reference[0]).RemoveTags(); } else if (modalType == EModalType.Puchichara) {
} content = ((string)reference[0]).RemoveTags();
else if (modalType == EModalType.Character) } else if (modalType == EModalType.Song) {
{ content = ((string)reference[0]).RemoveTags();
content = ((string)reference[0]).RemoveTags(); }
}
else if (modalType == EModalType.Puchichara)
{
content = ((string)reference[0]).RemoveTags();
}
else if (modalType == EModalType.Song)
{
content = ((string)reference[0]).RemoveTags();
}
TitleTextureKey _content = new TitleTextureKey( TitleTextureKey _content = new TitleTextureKey(
content, content,
(modalFormat == EModalFormat.Full) (modalFormat == EModalFormat.Full)
? _pfModalContentFull ? _pfModalContentFull
: _pfModalContentHalf, : _pfModalContentHalf,
Color.White, Color.White,
Color.Black, Color.Black,
1800); 1800);
_ModalText = TJAPlayer3.stageSongSelect.actSongList.ResolveTitleTexture(_content); _ModalText = TJAPlayer3.stageSongSelect.actSongList.ResolveTitleTexture(_content);
_ModalTitle = TJAPlayer3.stageSongSelect.actSongList.ResolveTitleTexture(_title); _ModalTitle = TJAPlayer3.stageSongSelect.actSongList.ResolveTitleTexture(_title);
} }
private CTexture _box; private CTexture _box;
private Rectangle _boxRect; private Rectangle _boxRect;
private bool _isSet; private bool _isSet;
private static CCachedFontRenderer _pfModalTitleHalf; private static CCachedFontRenderer _pfModalTitleHalf;
private static CCachedFontRenderer _pfModalContentHalf; private static CCachedFontRenderer _pfModalContentHalf;
private static CCachedFontRenderer _pfModalTitleFull; private static CCachedFontRenderer _pfModalTitleFull;
private static CCachedFontRenderer _pfModalContentFull; private static CCachedFontRenderer _pfModalContentFull;
private CTexture _ModalTitle; private CTexture _ModalTitle;
private CTexture _ModalText; private CTexture _ModalText;
#endregion #endregion
} }
} }

View File

@ -1,82 +1,68 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; internal class ModalQueue {
using System.Linq; public ModalQueue(Modal.EModalFormat mf) {
using System.Text; _modalQueues = new Queue<Modal>[] { new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>() };
using System.Threading.Tasks; _modalFormat = mf;
}
namespace TJAPlayer3 // Add two modals (one per player) at the same time
{ public void tAddModal(Modal mp1, Modal mp2, Modal mp3, Modal mp4, Modal mp5) {
internal class ModalQueue mp1.modalFormat = _modalFormat;
{ mp2.modalFormat = _modalFormat;
public ModalQueue(Modal.EModalFormat mf) mp3.modalFormat = _modalFormat;
{ mp4.modalFormat = _modalFormat;
_modalQueues = new Queue<Modal>[] { new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>() }; mp5.modalFormat = _modalFormat;
_modalFormat = mf; mp1.player = 0;
} mp2.player = 1;
mp3.player = 2;
mp4.player = 3;
mp5.player = 4;
mp1.tSetupModal();
mp2.tSetupModal();
mp3.tSetupModal();
mp4.tSetupModal();
mp5.tSetupModal();
// Add two modals (one per player) at the same time if (mp1 != null)
public void tAddModal(Modal mp1, Modal mp2, Modal mp3, Modal mp4, Modal mp5) _modalQueues[0].Enqueue(mp1);
{ if (mp2 != null)
mp1.modalFormat = _modalFormat; _modalQueues[1].Enqueue(mp2);
mp2.modalFormat = _modalFormat; if (mp3 != null)
mp3.modalFormat = _modalFormat; _modalQueues[2].Enqueue(mp3);
mp4.modalFormat = _modalFormat; if (mp4 != null)
mp5.modalFormat = _modalFormat; _modalQueues[3].Enqueue(mp4);
mp1.player = 0; if (mp5 != null)
mp2.player = 1; _modalQueues[4].Enqueue(mp5);
mp3.player = 2; }
mp4.player = 3;
mp5.player = 4;
mp1.tSetupModal();
mp2.tSetupModal();
mp3.tSetupModal();
mp4.tSetupModal();
mp5.tSetupModal();
if (mp1 != null) // Add a single modal
_modalQueues[0].Enqueue(mp1); public void tAddModal(Modal mp, int player) {
if (mp2 != null) mp.modalFormat = _modalFormat;
_modalQueues[1].Enqueue(mp2); mp.player = player;
if (mp3 != null) mp.tSetupModal();
_modalQueues[2].Enqueue(mp3);
if (mp4 != null)
_modalQueues[3].Enqueue(mp4);
if (mp5 != null)
_modalQueues[4].Enqueue(mp5);
}
// Add a single modal if (mp != null && player >= 0 && player < TJAPlayer3.ConfigIni.nPlayerCount)
public void tAddModal(Modal mp, int player) _modalQueues[player].Enqueue(mp);
{ }
mp.modalFormat = _modalFormat;
mp.player = player;
mp.tSetupModal();
if (mp != null && player >= 0 && player < TJAPlayer3.ConfigIni.nPlayerCount) public Modal tPopModal(int player) {
_modalQueues[player].Enqueue(mp); if (!tIsQueueEmpty(player))
} return _modalQueues[player].Dequeue();
return null;
}
public Modal tPopModal(int player) public bool tIsQueueEmpty(int player) {
{ if (player < 0 || player >= TJAPlayer3.ConfigIni.nPlayerCount)
if (!tIsQueueEmpty(player)) return true;
return _modalQueues[player].Dequeue();
return null;
}
public bool tIsQueueEmpty(int player) return _modalQueues[player].Count < 1;
{ }
if (player < 0 || player >= TJAPlayer3.ConfigIni.nPlayerCount)
return true;
return _modalQueues[player].Count < 1; public bool tAreBothQueuesEmpty() {
} return tIsQueueEmpty(0) && tIsQueueEmpty(1) && tIsQueueEmpty(2) && tIsQueueEmpty(3) && tIsQueueEmpty(4);
}
public bool tAreBothQueuesEmpty() private Modal.EModalFormat _modalFormat;
{ private Queue<Modal>[] _modalQueues;
return tIsQueueEmpty(0) && tIsQueueEmpty(1) && tIsQueueEmpty(2) && tIsQueueEmpty(3) && tIsQueueEmpty(4); }
}
private Modal.EModalFormat _modalFormat;
private Queue<Modal>[] _modalQueues;
}
} }

View File

@ -1,249 +1,223 @@
using System; using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ class NamePlateConfig {
class NamePlateConfig public void tNamePlateConfig() {
{ // Deprecated, only converts to new format
public void tNamePlateConfig() /*
{
// Deprecated, only converts to new format
/*
if (!File.Exists("NamePlate.json")) if (!File.Exists("NamePlate.json"))
tSaveFile(); tSaveFile();
*/ */
tLoadFile(); tLoadFile();
} }
#region [Medals] #region [Medals]
public void tEarnCoins(int[] amounts) public void tEarnCoins(int[] amounts) {
{ if (amounts.Length < 2)
if (amounts.Length < 2) return;
return;
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++) {
{ int p = TJAPlayer3.GetActualPlayer(i);
int p = TJAPlayer3.GetActualPlayer(i);
data.Medals[p] += amounts[i]; data.Medals[p] += amounts[i];
} }
tSaveFile(); tSaveFile();
} }
// Return false if the current amount of coins is to low // Return false if the current amount of coins is to low
public bool tSpendCoins(int amount, int player) public bool tSpendCoins(int amount, int player) {
{ if (player > 1 || player < 0)
if (player > 1 || player < 0) return false;
return false;
if (data.Medals[player] < amount) if (data.Medals[player] < amount)
return false; return false;
data.Medals[player] -= amount; data.Medals[player] -= amount;
tSaveFile(); tSaveFile();
return true; return true;
} }
#endregion #endregion
#region [Dan titles] #region [Dan titles]
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus, int player) public bool tUpdateDanTitle(string title, bool isGold, int clearStatus, int player) {
{ bool changed = false;
bool changed = false;
bool iG = isGold; bool iG = isGold;
int cs = clearStatus; int cs = clearStatus;
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player] == null) if (TJAPlayer3.NamePlateConfig.data.DanTitles[player] == null)
TJAPlayer3.NamePlateConfig.data.DanTitles[player] = new Dictionary<string, SaveFile.CDanTitle>(); TJAPlayer3.NamePlateConfig.data.DanTitles[player] = new Dictionary<string, SaveFile.CDanTitle>();
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title)) if (TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title)) {
{ if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus > cs)
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus > cs) cs = TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus;
cs = TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus; if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].isGold)
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].isGold) iG = true;
iG = true; }
}
// Automatically set the dan to nameplate if new // Automatically set the dan to nameplate if new
// Add a function within the NamePlate.cs file to update the title texture // Add a function within the NamePlate.cs file to update the title texture
if (!TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title) || cs != clearStatus || iG != isGold) if (!TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title) || cs != clearStatus || iG != isGold) {
{ changed = true;
changed = true; /*
/*
TJAPlayer3.NamePlateConfig.data.Dan[player] = title; TJAPlayer3.NamePlateConfig.data.Dan[player] = title;
TJAPlayer3.NamePlateConfig.data.DanGold[player] = iG; TJAPlayer3.NamePlateConfig.data.DanGold[player] = iG;
TJAPlayer3.NamePlateConfig.data.DanType[player] = cs; TJAPlayer3.NamePlateConfig.data.DanType[player] = cs;
*/ */
} }
SaveFile.CDanTitle danTitle = new SaveFile.CDanTitle(iG, cs); SaveFile.CDanTitle danTitle = new SaveFile.CDanTitle(iG, cs);
TJAPlayer3.NamePlateConfig.data.DanTitles[player][title] = danTitle; TJAPlayer3.NamePlateConfig.data.DanTitles[player][title] = danTitle;
tSaveFile(); tSaveFile();
return changed; return changed;
} }
#endregion #endregion
#region [Auxilliary classes] #region [Auxilliary classes]
public class CDanTitle public class CDanTitle {
{ public CDanTitle(bool iG, int cs) {
public CDanTitle(bool iG, int cs) isGold = iG;
{ clearStatus = cs;
isGold = iG; }
clearStatus = cs;
}
[JsonProperty("isGold")] [JsonProperty("isGold")]
public bool isGold; public bool isGold;
[JsonProperty("clearStatus")] [JsonProperty("clearStatus")]
public int clearStatus; public int clearStatus;
} }
public class CNamePlateTitle public class CNamePlateTitle {
{ public CNamePlateTitle(int type) {
public CNamePlateTitle(int type) iType = type;
{ }
iType = type;
}
[JsonProperty("iType")] [JsonProperty("iType")]
public int iType; public int iType;
} }
#endregion #endregion
#region [Heya] #region [Heya]
public void tReindexCharacter(int p, string[] characterNamesList) public void tReindexCharacter(int p, string[] characterNamesList) {
{ string character = this.data.CharacterName[p];
string character = this.data.CharacterName[p];
if (characterNamesList.Contains(character)) if (characterNamesList.Contains(character))
this.data.Character[p] = characterNamesList.ToList().IndexOf(character); this.data.Character[p] = characterNamesList.ToList().IndexOf(character);
} }
public void tUpdateCharacterName(int p, string newChara) public void tUpdateCharacterName(int p, string newChara) {
{ this.data.CharacterName[p] = newChara;
this.data.CharacterName[p] = newChara; }
}
public void tApplyHeyaChanges() public void tApplyHeyaChanges() {
{ this.tSaveFile();
this.tSaveFile(); }
}
#endregion #endregion
public class Data public class Data {
{ [JsonProperty("name")]
[JsonProperty("name")] public string[] Name = { "プレイヤー1", "プレイヤー2", "プレイヤー3", "プレイヤー4", "プレイヤー5" };
public string[] Name = { "プレイヤー1", "プレイヤー2", "プレイヤー3", "プレイヤー4", "プレイヤー5" };
[JsonProperty("title")] [JsonProperty("title")]
public string[] Title = { "初心者", "初心者", "初心者", "初心者", "初心者" }; public string[] Title = { "初心者", "初心者", "初心者", "初心者", "初心者" };
[JsonProperty("dan")] [JsonProperty("dan")]
public string[] Dan = { "新人", "新人", "新人", "新人", "新人" }; public string[] Dan = { "新人", "新人", "新人", "新人", "新人" };
[JsonProperty("danGold")] [JsonProperty("danGold")]
public bool[] DanGold = { false, false, false, false, false }; public bool[] DanGold = { false, false, false, false, false };
[JsonProperty("danType")] [JsonProperty("danType")]
public int[] DanType = { 0, 0, 0, 0, 0 }; public int[] DanType = { 0, 0, 0, 0, 0 };
[JsonProperty("titleType")] [JsonProperty("titleType")]
public int[] TitleType = { 0, 0, 0, 0, 0 }; public int[] TitleType = { 0, 0, 0, 0, 0 };
[JsonProperty("puchiChara")] [JsonProperty("puchiChara")]
public string[] PuchiChara = { "0", "0", "0", "0", "0" }; public string[] PuchiChara = { "0", "0", "0", "0", "0" };
[JsonProperty("medals")] [JsonProperty("medals")]
public int[] Medals = { 0, 0, 0, 0, 0 }; public int[] Medals = { 0, 0, 0, 0, 0 };
[JsonProperty("character")] [JsonProperty("character")]
public int[] Character = { 0, 0, 0, 0, 0 }; public int[] Character = { 0, 0, 0, 0, 0 };
[JsonProperty("characterName")] [JsonProperty("characterName")]
public string[] CharacterName = { "0", "0", "0", "0", "0" }; public string[] CharacterName = { "0", "0", "0", "0", "0" };
[JsonProperty("danTitles")] [JsonProperty("danTitles")]
public Dictionary<string, SaveFile.CDanTitle>[] DanTitles = new Dictionary<string, SaveFile.CDanTitle>[5]; public Dictionary<string, SaveFile.CDanTitle>[] DanTitles = new Dictionary<string, SaveFile.CDanTitle>[5];
[JsonProperty("namePlateTitles")] [JsonProperty("namePlateTitles")]
public Dictionary<string, SaveFile.CNamePlateTitle>[] NamePlateTitles = new Dictionary<string, SaveFile.CNamePlateTitle>[5]; public Dictionary<string, SaveFile.CNamePlateTitle>[] NamePlateTitles = new Dictionary<string, SaveFile.CNamePlateTitle>[5];
[JsonProperty("unlockedPuchicharas")] [JsonProperty("unlockedPuchicharas")]
public List<string>[] UnlockedPuchicharas = new List<string>[5] public List<string>[] UnlockedPuchicharas = new List<string>[5]
{ {
new List<string>(), new List<string>(),
new List<string>(), new List<string>(),
new List<string>(), new List<string>(),
new List<string>(), new List<string>(),
new List<string>() new List<string>()
}; };
} }
public Data data = new Data(); public Data data = new Data();
#region [private] #region [private]
private void tSaveFile() private void tSaveFile() {
{ ConfigManager.SaveConfig(data, "NamePlate.json");
ConfigManager.SaveConfig(data, "NamePlate.json"); }
}
private void tLoadFile() private void tLoadFile() {
{ //data = ConfigManager.GetConfig<Data>(@"NamePlate.json");
//data = ConfigManager.GetConfig<Data>(@"NamePlate.json");
if (!File.Exists("NamePlate.json")) if (!File.Exists("NamePlate.json"))
return; return;
var _data = ConfigManager.GetConfig<Data>(@"NamePlate.json"); var _data = ConfigManager.GetConfig<Data>(@"NamePlate.json");
for (int i = 0; i < _data.Name.Length; i++) for (int i = 0; i < _data.Name.Length; i++) {
{ var _sf = new SaveFile();
var _sf = new SaveFile(); _sf.tSaveFile((i + 1) + "P");
_sf.tSaveFile((i + 1) + "P"); _sf.data.Name = _data.Name[i];
_sf.data.Name = _data.Name[i]; _sf.data.Title = _data.Title[i];
_sf.data.Title = _data.Title[i]; _sf.data.Dan = _data.Dan[i];
_sf.data.Dan = _data.Dan[i]; _sf.data.DanGold = _data.DanGold[i];
_sf.data.DanGold = _data.DanGold[i]; _sf.data.DanType = _data.DanType[i];
_sf.data.DanType = _data.DanType[i]; _sf.data.TitleType = _data.TitleType[i];
_sf.data.TitleType = _data.TitleType[i]; _sf.data.PuchiChara = _data.PuchiChara[i];
_sf.data.PuchiChara = _data.PuchiChara[i]; _sf.data.Medals = _data.Medals[i];
_sf.data.Medals = _data.Medals[i]; _sf.data.Character = _data.Character[i];
_sf.data.Character = _data.Character[i]; _sf.data.CharacterName = _data.CharacterName[i];
_sf.data.CharacterName = _data.CharacterName[i]; _sf.data.DanTitles = _data.DanTitles[i];
_sf.data.DanTitles = _data.DanTitles[i]; _sf.data.NamePlateTitles = _data.NamePlateTitles[i];
_sf.data.NamePlateTitles = _data.NamePlateTitles[i]; _sf.data.UnlockedPuchicharas = _data.UnlockedPuchicharas[i];
_sf.data.UnlockedPuchicharas = _data.UnlockedPuchicharas[i]; _sf.tApplyHeyaChanges();
_sf.tApplyHeyaChanges(); }
}
System.IO.File.Move(@"NamePlate.json", @"NamePlate_old.json"); System.IO.File.Move(@"NamePlate.json", @"NamePlate_old.json");
} }
#endregion #endregion
} }
} }

View File

@ -1,79 +1,63 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.IO;
using FDK;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class Program {
internal class Program
{
#region [ DLL存在チェック ] #region [ DLL存在チェック ]
//----------------------------- //-----------------------------
private static Mutex mutex二重起動防止用; private static Mutex mutex二重起動防止用;
private static bool tDLLの存在チェック( string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en, bool bLoadDllCheck ) private static bool tDLLの存在チェック(string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en, bool bLoadDllCheck) {
{ string str存在しないときに表示するエラー文字列 = (CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ja") ?
string str存在しないときに表示するエラー文字列 = ( CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ja" ) ?
str存在しないときに表示するエラー文字列jp : str存在しないときに表示するエラー文字列en; str存在しないときに表示するエラー文字列jp : str存在しないときに表示するエラー文字列en;
if ( bLoadDllCheck ) if (bLoadDllCheck) {
{ IntPtr hModule = LoadLibrary(strDll名); // 実際にLoadDll()してチェックする
IntPtr hModule = LoadLibrary( strDll名 ); // 実際にLoadDll()してチェックする if (hModule == IntPtr.Zero) {
if ( hModule == IntPtr.Zero )
{
//MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand ); //MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand );
return false; return false;
} }
FreeLibrary( hModule ); FreeLibrary(hModule);
} } else { // 単純にファイルの存在有無をチェックするだけ (プロジェクトで「参照」していたり、アンマネージドなDLLが暗黙リンクされるものはこちら)
else string path = Path.Combine(System.IO.Directory.GetCurrentDirectory(), strDll名);
{ // 単純にファイルの存在有無をチェックするだけ (プロジェクトで「参照」していたり、アンマネージドなDLLが暗黙リンクされるものはこちら) if (!File.Exists(path)) {
string path = Path.Combine( System.IO.Directory.GetCurrentDirectory(), strDll名 );
if ( !File.Exists( path ) )
{
//MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand ); //MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand );
return false; return false;
} }
} }
return true; return true;
} }
private static bool tDLLの存在チェック( string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en ) private static bool tDLLの存在チェック(string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en) {
{
return true; return true;
//return tDLLの存在チェック( strDll名, str存在しないときに表示するエラー文字列jp, str存在しないときに表示するエラー文字列en, false ); //return tDLLの存在チェック( strDll名, str存在しないときに表示するエラー文字列jp, str存在しないときに表示するエラー文字列en, false );
} }
#region [DllImport] #region [DllImport]
[DllImport( "kernel32", CharSet = CharSet.Unicode, SetLastError = true )] [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern void FreeLibrary( IntPtr hModule ); internal static extern void FreeLibrary(IntPtr hModule);
[DllImport( "kernel32", CharSet = CharSet.Unicode, SetLastError = true )] [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary( string lpFileName ); internal static extern IntPtr LoadLibrary(string lpFileName);
#endregion #endregion
//----------------------------- //-----------------------------
#endregion #endregion
[STAThread] [STAThread]
static void Main() static void Main() {
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
mutex二重起動防止用 = new Mutex( false, "DTXManiaMutex" );
if ( mutex二重起動防止用.WaitOne( 0, false ) ) mutex二重起動防止用 = new Mutex(false, "DTXManiaMutex");
{
if (mutex二重起動防止用.WaitOne(0, false)) {
string newLine = Environment.NewLine; string newLine = Environment.NewLine;
bool bDLLnotfound = false; bool bDLLnotfound = false;
Trace.WriteLine( "Current Directory: " + Environment.CurrentDirectory ); Trace.WriteLine("Current Directory: " + Environment.CurrentDirectory);
//Trace.WriteLine( "EXEのあるフォルダ: " + Path.GetDirectoryName( Application.ExecutablePath ) ); //Trace.WriteLine( "EXEのあるフォルダ: " + Path.GetDirectoryName( Application.ExecutablePath ) );
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
{ {
@ -83,7 +67,7 @@ namespace TJAPlayer3
try try
#endif #endif
{ {
string osplatform = ""; string osplatform = "";
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
osplatform = "win"; osplatform = "win";
@ -96,8 +80,7 @@ namespace TJAPlayer3
string platform = ""; string platform = "";
switch (RuntimeInformation.ProcessArchitecture) switch (RuntimeInformation.ProcessArchitecture) {
{
case Architecture.X64: case Architecture.X64:
platform = "x64"; platform = "x64";
break; break;
@ -114,20 +97,19 @@ namespace TJAPlayer3
throw new PlatformNotSupportedException($"TJAPlayer3 does not support this Architecture. ({RuntimeInformation.ProcessArchitecture})"); throw new PlatformNotSupportedException($"TJAPlayer3 does not support this Architecture. ({RuntimeInformation.ProcessArchitecture})");
} }
FFmpeg.AutoGen.ffmpeg.RootPath = AppContext.BaseDirectory + @"FFmpeg/" + osplatform + "-" + platform + "/"; FFmpeg.AutoGen.ffmpeg.RootPath = AppContext.BaseDirectory + @"FFmpeg/" + osplatform + "-" + platform + "/";
DirectoryInfo info = new DirectoryInfo(AppContext.BaseDirectory + @"Libs/" + osplatform + "-" + platform + "/"); DirectoryInfo info = new DirectoryInfo(AppContext.BaseDirectory + @"Libs/" + osplatform + "-" + platform + "/");
//実行ファイルの階層にライブラリをコピー //実行ファイルの階層にライブラリをコピー
foreach (FileInfo fileinfo in info.GetFiles()) foreach (FileInfo fileinfo in info.GetFiles()) {
{
fileinfo.CopyTo(AppContext.BaseDirectory + fileinfo.Name, true); fileinfo.CopyTo(AppContext.BaseDirectory + fileinfo.Name, true);
} }
using ( var mania = new TJAPlayer3() ) using (var mania = new TJAPlayer3())
mania.Run(); mania.Run();
Trace.WriteLine( "" ); Trace.WriteLine("");
Trace.WriteLine( "遊んでくれてありがとう!" ); Trace.WriteLine("遊んでくれてありがとう!");
} }
#if !DEBUG #if !DEBUG
catch( Exception e ) catch( Exception e )
@ -144,8 +126,8 @@ namespace TJAPlayer3
// END #24606 2011.03.08 from // END #24606 2011.03.08 from
// END #23670 2010.11.13 from // END #23670 2010.11.13 from
if ( Trace.Listeners.Count > 1 ) if (Trace.Listeners.Count > 1)
Trace.Listeners.RemoveAt( 1 ); Trace.Listeners.RemoveAt(1);
} }
// BEGIN #24615 2011.03.09 from: Mutex.WaitOne() が true を返した場合は、Mutex のリリースが必要である。 // BEGIN #24615 2011.03.09 from: Mutex.WaitOne() が true を返した場合は、Mutex のリリースが必要である。
@ -154,14 +136,13 @@ namespace TJAPlayer3
mutex二重起動防止用 = null; mutex二重起動防止用 = null;
// END #24615 2011.03.09 from // END #24615 2011.03.09 from
} } else // DTXManiaが既に起動中
else // DTXManiaが既に起動中 {
{
// → 引数が0個の時はそのまま終了 // → 引数が0個の時はそのまま終了
// 1個( コンパクトモード or DTXV -S) か2個 (DTXV -Nxxx ファイル名)のときは、そのプロセスにコマンドラインを丸々投げて終了する // 1個( コンパクトモード or DTXV -S) か2個 (DTXV -Nxxx ファイル名)のときは、そのプロセスにコマンドラインを丸々投げて終了する
for ( int i = 0; i < 5; i++ ) // 検索結果のハンドルがZeroになることがあるので、200ms間隔で5回リトライする for (int i = 0; i < 5; i++) // 検索結果のハンドルがZeroになることがあるので、200ms間隔で5回リトライする
{ {
#region [ DTXManiaプロセスを検索する] #region [ DTXManiaプロセスを検索する]
// このやり方だと、ShowInTaskbar=falseでタスクバーに表示されないパターンの時に検索に失敗するようだが // このやり方だと、ShowInTaskbar=falseでタスクバーに表示されないパターンの時に検索に失敗するようだが
@ -169,16 +150,14 @@ namespace TJAPlayer3
// FindWindowを使えばこのパターンにも対応できるが、C#でビルドするアプリはウインドウクラス名を自前指定できないので、これは使わない。 // FindWindowを使えばこのパターンにも対応できるが、C#でビルドするアプリはウインドウクラス名を自前指定できないので、これは使わない。
Process current = Process.GetCurrentProcess(); Process current = Process.GetCurrentProcess();
Process[] running = Process.GetProcessesByName( current.ProcessName ); Process[] running = Process.GetProcessesByName(current.ProcessName);
Process target = null; Process target = null;
//IntPtr hWnd = FindWindow( null, "DTXMania .NET style release " + CDTXMania.VERSION ); //IntPtr hWnd = FindWindow( null, "DTXMania .NET style release " + CDTXMania.VERSION );
foreach ( Process p in running ) foreach (Process p in running) {
{ if (p.Id != current.Id) // プロセス名は同じでかつ、プロセスIDが自分自身とは異なるものを探す
if ( p.Id != current.Id ) // プロセス名は同じでかつ、プロセスIDが自分自身とは異なるものを探す
{ {
if ( p.MainModule.FileName == current.MainModule.FileName && p.MainWindowHandle != IntPtr.Zero ) if (p.MainModule.FileName == current.MainModule.FileName && p.MainWindowHandle != IntPtr.Zero) {
{
target = p; target = p;
break; break;
} }
@ -187,31 +166,24 @@ namespace TJAPlayer3
#endregion #endregion
#region [ DTXManiaがいれば ] #region [ DTXManiaがいれば ]
if ( target != null ) if (target != null) {
{
string[] commandLineArgs = Environment.GetCommandLineArgs(); string[] commandLineArgs = Environment.GetCommandLineArgs();
if ( commandLineArgs != null && commandLineArgs.Length > 1 ) if (commandLineArgs != null && commandLineArgs.Length > 1) {
{
string arg = null; string arg = null;
for ( int j = 1; j < commandLineArgs.Length; j++ ) for (int j = 1; j < commandLineArgs.Length; j++) {
{ if (j == 1) {
if ( j == 1 ) arg += commandLineArgs[j];
{ } else {
arg += commandLineArgs[ j ]; arg += " " + "\"" + commandLineArgs[j] + "\"";
}
else
{
arg += " " + "\"" + commandLineArgs[ j ] + "\"";
} }
} }
} }
break; break;
} }
#endregion #endregion
else else {
{ Trace.TraceInformation("メッセージ送信先のプロセスが見つからず。5回リトライします。");
Trace.TraceInformation( "メッセージ送信先のプロセスが見つからず。5回リトライします。" ); Thread.Sleep(200);
Thread.Sleep( 200 );
} }
} }
} }

View File

@ -1,57 +1,43 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; internal class RecentlyPlayedSongs {
using System.IO; public void tRecentlyPlayedSongs() {
using System.Linq; if (!File.Exists("RecentlyPlayedSongs.json"))
using System.Text; tSaveFile();
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3 tLoadFile();
{ }
internal class RecentlyPlayedSongs
{
public void tRecentlyPlayedSongs() {
if (!File.Exists("RecentlyPlayedSongs.json"))
tSaveFile();
tLoadFile(); #region [Auxiliary methods]
}
#region [Auxiliary methods] public void tAddChart(string chartID) {
if (!data.recentlyplayedsongs[TJAPlayer3.SaveFile].Contains(chartID))
data.recentlyplayedsongs[TJAPlayer3.SaveFile].Enqueue(chartID);
public void tAddChart(string chartID) while (data.recentlyplayedsongs[TJAPlayer3.SaveFile].Count > TJAPlayer3.ConfigIni.nRecentlyPlayedMax)
{ data.recentlyplayedsongs[TJAPlayer3.SaveFile].Dequeue();
if (!data.recentlyplayedsongs[TJAPlayer3.SaveFile].Contains(chartID))
data.recentlyplayedsongs[TJAPlayer3.SaveFile].Enqueue(chartID);
while (data.recentlyplayedsongs[TJAPlayer3.SaveFile].Count > TJAPlayer3.ConfigIni.nRecentlyPlayedMax) tSaveFile();
data.recentlyplayedsongs[TJAPlayer3.SaveFile].Dequeue(); }
tSaveFile(); #endregion
}
#endregion public class Data {
public Queue<string>[] recentlyplayedsongs = new Queue<string>[2] { new Queue<string>(), new Queue<string>() };
}
public class Data public Data data = new Data();
{
public Queue<string>[] recentlyplayedsongs = new Queue<string>[2] { new Queue<string>(), new Queue<string>() };
}
public Data data = new Data(); #region [private]
#region [private] private void tSaveFile() {
ConfigManager.SaveConfig(data, "RecentlyPlayedSongs.json");
}
private void tSaveFile() private void tLoadFile() {
{ data = ConfigManager.GetConfig<Data>(@"RecentlyPlayedSongs.json");
ConfigManager.SaveConfig(data, "RecentlyPlayedSongs.json"); }
}
private void tLoadFile() #endregion
{ }
data = ConfigManager.GetConfig<Data>(@"RecentlyPlayedSongs.json");
}
#endregion
}
} }

View File

@ -1,405 +1,359 @@
using System; using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ internal class SaveFile {
internal class SaveFile
{
public void tSaveFile(string filename) public void tSaveFile(string filename) {
{ path = @$"Saves{Path.DirectorySeparatorChar}" + filename + @".json";
path = @$"Saves{Path.DirectorySeparatorChar}" + filename + @".json"; name = filename;
name = filename;
if (!File.Exists(path)) if (!File.Exists(path)) {
{ this.data.Name = filename;
this.data.Name = filename; tSaveFile();
tSaveFile(); }
}
tLoadFile();
tInitSaveFile(); tLoadFile();
}
public void tInitSaveFile() tInitSaveFile();
{ }
data.bestPlays = DBSaves.GetBestPlaysAsDict(data.SaveId);
data.tFactorizeBestPlays();
}
public void tLoadUnlockables() public void tInitSaveFile() {
{ data.bestPlays = DBSaves.GetBestPlaysAsDict(data.SaveId);
data.UnlockedCharacters = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_characters"); data.tFactorizeBestPlays();
data.UnlockedPuchicharas = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_puchicharas"); }
data.UnlockedSongs = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_songs");
data.UnlockedNameplateIds = DBSaves.FetchUnlockedNameplateIds(data.SaveId);
data.DanTitles = DBSaves.FetchUnlockedDanTitles(data.SaveId);
}
#region [Medals and PlayCount] public void tLoadUnlockables() {
data.UnlockedCharacters = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_characters");
data.UnlockedPuchicharas = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_puchicharas");
data.UnlockedSongs = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_songs");
data.UnlockedNameplateIds = DBSaves.FetchUnlockedNameplateIds(data.SaveId);
data.DanTitles = DBSaves.FetchUnlockedDanTitles(data.SaveId);
}
public void tEarnCoins(int amount)
{
data.Medals += amount;
data.TotalEarnedMedals += amount;
// Small trick here, each actual play (excluding Auto, AI, etc) are worth at least 5 coins for the player, whatever which mode it is (Dan, Tower, Taiko mode, etc) #region [Medals and PlayCount]
// Earn Coins is also called once per play, so we just add 1 here to the total playcount
data.TotalPlaycount += 1;
DBSaves.AlterCoinsAndTotalPlayCount(data.SaveId, amount, 1);
//tSaveFile();
}
// Return false if the current amount of coins is to low public void tEarnCoins(int amount) {
public bool tSpendCoins(int amount) data.Medals += amount;
{ data.TotalEarnedMedals += amount;
if (data.Medals < amount)
return false;
data.Medals -= amount; // Small trick here, each actual play (excluding Auto, AI, etc) are worth at least 5 coins for the player, whatever which mode it is (Dan, Tower, Taiko mode, etc)
DBSaves.AlterCoinsAndTotalPlayCount(data.SaveId, -amount, 0); // Earn Coins is also called once per play, so we just add 1 here to the total playcount
//tSaveFile(); data.TotalPlaycount += 1;
DBSaves.AlterCoinsAndTotalPlayCount(data.SaveId, amount, 1);
//tSaveFile();
}
return true; // Return false if the current amount of coins is to low
} public bool tSpendCoins(int amount) {
if (data.Medals < amount)
return false;
public void tRegisterAIBattleModePlay(bool IsWon) data.Medals -= amount;
{ DBSaves.AlterCoinsAndTotalPlayCount(data.SaveId, -amount, 0);
data.AIBattleModePlaycount++; //tSaveFile();
if (IsWon) data.AIBattleModeWins++;
DBSaves.RegisterAIBattleModePlay(data.SaveId, IsWon);
}
#endregion return true;
}
#region [Dan titles] public void tRegisterAIBattleModePlay(bool IsWon) {
data.AIBattleModePlaycount++;
if (IsWon) data.AIBattleModeWins++;
DBSaves.RegisterAIBattleModePlay(data.SaveId, IsWon);
}
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus) #endregion
{
bool changed = false;
bool iG = isGold; #region [Dan titles]
int cs = clearStatus;
if (this.data.DanTitles == null) public bool tUpdateDanTitle(string title, bool isGold, int clearStatus) {
this.data.DanTitles = new Dictionary<string, CDanTitle>(); bool changed = false;
if (this.data.DanTitles.ContainsKey(title)) bool iG = isGold;
{ int cs = clearStatus;
if (this.data.DanTitles[title].clearStatus > cs)
cs = this.data.DanTitles[title].clearStatus;
if (this.data.DanTitles[title].isGold)
iG = true;
}
// Automatically set the dan to nameplate if new if (this.data.DanTitles == null)
// Add a function within the NamePlate.cs file to update the title texture this.data.DanTitles = new Dictionary<string, CDanTitle>();
if (!this.data.DanTitles.ContainsKey(title) || cs != clearStatus || iG != isGold) if (this.data.DanTitles.ContainsKey(title)) {
{ if (this.data.DanTitles[title].clearStatus > cs)
DBSaves.RegisterDanTitle(data.SaveId, title, clearStatus, isGold); cs = this.data.DanTitles[title].clearStatus;
changed = true; if (this.data.DanTitles[title].isGold)
/* iG = true;
}
// Automatically set the dan to nameplate if new
// Add a function within the NamePlate.cs file to update the title texture
if (!this.data.DanTitles.ContainsKey(title) || cs != clearStatus || iG != isGold) {
DBSaves.RegisterDanTitle(data.SaveId, title, clearStatus, isGold);
changed = true;
/*
TJAPlayer3.NamePlateConfig.data.Dan[player] = title; TJAPlayer3.NamePlateConfig.data.Dan[player] = title;
TJAPlayer3.NamePlateConfig.data.DanGold[player] = iG; TJAPlayer3.NamePlateConfig.data.DanGold[player] = iG;
TJAPlayer3.NamePlateConfig.data.DanType[player] = cs; TJAPlayer3.NamePlateConfig.data.DanType[player] = cs;
*/ */
} }
CDanTitle danTitle = new CDanTitle(iG, cs); CDanTitle danTitle = new CDanTitle(iG, cs);
this.data.DanTitles[title] = danTitle; this.data.DanTitles[title] = danTitle;
//tSaveFile(); //tSaveFile();
return changed; return changed;
} }
#endregion #endregion
#region [Auxilliary classes] #region [Auxilliary classes]
public class CDanTitle public class CDanTitle {
{ public CDanTitle(bool iG, int cs) {
public CDanTitle(bool iG, int cs) isGold = iG;
{ clearStatus = cs;
isGold = iG; }
clearStatus = cs;
}
public CDanTitle() public CDanTitle() {
{ isGold = false;
isGold = false; clearStatus = 0;
clearStatus = 0; }
}
[JsonProperty("isGold")] [JsonProperty("isGold")]
public bool isGold; public bool isGold;
[JsonProperty("clearStatus")] [JsonProperty("clearStatus")]
public int clearStatus; public int clearStatus;
} }
public class CNamePlateTitle public class CNamePlateTitle {
{ public CNamePlateTitle(int type) {
public CNamePlateTitle(int type) iType = type;
{ cld = new CLocalizationData();
iType = type; }
cld = new CLocalizationData();
}
[JsonProperty("iType")] [JsonProperty("iType")]
public int iType; public int iType;
[JsonProperty("Localization")] [JsonProperty("Localization")]
public CLocalizationData cld; public CLocalizationData cld;
} }
public class CPassStatus public class CPassStatus {
{ public CPassStatus() {
public CPassStatus() d = new int[5] { -1, -1, -1, -1, -1 };
{ }
d = new int[5] { -1, -1, -1, -1, -1 };
}
public int[] d; public int[] d;
} }
#endregion #endregion
#region [Heya] #region [Heya]
public void tReindexCharacter(string[] characterNamesList) public void tReindexCharacter(string[] characterNamesList) {
{ string character = this.data.CharacterName;
string character = this.data.CharacterName;
if (characterNamesList.Contains(character)) if (characterNamesList.Contains(character))
this.data.Character = characterNamesList.ToList().IndexOf(character); this.data.Character = characterNamesList.ToList().IndexOf(character);
} }
public void tUpdateCharacterName(string newChara) public void tUpdateCharacterName(string newChara) {
{ this.data.CharacterName = newChara;
this.data.CharacterName = newChara; }
}
public void tApplyHeyaChanges() public void tApplyHeyaChanges() {
{ DBSaves.ApplyChangesFromMyRoom(this);
DBSaves.ApplyChangesFromMyRoom(this); //this.tSaveFile();
//this.tSaveFile(); }
}
#endregion #endregion
public class Data public class Data {
{ [JsonProperty("saveId")]
[JsonProperty("saveId")] public Int64 SaveId = 0;
public Int64 SaveId = 0;
[JsonProperty("name")] [JsonProperty("name")]
public string Name = "プレイヤー1"; public string Name = "プレイヤー1";
[JsonProperty("title")] [JsonProperty("title")]
public string Title = "初心者"; public string Title = "初心者";
[JsonProperty("dan")] [JsonProperty("dan")]
public string Dan = "新人"; public string Dan = "新人";
[JsonProperty("danGold")] [JsonProperty("danGold")]
public bool DanGold = false; public bool DanGold = false;
[JsonProperty("danType")] [JsonProperty("danType")]
public int DanType = 0; public int DanType = 0;
[JsonProperty("titleType")] [JsonProperty("titleType")]
public int TitleType = 0; public int TitleType = 0;
[JsonIgnore] [JsonIgnore]
public int TitleRarityInt = 1; public int TitleRarityInt = 1;
[JsonIgnore] [JsonIgnore]
public int TitleId = -1; public int TitleId = -1;
[JsonProperty("puchiChara")] [JsonProperty("puchiChara")]
public string PuchiChara = "0"; public string PuchiChara = "0";
[JsonProperty("medals")]
public Int64 Medals = 0;
[JsonIgnore] [JsonProperty("medals")]
public Int64 TotalEarnedMedals = 0; public Int64 Medals = 0;
[JsonIgnore] [JsonIgnore]
public int TotalPlaycount = 0; public Int64 TotalEarnedMedals = 0;
[JsonIgnore] [JsonIgnore]
public int AIBattleModePlaycount = 0; public int TotalPlaycount = 0;
[JsonIgnore] [JsonIgnore]
public int AIBattleModeWins = 0; public int AIBattleModePlaycount = 0;
[JsonProperty("character")] [JsonIgnore]
public int Character = 0; public int AIBattleModeWins = 0;
[JsonProperty("characterName")] [JsonProperty("character")]
public string CharacterName = "0"; public int Character = 0;
[JsonProperty("danTitles")] [JsonProperty("characterName")]
public Dictionary<string, CDanTitle> DanTitles = new Dictionary<string, CDanTitle>(); public string CharacterName = "0";
// Deprecated [JsonProperty("danTitles")]
[JsonProperty("namePlateTitles")] public Dictionary<string, CDanTitle> DanTitles = new Dictionary<string, CDanTitle>();
public Dictionary<string, CNamePlateTitle> NamePlateTitles = new Dictionary<string, CNamePlateTitle>();
// Deprecated
[JsonProperty("unlockedCharacters")] [JsonProperty("namePlateTitles")]
public List<string> UnlockedCharacters = new List<string>(); public Dictionary<string, CNamePlateTitle> NamePlateTitles = new Dictionary<string, CNamePlateTitle>();
[JsonProperty("unlockedPuchicharas")] [JsonProperty("unlockedCharacters")]
public List<string> UnlockedPuchicharas = new List<string>(); public List<string> UnlockedCharacters = new List<string>();
[JsonIgnore] [JsonProperty("unlockedPuchicharas")]
public List<string> UnlockedSongs = new List<string>(); public List<string> UnlockedPuchicharas = new List<string>();
[JsonIgnore] [JsonIgnore]
public List<int> UnlockedNameplateIds = new List<int>(); public List<string> UnlockedSongs = new List<string>();
[JsonProperty("activeTriggers")] [JsonIgnore]
public HashSet<string> ActiveTriggers = new HashSet<string>(); public List<int> UnlockedNameplateIds = new List<int>();
[JsonIgnore] [JsonProperty("activeTriggers")]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord> (); public HashSet<string> ActiveTriggers = new HashSet<string>();
[JsonIgnore] [JsonIgnore]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>(); public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
[JsonIgnore] [JsonIgnore]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>(); public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
[JsonIgnore] [JsonIgnore]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysSongSelectTables = new Dictionary<string, BestPlayRecords.CBestPlayRecord>(); public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
[JsonIgnore] [JsonIgnore]
public Dictionary<string, BestPlayRecords.CSongSelectTableEntry> songSelectTableEntries = new Dictionary<string, BestPlayRecords.CSongSelectTableEntry>(); public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysSongSelectTables = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
[JsonIgnore] [JsonIgnore]
public BestPlayRecords.CBestPlayStats bestPlaysStats = new BestPlayRecords.CBestPlayStats(); public Dictionary<string, BestPlayRecords.CSongSelectTableEntry> songSelectTableEntries = new Dictionary<string, BestPlayRecords.CSongSelectTableEntry>();
public BestPlayRecords.CSongSelectTableEntry tGetSongSelectTableEntry(string uniqueId) [JsonIgnore]
{ public BestPlayRecords.CBestPlayStats bestPlaysStats = new BestPlayRecords.CBestPlayStats();
if (songSelectTableEntries.ContainsKey(uniqueId)) return songSelectTableEntries[uniqueId];
return new BestPlayRecords.CSongSelectTableEntry(); public BestPlayRecords.CSongSelectTableEntry tGetSongSelectTableEntry(string uniqueId) {
} if (songSelectTableEntries.ContainsKey(uniqueId)) return songSelectTableEntries[uniqueId];
return new BestPlayRecords.CSongSelectTableEntry();
#region [Factorize best plays] }
public void tFactorizeBestPlays() #region [Factorize best plays]
{
bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>(); public void tFactorizeBestPlays() {
bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlays.Values)
{ foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlays.Values) {
string key = bestPlay.ChartUniqueId + bestPlay.ChartDifficulty.ToString(); string key = bestPlay.ChartUniqueId + bestPlay.ChartDifficulty.ToString();
if (!bestPlaysDistinctCharts.ContainsKey(key)) if (!bestPlaysDistinctCharts.ContainsKey(key)) {
{ bestPlaysDistinctCharts[key] = bestPlay.Copy();
bestPlaysDistinctCharts[key] = bestPlay.Copy(); } else {
} if (bestPlay.HighScore > bestPlaysDistinctCharts[key].HighScore) {
else bestPlaysDistinctCharts[key].HighScore = bestPlay.HighScore;
{ bestPlaysDistinctCharts[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
if (bestPlay.HighScore > bestPlaysDistinctCharts[key].HighScore) bestPlaysDistinctCharts[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
{ bestPlaysDistinctCharts[key].HighScoreBadCount = bestPlay.HighScoreBadCount;
bestPlaysDistinctCharts[key].HighScore = bestPlay.HighScore; bestPlaysDistinctCharts[key].HighScoreRollCount = bestPlay.HighScoreRollCount;
bestPlaysDistinctCharts[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount; bestPlaysDistinctCharts[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount;
bestPlaysDistinctCharts[key].HighScoreOkCount = bestPlay.HighScoreOkCount; bestPlaysDistinctCharts[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo;
bestPlaysDistinctCharts[key].HighScoreBadCount = bestPlay.HighScoreBadCount; bestPlaysDistinctCharts[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount;
bestPlaysDistinctCharts[key].HighScoreRollCount = bestPlay.HighScoreRollCount; }
bestPlaysDistinctCharts[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount; bestPlaysDistinctCharts[key].ScoreRank = Math.Max(bestPlaysDistinctCharts[key].ScoreRank, bestPlay.ScoreRank);
bestPlaysDistinctCharts[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo; bestPlaysDistinctCharts[key].ClearStatus = Math.Max(bestPlaysDistinctCharts[key].ClearStatus, bestPlay.ClearStatus);
bestPlaysDistinctCharts[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount; }
} }
bestPlaysDistinctCharts[key].ScoreRank = Math.Max(bestPlaysDistinctCharts[key].ScoreRank, bestPlay.ScoreRank);
bestPlaysDistinctCharts[key].ClearStatus = Math.Max(bestPlaysDistinctCharts[key].ClearStatus, bestPlay.ClearStatus); bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
} songSelectTableEntries = new Dictionary<string, BestPlayRecords.CSongSelectTableEntry>();
}
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlaysDistinctCharts.Values) {
bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>(); string key = bestPlay.ChartUniqueId;
songSelectTableEntries = new Dictionary<string, BestPlayRecords.CSongSelectTableEntry>(); if (!bestPlaysDistinctSongs.ContainsKey(key)) {
bestPlaysDistinctSongs[key] = bestPlay.Copy();
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlaysDistinctCharts.Values) } else {
{ if (bestPlay.HighScore > bestPlaysDistinctSongs[key].HighScore) {
string key = bestPlay.ChartUniqueId; bestPlaysDistinctSongs[key].HighScore = bestPlay.HighScore;
if (!bestPlaysDistinctSongs.ContainsKey(key)) bestPlaysDistinctSongs[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
{ bestPlaysDistinctSongs[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
bestPlaysDistinctSongs[key] = bestPlay.Copy(); bestPlaysDistinctSongs[key].HighScoreBadCount = bestPlay.HighScoreBadCount;
} bestPlaysDistinctSongs[key].HighScoreRollCount = bestPlay.HighScoreRollCount;
else bestPlaysDistinctSongs[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount;
{ bestPlaysDistinctSongs[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo;
if (bestPlay.HighScore > bestPlaysDistinctSongs[key].HighScore) bestPlaysDistinctSongs[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount;
{ }
bestPlaysDistinctSongs[key].HighScore = bestPlay.HighScore; bestPlaysDistinctSongs[key].ScoreRank = Math.Max(bestPlaysDistinctSongs[key].ScoreRank, bestPlay.ScoreRank);
bestPlaysDistinctSongs[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount; bestPlaysDistinctSongs[key].ClearStatus = Math.Max(bestPlaysDistinctSongs[key].ClearStatus, bestPlay.ClearStatus);
bestPlaysDistinctSongs[key].HighScoreOkCount = bestPlay.HighScoreOkCount; }
bestPlaysDistinctSongs[key].HighScoreBadCount = bestPlay.HighScoreBadCount;
bestPlaysDistinctSongs[key].HighScoreRollCount = bestPlay.HighScoreRollCount; // Entries to replace score.GPInfo on the song select menus
bestPlaysDistinctSongs[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount; if (!songSelectTableEntries.ContainsKey(key)) {
bestPlaysDistinctSongs[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo; songSelectTableEntries[key] = new BestPlayRecords.CSongSelectTableEntry();
bestPlaysDistinctSongs[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount; }
} if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ScoreRankDifficulty && bestPlay.ScoreRank >= 0) {
bestPlaysDistinctSongs[key].ScoreRank = Math.Max(bestPlaysDistinctSongs[key].ScoreRank, bestPlay.ScoreRank); songSelectTableEntries[key].ScoreRankDifficulty = (int)bestPlay.ChartDifficulty;
bestPlaysDistinctSongs[key].ClearStatus = Math.Max(bestPlaysDistinctSongs[key].ClearStatus, bestPlay.ClearStatus); songSelectTableEntries[key].ScoreRank = (int)bestPlay.ScoreRank;
} }
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ClearStatusDifficulty && bestPlay.ClearStatus >= 0) {
// Entries to replace score.GPInfo on the song select menus songSelectTableEntries[key].ClearStatusDifficulty = (int)bestPlay.ChartDifficulty;
if (!songSelectTableEntries.ContainsKey(key)) songSelectTableEntries[key].ClearStatus = (int)bestPlay.ClearStatus;
{ }
songSelectTableEntries[key] = new BestPlayRecords.CSongSelectTableEntry(); if ((int)bestPlay.ChartDifficulty == (int)Difficulty.Tower) songSelectTableEntries[key].TowerReachedFloor = (int)bestPlay.TowerBestFloor;
} songSelectTableEntries[key].HighScore[(int)bestPlay.ChartDifficulty] = (int)bestPlay.HighScore;
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ScoreRankDifficulty && bestPlay.ScoreRank >= 0) songSelectTableEntries[key].ScoreRanks[(int)bestPlay.ChartDifficulty] = (int)bestPlay.ScoreRank + 1; // 0 start
{ songSelectTableEntries[key].ClearStatuses[(int)bestPlay.ChartDifficulty] = (int)bestPlay.ClearStatus + 1; // 0 start
songSelectTableEntries[key].ScoreRankDifficulty = (int)bestPlay.ChartDifficulty; }
songSelectTableEntries[key].ScoreRank = (int)bestPlay.ScoreRank;
} bestPlaysStats = BestPlayRecords.tGenerateBestPlayStats(bestPlaysDistinctCharts.Values, bestPlaysDistinctSongs.Values);
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ClearStatusDifficulty && bestPlay.ClearStatus >= 0) }
{
songSelectTableEntries[key].ClearStatusDifficulty = (int)bestPlay.ChartDifficulty; #endregion
songSelectTableEntries[key].ClearStatus = (int)bestPlay.ClearStatus; }
}
if ((int)bestPlay.ChartDifficulty == (int)Difficulty.Tower) songSelectTableEntries[key].TowerReachedFloor = (int)bestPlay.TowerBestFloor; public Data data = new Data();
songSelectTableEntries[key].HighScore[(int)bestPlay.ChartDifficulty] = (int)bestPlay.HighScore; public string path = "Save.json";
songSelectTableEntries[key].ScoreRanks[(int)bestPlay.ChartDifficulty] = (int)bestPlay.ScoreRank + 1; // 0 start public string name = "Save";
songSelectTableEntries[key].ClearStatuses[(int)bestPlay.ChartDifficulty] = (int)bestPlay.ClearStatus + 1; // 0 start
} #region [private]
bestPlaysStats = BestPlayRecords.tGenerateBestPlayStats(bestPlaysDistinctCharts.Values, bestPlaysDistinctSongs.Values); private void tSaveFile() {
} ConfigManager.SaveConfig(data, path);
}
#endregion
} private void tLoadFile() {
data = ConfigManager.GetConfig<Data>(path);
public Data data = new Data(); }
public string path = "Save.json";
public string name = "Save"; #endregion
}
#region [private]
private void tSaveFile()
{
ConfigManager.SaveConfig(data, path);
}
private void tLoadFile()
{
data = ConfigManager.GetConfig<Data>(path);
}
#endregion
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,4 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; internal class CGimmickValue {
using System.Linq; }
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3
{
internal class CGimmickValue
{
}
} }

View File

@ -1,36 +1,26 @@
using System; using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3 namespace TJAPlayer3 {
{ [Serializable]
[Serializable] internal class CLocalizationData {
internal class CLocalizationData [JsonProperty("strings")]
{ private Dictionary<string, string> Strings = new Dictionary<string, string>();
[JsonProperty("strings")]
private Dictionary<string, string> Strings = new Dictionary<string, string>();
public CLocalizationData() public CLocalizationData() {
{ Strings = new Dictionary<string, string>();
Strings = new Dictionary<string, string>(); }
}
public string GetString(string defaultsDefault) public string GetString(string defaultsDefault) {
{ string _lang = CLangManager.fetchLang();
string _lang = CLangManager.fetchLang(); if (Strings.ContainsKey(_lang))
if (Strings.ContainsKey(_lang)) return Strings[_lang];
return Strings[_lang]; else if (Strings.ContainsKey("default"))
else if (Strings.ContainsKey("default")) return Strings["default"];
return Strings["default"]; return defaultsDefault;
return defaultsDefault; }
}
public void SetString(string langcode, string str) public void SetString(string langcode, string str) {
{ Strings[langcode] = str;
Strings[langcode] = str; }
} }
}
} }

View File

@ -1,16 +1,6 @@
using System; namespace TJAPlayer3 {
using System.Collections.Generic; class CSongReplay {
using System.Linq; /* Game version used for the replay
using System.Text;
using System.Threading.Tasks;
using System.IO;
using static SevenZip.Compression.LZMA.SevenZipHelper;
namespace TJAPlayer3
{
class CSongReplay
{
/* Game version used for the replay
* 521 = 0.5.2.1 * 521 = 0.5.2.1
* 530 = 0.5.3 * 530 = 0.5.3
* 531 = 0.5.3.1 * 531 = 0.5.3.1
@ -19,10 +9,10 @@ namespace TJAPlayer3
* 700 = 0.7.0 * 700 = 0.7.0
* 1000 = 1.0.0 * 1000 = 1.0.0
*/ */
public int STORED_GAME_VERSION = 600; public int STORED_GAME_VERSION = 600;
public string REPLAY_FOLDER_NAME = "Replay"; public string REPLAY_FOLDER_NAME = "Replay";
/* Mod Flags /* Mod Flags
* Bit Offsets (Values) : * Bit Offsets (Values) :
* - 0 (1) : Mirror * - 0 (1) : Mirror
* - 1 (2) : Random (Kimagure) * - 1 (2) : Random (Kimagure)
@ -34,292 +24,262 @@ namespace TJAPlayer3
* - 7 (128) : Just (Ok => Bad) * - 7 (128) : Just (Ok => Bad)
* - 8 (256) : Safe (Bad => Ok) * - 8 (256) : Safe (Bad => Ok)
*/ */
[Flags] [Flags]
public enum EModFlag public enum EModFlag {
{ None = 0,
None = 0, Mirror = 1 << 0,
Mirror = 1 << 0, Random = 1 << 1,
Random = 1 << 1, SuperRandom = 1 << 2,
SuperRandom = 1 << 2, Invisible = 1 << 3,
Invisible = 1 << 3, PerfectMemory = 1 << 4,
PerfectMemory = 1 << 4, Avalanche = 1 << 5,
Avalanche = 1 << 5, Minesweeper = 1 << 6,
Minesweeper = 1 << 6, Just = 1 << 7,
Just = 1 << 7, Safe = 1 << 8
Safe = 1 << 8 }
}
public CSongReplay() public CSongReplay() {
{ replayFolder = "";
replayFolder = ""; storedPlayer = 0;
storedPlayer = 0; }
}
public CSongReplay(string ChartPath, int player) public CSongReplay(string ChartPath, int player) {
{ string _chartFolder = Path.GetDirectoryName(ChartPath);
string _chartFolder = Path.GetDirectoryName(ChartPath); replayFolder = Path.Combine(_chartFolder, REPLAY_FOLDER_NAME);
replayFolder = Path.Combine(_chartFolder, REPLAY_FOLDER_NAME);
try try {
{ Directory.CreateDirectory(replayFolder);
Directory.CreateDirectory(replayFolder);
Console.WriteLine("Folder Path: " + replayFolder); Console.WriteLine("Folder Path: " + replayFolder);
} } catch (Exception ex) {
catch (Exception ex) Console.WriteLine("An error occurred: " + ex.Message);
{ }
Console.WriteLine("An error occurred: " + ex.Message);
}
storedPlayer = player; storedPlayer = player;
} }
public void tRegisterInput(double timestamp, byte keypress) public void tRegisterInput(double timestamp, byte keypress) {
{ allInputs.Add(Tuple.Create(timestamp, keypress));
allInputs.Add(Tuple.Create(timestamp, keypress)); }
}
#region [Dan methods] #region [Dan methods]
public void tDanRegisterSongCount(int songCount)
{
DanSongCount = songCount;
IndividualGoodCount = new int[songCount];
IndividualOkCount = new int[songCount];
IndividualBadCount = new int[songCount];
IndividualRollCount = new int[songCount];
IndividualMaxCombo = new int[songCount];
IndividualBoomCount = new int[songCount];
IndividualADLibCount = new int[songCount];
IndividualScore = new int[songCount];
}
public void tDanInputSongResults(int songNo) public void tDanRegisterSongCount(int songCount) {
{ DanSongCount = songCount;
if (songNo >= DanSongCount) return; IndividualGoodCount = new int[songCount];
if (songNo < 0) return; IndividualOkCount = new int[songCount];
IndividualGoodCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n良[songNo]; IndividualBadCount = new int[songCount];
IndividualOkCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n可[songNo]; IndividualRollCount = new int[songCount];
IndividualBadCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n不可[songNo]; IndividualMaxCombo = new int[songCount];
IndividualRollCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n連打[songNo]; IndividualBoomCount = new int[songCount];
IndividualMaxCombo[songNo] = TJAPlayer3.stage演奏ドラム画面.nHighestCombo[songNo]; IndividualADLibCount = new int[songCount];
IndividualBoomCount[songNo] = TJAPlayer3.stage演奏ドラム画面.nMine[songNo]; IndividualScore = new int[songCount];
IndividualADLibCount[songNo] = TJAPlayer3.stage演奏ドラム画面.nADLIB[songNo]; }
danAccumulatedScore = 0;
for (int acc = 0; acc < songNo; acc++) danAccumulatedScore += IndividualScore[acc];
IndividualScore[songNo] = (int)TJAPlayer3.stage演奏ドラム画面.actScore.GetScore(0) - danAccumulatedScore;
}
#endregion public void tDanInputSongResults(int songNo) {
if (songNo >= DanSongCount) return;
if (songNo < 0) return;
IndividualGoodCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n良[songNo];
IndividualOkCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n可[songNo];
IndividualBadCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n不可[songNo];
IndividualRollCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n連打[songNo];
IndividualMaxCombo[songNo] = TJAPlayer3.stage演奏ドラム画面.nHighestCombo[songNo];
IndividualBoomCount[songNo] = TJAPlayer3.stage演奏ドラム画面.nMine[songNo];
IndividualADLibCount[songNo] = TJAPlayer3.stage演奏ドラム画面.nADLIB[songNo];
danAccumulatedScore = 0;
for (int acc = 0; acc < songNo; acc++) danAccumulatedScore += IndividualScore[acc];
IndividualScore[songNo] = (int)TJAPlayer3.stage演奏ドラム画面.actScore.GetScore(0) - danAccumulatedScore;
}
#region [Load methods] #endregion
private List<Tuple<double, byte>> ConvertByteArrayToTupleList(byte[] byteArray) #region [Load methods]
{
List<Tuple<double, byte>> tupleList = new List<Tuple<double, byte>>();
for (int i = 0; i < byteArray.Length; i += sizeof(double) + sizeof(byte)) private List<Tuple<double, byte>> ConvertByteArrayToTupleList(byte[] byteArray) {
{ List<Tuple<double, byte>> tupleList = new List<Tuple<double, byte>>();
double doubleValue = BitConverter.ToDouble(byteArray, i);
byte byteValue = byteArray[i + sizeof(double)];
tupleList.Add(Tuple.Create(doubleValue, byteValue));
}
return tupleList; for (int i = 0; i < byteArray.Length; i += sizeof(double) + sizeof(byte)) {
} double doubleValue = BitConverter.ToDouble(byteArray, i);
byte byteValue = byteArray[i + sizeof(double)];
tupleList.Add(Tuple.Create(doubleValue, byteValue));
}
public void tLoadReplayFile(string optkrFilePath) return tupleList;
{ }
try
{
using (FileStream fileStream = new FileStream(optkrFilePath, FileMode.Open))
{
using (BinaryReader reader = new BinaryReader(fileStream))
{
GameMode = reader.ReadByte();
GameVersion = reader.ReadInt32();
ChartChecksum = reader.ReadString();
PlayerName = reader.ReadString();
GoodCount = reader.ReadInt32();
OkCount = reader.ReadInt32();
BadCount = reader.ReadInt32();
RollCount = reader.ReadInt32();
MaxCombo = reader.ReadInt32();
BoomCount = reader.ReadInt32();
ADLibCount = reader.ReadInt32();
Score = reader.ReadInt32();
CoinValue = reader.ReadInt16();
ReachedFloor = reader.ReadInt32();
RemainingLives = reader.ReadInt32();
DanSongCount = reader.ReadInt32();
for (int i = 0; i < DanSongCount; i++)
{
IndividualGoodCount[i] = reader.ReadInt32();
IndividualOkCount[i] = reader.ReadInt32();
IndividualBadCount[i] = reader.ReadInt32();
IndividualRollCount[i] = reader.ReadInt32();
IndividualMaxCombo[i] = reader.ReadInt32();
IndividualBoomCount[i] = reader.ReadInt32();
IndividualADLibCount[i] = reader.ReadInt32();
IndividualScore[i] = reader.ReadInt32();
}
ClearStatus = reader.ReadByte();
ScoreRank = reader.ReadByte();
ScrollSpeedValue = reader.ReadInt32();
SongSpeedValue = reader.ReadInt32();
JudgeStrictnessAdjust = reader.ReadInt32();
ModFlags = reader.ReadInt32();
GaugeType = reader.ReadByte();
GaugeFill = reader.ReadSingle();
Timestamp = reader.ReadInt64();
CompressedInputsSize = reader.ReadInt32();
CompressedInputs = reader.ReadBytes(CompressedInputsSize);
var uncomp = SevenZip.Compression.LZMA.SevenZipHelper.Decompress(CompressedInputs);
allInputs = ConvertByteArrayToTupleList(uncomp);
ChartUniqueID = reader.ReadString();
ChartDifficulty = reader.ReadByte();
ChartLevel = reader.ReadByte();
OnlineScoreID = reader.ReadInt64();
}
}
}
catch (Exception ex)
{
} public void tLoadReplayFile(string optkrFilePath) {
} try {
using (FileStream fileStream = new FileStream(optkrFilePath, FileMode.Open)) {
using (BinaryReader reader = new BinaryReader(fileStream)) {
GameMode = reader.ReadByte();
GameVersion = reader.ReadInt32();
ChartChecksum = reader.ReadString();
PlayerName = reader.ReadString();
GoodCount = reader.ReadInt32();
OkCount = reader.ReadInt32();
BadCount = reader.ReadInt32();
RollCount = reader.ReadInt32();
MaxCombo = reader.ReadInt32();
BoomCount = reader.ReadInt32();
ADLibCount = reader.ReadInt32();
Score = reader.ReadInt32();
CoinValue = reader.ReadInt16();
ReachedFloor = reader.ReadInt32();
RemainingLives = reader.ReadInt32();
DanSongCount = reader.ReadInt32();
for (int i = 0; i < DanSongCount; i++) {
IndividualGoodCount[i] = reader.ReadInt32();
IndividualOkCount[i] = reader.ReadInt32();
IndividualBadCount[i] = reader.ReadInt32();
IndividualRollCount[i] = reader.ReadInt32();
IndividualMaxCombo[i] = reader.ReadInt32();
IndividualBoomCount[i] = reader.ReadInt32();
IndividualADLibCount[i] = reader.ReadInt32();
IndividualScore[i] = reader.ReadInt32();
}
ClearStatus = reader.ReadByte();
ScoreRank = reader.ReadByte();
ScrollSpeedValue = reader.ReadInt32();
SongSpeedValue = reader.ReadInt32();
JudgeStrictnessAdjust = reader.ReadInt32();
ModFlags = reader.ReadInt32();
GaugeType = reader.ReadByte();
GaugeFill = reader.ReadSingle();
Timestamp = reader.ReadInt64();
CompressedInputsSize = reader.ReadInt32();
CompressedInputs = reader.ReadBytes(CompressedInputsSize);
var uncomp = SevenZip.Compression.LZMA.SevenZipHelper.Decompress(CompressedInputs);
allInputs = ConvertByteArrayToTupleList(uncomp);
ChartUniqueID = reader.ReadString();
ChartDifficulty = reader.ReadByte();
ChartLevel = reader.ReadByte();
OnlineScoreID = reader.ReadInt64();
}
}
} catch (Exception ex) {
#endregion }
}
#region [Save methods] #endregion
private byte[] ConvertTupleListToByteArray(List<Tuple<double, byte>> tupleList) #region [Save methods]
{
List<byte> byteArray = new List<byte>();
foreach (var tuple in tupleList) private byte[] ConvertTupleListToByteArray(List<Tuple<double, byte>> tupleList) {
{ List<byte> byteArray = new List<byte>();
byte[] doubleBytes = BitConverter.GetBytes(tuple.Item1);
byteArray.AddRange(doubleBytes);
byteArray.Add(tuple.Item2);
}
return byteArray.ToArray(); foreach (var tuple in tupleList) {
} byte[] doubleBytes = BitConverter.GetBytes(tuple.Item1);
byteArray.AddRange(doubleBytes);
byteArray.Add(tuple.Item2);
}
public void tSaveReplayFile() return byteArray.ToArray();
{ }
string _path = replayFolder + @"/Replay_" + ChartUniqueID + @"_" + PlayerName + @"_" + Timestamp.ToString() + @".optkr";
try public void tSaveReplayFile() {
{ string _path = replayFolder + @"/Replay_" + ChartUniqueID + @"_" + PlayerName + @"_" + Timestamp.ToString() + @".optkr";
using (FileStream fileStream = new FileStream(_path, FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
writer.Write(GameMode);
writer.Write(GameVersion);
writer.Write(ChartChecksum);
writer.Write(PlayerName);
writer.Write(GoodCount);
writer.Write(OkCount);
writer.Write(BadCount);
writer.Write(RollCount);
writer.Write(MaxCombo);
writer.Write(BoomCount);
writer.Write(ADLibCount);
writer.Write(Score);
writer.Write(CoinValue);
writer.Write(ReachedFloor);
writer.Write(RemainingLives);
writer.Write(DanSongCount);
for (int i = 0; i < DanSongCount; i++)
{
writer.Write(IndividualGoodCount[i]);
writer.Write(IndividualOkCount[i]);
writer.Write(IndividualBadCount[i]);
writer.Write(IndividualRollCount[i]);
writer.Write(IndividualMaxCombo[i]);
writer.Write(IndividualBoomCount[i]);
writer.Write(IndividualADLibCount[i]);
writer.Write(IndividualScore[i]);
}
writer.Write(ClearStatus);
writer.Write(ScoreRank);
writer.Write(ScrollSpeedValue);
writer.Write(SongSpeedValue);
writer.Write(JudgeStrictnessAdjust);
writer.Write(ModFlags);
writer.Write(GaugeType);
writer.Write(GaugeFill);
writer.Write(Timestamp);
writer.Write(CompressedInputsSize);
writer.Write(CompressedInputs);
writer.Write(ChartUniqueID);
writer.Write(ChartDifficulty);
writer.Write(ChartLevel);
writer.Write(OnlineScoreID);
}
}
}
catch (Exception ex)
{
} try {
} using (FileStream fileStream = new FileStream(_path, FileMode.Create)) {
using (BinaryWriter writer = new BinaryWriter(fileStream)) {
writer.Write(GameMode);
writer.Write(GameVersion);
writer.Write(ChartChecksum);
writer.Write(PlayerName);
writer.Write(GoodCount);
writer.Write(OkCount);
writer.Write(BadCount);
writer.Write(RollCount);
writer.Write(MaxCombo);
writer.Write(BoomCount);
writer.Write(ADLibCount);
writer.Write(Score);
writer.Write(CoinValue);
writer.Write(ReachedFloor);
writer.Write(RemainingLives);
writer.Write(DanSongCount);
for (int i = 0; i < DanSongCount; i++) {
writer.Write(IndividualGoodCount[i]);
writer.Write(IndividualOkCount[i]);
writer.Write(IndividualBadCount[i]);
writer.Write(IndividualRollCount[i]);
writer.Write(IndividualMaxCombo[i]);
writer.Write(IndividualBoomCount[i]);
writer.Write(IndividualADLibCount[i]);
writer.Write(IndividualScore[i]);
}
writer.Write(ClearStatus);
writer.Write(ScoreRank);
writer.Write(ScrollSpeedValue);
writer.Write(SongSpeedValue);
writer.Write(JudgeStrictnessAdjust);
writer.Write(ModFlags);
writer.Write(GaugeType);
writer.Write(GaugeFill);
writer.Write(Timestamp);
writer.Write(CompressedInputsSize);
writer.Write(CompressedInputs);
writer.Write(ChartUniqueID);
writer.Write(ChartDifficulty);
writer.Write(ChartLevel);
writer.Write(OnlineScoreID);
}
}
} catch (Exception ex) {
public void tResultsRegisterReplayInformations(int Coins, int Clear, int SRank) }
{ }
// Actual player (Used for saved informations)
int actualPlayer = TJAPlayer3.GetActualPlayer(storedPlayer);
// Game mode public void tResultsRegisterReplayInformations(int Coins, int Clear, int SRank) {
switch (TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[0]) // Actual player (Used for saved informations)
{ int actualPlayer = TJAPlayer3.GetActualPlayer(storedPlayer);
case (int)Difficulty.Dan:
GameMode = 1;
break;
case (int)Difficulty.Tower:
GameMode = 2;
break;
default:
GameMode = 0;
break;
}
// Game version
GameVersion = STORED_GAME_VERSION;
// Chart Checksum (temporary)
ChartChecksum = "";
// Player Name
PlayerName = TJAPlayer3.SaveFileInstances[actualPlayer].data.Name;
// Performance informations
GoodCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nGreat;
OkCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nGood;
BadCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nMiss;
RollCount = TJAPlayer3.stage演奏ドラム画面.GetRoll(storedPlayer);
MaxCombo = TJAPlayer3.stage演奏ドラム画面.actCombo.n現在のコンボ数.[storedPlayer];
BoomCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nMine;
ADLibCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nADLIB;
Score = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nScore;
CoinValue = (short)Coins;
// Tower parameters
if (GameMode == 2)
{
ReachedFloor = CFloorManagement.LastRegisteredFloor;
RemainingLives = CFloorManagement.CurrentNumberOfLives;
}
// Clear status
ClearStatus = (byte)Clear;
// Score rank
ScoreRank = (byte)SRank;
// Scroll speed value (as on ConfigIni, 9 is x1)
ScrollSpeedValue = TJAPlayer3.ConfigIni.nScrollSpeed[actualPlayer];
// Song speed value (as on ConfigIni, 20 is x1)
SongSpeedValue = TJAPlayer3.ConfigIni.nSongSpeed;
// Just strictess adjust mod value (as on ConfigIni, between -2 for lenient and 2 for rigorous)
JudgeStrictnessAdjust = TJAPlayer3.ConfigIni.nTimingZones[actualPlayer];
/* Mod Flags // Game mode
switch (TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[0]) {
case (int)Difficulty.Dan:
GameMode = 1;
break;
case (int)Difficulty.Tower:
GameMode = 2;
break;
default:
GameMode = 0;
break;
}
// Game version
GameVersion = STORED_GAME_VERSION;
// Chart Checksum (temporary)
ChartChecksum = "";
// Player Name
PlayerName = TJAPlayer3.SaveFileInstances[actualPlayer].data.Name;
// Performance informations
GoodCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nGreat;
OkCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nGood;
BadCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nMiss;
RollCount = TJAPlayer3.stage演奏ドラム画面.GetRoll(storedPlayer);
MaxCombo = TJAPlayer3.stage演奏ドラム画面.actCombo.n現在のコンボ数.[storedPlayer];
BoomCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nMine;
ADLibCount = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nADLIB;
Score = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nScore;
CoinValue = (short)Coins;
// Tower parameters
if (GameMode == 2) {
ReachedFloor = CFloorManagement.LastRegisteredFloor;
RemainingLives = CFloorManagement.CurrentNumberOfLives;
}
// Clear status
ClearStatus = (byte)Clear;
// Score rank
ScoreRank = (byte)SRank;
// Scroll speed value (as on ConfigIni, 9 is x1)
ScrollSpeedValue = TJAPlayer3.ConfigIni.nScrollSpeed[actualPlayer];
// Song speed value (as on ConfigIni, 20 is x1)
SongSpeedValue = TJAPlayer3.ConfigIni.nSongSpeed;
// Just strictess adjust mod value (as on ConfigIni, between -2 for lenient and 2 for rigorous)
JudgeStrictnessAdjust = TJAPlayer3.ConfigIni.nTimingZones[actualPlayer];
/* Mod Flags
* Bit Offsets (Values) : * Bit Offsets (Values) :
* - 0 (1) : Mirror * - 0 (1) : Mirror
* - 1 (2) : Random (Kimagure) * - 1 (2) : Random (Kimagure)
@ -331,72 +291,72 @@ namespace TJAPlayer3
* - 7 (128) : Just (Ok => Bad) * - 7 (128) : Just (Ok => Bad)
* - 8 (256) : Safe (Bad => Ok) * - 8 (256) : Safe (Bad => Ok)
*/ */
ModFlags = (int)EModFlag.None; ModFlags = (int)EModFlag.None;
if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.MIRROR) ModFlags |= (int)EModFlag.Mirror; if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.MIRROR) ModFlags |= (int)EModFlag.Mirror;
if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.RANDOM) ModFlags |= (int)EModFlag.Random; if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.RANDOM) ModFlags |= (int)EModFlag.Random;
if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.SUPERRANDOM) ModFlags |= (int)EModFlag.SuperRandom; if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.SUPERRANDOM) ModFlags |= (int)EModFlag.SuperRandom;
if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.MIRRORRANDOM) ModFlags |= ((int)EModFlag.Random | (int)EModFlag.Mirror); if (TJAPlayer3.ConfigIni.eRandom[actualPlayer] == ERandomMode.MIRRORRANDOM) ModFlags |= ((int)EModFlag.Random | (int)EModFlag.Mirror);
if (TJAPlayer3.ConfigIni.eSTEALTH[actualPlayer] == EStealthMode.DORON) ModFlags |= (int)EModFlag.Invisible; if (TJAPlayer3.ConfigIni.eSTEALTH[actualPlayer] == EStealthMode.DORON) ModFlags |= (int)EModFlag.Invisible;
if (TJAPlayer3.ConfigIni.eSTEALTH[actualPlayer] == EStealthMode.STEALTH) ModFlags |= (int)EModFlag.PerfectMemory; if (TJAPlayer3.ConfigIni.eSTEALTH[actualPlayer] == EStealthMode.STEALTH) ModFlags |= (int)EModFlag.PerfectMemory;
if (TJAPlayer3.ConfigIni.nFunMods[actualPlayer] == EFunMods.AVALANCHE) ModFlags |= (int)EModFlag.Avalanche; if (TJAPlayer3.ConfigIni.nFunMods[actualPlayer] == EFunMods.AVALANCHE) ModFlags |= (int)EModFlag.Avalanche;
if (TJAPlayer3.ConfigIni.nFunMods[actualPlayer] == EFunMods.MINESWEEPER) ModFlags |= (int)EModFlag.Minesweeper; if (TJAPlayer3.ConfigIni.nFunMods[actualPlayer] == EFunMods.MINESWEEPER) ModFlags |= (int)EModFlag.Minesweeper;
if (TJAPlayer3.ConfigIni.bJust[actualPlayer] == 1) ModFlags |= (int)EModFlag.Just; if (TJAPlayer3.ConfigIni.bJust[actualPlayer] == 1) ModFlags |= (int)EModFlag.Just;
if (TJAPlayer3.ConfigIni.bJust[actualPlayer] == 2) ModFlags |= (int)EModFlag.Safe; if (TJAPlayer3.ConfigIni.bJust[actualPlayer] == 2) ModFlags |= (int)EModFlag.Safe;
/* Gauge type /* Gauge type
* - 0 : Normal * - 0 : Normal
* - 1 : Hard * - 1 : Hard
* - 2 : Extreme * - 2 : Extreme
*/ */
var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[actualPlayer].data.Character]; var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[actualPlayer].data.Character];
GaugeType = (byte)HGaugeMethods.tGetGaugeTypeEnum(chara.effect.tGetGaugeType()); GaugeType = (byte)HGaugeMethods.tGetGaugeTypeEnum(chara.effect.tGetGaugeType());
// Gauge fill value // Gauge fill value
GaugeFill = (float)TJAPlayer3.stage演奏ドラム画面.actGauge.db現在のゲージ値[storedPlayer]; GaugeFill = (float)TJAPlayer3.stage演奏ドラム画面.actGauge.db現在のゲージ値[storedPlayer];
// Generation timestamp (in ticks) // Generation timestamp (in ticks)
Timestamp = DateTime.Now.Ticks; Timestamp = DateTime.Now.Ticks;
// Compressed inputs and size // Compressed inputs and size
byte[] barr = ConvertTupleListToByteArray(allInputs); byte[] barr = ConvertTupleListToByteArray(allInputs);
CompressedInputs = SevenZip.Compression.LZMA.SevenZipHelper.Compress(barr); CompressedInputs = SevenZip.Compression.LZMA.SevenZipHelper.Compress(barr);
CompressedInputsSize = CompressedInputs.Length; CompressedInputsSize = CompressedInputs.Length;
// Chart metadata // Chart metadata
ChartUniqueID = TJAPlayer3.stageSongSelect.rChoosenSong.uniqueId.data.id; ChartUniqueID = TJAPlayer3.stageSongSelect.rChoosenSong.uniqueId.data.id;
ChartDifficulty = (byte)TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[storedPlayer]; ChartDifficulty = (byte)TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[storedPlayer];
ChartLevel = (byte)Math.Min(255, TJAPlayer3.stageSongSelect.rChoosenSong.arスコア[ChartDifficulty]..nレベル[ChartDifficulty]); ChartLevel = (byte)Math.Min(255, TJAPlayer3.stageSongSelect.rChoosenSong.arスコア[ChartDifficulty]..nレベル[ChartDifficulty]);
// Online score ID used for online leaderboards linking, given by the server (Defaulted to 0 for now) // Online score ID used for online leaderboards linking, given by the server (Defaulted to 0 for now)
OnlineScoreID = 0; OnlineScoreID = 0;
// Replay Checksum (Calculate at the end) // Replay Checksum (Calculate at the end)
ReplayChecksum = ""; ReplayChecksum = "";
} }
#endregion #endregion
#region [Helper variables] #region [Helper variables]
private string chartPath; private string chartPath;
private string replayFolder; private string replayFolder;
private int storedPlayer; private int storedPlayer;
private int danAccumulatedScore = 0; private int danAccumulatedScore = 0;
private List<Tuple<double, byte>> allInputs = new List<Tuple<double, byte>>(); private List<Tuple<double, byte>> allInputs = new List<Tuple<double, byte>>();
#endregion #endregion
#region [Replay file variables] #region [Replay file variables]
/* Game mode of the replay /* Game mode of the replay
* 0 = Regular * 0 = Regular
* 1 = Dan * 1 = Dan
* 2 = Tower * 2 = Tower
*/ */
public byte GameMode = 0; public byte GameMode = 0;
// Game version used for the replay // Game version used for the replay
public int GameVersion; public int GameVersion;
// MD5 checksum of the chart // MD5 checksum of the chart
public string ChartChecksum; public string ChartChecksum;
// Player name // Player name
public string PlayerName; public string PlayerName;
// Replay hash // Replay hash
public string ReplayChecksum; public string ReplayChecksum;
/* Performance informations /* Performance informations
* - Good count (Int) * - Good count (Int)
* - Ok count (Int) * - Ok count (Int)
* - Bad count (Int) * - Bad count (Int)
@ -407,32 +367,32 @@ namespace TJAPlayer3
* - Score (Int) * - Score (Int)
* - Coin value of the play (Short) * - Coin value of the play (Short)
*/ */
public int GoodCount; public int GoodCount;
public int OkCount; public int OkCount;
public int BadCount; public int BadCount;
public int RollCount; public int RollCount;
public int MaxCombo; public int MaxCombo;
public int BoomCount; public int BoomCount;
public int ADLibCount; public int ADLibCount;
public int Score; public int Score;
public short CoinValue; public short CoinValue;
/* Performance informations (Tower only) /* Performance informations (Tower only)
* - Reached floor (Int) * - Reached floor (Int)
* - Remaining lives (Int) * - Remaining lives (Int)
*/ */
public int ReachedFloor = 0; public int ReachedFloor = 0;
public int RemainingLives = 0; public int RemainingLives = 0;
// Individual performance informations (Dan only) // Individual performance informations (Dan only)
public int DanSongCount = 0; public int DanSongCount = 0;
public int[] IndividualGoodCount; public int[] IndividualGoodCount;
public int[] IndividualOkCount; public int[] IndividualOkCount;
public int[] IndividualBadCount; public int[] IndividualBadCount;
public int[] IndividualRollCount; public int[] IndividualRollCount;
public int[] IndividualMaxCombo; public int[] IndividualMaxCombo;
public int[] IndividualBoomCount; public int[] IndividualBoomCount;
public int[] IndividualADLibCount; public int[] IndividualADLibCount;
public int[] IndividualScore; public int[] IndividualScore;
/* Clear status /* Clear status
* - Regular : * - Regular :
* > 0 : Failed (None) * > 0 : Failed (None)
* > 1 : Assisted clear (Bronze) * > 1 : Assisted clear (Bronze)
@ -460,8 +420,8 @@ namespace TJAPlayer3
* > 7 : Red perfect - Dan title * > 7 : Red perfect - Dan title
* > 8 : Gold perfect - Dan title * > 8 : Gold perfect - Dan title
*/ */
public byte ClearStatus; public byte ClearStatus;
/* Score Rank (Regular only) /* Score Rank (Regular only)
* - 0 : F (Under 500k, Press F for respects) * - 0 : F (Under 500k, Press F for respects)
* - 1 : E (500k ~ Under 600k, Ew...) * - 1 : E (500k ~ Under 600k, Ew...)
* - 2 : D (600k ~ Under 700k, Disappointing) * - 2 : D (600k ~ Under 700k, Disappointing)
@ -471,14 +431,14 @@ namespace TJAPlayer3
* - 6 : S (950k and more, Splendiferous!!) * - 6 : S (950k and more, Splendiferous!!)
* - 7 : Ω ((Around) 1M and more, Ωut-of-this-world!!!) * - 7 : Ω ((Around) 1M and more, Ωut-of-this-world!!!)
*/ */
public byte ScoreRank; public byte ScoreRank;
// Scroll speed value (as on ConfigIni, 9 is x1) // Scroll speed value (as on ConfigIni, 9 is x1)
public int ScrollSpeedValue; public int ScrollSpeedValue;
// Song speed value (as on ConfigIni, 20 is x1) // Song speed value (as on ConfigIni, 20 is x1)
public int SongSpeedValue; public int SongSpeedValue;
// Just strictess adjust mod value (as on ConfigIni, between -2 for lenient and 2 for rigorous) // Just strictess adjust mod value (as on ConfigIni, between -2 for lenient and 2 for rigorous)
public int JudgeStrictnessAdjust; public int JudgeStrictnessAdjust;
/* Mod Flags /* Mod Flags
* Bit Offsets (Values) : * Bit Offsets (Values) :
* - 0 (1) : Mirror * - 0 (1) : Mirror
* - 1 (2) : Random (Kimagure) * - 1 (2) : Random (Kimagure)
@ -490,32 +450,32 @@ namespace TJAPlayer3
* - 7 (128) : Just (Ok => Bad) * - 7 (128) : Just (Ok => Bad)
* - 8 (256) : Safe (Bad => Ok) * - 8 (256) : Safe (Bad => Ok)
*/ */
public int ModFlags; public int ModFlags;
/* Gauge type /* Gauge type
* - 0 : Normal * - 0 : Normal
* - 1 : Hard * - 1 : Hard
* - 2 : Extreme * - 2 : Extreme
*/ */
public byte GaugeType; public byte GaugeType;
// Gauge fill value // Gauge fill value
public float GaugeFill; public float GaugeFill;
// Generation timestamp (in ticks) // Generation timestamp (in ticks)
public long Timestamp; public long Timestamp;
// Size in bytes of the compressed inputs (replay data) array // Size in bytes of the compressed inputs (replay data) array
public int CompressedInputsSize; public int CompressedInputsSize;
// Compressed inputs (replay data) // Compressed inputs (replay data)
public byte[] CompressedInputs; public byte[] CompressedInputs;
/* Chart metadata /* Chart metadata
* - Chart unique ID : String * - Chart unique ID : String
* - Chart difficulty : Byte (Between 0 and 6) * - Chart difficulty : Byte (Between 0 and 6)
* - Chart level : Byte (Rounded to 255, usually between 0 and 13) * - Chart level : Byte (Rounded to 255, usually between 0 and 13)
*/ */
public string ChartUniqueID; public string ChartUniqueID;
public byte ChartDifficulty; public byte ChartDifficulty;
public byte ChartLevel; public byte ChartLevel;
// Online score ID used for online leaderboards linking, given by the server // Online score ID used for online leaderboards linking, given by the server
public long OnlineScoreID; public long OnlineScoreID;
#endregion #endregion
} }
} }

Some files were not shown because too many files have changed in this diff Show More