1
0
mirror of synced 2024-11-27 17:00:50 +01:00

First commit

This commit is contained in:
0aubsq 2021-09-21 00:16:38 +02:00
parent 26997a387e
commit 1035db6506
332 changed files with 183853 additions and 0 deletions

389
Config.ini Normal file
View File

@ -0,0 +1,389 @@
;-------------------
[System]
; リリースバージョン
; Release Version.
Version=1.5.7
; 譜面ファイルが格納されているフォルダへのパス。
; セミコロン(;)で区切ることにより複数のパスを指定できます。(例: d:\tja\;e:\tja2\
; Pathes for TJA data.
; You can specify many pathes separated with semicolon(;). (e.g. d:\tja\;e:\tja2\)
TJAPath=.\
; 使用するSkinのフォルダ名。
; 例えば System\Default\Graphics\... などの場合は、SkinPath=.\Default\ を指定します。
; Skin folder path.
; e.g. System\Default\Graphics\... -> Set SkinPath=.\Default\
SkinPath=SimpleStyle\
; 事前画像描画機能を使うかどうか。(0: OFF, 1: ON)
; Use pre-textures render.
FastRender=1
; 画面モード(0:ウィンドウ, 1:全画面)
; Screen mode. (0:Window, 1:Fullscreen)
FullScreen=0
; ウインドウモード時の画面幅
; A width size in the window mode.
WindowWidth=1280
; ウインドウモード時の画面高さ
; A height size in the window mode.
WindowHeight=720
; ウィンドウモード時の位置X
; X position in the window mode.
WindowX=310
; ウィンドウモード時の位置Y
; Y position in the window mode.
WindowY=152
; ウインドウをダブルクリックした時にフルスクリーンに移行するか(0:移行しない,1:移行する)
; Whether double click to go full screen mode or not.(0:No, 1:Yes)
DoubleClickFullScreen=1
; ALT+SPACEのメニュー表示を抑制するかどうか(0:抑制する 1:抑制しない)
; Whether ALT+SPACE menu would be masked or not.(0=masked 1=not masked)
EnableSystemMenu=1
; 非フォーカス時のsleep値[ms]
; A sleep time[ms] while the window is inactive.
BackSleep=1
; フォントレンダリングに使用するフォント名
; Font name used for font rendering.
FontName=FOT-大江戸勘亭流 Std E
; 垂直帰線同期(0:OFF,1:ON)
VSyncWait=1
; フレーム毎のsleep値[ms] (-1でスリープ無し, 0以上で毎フレームスリープ。動画キャプチャ等で活用下さい)
; A sleep time[ms] per frame.
SleepTimePerFrame=-1
; サウンド出力方式(0=ACM(って今はまだDirectSoundですが), 1=ASIO, 2=WASAPI)
; WASAPIはVista以降のOSで使用可能。推奨方式はWASAPI。
; なお、WASAPIが使用不可ならASIOを、ASIOが使用不可ならACMを使用します。
; Sound device type(0=ACM, 1=ASIO, 2=WASAPI)
; WASAPI can use on Vista or later OSs.
; If WASAPI is not available, DTXMania try to use ASIO. If ASIO can't be used, ACM is used.
SoundDeviceType=2
; WASAPI使用時のサウンドバッファサイズ
; (0=デバイスに設定されている値を使用, 19999=バッファサイズ(単位:ms)の手動指定
; WASAPI Sound Buffer Size.
; (0=Use system default buffer size, 1-9999=specify the buffer size(ms) by yourself)
WASAPIBufferSizeMs=50
; ASIO使用時のサウンドデバイス
; 存在しないデバイスを指定すると、DTXManiaが起動しないことがあります。
; Sound device used by ASIO.
; Don't specify unconnected device, as the DTXMania may not bootup.
; 0: None
ASIODevice=0
; WASAPI/ASIO時に使用する演奏タイマーの種類
; Playback timer used for WASAPI/ASIO
; (0=FDK Timer, 1=System Timer)
SoundTimerType=0
; 背景画像の半透明割合(0:透明255:不透明)
; Transparency for background image in playing screen.(0:tranaparent - 255:no transparent)
BGAlpha=100
; ゲージゼロでSTAGE FAILED (0:OFF, 1:ON)
StageFailed=1
; AVIの表示(0:OFF, 1:ON)
AVI=0
; BGAの表示(0:OFF, 1:ON)
BGA=1
; 動画表示モード( 0:表示しない, 1:背景のみ, 2:窓表示のみ, 3:両方)
ClipDispType=1
; 曲選択からプレビュー音の再生までのウェイト[ms]
PreviewSoundWait=1000
; 曲選択からプレビュー画像表示までのウェイト[ms]
PreviewImageWait=100
; BGM の再生(0:OFF, 1:ON)
BGMSound=1
; 演奏記録(~.score.iniの出力 (0:OFF, 1:ON)
SaveScoreIni=1
; 最小表示コンボ数
MinComboDrums=10
; RANDOM SELECT で子BOXを検索対象に含める (0:OFF, 1:ON)
RandomFromSubBox=1
; 演奏情報を表示する (0:OFF, 1:ON)
; Showing playing info on the playing screen. (0:OFF, 1:ON)
ShowDebugStatus=0
; BS1770GAIN によるラウドネスメータの測量を適用する (0:OFF, 1:ON)
; Apply BS1770GAIN loudness metadata (0:OFF, 1:ON)
ApplyLoudnessMetadata=1
; BS1770GAIN によるラウドネスメータの目標値 (0). (-100-10)
; Loudness Target in dB (decibels) relative to full scale (0). (-100-10)
TargetLoudness=-7.4
; .tjaファイルのSONGVOLヘッダを音源の音量に適用する (0:OFF, 1:ON)
; Apply SONGVOL (0:OFF, 1:ON)
ApplySongVol=0
; 効果音の音量 (0-100%)
; Sound effect level (0-100%)
SoundEffectLevel=100
; 各ボイス、コンボボイスの音量 (0-100%)
; Voice level (0-100%)
VoiceLevel=90
; 選曲画面のプレビュー時の音量 (0-100%)
; Song preview level (0-100%)
SongPreviewLevel=80
; ゲーム中の音源の音量 (0-100%)
; Song playback level (0-100%)
SongPlaybackLevel=100
; キーボードによる音量変更の増加量、減少量 (1-20)
; Keyboard sound level increment (1-20)
KeyboardSoundLevelIncrement=5
; 2P演奏時に叩いた音を左右別々にならすか (0:OFF, 1:ON)
; Use panning for SE (0:OFF, 1:ON)
UsePanning=1
; 音源再生前の空白時間 (ms)
; Blank time before music source to play. (ms)
MusicPreTimeMs=1000
; ストイックモード(0:OFF, 1:ON)
; Stoic mode. (0:OFF, 1:ON)
StoicMode=0
; バッファ入力モード(0:OFF, 1:ON)
; Using Buffered input (0:OFF, 1:ON)
BufferedInput=1
; リザルト画像自動保存機能(0:OFF, 1:ON)
; Set "1" if you'd like to save result screen image automatically
; when you get hiscore/hiskill.
AutoResultCapture=0
; Discordに再生中の譜面情報を送信する(0:OFF, 1:ON)
; Share Playing .tja file infomation on Discord.
SendDiscordPlayingInformation=1
; 再生速度変更を、ピッチ変更で行うかどうか(0:ピッチ変更, 1:タイムストレッチ
; (WASAPI/ASIO使用時のみ有効)
; Set "0" if you'd like to use pitch shift with PlaySpeed.
; Set "1" for time stretch.
; (Only available when you're using using WASAPI or ASIO)
TimeStretch=0
; 動画再生にDirectShowを使用する(0:OFF, 1:ON)
; 動画再生にDirectShowを使うことによって、再生時の負担を軽減できます。
; ただし使用時にはセットアップが必要になるのでご注意ください。
DirectShowMode=0
; 判定タイミング調整(-9999)[ms]
; Revision value to adjust judgment timing.
InputAdjustTime=11
; 判定ラインの表示位置調整(ドラム, ギター, ベース)(-9999)[px]
; Offset value to adjust displaying judgement line for the drums, guitar and bass.
JudgeLinePosOffsetDrums=0
; 「また遊んでね」画面(0:OFF, 1:ON)
EndingAnime=0
;-------------------
[AutoPlay]
; 自動演奏(0:OFF, 1:ON)
Taiko=0
Taiko2P=0
TaikoAutoRoll=1
;-------------------
[HitRange]
; PerfectPoor とみなされる範囲[ms]
Perfect=30
Good=100
Poor=130
;-------------------
[Log]
; Log出力(0:OFF, 1:ON)
OutputLog=1
; 曲データ検索に関するLog出力(0:OFF, 1:ON)
TraceSongSearch=0
; 画像やサウンドの作成_解放に関するLog出力(0:OFF, 1:ON)
TraceCreatedDisposed=0
; DTX読み込み詳細に関するLog出力(0:OFF, 1:ON)
TraceDTXDetails=0
;-------------------
[PlayOption]
; 各画像の表示設定
; キャラクター画像を表示する (0:OFF, 1:ON)
ShowChara=1
; ダンサー画像を表示する (0:OFF, 1:ON)
ShowDancer=1
; ランナー画像を表示する (0:OFF, 1:ON)
ShowRunner=1
; モブ画像を表示する (0:OFF, 1:ON)
ShowMob=1
; フッター画像 (0:OFF, 1:ON)
ShowFooter=1
; ぷちキャラ画像 (0:OFF, 1:ON)
ShowPuchiChara=1
; DARKモード(0:OFF, 1:HALF, 2:FULL)
Dark=0
; 選曲画面でのタイマーを有効にするかどうか(0:無効,1:有効)
; Enable countdown in songselect.(0:No, 1:Yes)
EnableCountDownTimer=1
; ドラムSUDDENモード(0:OFF, 1:ON)
DrumsSudden=0
; ドラムHIDDENモード(0:OFF, 1:ON)
DrumsHidden=0
; ドラムチップ非表示モード (0:OFF, 1=SEMI, 2:FULL)
; Drums chip invisible mode
DrumsInvisible=0
; ドラムREVERSEモード(0:OFF, 1:ON)
DrumsReverse=0
; RISKYモード(0:OFF, 1-10)
; RISKY mode. 0=OFF, 1-10 is the times of misses to be Failed.
Risky=0
; TIGHTモード(0:OFF, 1:ON)
; TIGHT mode. 0=OFF, 1=ON
DrumsTight=0
; ドラム譜面スクロール速度(0:x0.5, 1:x1.0, 2:x1.5,…,1999:x1000.0)
DrumsScrollSpeed=1
; 演奏速度(540)(→x5/20x40/20)
PlaySpeed=20
; 演奏速度が一倍速であるときのみBGMを再生する(0:OFF, 1:ON)
PlaySpeedNotEqualOneNoSound=0
; デフォルトで選択される難易度
DefaultCourse=3
; 譜面分岐のガイド表示(0:OFF, 1:ON)
BranchGuide=0
; スコア計算方法(0:旧配点, 1:旧筐体配点, 2:新配点)
ScoreMode=2
; 真打モード (0:OFF, 1:ON)
; Fixed score mode (0:OFF, 1:ON)
ShinuchiMode=1
; 大音符の両手入力待機時間(ms)
BigNotesWaitTime=50
; 大音符の両手判定(0:OFF, 1:ON)
BigNotesJudge=0
; NoInfo(0:OFF, 1:ON)
NoInfo=0
; 譜面分岐のアニメーション(0:714, 1:15)
BranchAnime=1
; デフォルトの曲ソート(0:絶対パス順, 1:ジャンル名ソートOLD, 2:ジャンル名ソートNEW )
0:Path, 1:GenreName(AC8AC14), 2GenreName(AC15)
DefaultSongSort=2
; RANDOMモード(0:OFF, 1:Random, 2:Mirorr 3:SuperRandom, 4:HyperRandom)
TaikoRandom=0
; STEALTHモード(0:OFF, 1:ドロン, 2:ステルス)
TaikoStealth=0
; ゲーム(0:OFF, 1:完走!叩ききりまショー!, 2:完走!叩ききりまショー!(激辛) )
GameMode=0
; 特訓モード時にPgUp/PgDnで何小節飛ばすか
TokkunSkipMeasures=0
; 特訓モード時にジャンプポイントに飛ばすための時間(ms)
; 指定ms以内に5回縁を叩きましょう
TokkunMashInterval=750
; JUST(0:OFF, 1:ON)
Just=0
; 判定数の表示(0:OFF, 1:ON)
JudgeCountDisplay=0
; プレイ人数
PlayerCount=1
;-------------------
[GUID]
;-------------------
; キーアサイン
; 項 Keyboard → 'K''0'+キーコード(10進数)
; Mouse → 'N''0'+ボタン番号(07)
; MIDI In → 'M'デバイス番号1桁(09,AZ)+ノート番号(10進数)
; Joystick → 'J'デバイス番号1桁(09,AZ) 0 ...... X減少(左)ボタン
; 1 ...... X増加(右)ボタン
; 2 ...... Y減少(上)ボタン
; 3 ...... Y増加(下)ボタン
; 4 ...... Z減少(前)ボタン
; 5 ...... Z増加(後)ボタン
; 6133.. ボタン1128
; これらの項目を 16 個まで指定可能(',' で区切って記述)。
;
; 表記例HH=K044,M042,J16
; → HiHat を Keyboard の 44 ('Z'), MidiIn#0 の 42, JoyPad#1 の 6(ボタン1) に割当て
;
; ※Joystick のデバイス番号とデバイスとの関係は [GUID] セクションに記してあるものが有効。
;
[DrumsKeyAssign]
LeftRed=K016,K015
RightRed=K017,K019
LeftBlue=K028,K013
RightBlue=K020,K021
LeftRed2P=K031,K011
RightRed2P=K022,K023
LeftBlue2P=K033,K012
RightBlue2P=K0111,K047
[SystemKeyAssign]
Capture=K065

205
FDK19/FDK19.csproj Normal file
View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FDK</RootNamespace>
<AssemblyName>FDK</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<ApplicationIcon>
</ApplicationIcon>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>
</DocumentationFile>
<UseVSHostingProcess>false</UseVSHostingProcess>
<NoWarn>0219</NoWarn>
<DefineConstants>TRACE;TEST_CancelEnterCodeInAltEnter2 TEST_Direct3D9Ex_</DefineConstants>
<Optimize>false</Optimize>
<DebugType>full</DebugType>
<LangVersion>7.3</LangVersion>
<DebugSymbols>true</DebugSymbols>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>
</DocumentationFile>
<UseVSHostingProcess>true</UseVSHostingProcess>
<NoWarn>0219</NoWarn>
<DefineConstants>TRACE;TEST_ENGLISH_ TEST_Direct3D9Ex_</DefineConstants>
<Optimize>true</Optimize>
<LangVersion>7.3</LangVersion>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Bass.Net">
<HintPath>..\Test\dll\Bass.Net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DirectShowLib-2005, Version=2.1.0.0, Culture=neutral, PublicKeyToken=67e7b740cdfc2d3f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Test\dll\DirectShowLib-2005.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="コード\00.共通\CJudgeTextEncoding.cs" />
<Compile Include="コード\00.共通\COS.cs" />
<Compile Include="コード\00.共通\CPowerManagement.cs" />
<Compile Include="コード\00.共通\CSendMessage.cs" />
<Compile Include="コード\00.共通\CTimerBase.cs" />
<Compile Include="コード\00.共通\C一定間隔処理.cs" />
<Compile Include="コード\00.共通\C共通.cs" />
<Compile Include="コード\00.共通\ExtensionMethods\DoubleExtensions.cs" />
<Compile Include="コード\00.共通\ExtensionMethods\Int32Extensions.cs" />
<Compile Include="コード\01.フレームワーク\Core\GameWindowSize.cs" />
<Compile Include="コード\01.フレームワーク\Core\Game.cs" />
<Compile Include="コード\01.フレームワーク\Core\GameClock.cs" />
<Compile Include="コード\01.フレームワーク\Core\GameTime.cs" />
<Compile Include="コード\01.フレームワーク\Core\GameWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="コード\01.フレームワーク\DeviceSettings\ConversionMethods.cs" />
<Compile Include="コード\01.フレームワーク\DeviceSettings\DeviceSettings.cs" />
<Compile Include="コード\01.フレームワーク\DeviceSettings\Direct3D9Settings.cs" />
<Compile Include="コード\01.フレームワーク\Enumeration\Enumeration9.cs" />
<Compile Include="コード\01.フレームワーク\Properties\Resources.Designer.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\DeviceCreationException.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\DeviceCache.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\Direct3D9Manager.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\Enums.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\GraphicsDeviceManager.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\NoCompatibleDevicesException.cs" />
<Compile Include="コード\01.フレームワーク\Rendering\VertexElementAttribute.cs" />
<Compile Include="コード\01.フレームワーク\Utilities\Camera.cs" />
<Compile Include="コード\01.フレームワーク\Utilities\TransformedColoredTexturedVertex.cs" />
<Compile Include="コード\01.フレームワーク\Utilities\TransformedColoredVertex.cs" />
<Compile Include="コード\01.フレームワーク\Win32\NativeMethods.cs" />
<Compile Include="コード\01.フレームワーク\Win32\NativeStructures.cs" />
<Compile Include="コード\01.フレームワーク\Win32\WindowConstants.cs" />
<Compile Include="コード\02.入力\CInputJoystick.cs" />
<Compile Include="コード\02.入力\CInputKeyboard.cs" />
<Compile Include="コード\02.入力\CInputMIDI.cs" />
<Compile Include="コード\02.入力\CInputMouse.cs" />
<Compile Include="コード\02.入力\CInput管理.cs" />
<Compile Include="コード\02.入力\DeviceConstantConverter.cs" />
<Compile Include="コード\02.入力\E入力デバイス種別.cs" />
<Compile Include="コード\02.入力\IInputDevice.cs" />
<Compile Include="コード\02.入力\SlimDXKeys.cs" />
<Compile Include="コード\02.入力\STInputEvent.cs" />
<Compile Include="コード\03.サウンド\Cmp3.cs" />
<Compile Include="コード\03.サウンド\Cogg.cs" />
<Compile Include="コード\03.サウンド\CSound.cs" />
<Compile Include="コード\03.サウンド\CSoundDeviceASIO.cs" />
<Compile Include="コード\03.サウンド\CSoundDeviceDirectSound.cs" />
<Compile Include="コード\03.サウンド\CSoundDeviceWASAPI.cs" />
<Compile Include="コード\03.サウンド\CSoundTimer.cs" />
<Compile Include="コード\03.サウンド\Cxa.cs" />
<Compile Include="コード\03.サウンド\ESoundDeviceType.cs" />
<Compile Include="コード\03.サウンド\ESoundGroup.cs" />
<Compile Include="コード\03.サウンド\LoudnessMetadata.cs" />
<Compile Include="コード\03.サウンド\LoudnessMetadataScanner.cs" />
<Compile Include="コード\03.サウンド\Lufs.cs" />
<Compile Include="コード\03.サウンド\SongGainController.cs" />
<Compile Include="コード\03.サウンド\SoundDecoder.cs" />
<Compile Include="コード\03.サウンド\ISoundDevice.cs" />
<Compile Include="コード\03.サウンド\SoundGroupLevelController.cs" />
<Compile Include="コード\04.グラフィック\BitmapUtil.cs" />
<Compile Include="コード\04.グラフィック\CAero.cs" />
<Compile Include="コード\04.グラフィック\CAvi.cs" />
<Compile Include="コード\04.グラフィック\CTaskBar.cs" />
<Compile Include="コード\04.グラフィック\CTextureAutofold.cs" />
<Compile Include="コード\04.グラフィック\頂点フォーマット%28Vertex%29\ColoredVertex.cs" />
<Compile Include="コード\04.グラフィック\CTexture.cs" />
<Compile Include="コード\04.グラフィック\CTextureCreateFailedException.cs" />
<Compile Include="コード\04.グラフィック\頂点フォーマット%28Vertex%29\PositionColoredTexturedVertex.cs" />
<Compile Include="コード\04.グラフィック\頂点フォーマット%28Vertex%29\TexturedVertex.cs" />
<Compile Include="コード\04.グラフィック\頂点フォーマット%28Vertex%29\TransformedColoredTexturedVertex.cs" />
<Compile Include="コード\04.グラフィック\頂点フォーマット%28Vertex%29\TransformedColoredVertex.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="コード\00.共通\CActivity.cs" />
<Compile Include="コード\00.共通\CCounter.cs" />
<Compile Include="コード\00.共通\CFPS.cs" />
<Compile Include="コード\00.共通\CIniFile.cs" />
<Compile Include="コード\00.共通\CTimer.cs" />
<Compile Include="コード\00.共通\CTraceLogListener.cs" />
<Compile Include="コード\00.共通\CWin32.cs" />
<Compile Include="コード\00.共通\C変換.cs" />
<Compile Include="コード\05.DirectShow\CDirectShow.cs" />
<Compile Include="コード\05.DirectShow\CDStoWAVFileImage.cs" />
<Compile Include="コード\05.DirectShow\MemoryRenderer.cs" />
<Compile Include="コード\06.Tempo\CBeatDetect.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="コード\01.フレームワーク\Core\GameWindow.resx">
<DependentUpon>GameWindow.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="コード\01.フレームワーク\Properties\Resources.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="コード\01.フレームワーク\Resources\sdx_icon_black.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReadJEnc">
<Version>1.3.1.2</Version>
</PackageReference>
<PackageReference Include="SharpDX">
<Version>4.2.0</Version>
</PackageReference>
<PackageReference Include="SharpDX.Direct3D9">
<Version>4.2.0</Version>
</PackageReference>
<PackageReference Include="SharpDX.DirectInput">
<Version>4.2.0</Version>
</PackageReference>
<PackageReference Include="SharpDX.DirectSound">
<Version>4.2.0</Version>
</PackageReference>
<PackageReference Include="SlimDX">
<Version>4.0.13.44</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

7
FDK19/FDK19.csproj.user Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ReferencePath>
</ReferencePath>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,39 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Resources;
// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。
// アセンブリに関連付けられている情報を変更するには、
// これらの属性値を変更してください。
[assembly: AssemblyTitle( "FDKライブラリ" )]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct( "FDKライブラリ ver.21" )]
[assembly: AssemblyCopyright( "Copyright(C) 2000-2013 DTXMania Group" )]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//[assembly: AssemblyKeyName( "FROMsCspContainer" )]
// ComVisible を false に設定すると、その型はこのアセンブリ内で COM コンポーネントから
// 参照不可能になります。COM からこのアセンブリ内の型にアクセスする場合は、
// その型の ComVisible 属性を true に設定してください。
[assembly: ComVisible(false)]
// 次の GUID は、このプロジェクトが COM に公開される場合の、typelib の ID です
[assembly: Guid("c5f9e698-bec1-4d94-b8a4-3e39b636ccb8")]
// アセンブリのバージョン情報は、以下の 4 つの値で構成されています:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を
// 既定値にすることができます:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "21.0.0.0" )]
[assembly: AssemblyFileVersion( "21.0.0.0" )]
[assembly: NeutralResourcesLanguageAttribute("ja-JP")]

11
FDK19/packages.config Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ReadJEnc" version="1.3.1.2" targetFramework="net35" />
<package id="SharpDX" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.Direct3D9" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.DirectInput" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.DirectSound" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.DXGI" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net472" />
<package id="SlimDX" version="4.0.13.44" targetFramework="net35" />
</packages>

View File

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public class CActivity
{
// プロパティ
public bool b活性化してる { get; private set; }
public bool b活性化してない
{
get
{
return !this.b活性化してる;
}
set
{
this.b活性化してる = !value;
}
}
public List<CActivity> list子Activities;
/// <summary>
/// <para>初めて On進行描画() を呼び出す場合に true を示す。On活性化() 内で true にセットされる。)</para>
/// <para>このフラグは、On活性化() では行えないタイミングのシビアな初期化を On進行描画() で行うために準備されている。利用は必須ではない。</para>
/// <para>On進行描画() 側では、必要な初期化を追えたら false をセットすること。</para>
/// </summary>
protected bool b初めての進行描画 = true;
// コンストラクタ
public CActivity()
{
this.b活性化してない = true;
this.list子Activities = new List<CActivity>();
}
// ライフサイクルメソッド
#region [ override ]
//-----------------
public virtual void On活性化()
{
// すでに活性化してるなら何もしない。
if( this.b活性化してる )
return;
this.b活性化してる = true; // このフラグは、以下の処理をする前にセットする。
// 自身のリソースを作成する。
this.OnManagedリソースの作成();
this.OnUnmanagedリソースの作成();
// すべての子 Activity を活性化する。
foreach( CActivity activity in this.list子Activities )
activity.On活性化();
// その他の初期化
this.b初めての進行描画 = true;
}
public virtual void On非活性化()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return;
// 自身のリソースを解放する。
this.OnUnmanagedリソースの解放();
this.OnManagedリソースの解放();
// すべての 子Activity を非活性化する。
foreach( CActivity activity in this.list子Activities )
activity.On非活性化();
this.b活性化してない = true; // このフラグは、以上のメソッドを呼び出した後にセットする。
}
/// <summary>
/// <para>Managed リソースの作成を行う。</para>
/// <para>Direct3D デバイスが作成された直後に呼び出されるので、自分が活性化している時に限り、
/// Managed リソースを作成(または再構築)すること。</para>
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void OnManagedリソースの作成()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return;
// すべての 子Activity の Managed リソースを作成する。
foreach( CActivity activity in this.list子Activities )
activity.OnManagedリソースの作成();
}
/// <summary>
/// <para>Unmanaged リソースの作成を行う。</para>
/// <para>Direct3D デバイスが作成またはリセットされた直後に呼び出されるので、自分が活性化している時に限り、
/// Unmanaged リソースを作成(または再構築)すること。</para>
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void OnUnmanagedリソースの作成()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return;
// すべての 子Activity の Unmanaged リソースを作成する。
foreach( CActivity activity in this.list子Activities )
activity.OnUnmanagedリソースの作成();
}
/// <summary>
/// <para>Unmanaged リソースの解放を行う。</para>
/// <para>Direct3D デバイスの解放直前またはリセット直前に呼び出される。</para>
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void OnUnmanagedリソースの解放()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return;
// すべての 子Activity の Unmanaged リソースを解放する。
foreach( CActivity activity in this.list子Activities )
activity.OnUnmanagedリソースの解放();
}
/// <summary>
/// <para>Managed リソースの解放を行う。</para>
/// <para>Direct3D デバイスの解放直前に呼び出される。
/// Unmanaged リソースとは異なり、Direct3D デバイスのリセット時には呼び出されない。)</para>
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void OnManagedリソースの解放()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return;
// すべての 子Activity の Managed リソースを解放する。
foreach( CActivity activity in this.list子Activities )
activity.OnManagedリソースの解放();
}
/// <summary>
/// <para>進行と描画を行う。(これらは分離されず、この1つのメソッドだけで実装する。)</para>
/// <para>このメソッドは BeginScene() の後に呼び出されるので、メソッド内でいきなり描画を行ってかまわない。</para>
/// </summary>
/// <returns>任意の整数。呼び出し元との整合性を合わせておくこと。</returns>
public virtual int On進行描画()
{
// 活性化してないなら何もしない。
if( this.b活性化してない )
return 0;
/* ここで進行と描画を行う。*/
// 戻り値とその意味は子クラスで自由に決めていい。
return 0;
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary>
/// 一定間隔で単純増加する整数(カウント値)を扱う。
/// </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 b開始した
{
get;
set;
}
// 値プロパティ
public float n開始値
{
get;
private set;
}
public float n終了値
{
get;
set;
}
public int n現在の値
{
get;
set;
}
public double _n間隔
{
get
{
return this.n間隔;
}
set
{
this.n間隔 = value >= 0 ? value : value * -1;
}
}
public float n現在の経過時間ms
{
get;
set;
}
// 状態プロパティ
public bool b進行中
{
get { return (this.n現在の経過時間ms != -1); }
}
public bool b停止中
{
get { return !this.b進行中; }
}
public bool b終了値に達した
{
get { return (this.n現在の値 >= this.n終了値); }
}
public bool b終了値に達してない
{
get { return !this.b終了値に達した; }
}
// コンストラクタ
public CCounter()
{
this.timer = null;
this.n開始値 = 0;
this.n終了値 = 0;
this.n現在の値 = 0;
this.n現在の値 = 0;
this.n現在の経過時間ms = CSoundTimer.n未使用;
}
/// <summary>生成と同時に開始する。</summary>
public CCounter(float n開始値, float n終了値, float n間隔ms, CTimer timer)
: this()
{
this.t開始(n開始値, n終了値, n間隔ms, timer);
}
/// <summary>生成と同時に開始する。(double版)</summary>
public CCounter(double db開始値, double db終了値, double db間隔, CSoundTimer timer)
: this()
{
this.t開始(db開始値, db終了値, db間隔 * 1000.0f, timer);
}
// 状態操作メソッド
/// <summary>
/// カウントを開始する。
/// </summary>
/// <param name="n開始値">最初のカウント値。</param>
/// <param name="n終了値">最後のカウント値。</param>
/// <param name="n間隔ms">カウント値を1増加させるのにかける時間(ミリ秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param>
public void t開始(float n開始値, float n終了値, float n間隔ms, CTimer timer)
{
this.n開始値 = n開始値;
this.n終了値 = n終了値;
this._n間隔 = n間隔ms;
this.timer = timer;
this.n現在の経過時間ms = this.timer.n現在時刻;
this.n現在の値 = (int)n開始値;
this.b開始した = true;
}
/// <summary>
/// カウントを開始する。(double版)
/// </summary>
/// <param name="db開始値">最初のカウント値。</param>
/// <param name="db終了値">最後のカウント値。</param>
/// <param name="db間隔">カウント値を1増加させるのにかける時間(秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param>
public void t開始(double db開始値, double db終了値, double db間隔, CSoundTimer timer)
{
this.n開始値 = (float)db開始値;
this.n終了値 = (float)db終了値;
this._n間隔 = db間隔;
this.timerdb = timer;
this.n現在の経過時間ms = (float)this.timerdb.dbシステム時刻;
this.n現在の値 = (int)db開始値;
this.b開始した = true;
}
/// <summary>
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary>
public void t進行()
{
if ((this.timer != null) && (this.n現在の経過時間ms != CTimer.n未使用))
{
long num = this.timer.n現在時刻;
if (num < this.n現在の経過時間ms)
this.n現在の経過時間ms = num;
while ((num - this.n現在の経過時間ms) >= this.n間隔)
{
if (++this.n現在の値 > this.n終了値)
this.n現在の値 = (int)this.n終了値;
this.n現在の経過時間ms += (float)this.n間隔;
}
}
}
/// <summary>
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary>
public void t進行db()
{
if ((this.timerdb != null) && (this.n現在の経過時間ms != CSoundTimer.n未使用))
{
double num = this.timerdb.n現在時刻;
if (num < this.n現在の経過時間ms)
this.n現在の経過時間ms = (float)num;
while ((num - this.n現在の経過時間ms) >= this.n間隔)
{
if (++this.n現在の値 > this.n終了値)
this.n現在の値 = (int)this.n終了値;
this.n現在の経過時間ms += (float)this.n間隔;
}
}
}
/// <summary>
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary>
public void t進行Loop()
{
if ((this.timer != null) && (this.n現在の経過時間ms != CTimer.n未使用))
{
long num = this.timer.n現在時刻;
if (num < this.n現在の経過時間ms)
this.n現在の経過時間ms = num;
while ((num - this.n現在の経過時間ms) >= this.n間隔)
{
if (++this.n現在の値 > this.n終了値)
this.n現在の値 = (int)this.n開始値;
this.n現在の経過時間ms += (float)this.n間隔;
}
}
}
/// <summary>
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary>
public void t進行LoopDb()
{
if ((this.timerdb != null) && (this.n現在の経過時間ms != CSoundTimer.n未使用))
{
double num = this.timerdb.n現在時刻;
if (num < this.n現在の経過時間ms)
this.n現在の経過時間ms = (float)num;
while ((num - this.n現在の経過時間ms) >= this.n間隔)
{
if (++this.n現在の値 > this.n終了値)
this.n現在の値 = (int)this.n開始値;
this.n現在の経過時間ms += (float)this.n間隔;
}
}
}
/// <summary>
/// カウントを停止する。
/// これ以降に t進行() や t進行Loop() を呼び出しても何も処理されない。
/// </summary>
public void t停止()
{
this.n現在の経過時間ms = CTimer.n未使用;
}
public void t間隔値変更(double Value)
{
this._n間隔 = Value;
}
// その他
#region [ ]
//-----------------
/// <summary>
/// <para>「bキー押下」引数が true の間中、「tキー処理」デリゲート引数を呼び出す。</para>
/// <para>ただし、2回目の呼び出しは1回目から 200ms の間を開けてから行い、3回目以降の呼び出しはそれぞれ 30ms の間隔で呼び出す。</para>
/// <para>「bキー押下」が false の場合は何もせず、呼び出し回数を 0 にリセットする。</para>
/// </summary>
/// <param name="bキー押下">キーが押下されている場合は true。</param>
/// <param name="tキー処理">キーが押下されている場合に実行する処理。</param>
public void tキー反復(bool bキー押下, DGキー処理 tキー処理)
{
const int n1回目 = 0;
const int n2回目 = 1;
const int n3回目以降 = 2;
if (bキー押下)
{
switch (this.n現在の値)
{
case n1回目:
tキー処理();
this.n現在の値 = n2回目;
this.n現在の経過時間ms = this.timer.n現在時刻;
return;
case n2回目:
if ((this.timer.n現在時刻 - this.n現在の経過時間ms) > 200)
{
tキー処理();
this.n現在の経過時間ms = this.timer.n現在時刻;
this.n現在の値 = n3回目以降;
}
return;
case n3回目以降:
if ((this.timer.n現在時刻 - this.n現在の経過時間ms) > 30)
{
tキー処理();
this.n現在の経過時間ms = this.timer.n現在時刻;
}
return;
}
}
else
{
this.n現在の値 = n1回目;
}
}
public delegate void DGキー処理();
//-----------------
#endregion
#region [ private ]
//-----------------
private CTimer timer;
private CSoundTimer timerdb;
private double n間隔;
//-----------------
#endregion
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace FDK
{
public static class CpuCores
{
[DllImport("kernel32")]
public static extern void GetSystemInfo(ref SYSTEM_INFO ptmpsi);
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO {
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public class CFPS
{
// プロパティ
public int n現在のFPS
{
get;
private set;
}
public bool bFPSの値が変化した
{
get;
private set;
}
// コンストラクタ
public CFPS()
{
this.n現在のFPS = 0;
this.timer = new CTimer( CTimer.E種別.MultiMedia );
this.ms = this.timer.n現在時刻;
this.FPS = 0;
this.bFPSの値が変化した = false;
}
// メソッド
public void tカウンタ更新()
{
this.timer.t更新();
this.bFPSの値が変化した = false;
const long INTERVAL = 1000;
while( ( this.timer.n現在時刻 - this.ms ) >= INTERVAL )
{
this.n現在のFPS = this.FPS;
this.FPS = 0;
this.bFPSの値が変化した = true;
this.ms += INTERVAL;
}
this.FPS++;
}
// その他
#region [ private ]
//-----------------
private CTimer timer;
private long ms;
private int FPS;
//-----------------
#endregion
}
}

View File

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

View File

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace TJAPlayer3
{
public class CJudgeTextEncoding
{
/// <summary>
/// Hnc8様のReadJEncを使用して文字コードの判別をする。
/// </summary>
public static Encoding JudgeFileEncoding(string path)
{
if (!File.Exists(path)) return null;
Encoding enc;
FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file))
{
// 判別読み出し実行。判別結果はReadメソッドの戻り値で把握できます
Hnx8.ReadJEnc.CharCode c = reader.Read(file);
// 戻り値のNameプロパティから文字コード名を取得できます
string name = c.Name;
Console.WriteLine("【" + name + "】" + file.Name);
// GetEncoding()を呼び出すと、エンコーディングを取得できます
enc = c.GetEncoding();
}
Debug.Print(path + " Encoding=" + enc.CodePage);
if (enc == null)
{
enc = Encoding.GetEncoding(932);
}
return enc;
}
/// <summary>
/// Hnc8様のReadJEncを使用してテキストファイルを読み込む。
/// 改行文字は、勝手に\nに統一する
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string ReadTextFile(string path)
{
if (!File.Exists(path)) return null;
string str = null;
FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file))
{
reader.Read(file);
str = reader.Text;
}
str = str.Replace(JudgeNewLine(str), "\n");
return str;
}
/// <summary>
/// Environment.NewLineはプラットフォーム依存である。
/// だが、ファイルごとに改行コードは違うので、使用すべきではない。
/// なので、勝手に改行文字を判断する。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string JudgeNewLine(string str)
{
if (str.Contains("\r\n"))
return ("\r\n");
if (str.Contains("\r"))
return ("\r");
return ("\n");
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public static class COS
{
/// <summary>
/// OSがXP以前ならfalse, Vista以降ならtrueを返す
/// </summary>
/// <returns></returns>
public static bool bIsVistaOrLater
{
get
{
//プラットフォームの取得
System.OperatingSystem os = System.Environment.OSVersion;
if ( os.Platform != PlatformID.Win32NT ) // NT系でなければ、XP以前か、PC Windows系以外のOSのため、Vista以降ではない。よってfalseを返す。
{
return false;
}
if ( os.Version.Major >= 6 )
{
return true;
}
else
{
return false;
}
}
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary>
/// システムとモニタの省電力制御を行う
/// </summary>
public static class CPowerManagement
{
/// <summary>
/// 本体/モニタの省電力モード移行を抑止する
/// </summary>
public static void tDisableMonitorSuspend()
{
CWin32.SetThreadExecutionState( CWin32.ExecutionState.SystemRequired | CWin32.ExecutionState.DisplayRequired );
}
/// <summary>
/// 本体/モニタの省電力モード移行抑制を解除する
/// </summary>
public static void tEnableMonitorSuspend()
{
CWin32.SetThreadExecutionState( CWin32.ExecutionState.Continuous ); // スリープ抑止状態を解除
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
namespace FDK
{
public static class CSendMessage
{
[DllImport( "USER32.dll" )]
static extern uint SendMessage( IntPtr window, int msg, IntPtr wParam, ref SampleFramework.COPYDATASTRUCT lParam );
public static uint sendmessage( IntPtr MainWindowHandle, IntPtr FromWindowHandle, string arg)
{
uint len = (uint) arg.Length;
SampleFramework.COPYDATASTRUCT cds;
cds.dwData = IntPtr.Zero; // 使用しない
cds.lpData = Marshal.StringToHGlobalUni( arg ); // テキストのポインターをセット
cds.cbData = ( len + 1 ) * 2; // 長さをセット
//文字列を送る
uint result = SendMessage( MainWindowHandle, SampleFramework.WindowConstants.WM_COPYDATA, FromWindowHandle, ref cds );
Marshal.FreeHGlobal( cds.lpData );
return result;
}
}
}

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using DirectShowLib;
namespace FDK
{
public class CTimer : CTimerBase
{
public enum E種別
{
Unknown = -1,
PerformanceCounter = 0,
MultiMedia = 1,
GetTickCount = 2,
}
public E種別 eタイマ種別
{
get;
protected set;
}
public override long nシステム時刻ms
{
get
{
switch( this.eタイマ種別 )
{
case E種別.PerformanceCounter:
{
double num = 0.0;
if( this.n現在の周波数 != 0L )
{
long x = 0L;
QueryPerformanceCounter( ref x );
num = ( (double) x ) / ( ( (double) this.n現在の周波数 ) / 1000.0 );
}
return (long) num;
}
case E種別.MultiMedia:
return (long) timeGetTime();
case E種別.GetTickCount:
return (long) Environment.TickCount;
}
return 0;
}
}
public CTimer( E種別 eタイマ種別 )
:base()
{
this.eタイマ種別 = eタイマ種別;
if( n参照カウント[ (int) this.eタイマ種別 ] == 0 )
{
switch( this.eタイマ種別 )
{
case E種別.PerformanceCounter:
if( !this.b確認と設定_PerformanceCounter() && !this.b確認と設定_MultiMedia() )
this.b確認と設定_GetTickCount();
break;
case E種別.MultiMedia:
if( !this.b確認と設定_MultiMedia() && !this.b確認と設定_PerformanceCounter() )
this.b確認と設定_GetTickCount();
break;
case E種別.GetTickCount:
this.b確認と設定_GetTickCount();
break;
default:
throw new ArgumentException( string.Format( "未知のタイマ種別です。[{0}]", this.eタイマ種別 ) );
}
}
base.tリセット();
n参照カウント[ (int) this.eタイマ種別 ]++;
}
public override void Dispose()
{
if( this.eタイマ種別 == E種別.Unknown )
return;
int type = (int) this.eタイマ種別;
n参照カウント[ type ] = Math.Max( n参照カウント[ type ] - 1, 0 );
if( n参照カウント[ type ] == 0 )
{
if( this.eタイマ種別 == E種別.MultiMedia )
timeEndPeriod( this.timeCaps.wPeriodMin );
}
this.eタイマ種別 = E種別.Unknown;
}
#region [ protected ]
//-----------------
protected long n現在の周波数;
protected static int[] n参照カウント = new int[ 3 ];
protected TimeCaps timeCaps;
protected bool b確認と設定_GetTickCount()
{
this.eタイマ種別 = E種別.GetTickCount;
return true;
}
protected bool b確認と設定_MultiMedia()
{
this.timeCaps = new TimeCaps();
if( ( timeGetDevCaps( out this.timeCaps, (uint) Marshal.SizeOf( typeof( TimeCaps ) ) ) == 0 ) && ( this.timeCaps.wPeriodMin < 10 ) )
{
this.eタイマ種別 = E種別.MultiMedia;
timeBeginPeriod( this.timeCaps.wPeriodMin );
return true;
}
return false;
}
protected bool b確認と設定_PerformanceCounter()
{
if( QueryPerformanceFrequency( ref this.n現在の周波数 ) != 0 )
{
this.eタイマ種別 = E種別.PerformanceCounter;
return true;
}
return false;
}
//-----------------
#endregion
#region [ DllImport ]
//-----------------
[DllImport( "kernel32.dll" )]
protected static extern short QueryPerformanceCounter( ref long x );
[DllImport( "kernel32.dll" )]
protected static extern short QueryPerformanceFrequency( ref long x );
[DllImport( "winmm.dll" )]
protected static extern void timeBeginPeriod( uint x );
[DllImport( "winmm.dll" )]
protected static extern void timeEndPeriod( uint x );
[DllImport( "winmm.dll" )]
protected static extern uint timeGetDevCaps( out TimeCaps timeCaps, uint size );
[DllImport( "winmm.dll" )]
protected static extern uint timeGetTime();
[StructLayout( LayoutKind.Sequential )]
protected struct TimeCaps
{
public uint wPeriodMin;
public uint wPeriodMax;
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary>
/// <para>タイマの抽象クラス。</para>
/// <para>このクラスを継承し、override したクラスを作成することで、任意のクロックを持つタイマを作成できる。</para>
/// </summary>
public abstract class CTimerBase : IDisposable
{
public const long n未使用 = -1;
// この2つを override する。
public abstract long nシステム時刻ms
{
get;
}
public double dbシステム時刻ms
{
get;
set;
}
public abstract void Dispose();
#region [ DTXMania用にmsのつかない宣言を追加 ]
public long nシステム時刻
{
get { return nシステム時刻ms; }
}
public long n現在時刻
{
get { return n現在時刻ms; }
set { n現在時刻ms = value; }
}
public long n前回リセットした時のシステム時刻
{
get { return n前回リセットした時のシステム時刻ms; }
}
//double
public double dbシステム時刻
{
get { return dbシステム時刻ms; }
}
public double db現在時刻
{
get { return db現在時刻ms; }
set { db現在時刻ms = value; }
}
public double db前回リセットした時のシステム時刻
{
get { return db前回リセットした時のシステム時刻ms; }
}
#endregion
public long n現在時刻ms
{
get
{
if( this.n停止数 > 0 )
return ( this.n一時停止システム時刻ms - this.n前回リセットした時のシステム時刻ms );
return ( this.n更新システム時刻ms - this.n前回リセットした時のシステム時刻ms );
}
set
{
if( this.n停止数 > 0 )
this.n前回リセットした時のシステム時刻ms = this.n一時停止システム時刻ms - value;
else
this.n前回リセットした時のシステム時刻ms = this.n更新システム時刻ms - value;
}
}
public long nリアルタイム現在時刻ms
{
get
{
if( this.n停止数 > 0 )
return ( this.n一時停止システム時刻ms - this.n前回リセットした時のシステム時刻ms );
return ( this.nシステム時刻ms - this.n前回リセットした時のシステム時刻ms );
}
}
public long n前回リセットした時のシステム時刻ms
{
get;
protected set;
}
public double db現在時刻ms
{
get
{
if( this.n停止数 > 0 )
return ( this.db一時停止システム時刻ms - this.db前回リセットした時のシステム時刻ms );
return ( this.db更新システム時刻ms - this.db前回リセットした時のシステム時刻ms );
}
set
{
if( this.n停止数 > 0 )
this.db前回リセットした時のシステム時刻ms = this.db一時停止システム時刻ms - value;
else
this.db前回リセットした時のシステム時刻ms = this.db更新システム時刻ms - value;
}
}
public double dbリアルタイム現在時刻ms
{
get
{
if( this.n停止数 > 0 )
return ( this.db一時停止システム時刻ms - this.db前回リセットした時のシステム時刻ms );
return ( this.dbシステム時刻ms - this.db前回リセットした時のシステム時刻ms );
}
}
public double db前回リセットした時のシステム時刻ms
{
get;
protected set;
}
public bool b停止していない
{
get
{
return ( this.n停止数 == 0 );
}
}
public void tリセット()
{
this.t更新();
this.n前回リセットした時のシステム時刻ms = this.n更新システム時刻ms;
this.n一時停止システム時刻ms = this.n更新システム時刻ms;
this.n停止数 = 0;
}
public void t一時停止()
{
if( this.n停止数 == 0 )
{
this.n一時停止システム時刻ms = this.n更新システム時刻ms;
this.db一時停止システム時刻ms = this.db更新システム時刻ms;
}
this.n停止数++;
}
public void t更新()
{
this.n更新システム時刻ms = this.nシステム時刻ms;
this.db更新システム時刻ms = this.dbシステム時刻ms;
}
public void t再開()
{
if( this.n停止数 > 0 )
{
this.n停止数--;
if( this.n停止数 == 0 )
{
this.t更新();
this.n前回リセットした時のシステム時刻ms += this.n更新システム時刻ms - this.n一時停止システム時刻ms;
this.db前回リセットした時のシステム時刻ms += this.db更新システム時刻ms - this.db一時停止システム時刻ms;
}
}
}
#region [ protected ]
//-----------------
protected long n一時停止システム時刻ms = 0;
protected long n更新システム時刻ms = 0;
protected double db一時停止システム時刻ms = 0;
protected double db更新システム時刻ms = 0;
protected int n停止数 = 0;
//-----------------
#endregion
}
}

View File

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace FDK
{
public class CTraceLogListener : TraceListener
{
public CTraceLogListener( StreamWriter stream )
{
this.streamWriter = stream;
}
public override void Flush()
{
if( this.streamWriter != null )
{
try
{
this.streamWriter.Flush();
}
catch( ObjectDisposedException )
{
}
}
}
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message )
{
if( this.streamWriter != null )
{
try
{
this.tイベント種別を出力する( eventType );
this.tインデントを出力する();
this.streamWriter.WriteLine( message );
}
catch( ObjectDisposedException )
{
}
}
}
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args )
{
if( this.streamWriter != null )
{
try
{
this.tイベント種別を出力する( eventType );
this.tインデントを出力する();
this.streamWriter.WriteLine( string.Format( format, args ) );
}
catch( ObjectDisposedException )
{
}
}
}
public override void Write( string message )
{
if( this.streamWriter != null )
{
try
{
this.streamWriter.Write( message );
}
catch( ObjectDisposedException )
{
}
}
}
public override void WriteLine( string message )
{
if( this.streamWriter != null )
{
try
{
this.streamWriter.WriteLine( message );
}
catch( ObjectDisposedException )
{
}
}
}
protected override void Dispose( bool disposing )
{
if( this.streamWriter != null )
{
try
{
this.streamWriter.Close();
}
catch
{
}
this.streamWriter = null;
}
base.Dispose( disposing );
}
#region [ private ]
//-----------------
private StreamWriter streamWriter;
private void tイベント種別を出力する( TraceEventType eventType )
{
if( this.streamWriter != null )
{
try
{
var now = DateTime.Now;
this.streamWriter.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 )
{
case TraceEventType.Error:
this.streamWriter.Write( "[ERROR] " );
return;
case ( TraceEventType.Error | TraceEventType.Critical ):
return;
case TraceEventType.Warning:
this.streamWriter.Write( "[WARNING] " );
return;
case TraceEventType.Information:
break;
default:
return;
}
this.streamWriter.Write( "[INFO] " );
}
catch( ObjectDisposedException )
{
}
}
}
private void tインデントを出力する()
{
if( ( this.streamWriter != null ) && ( base.IndentLevel > 0 ) )
{
try
{
for( int i = 0; i < base.IndentLevel; i++ )
this.streamWriter.Write( " " );
}
catch( ObjectDisposedException )
{
}
}
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,661 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
namespace FDK
{
public class CWin32
{
#region [ Win32 ]
//-----------------
public const int S_OK = 0x00000000;
public const int S_FALSE = 0x00000001;
public const int E_FAIL = unchecked( (int) 0x80004005 );
public const int E_ABORT = unchecked( (int) 0x80004004 );
public const int BROADCAST_QUERY_DENY = 0x424d5144;
public const uint CALLBACK_FUNCTION = 0x30000;
public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_DISPLAY_REQUIRED = 2;
public const uint ES_SYSTEM_REQUIRED = 1;
public const uint ES_USER_PRESENT = 4;
public const int GWL_EXSTYLE = -20;
public const int GWL_HINSTANCE = -6;
public const int GWL_HWNDPARENT = -8;
public const int GWL_ID = -12;
public const int GWL_STYLE = -16;
public const int GWL_USERDATA = -21;
public const int GWL_WNDPROC = -4;
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr( -2 );
public static readonly IntPtr HWND_TOPMOST = new IntPtr( -1 );
public const uint MAXPNAMELEN = 0x20;
#region [ MIDIメッセージ ]
public const uint MIM_CLOSE = 0x3c2;
public const uint MIM_DATA = 0x3c3;
public const uint MIM_ERROR = 0x3c5;
public const uint MIM_LONGDATA = 0x3c4;
public const uint MIM_LONGERROR = 0x3c6;
public const uint MIM_OPEN = 0x3c1;
#endregion
public const int MONITOR_DEFAULTTOPRIMARY = 1;
public const int PBT_APMQUERYSTANDBY = 1;
public const int PBT_APMQUERYSUSPEND = 0;
public const int SC_MONITORPOWER = 0xf170;
public const int SC_SCREENSAVE = 0xf140;
public const int SIZE_MAXIMIZED = 2;
public const int SIZE_MINIMIZED = 1;
public const int SIZE_RESTORED = 0;
public const uint SWP_FRAMECHANGED = 0x20;
public const uint SWP_HIDEWINDOW = 0x80;
public const uint SWP_NOACTIVATE = 0x10;
public const uint SWP_NOCOPYBITS = 0x100;
public const uint SWP_NOMOVE = 2;
public const uint SWP_NOOWNERZORDER = 0x200;
public const uint SWP_NOREDRAW = 8;
public const uint SWP_NOSENDCHANGING = 0x400;
public const uint SWP_NOSIZE = 1;
public const uint SWP_NOZORDER = 4;
public const uint SWP_SHOWWINDOW = 0x40;
public const uint PM_NOREMOVE = 0;
public const uint PM_REMOVE = 1;
#region [ DirectShow, VFW ]
//-----------------
public const int S_WARN_OUTPUTRESET = 0x00009DD4;
public const int E_NOTINTREE = unchecked( (int) 0x80040400 );
public const int E_RENDER_ENGINE_IS_BROKEN = unchecked( (int) 0x80040401 );
public const int E_MUST_INIT_RENDERER = unchecked( (int) 0x80040402 );
public const int E_NOTDETERMINED = unchecked( (int) 0x80040403 );
public const int E_NO_TIMELINE = unchecked( (int) 0x80040404 );
public const int VFW_E_INVALIDMEDIATYPE = unchecked( (int) 0x80040200 );
public const int VFW_E_INVALIDSUBTYPE = unchecked( (int) 0x80040201 );
public const int VFW_E_NEED_OWNER = unchecked( (int) 0x80040202 );
public const int VFW_E_ENUM_OUT_OF_SYNC = unchecked( (int) 0x80040203 );
public const int VFW_E_ALREADY_CONNECTED = unchecked( (int) 0x80040204 );
public const int VFW_E_FILTER_ACTIVE = unchecked( (int) 0x80040205 );
public const int VFW_E_NO_TYPES = unchecked( (int) 0x80040206 );
public const int VFW_E_NO_ACCEPTABLE_TYPES = unchecked( (int) 0x80040207 );
public const int VFW_E_INVALID_DIRECTION = unchecked( (int) 0x80040208 );
public const int VFW_E_NOT_CONNECTED = unchecked( (int) 0x80040209 );
public const int VFW_E_NO_ALLOCATOR = unchecked( (int) 0x8004020A );
public const int VFW_E_RUNTIME_ERROR = unchecked( (int) 0x8004020B );
public const int VFW_E_BUFFER_NOTSET = unchecked( (int) 0x8004020C );
public const int VFW_E_BUFFER_OVERFLOW = unchecked( (int) 0x8004020D );
public const int VFW_E_BADALIGN = unchecked( (int) 0x8004020E );
public const int VFW_E_ALREADY_COMMITTED = unchecked( (int) 0x8004020F );
public const int VFW_E_BUFFERS_OUTSTANDING = unchecked( (int) 0x80040210 );
public const int VFW_E_NOT_COMMITTED = unchecked( (int) 0x80040211 );
public const int VFW_E_SIZENOTSET = unchecked( (int) 0x80040212 );
public const int VFW_E_NO_CLOCK = unchecked( (int) 0x80040213 );
public const int VFW_E_NO_SINK = unchecked( (int) 0x80040214 );
public const int VFW_E_NO_INTERFACE = unchecked( (int) 0x80040215 );
public const int VFW_E_NOT_FOUND = unchecked( (int) 0x80040216 );
public const int VFW_E_CANNOT_CONNECT = unchecked( (int) 0x80040217 );
public const int VFW_E_CANNOT_RENDER = unchecked( (int) 0x80040218 );
public const int VFW_E_CHANGING_FORMAT = unchecked( (int) 0x80040219 );
public const int VFW_E_NO_COLOR_KEY_SET = unchecked( (int) 0x8004021A );
public const int VFW_E_NOT_OVERLAY_CONNECTION = unchecked( (int) 0x8004021B );
public const int VFW_E_NOT_SAMPLE_CONNECTION = unchecked( (int) 0x8004021C );
public const int VFW_E_PALETTE_SET = unchecked( (int) 0x8004021D );
public const int VFW_E_COLOR_KEY_SET = unchecked( (int) 0x8004021E );
public const int VFW_E_NO_COLOR_KEY_FOUND = unchecked( (int) 0x8004021F );
public const int VFW_E_NO_PALETTE_AVAILABLE = unchecked( (int) 0x80040220 );
public const int VFW_E_NO_DISPLAY_PALETTE = unchecked( (int) 0x80040221 );
public const int VFW_E_TOO_MANY_COLORS = unchecked( (int) 0x80040222 );
public const int VFW_E_STATE_CHANGED = unchecked( (int) 0x80040223 );
public const int VFW_E_NOT_STOPPED = unchecked( (int) 0x80040224 );
public const int VFW_E_NOT_PAUSED = unchecked( (int) 0x80040225 );
public const int VFW_E_NOT_RUNNING = unchecked( (int) 0x80040226 );
public const int VFW_E_WRONG_STATE = unchecked( (int) 0x80040227 );
public const int VFW_E_START_TIME_AFTER_END = unchecked( (int) 0x80040228 );
public const int VFW_E_INVALID_RECT = unchecked( (int) 0x80040229 );
public const int VFW_E_TYPE_NOT_ACCEPTED = unchecked( (int) 0x8004022A );
public const int VFW_E_SAMPLE_REJECTED = unchecked( (int) 0x8004022B );
public const int VFW_E_SAMPLE_REJECTED_EOS = unchecked( (int) 0x8004022C );
public const int VFW_E_DUPLICATE_NAME = unchecked( (int) 0x8004022D );
public const int VFW_S_DUPLICATE_NAME = 0x0004022D;
public const int VFW_E_TIMEOUT = unchecked( (int) 0x8004022E );
public const int VFW_E_INVALID_FILE_FORMAT = unchecked( (int) 0x8004022F );
public const int VFW_E_ENUM_OUT_OF_RANGE = unchecked( (int) 0x80040230 );
public const int VFW_E_CIRCULAR_GRAPH = unchecked( (int) 0x80040231 );
public const int VFW_E_NOT_ALLOWED_TO_SAVE = unchecked( (int) 0x80040232 );
public const int VFW_E_TIME_ALREADY_PASSED = unchecked( (int) 0x80040233 );
public const int VFW_E_ALREADY_CANCELLED = unchecked( (int) 0x80040234 );
public const int VFW_E_CORRUPT_GRAPH_FILE = unchecked( (int) 0x80040235 );
public const int VFW_E_ADVISE_ALREADY_SET = unchecked( (int) 0x80040236 );
public const int VFW_S_STATE_INTERMEDIATE = 0x00040237;
public const int VFW_E_NO_MODEX_AVAILABLE = unchecked( (int) 0x80040238 );
public const int VFW_E_NO_ADVISE_SET = unchecked( (int) 0x80040239 );
public const int VFW_E_NO_FULLSCREEN = unchecked( (int) 0x8004023A );
public const int VFW_E_IN_FULLSCREEN_MODE = unchecked( (int) 0x8004023B );
public const int VFW_E_UNKNOWN_FILE_TYPE = unchecked( (int) 0x80040240 );
public const int VFW_E_CANNOT_LOAD_SOURCE_FILTER = unchecked( (int) 0x80040241 );
public const int VFW_S_PARTIAL_RENDER = 0x00040242;
public const int VFW_E_FILE_TOO_SHORT = unchecked( (int) 0x80040243 );
public const int VFW_E_INVALID_FILE_VERSION = unchecked( (int) 0x80040244 );
public const int VFW_S_SOME_DATA_IGNORED = 0x00040245;
public const int VFW_S_CONNECTIONS_DEFERRED = 0x00040246;
public const int VFW_E_INVALID_CLSID = unchecked( (int) 0x80040247 );
public const int VFW_E_INVALID_MEDIA_TYPE = unchecked( (int) 0x80040248 );
public const int VFW_E_SAMPLE_TIME_NOT_SET = unchecked( (int) 0x80040249 );
public const int VFW_S_RESOURCE_NOT_NEEDED = 0x00040250;
public const int VFW_E_MEDIA_TIME_NOT_SET = unchecked( (int) 0x80040251 );
public const int VFW_E_NO_TIME_FORMAT_SET = unchecked( (int) 0x80040252 );
public const int VFW_E_MONO_AUDIO_HW = unchecked( (int) 0x80040253 );
public const int VFW_S_MEDIA_TYPE_IGNORED = 0x00040254;
public const int VFW_E_NO_DECOMPRESSOR = unchecked( (int) 0x80040255 );
public const int VFW_E_NO_AUDIO_HARDWARE = unchecked( (int) 0x80040256 );
public const int VFW_S_VIDEO_NOT_RENDERED = 0x00040257;
public const int VFW_S_AUDIO_NOT_RENDERED = 0x00040258;
public const int VFW_E_RPZA = unchecked( (int) 0x80040259 );
public const int VFW_S_RPZA = 0x0004025A;
public const int VFW_E_PROCESSOR_NOT_SUITABLE = unchecked( (int) 0x8004025B );
public const int VFW_E_UNSUPPORTED_AUDIO = unchecked( (int) 0x8004025C );
public const int VFW_E_UNSUPPORTED_VIDEO = unchecked( (int) 0x8004025D );
public const int VFW_E_MPEG_NOT_CONSTRAINED = unchecked( (int) 0x8004025E );
public const int VFW_E_NOT_IN_GRAPH = unchecked( (int) 0x8004025F );
public const int VFW_S_ESTIMATED = 0x00040260;
public const int VFW_E_NO_TIME_FORMAT = unchecked( (int) 0x80040261 );
public const int VFW_E_READ_ONLY = unchecked( (int) 0x80040262 );
public const int VFW_S_RESERVED = 0x00040263;
public const int VFW_E_BUFFER_UNDERFLOW = unchecked( (int) 0x80040264 );
public const int VFW_E_UNSUPPORTED_STREAM = unchecked( (int) 0x80040265 );
public const int VFW_E_NO_TRANSPORT = unchecked( (int) 0x80040266 );
public const int VFW_S_STREAM_OFF = 0x00040267;
public const int VFW_S_CANT_CUE = 0x00040268;
public const int VFW_E_BAD_VIDEOCD = unchecked( (int) 0x80040269 );
public const int VFW_S_NO_STOP_TIME = 0x00040270;
public const int VFW_E_OUT_OF_VIDEO_MEMORY = unchecked( (int) 0x80040271 );
public const int VFW_E_VP_NEGOTIATION_FAILED = unchecked( (int) 0x80040272 );
public const int VFW_E_DDRAW_CAPS_NOT_SUITABLE = unchecked( (int) 0x80040273 );
public const int VFW_E_NO_VP_HARDWARE = unchecked( (int) 0x80040274 );
public const int VFW_E_NO_CAPTURE_HARDWARE = unchecked( (int) 0x80040275 );
public const int VFW_E_DVD_OPERATION_INHIBITED = unchecked( (int) 0x80040276 );
public const int VFW_E_DVD_INVALIDDOMAIN = unchecked( (int) 0x80040277 );
public const int VFW_E_DVD_NO_BUTTON = unchecked( (int) 0x80040278 );
public const int VFW_E_DVD_GRAPHNOTREADY = unchecked( (int) 0x80040279 );
public const int VFW_E_DVD_RENDERFAIL = unchecked( (int) 0x8004027A );
public const int VFW_E_DVD_DECNOTENOUGH = unchecked( (int) 0x8004027B );
public const int VFW_E_DVD_NOT_IN_KARAOKE_MODE = unchecked( (int) 0x8004028B );
public const int VFW_E_FRAME_STEP_UNSUPPORTED = unchecked( (int) 0x8004028E );
public const int VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD = unchecked( (int) 0x80040293 );
public const int VFW_E_PIN_ALREADY_BLOCKED = unchecked( (int) 0x80040294 );
public const int VFW_E_CERTIFICATION_FAILURE = unchecked( (int) 0x80040295 );
public const int VFW_E_BAD_KEY = unchecked( (int) 0x800403F2 );
//-----------------
#endregion
#region [ Windowsメッセージ ]
public const uint WM_ACTIVATEAPP = 0x1c;
public const uint WM_COPYDATA = 0x4a;
public const uint WM_CLOSE = 0x10;
public const uint WM_POWERBROADCAST = 0x218;
public const uint WM_SIZE = 5;
public const uint WM_SYSCOMMAND = 0x112;
public const uint WM_SYSKEYDOWN = 260;
public const uint WM_APP = 0x00008000;
public const uint WM_QUIT = 0x12;
public const uint WPF_RESTORETOMAXIMIZED = 2;
#endregion
#region [ WindowsStyle ]
public const long WS_BORDER = 0x800000L;
public const long WS_CAPTION = 0xc00000L;
public const long WS_CHILD = 0x40000000L;
public const long WS_CHILDWINDOW = 0x40000000L;
public const long WS_CLIPCHILDREN = 0x2000000L;
public const long WS_CLIPSIBLINGS = 0x4000000L;
public const long WS_DISABLED = 0x8000000L;
public const long WS_DLGFRAME = 0x400000L;
public const long WS_GROUP = 0x20000L;
public const long WS_HSCROLL = 0x100000L;
public const long WS_ICONIC = 0x20000000L;
public const long WS_MAXIMIZE = 0x1000000L;
public const long WS_MAXIMIZEBOX = 0x10000L;
public const long WS_MINIMIZE = 0x20000000L;
public const long WS_MINIMIZEBOX = 0x20000L;
public const long WS_OVERLAPPED = 0L;
public const long WS_OVERLAPPEDWINDOW = 0xcf0000L;
public const long WS_POPUP = 0x80000000L;
public const long WS_POPUPWINDOW = 0x80880000L;
public const long WS_SIZEBOX = 0x40000L;
public const long WS_SYSMENU = 0x80000L;
public const long WS_TABSTOP = 0x10000L;
public const long WS_THICKFRAME = 0x40000L;
public const long WS_TILED = 0L;
public const long WS_TILEDWINDOW = 0xcf0000L;
public const long WS_VISIBLE = 0x10000000L;
public const long WS_VSCROLL = 0x200000L;
public const long WS_EX_ACCEPTFILES = 0x10L;
public const long WS_EX_APPWINDOW = 0x40000L;
public const long WS_EX_CLIENTEDGE = 0x200L;
public const long WS_EX_COMPOSITED = 0x2000000L;
public const long WS_EX_CONTEXTHELP = 0x400L;
public const long WS_EX_CONTROLPARENT = 0x10000L;
public const long WS_EX_DLGMODALFRAME = 1L;
public const long WS_EX_LAYERED = 0x80000L;
public const long WS_EX_LAYOUTRTL = 0x400000L;
public const long WS_EX_LEFT = 0L;
public const long WS_EX_LEFTSCROLLBAR = 0x4000L;
public const long WS_EX_LTRREADING = 0L;
public const long WS_EX_MDICHILD = 0x40L;
public const long WS_EX_NOACTIVATE = 0x8000000L;
public const long WS_EX_NOINHERITLAYOUT = 0x100000L;
public const long WS_EX_NOPARENTNOTIFY = 4L;
public const long WS_EX_OVERLAPPEDWINDOW = 0x300L;
public const long WS_EX_PALETTEWINDOW = 0x188L;
public const long WS_EX_RIGHT = 0x1000L;
public const long WS_EX_RIGHTSCROLLBAR = 0L;
public const long WS_EX_RTLREADING = 0x2000L;
public const long WS_EX_STATICEDGE = 0x20000L;
public const long WS_EX_TOOLWINDOW = 0x80L;
public const long WS_EX_TOPMOST = 8L;
public const long WS_EX_TRANSPARENT = 0x20L;
public const long WS_EX_WINDOWEDGE = 0x100L;
#endregion
public enum EShowWindow
{
ForceMinimize = 11,
Hide = 0,
Maximize = 3,
Minimize = 6,
Normal = 1,
Restore = 9,
Show = 5,
ShowDefault = 10,
ShowMaximized = 3,
ShowMinimized = 2,
ShowMinNoActive = 7,
ShowNA = 8,
ShowNoActivate = 4
}
public enum MMSYSERR
{
NOERROR,
ERROR,
BADDEVICEID,
NOTENABLED,
ALLOCATED,
INVALHANDLE,
NODRIVER,
NOMEM,
NOTSUPPORTED,
BADERRNUM,
INVALFLAG,
INVALPARAM,
HANDLEBUSY,
INVALIDALIAS,
BADDB,
KEYNOTFOUND,
READERROR,
WRITEERROR,
DELETEERROR,
VALNOTFOUND,
NODRIVERCB,
MOREDATA
}
[FlagsAttribute]
internal enum ExecutionState : uint
{
Null = 0, // 関数が失敗した時の戻り値
SystemRequired = 1, // スタンバイを抑止
DisplayRequired = 2, // 画面OFFを抑止
Continuous = 0x80000000, // 効果を永続させる。ほかオプションと併用する。
}
//-----------------
#endregion
#region [ Win32 ]
//-----------------
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool AdjustWindowRect( ref RECT lpRect, uint dwStyle, [MarshalAs( UnmanagedType.Bool )] bool bMenu );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool GetClientRect( IntPtr hWnd, out RECT lpRect );
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern uint GetWindowLong( IntPtr hWnd, int nIndex );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool GetWindowPlacement( IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern bool IsIconic( IntPtr hWnd );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern bool IsWindowVisible( IntPtr hWnd );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern bool IsZoomed( IntPtr hWnd );
[DllImport("winmm.dll")]
public static extern uint midiInClose(IntPtr hMidiIn);
[DllImport("winmm.dll")]
public static extern uint midiInGetDevCaps(uint uDeviceID, ref MIDIINCAPS lpMidiInCaps, uint cbMidiInCaps);
[DllImport("winmm.dll")]
public static extern uint midiInGetID(IntPtr hMidiIn, ref IntPtr puDeviceID);
[DllImport("winmm.dll")]
public static extern uint midiInGetNumDevs();
[DllImport("winmm.dll")]
public static extern uint midiInOpen(ref IntPtr phMidiIn, uint uDeviceID, MidiInProc dwCallback, IntPtr dwInstance, int fdwOpen);
[DllImport("winmm.dll")]
public static extern uint midiInReset(IntPtr hMidiIn);
[DllImport("winmm.dll")]
public static extern uint midiInStart(IntPtr hMidiIn);
[DllImport("winmm.dll")]
public static extern uint midiInStop(IntPtr hMidiIn);
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern IntPtr MonitorFromWindow( IntPtr hwnd, uint dwFlags );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern bool PeekMessage( out WindowMessage message, IntPtr hwnd, uint messageFilterMin, uint messageFilterMax, uint flags );
[DllImport( "kernel32.dll", CharSet = CharSet.Auto )]
public static extern uint SetThreadExecutionState( uint esFlags );
[DllImport( "Kernel32.Dll" )]
public static unsafe extern void CopyMemory( void* pDest, void* pSrc, uint numOfBytes );
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern uint SetWindowLong( IntPtr hWnd, int nIndex, uint dwNewLong );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool SetWindowPlacement( IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
public static extern bool ShowWindow( IntPtr hWnd, EShowWindow nCmdShow );
[return: MarshalAs( UnmanagedType.Bool )]
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool SystemParametersInfo( uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni );
[DllImport( "kernel32.dll" )]
public static extern void GetSystemInfo( ref SYSTEM_INFO ptmpsi );
[DllImport( "kernel32.dll" )]
internal static extern ExecutionState SetThreadExecutionState( ExecutionState esFlags );
//-----------------
#endregion
#region [ Win32 ]
//-----------------
[StructLayout( LayoutKind.Sequential )]
private struct FILTERKEYS
{
public int cbSize;
public int dwFlags;
}
[StructLayout( LayoutKind.Sequential )]
public struct MIDIINCAPS
{
public ushort wMid;
public ushort wPid;
public uint vDriverVersion;
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 0x20 )]
public string szPname;
public uint dwSupport;
}
[StructLayout( LayoutKind.Sequential )]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout( LayoutKind.Sequential )]
private struct STICKYKEYS
{
public int cbSize;
public int dwFlags;
}
[StructLayout( LayoutKind.Sequential )]
private struct TOGGLEKEYS
{
public int cbSize;
public int dwFlags;
}
[StructLayout( LayoutKind.Sequential )]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
[StructLayout( LayoutKind.Sequential )]
public struct WindowMessage
{
public IntPtr hWnd;
public uint msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public Point p;
}
[StructLayout( LayoutKind.Sequential )]
public struct WINDOWPLACEMENT
{
public int length;
public int flags;
public CWin32.EShowWindow showCmd;
public Point ptMinPosition;
public Point ptMaxPosition;
public CWin32.RECT rcNormalPosition;
public static int Length
{
get
{
return Marshal.SizeOf( typeof( CWin32.WINDOWPLACEMENT ) );
}
}
}
[StructLayout( LayoutKind.Sequential )]
public struct SYSTEM_INFO
{
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
//-----------------
#endregion
// プロパティ
public static bool bアプリがIdle状態である
{
get
{
WindowMessage message;
return !PeekMessage( out message, IntPtr.Zero, 0, 0, 0 );
}
}
// キーボードの特殊機能の制御
public static class Cトグルキー機能
{
public static void t無効化する()
{
if( ( stored.dwFlags & 1L ) == 0L )
{
CWin32.TOGGLEKEYS structure = new CWin32.TOGGLEKEYS();
structure.dwFlags = stored.dwFlags;
structure.cbSize = stored.cbSize;
structure.dwFlags &= -5;
structure.dwFlags &= -9;
int cb = Marshal.SizeOf( structure );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( structure, ptr, false );
CWin32.SystemParametersInfo( 0x35, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
}
public static void t復元する()
{
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 0x35, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
#region [ private ]
//-----------------
static Cトグルキー機能()
{
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 0x34, (uint) cb, ptr, 0 );
stored = (CWin32.TOGGLEKEYS) Marshal.PtrToStructure( ptr, typeof( CWin32.TOGGLEKEYS ) );
Marshal.FreeCoTaskMem( ptr );
}
private const uint SPI_GETTOGGLEKEYS = 0x34;
private const uint SPI_SETTOGGLEKEYS = 0x35;
private static CWin32.TOGGLEKEYS stored = new CWin32.TOGGLEKEYS();
private const uint TKF_CONFIRMHOTKEY = 8;
private const uint TKF_HOTKEYACTIVE = 4;
private const uint TKF_TOGGLEKEYSON = 1;
//-----------------
#endregion
}
public static class Cフィルタキー機能
{
public static void t無効化する()
{
if( ( stored.dwFlags & 1L ) == 0L )
{
CWin32.FILTERKEYS structure = new CWin32.FILTERKEYS();
structure.dwFlags = stored.dwFlags;
structure.cbSize = stored.cbSize;
structure.dwFlags &= -5;
structure.dwFlags &= -9;
int cb = Marshal.SizeOf( structure );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( structure, ptr, false );
CWin32.SystemParametersInfo( 0x3b, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
}
public static void t復元する()
{
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 0x3b, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
#region [ private ]
//-----------------
static Cフィルタキー機能()
{
stored.cbSize = 0;
stored.dwFlags = 0;
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 50, (uint) cb, ptr, 0 );
stored = (CWin32.FILTERKEYS) Marshal.PtrToStructure( ptr, typeof( CWin32.FILTERKEYS ) );
Marshal.FreeCoTaskMem( ptr );
}
private const uint FKF_CONFIRMHOTKEY = 8;
private const uint FKF_FILTERKEYSON = 1;
private const uint FKF_HOTKEYACTIVE = 4;
private const uint SPI_GETFILTERKEYS = 50;
private const uint SPI_SETFILTERKEYS = 0x3b;
private static CWin32.FILTERKEYS stored = new CWin32.FILTERKEYS();
//-----------------
#endregion
}
public static class C固定キー機能
{
public static void t無効化する()
{
if( ( stored.dwFlags & 1L ) == 0L )
{
CWin32.STICKYKEYS structure = new CWin32.STICKYKEYS();
structure.dwFlags = stored.dwFlags;
structure.cbSize = stored.cbSize;
structure.dwFlags &= -5;
structure.dwFlags &= -9;
int cb = Marshal.SizeOf( structure );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( structure, ptr, false );
CWin32.SystemParametersInfo( 0x3b, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
}
public static void t復元する()
{
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 0x3b, (uint) cb, ptr, 0 );
Marshal.FreeCoTaskMem( ptr );
}
#region [ private ]
//-----------------
static C固定キー機能()
{
stored.cbSize = 0;
stored.dwFlags = 0;
int cb = Marshal.SizeOf( stored );
IntPtr ptr = Marshal.AllocCoTaskMem( cb );
Marshal.StructureToPtr( stored, ptr, false );
CWin32.SystemParametersInfo( 0x3a, (uint) cb, ptr, 0 );
stored = (CWin32.STICKYKEYS) Marshal.PtrToStructure( ptr, typeof( CWin32.STICKYKEYS ) );
Marshal.FreeCoTaskMem( ptr );
}
private const uint SKF_CONFIRMHOTKEY = 8;
private const uint SKF_HOTKEYACTIVE = 4;
private const uint SKF_STICKYKEYSON = 1;
private const uint SPI_GETSTICKYKEYS = 0x3a;
private const uint SPI_SETSTICKYKEYS = 0x3b;
private static CWin32.STICKYKEYS stored = new CWin32.STICKYKEYS();
//-----------------
#endregion
}
// Win32 メッセージ処理デリゲート
public delegate void MidiInProc(IntPtr hMidiIn, uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2);
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
/// <summary>
/// <para>一定の間隔で処理を行うテンプレートパターンの定義。</para>
/// <para>たとえば、t進行() で 5ms ごとに行う処理を前回のt進行()の呼び出しから 15ms 後に呼び出した場合は、処理が 3回 実行される。</para>
/// </summary>
public class C一定間隔処理 : IDisposable
{
public delegate void dg処理();
public void t進行( long n間隔ms, dg処理 dg処理 )
{
// タイマ更新
if( this.timer == null )
return;
this.timer.t更新();
// 初めての進行処理
if( this.n前回の時刻 == CTimer.n未使用 )
this.n前回の時刻 = this.timer.n現在時刻ms;
// タイマが一回りしてしまった時のため……
if( this.timer.n現在時刻ms < this.n前回の時刻 )
this.n前回の時刻 = this.timer.n現在時刻ms;
// 時間内の処理を実行。
while( ( this.timer.n現在時刻ms - this.n前回の時刻 ) >= n間隔ms )
{
dg処理();
this.n前回の時刻 += n間隔ms;
}
}
#region [ IDisposable ]
//-----------------
public void Dispose()
{
C共通.tDisposeする( ref this.timer );
}
//-----------------
#endregion
#region [ protected ]
//-----------------
protected CTimer timer = new CTimer( CTimer.E種別.MultiMedia );
protected long n前回の時刻 = CTimer.n未使用;
//-----------------
#endregion
}
}

View File

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace FDK
{
public class C共通
{
// 解放
public static void tDisposeする<T>( ref T obj )
{
if( obj == null )
return;
var d = obj as IDisposable;
if( d != null )
{
d.Dispose();
obj = default( T );
}
}
public static void tDisposeする<T>( T obj )
{
if( obj == null )
return;
var d = obj as IDisposable;
if( d != null )
d.Dispose();
}
public static void tCOMオブジェクトを解放する<T>( ref T obj )
{
if( obj != null )
{
try
{
Marshal.ReleaseComObject( obj );
}
catch
{
// COMがマネージドコードで書かれている場合、ReleaseComObject は例外を発生させる。
// http://www.infoq.com/jp/news/2010/03/ReleaseComObject-Dangerous
}
obj = default( T );
}
}
public static void t完全なガベージコレクションを実施する()
{
GC.Collect(); // アクセス不可能なオブジェクトを除去し、ファイナライぜーション実施。
GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッドを待機。
GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放。
// 出展: http://msdn.microsoft.com/ja-jp/library/ms998547.aspx#scalenetchapt05_topic10
}
// ログ
public static void LogBlock( string str処理名, MethodInvoker method )
{
Trace.TraceInformation( "--------------------" );
Trace.TraceInformation( "開始 - " + str処理名 );
Trace.Indent();
try
{
method();
}
finally
{
Trace.Unindent();
Trace.TraceInformation( "終了 - " + str処理名 );
Trace.TraceInformation( "--------------------" );
}
}
public static void t例外の詳細をログに出力する( Exception e )
{
Trace.WriteLine( "---例外ここから----" );
Trace.WriteLine( e.ToString() );
Trace.WriteLine( "---例外ここまで----" );
}
// IO
public static string t指定した拡張子を持つファイルを検索し最初に見つけたファイルの絶対パスを返す( string strフォルダパス, List<string> list拡張子リスト )
{
string[] files = Directory.GetFiles( strフォルダパス ); // GetFiles() は完全パスを返す。
// ファイル順より拡張子順を優先して検索する。→ 拡張子リストの前方の拡張子ほど先に発見されるようにするため。
foreach( string ext in list拡張子リスト )
{
foreach( string file in files )
{
string fileExt = Path.GetExtension( file );
if( fileExt.Equals( ext, StringComparison.OrdinalIgnoreCase ) )
return file; // あった
}
}
return null; // なかった
}
public static void tXMLファイルを読み込む<T>( string strXMLファイル名, out T xmlObject )
{
xmlObject = default( T );
FileStream fs = null;
StreamReader sr = null;
try
{
fs = new FileStream( strXMLファイル名, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。
sr = new StreamReader( fs, Encoding.UTF8 );
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) );
xmlObject = (T) xmlsl.Deserialize( sr );
}
finally
{
if( sr != null )
sr.Close(); // fr も一緒にClose()される
}
}
public static void tXMLファイルを保存する<T>( string strXMLファイル名, T xmlObject )
{
FileStream fs = null;
StreamWriter sw = null;
try
{
fs = new FileStream( strXMLファイル名, FileMode.Create, FileAccess.Write, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。
sw = new StreamWriter( fs, Encoding.UTF8 );
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) );
xmlsl.Serialize( sw, xmlObject );
}
finally
{
if( sw != null )
sw.Close(); // fs も一緒にClose()される
}
}
// 数学
public static double DegreeToRadian( double angle )
{
return ( ( Math.PI * angle ) / 180.0 );
}
public static double RadianToDegree( double angle )
{
return ( angle * 180.0 / Math.PI );
}
public static float DegreeToRadian( float angle )
{
return (float) DegreeToRadian( (double) angle );
}
public static float RadianToDegree( float angle )
{
return (float) RadianToDegree( (double) angle );
}
public static bool bToggleBoolian( ref bool bFlag )
{
if( bFlag == true ) bFlag = false;
else if( bFlag == false ) bFlag = true;
return true;
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using System;
namespace FDK.ExtensionMethods
{
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

@ -0,0 +1,12 @@
using System;
namespace FDK.ExtensionMethods
{
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

@ -0,0 +1,569 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using System.Collections.ObjectModel;
namespace SampleFramework
{
/// <summary>
/// Presents an easy to use wrapper for making games and samples.
/// </summary>
public abstract class Game : IDisposable
{
GameClock clock = new GameClock();
GameTime gameTime = new GameTime();
TimeSpan maximumElapsedTime = TimeSpan.FromMilliseconds(500.0);
TimeSpan totalGameTime;
TimeSpan accumulatedElapsedGameTime;
TimeSpan lastFrameElapsedGameTime;
TimeSpan lastFrameElapsedRealTime;
TimeSpan targetElapsedTime = TimeSpan.FromTicks(166667);
TimeSpan inactiveSleepTime = TimeSpan.FromMilliseconds(20.0);
int updatesSinceRunningSlowly1 = int.MaxValue;
int updatesSinceRunningSlowly2 = int.MaxValue;
bool forceElapsedTimeToZero;
bool drawRunningSlowly;
long lastUpdateFrame;
float lastUpdateTime;
/// <summary>
/// Occurs when the game is disposed.
/// </summary>
public event EventHandler Disposed;
/// <summary>
/// Occurs when the game is activated.
/// </summary>
public event EventHandler Activated;
/// <summary>
/// Occurs when the game is deactivated.
/// </summary>
public event EventHandler Deactivated;
/// <summary>
/// Occurs when the game is exiting.
/// </summary>
public event EventHandler Exiting;
/// <summary>
/// Occurs when a drawing frame is about to start.
/// </summary>
public event CancelEventHandler FrameStart;
/// <summary>
/// Occurs when a drawing frame ends.
/// </summary>
public event EventHandler FrameEnd;
/// <summary>
/// Gets or sets the inactive sleep time.
/// </summary>
/// <value>The inactive sleep time.</value>
public TimeSpan InactiveSleepTime
{
get { return inactiveSleepTime; }
set
{
// error checking
if (value < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("value", "Inactive sleep time cannot be less than zero.");
inactiveSleepTime = value;
}
}
/// <summary>
/// Gets or sets the target elapsed time.
/// </summary>
/// <value>The target elapsed time.</value>
public TimeSpan TargetElapsedTime
{
get { return targetElapsedTime; }
set
{
// error checking
if (value <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException("value", "Target elapsed time must be greater than zero.");
targetElapsedTime = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the game is using a fixed time step.
/// </summary>
/// <value>
/// <c>true</c> if the game is using a fixed time step; otherwise, <c>false</c>.
/// </value>
public bool IsFixedTimeStep
{
get;
set;
}
/// <summary>
/// Gets a value indicating whether this <see cref="Game"/> is exiting.
/// </summary>
/// <value><c>true</c> if exiting; otherwise, <c>false</c>.</value>
public bool IsExiting
{
get;
private set;
}
/// <summary>
/// Gets or sets a value indicating whether this instance is running.
/// </summary>
/// <value>
/// <c>true</c> if this instance is running; otherwise, <c>false</c>.
/// </value>
public bool IsRunning
{
get;
private set;
}
/// <summary>
/// Gets the game window.
/// </summary>
/// <value>The game window.</value>
public GameWindow Window
{
get;
private set;
}
/// <summary>
/// Gets the graphics device manager.
/// </summary>
/// <value>The graphics device manager.</value>
public GraphicsDeviceManager GraphicsDeviceManager
{
get;
private set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Game"/> is active.
/// </summary>
/// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
public bool IsActive
{
get;
private set;
}
/// <summary>
/// Initializes the <see cref="Game"/> class.
/// </summary>
static Game()
{
// configure SlimDX
Configuration.ThrowOnError = true;
Configuration.AddResultWatch(ResultCode.DeviceLost, ResultWatchFlags.AlwaysIgnore);
Configuration.AddResultWatch(ResultCode.WasStillDrawing, ResultWatchFlags.AlwaysIgnore);
#if DEBUG
Configuration.DetectDoubleDispose = true;
Configuration.EnableObjectTracking = true;
#else
Configuration.DetectDoubleDispose = false;
Configuration.EnableObjectTracking = false;
#endif
// setup the application
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
}
/// <summary>
/// Initializes a new instance of the <see cref="Game"/> class.
/// </summary>
protected Game()
{
IsFixedTimeStep = true;
Window = new GameWindow();
Window.ApplicationActivated += Window_ApplicationActivated;
Window.ApplicationDeactivated += Window_ApplicationDeactivated;
Window.Suspend += Window_Suspend;
Window.Resume += Window_Resume;
Window.Paint += Window_Paint;
GraphicsDeviceManager = new GraphicsDeviceManager(this);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
// GraphicsDeviceManager.Dispose will come around and call the Dispose(bool)
// overload, so we don't need to do it here. It's convoluted, but it works well.
if (GraphicsDeviceManager != null)
GraphicsDeviceManager.Dispose();
GraphicsDeviceManager = null;
if (Disposed != null)
Disposed(this, EventArgs.Empty);
GC.SuppressFinalize(this);
}
/// <summary>
/// Exits the game.
/// </summary>
public void Exit()
{
// request the game to terminate
IsExiting = true;
}
/// <summary>
/// Runs the game.
/// </summary>
public void Run()
{
IsRunning = true;
try
{
gameTime.ElapsedGameTime = 0;
gameTime.ElapsedRealTime = 0;
gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
gameTime.IsRunningSlowly = false;
Update(gameTime);
Application.Idle += Application_Idle;
Application.Run(Window);
}
finally
{
Application.Idle -= Application_Idle;
IsRunning = false;
OnExiting(EventArgs.Empty);
}
}
/// <summary>
/// Performs one complete frame for the game.
/// </summary>
public void Tick()
{
// if we are exiting, do nothing
if (IsExiting)
return;
// if we are inactive, sleep for a bit
//if (!IsActive)
// Thread.Sleep((int)InactiveSleepTime.TotalMilliseconds);
clock.Step();
gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
gameTime.ElapsedRealTime = (float)clock.ElapsedTime.TotalSeconds;
lastFrameElapsedRealTime += clock.ElapsedTime;
TimeSpan elapsedAdjustedTime = clock.ElapsedAdjustedTime;
if (elapsedAdjustedTime < TimeSpan.Zero)
elapsedAdjustedTime = TimeSpan.Zero;
if (forceElapsedTimeToZero)
{
gameTime.ElapsedRealTime = 0;
lastFrameElapsedRealTime = elapsedAdjustedTime = TimeSpan.Zero;
forceElapsedTimeToZero = false;
}
// cap the adjusted time
if (elapsedAdjustedTime > maximumElapsedTime)
elapsedAdjustedTime = maximumElapsedTime;
// check if we are using a fixed or variable time step
if (IsFixedTimeStep)
{
accumulatedElapsedGameTime += elapsedAdjustedTime;
long ratio = accumulatedElapsedGameTime.Ticks / TargetElapsedTime.Ticks;
accumulatedElapsedGameTime = TimeSpan.FromTicks(accumulatedElapsedGameTime.Ticks % TargetElapsedTime.Ticks);
lastFrameElapsedGameTime = TimeSpan.Zero;
if (ratio == 0)
return;
TimeSpan targetElapsedTime = TargetElapsedTime;
if (ratio > 1)
{
updatesSinceRunningSlowly2 = updatesSinceRunningSlowly1;
updatesSinceRunningSlowly1 = 0;
}
else
{
if (updatesSinceRunningSlowly1 < int.MaxValue)
updatesSinceRunningSlowly1++;
if (updatesSinceRunningSlowly2 < int.MaxValue)
updatesSinceRunningSlowly2++;
}
drawRunningSlowly = updatesSinceRunningSlowly2 < 20;
// update until it's time to draw the next frame
while (ratio > 0 && !IsExiting)
{
ratio -= 1;
try
{
gameTime.ElapsedGameTime = (float)targetElapsedTime.TotalSeconds;
gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
gameTime.IsRunningSlowly = drawRunningSlowly;
Update(gameTime);
}
finally
{
lastFrameElapsedGameTime += targetElapsedTime;
totalGameTime += targetElapsedTime;
}
}
}
else
{
drawRunningSlowly = false;
updatesSinceRunningSlowly1 = int.MaxValue;
updatesSinceRunningSlowly2 = int.MaxValue;
// make sure we shouldn't be exiting
if (!IsExiting)
{
try
{
gameTime.ElapsedGameTime = 0;
lastFrameElapsedGameTime = elapsedAdjustedTime;
gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
gameTime.IsRunningSlowly = false;
Update(gameTime);
}
finally
{
totalGameTime += elapsedAdjustedTime;
}
}
}
DrawFrame();
// refresh the FPS counter once per second
lastUpdateFrame++;
if ((float)clock.CurrentTime.TotalSeconds - lastUpdateTime > 1.0f)
{
gameTime.FramesPerSecond = (float)lastUpdateFrame / (float)(clock.CurrentTime.TotalSeconds - lastUpdateTime);
lastUpdateTime = (float)clock.CurrentTime.TotalSeconds;
lastUpdateFrame = 0;
}
}
/// <summary>
/// Resets the elapsed time.
/// </summary>
public void ResetElapsedTime()
{
forceElapsedTimeToZero = true;
updatesSinceRunningSlowly1 = int.MaxValue;
updatesSinceRunningSlowly2 = int.MaxValue;
}
/// <summary>
/// Allows the game to perform logic processing.
/// </summary>
/// <param name="gameTime">The time passed since the last update.</param>
protected virtual void Update(GameTime gameTime)
{
}
/// <summary>
/// Called when a frame is ready to be drawn.
/// </summary>
/// <param name="gameTime">The time passed since the last frame.</param>
protected virtual void Draw(GameTime gameTime)
{
}
/// <summary>
/// Initializes the game.
/// </summary>
protected internal virtual void Initialize()
{
}
/// <summary>
/// Loads graphical resources.
/// </summary>
protected internal virtual void LoadContent()
{
}
/// <summary>
/// Unloads graphical resources.
/// </summary>
protected internal virtual void UnloadContent()
{
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <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)
{
}
/// <summary>
/// Raises the <see cref="E:Activated"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnActivated(EventArgs e)
{
if (Activated != null)
Activated(this, e);
}
/// <summary>
/// Raises the <see cref="E:Deactivated"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnDeactivated(EventArgs e)
{
if (Deactivated != null)
Deactivated(this, e);
}
/// <summary>
/// Raises the <see cref="E:Exiting"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnExiting(EventArgs e)
{
if (Exiting != null)
Exiting(this, e);
}
/// <summary>
/// Raises the <see cref="E:FrameStart"/> event.
/// </summary>
/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
protected virtual void OnFrameStart(CancelEventArgs e)
{
if (FrameStart != null)
FrameStart(this, e);
}
/// <summary>
/// Raises the <see cref="E:FrameEnd"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnFrameEnd(EventArgs e)
{
if (FrameEnd != null)
FrameEnd(this, e);
}
void DrawFrame()
{
try
{
if ( !IsExiting /* && !Window.IsMinimized */ ) // #28230 2012.5.1 yyagi
{
CancelEventArgs e = new CancelEventArgs(false);
OnFrameStart(e);
if (!e.Cancel)
{
gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
gameTime.ElapsedRealTime = (float)lastFrameElapsedRealTime.TotalSeconds;
gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
gameTime.ElapsedGameTime = (float)lastFrameElapsedGameTime.TotalSeconds;
gameTime.IsRunningSlowly = drawRunningSlowly;
Draw(gameTime);
OnFrameEnd(EventArgs.Empty);
}
}
}
finally
{
lastFrameElapsedGameTime = TimeSpan.Zero;
lastFrameElapsedRealTime = TimeSpan.Zero;
}
}
void Application_Idle(object sender, EventArgs e)
{
NativeMessage message;
while (!NativeMethods.PeekMessage(out message, IntPtr.Zero, 0, 0, 0))
{
if (IsExiting)
Window.Close();
else
Tick();
}
}
void Window_ApplicationDeactivated(object sender, EventArgs e)
{
if (IsActive)
{
IsActive = false;
OnDeactivated(EventArgs.Empty);
}
}
void Window_ApplicationActivated(object sender, EventArgs e)
{
if (!IsActive)
{
IsActive = true;
OnActivated(EventArgs.Empty);
}
}
void Window_Paint(object sender, PaintEventArgs e)
{
DrawFrame();
}
void Window_Resume(object sender, EventArgs e)
{
clock.Resume();
}
void Window_Suspend(object sender, EventArgs e)
{
clock.Suspend();
}
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Diagnostics;
namespace SampleFramework
{
class GameClock
{
long baseRealTime;
long lastRealTime;
bool lastRealTimeValid;
int suspendCount;
long suspendStartTime;
long timeLostToSuspension;
TimeSpan currentTimeBase;
TimeSpan currentTimeOffset;
public TimeSpan CurrentTime
{
get { return currentTimeBase + currentTimeOffset; }
}
public TimeSpan ElapsedTime
{
get;
private set;
}
public TimeSpan ElapsedAdjustedTime
{
get;
private set;
}
public static long Frequency
{
get { return Stopwatch.Frequency; }
}
public GameClock()
{
Reset();
}
public void Reset()
{
currentTimeBase = TimeSpan.Zero;
currentTimeOffset = TimeSpan.Zero;
baseRealTime = Stopwatch.GetTimestamp();
lastRealTimeValid = false;
}
public void Suspend()
{
suspendCount++;
if (suspendCount == 1)
suspendStartTime = Stopwatch.GetTimestamp();
}
/// <summary>
/// Resumes a previously suspended clock.
/// </summary>
public void Resume()
{
suspendCount--;
if (suspendCount <= 0)
{
timeLostToSuspension += Stopwatch.GetTimestamp() - suspendStartTime;
suspendStartTime = 0;
}
}
public void Step()
{
long counter = Stopwatch.GetTimestamp();
if (!lastRealTimeValid)
{
lastRealTime = counter;
lastRealTimeValid = true;
}
try
{
currentTimeOffset = CounterToTimeSpan(counter - baseRealTime);
}
catch (OverflowException)
{
// update the base value and try again to adjust for overflow
currentTimeBase += currentTimeOffset;
baseRealTime = lastRealTime;
try
{
// get the current offset
currentTimeOffset = CounterToTimeSpan(counter - baseRealTime);
}
catch (OverflowException)
{
// account for overflow
baseRealTime = counter;
currentTimeOffset = TimeSpan.Zero;
}
}
try
{
ElapsedTime = CounterToTimeSpan(counter - lastRealTime);
}
catch (OverflowException)
{
ElapsedTime = TimeSpan.Zero;
}
try
{
ElapsedAdjustedTime = CounterToTimeSpan(counter - (lastRealTime + timeLostToSuspension));
timeLostToSuspension = 0;
}
catch (OverflowException)
{
ElapsedAdjustedTime = TimeSpan.Zero;
}
lastRealTime = counter;
}
static TimeSpan CounterToTimeSpan(long delta)
{
return TimeSpan.FromTicks((delta * 10000000) / Frequency);
}
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace SampleFramework
{
/// <summary>
/// Contains the current timing state of the game.
/// </summary>
public class GameTime
{
private float m_FramesPerSecond;
/// <summary>
/// Gets the current frames-per-second measure.
/// </summary>
/// <value>The current frames-per-second measure.</value>
public float FramesPerSecond
{
get { return m_FramesPerSecond; }
internal set { m_FramesPerSecond = value; }
}
private float m_ElapsedGameTime;
/// <summary>
/// Gets the elapsed game time, in seconds.
/// </summary>
/// <value>The elapsed game time.</value>
public float ElapsedGameTime
{
get { return m_ElapsedGameTime; }
internal set { m_ElapsedGameTime = value; }
}
private float m_ElapsedRealTime;
/// <summary>
/// Gets the elapsed real time, in seconds.
/// </summary>
/// <value>The elapsed real time.</value>
public float ElapsedRealTime
{
get { return m_ElapsedRealTime; }
internal set { m_ElapsedRealTime = value; }
}
private float m_TotalGameTime;
/// <summary>
/// Gets the total game time, in seconds.
/// </summary>
/// <value>The total game time.</value>
public float TotalGameTime
{
get { return m_TotalGameTime; }
internal set { m_TotalGameTime = value; }
}
private float m_TotalRealTime;
/// <summary>
/// Gets the total real time, in seconds.
/// </summary>
/// <value>The total real time.</value>
public float TotalRealTime
{
get { return m_TotalRealTime; }
internal set { m_TotalRealTime = value; }
}
private bool m_IsRunningSlowly;
/// <summary>
/// Gets or sets a value indicating whether this instance is running slowly.
/// </summary>
/// <value>
/// <c>true</c> if this instance is running slowly; otherwise, <c>false</c>.
/// </value>
public bool IsRunningSlowly
{
get { return m_IsRunningSlowly; }
internal set { m_IsRunningSlowly = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="GameTime"/> class.
/// </summary>
public GameTime()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GameTime"/> class.
/// </summary>
/// <param name="totalRealTime">The total real time.</param>
/// <param name="elapsedRealTime">The elapsed real time.</param>
/// <param name="totalGameTime">The total game time.</param>
/// <param name="elapsedGameTime">The elapsed game time.</param>
public GameTime(float totalRealTime, float elapsedRealTime, float totalGameTime, float elapsedGameTime)
{
TotalRealTime = totalRealTime;
ElapsedRealTime = elapsedRealTime;
TotalGameTime = totalGameTime;
ElapsedGameTime = elapsedGameTime;
}
}
}

View File

@ -0,0 +1,634 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using SampleFramework.Properties;
namespace SampleFramework
{
/// <summary>
/// Implements a specialized window for games and rendering.
/// </summary>
public class GameWindow : Form
{
const int DefaultWidth = 800;
const int DefaultHeight = 600;
const string DefaultTitle = "Game";
Size cachedSize;
bool minimized;
bool maximized;
bool inSizeMove;
/// <summary>
/// Occurs when the application is suspended.
/// </summary>
public event EventHandler Suspend;
/// <summary>
/// Occurs when the application is resumed.
/// </summary>
public event EventHandler Resume;
/// <summary>
/// Occurs when the user resizes the window.
/// </summary>
public event EventHandler UserResized;
/// <summary>
/// Occurs when the screen on which the window resides is changed.
/// </summary>
public event EventHandler ScreenChanged;
/// <summary>
/// Occurs when the application is activated.
/// </summary>
public event EventHandler ApplicationActivated;
/// <summary>
/// Occurs when the application is deactivated.
/// </summary>
public event EventHandler ApplicationDeactivated;
/// <summary>
/// Occurs when the system is suspended.
/// </summary>
public event EventHandler SystemSuspend;
/// <summary>
/// Occurs when the system is resumed.
/// </summary>
public event EventHandler SystemResume;
/// <summary>
/// Occurs when a screen saver is about to be activated.
/// </summary>
public event CancelEventHandler Screensaver;
/// <summary>
/// Gets a value indicating whether this instance is minimized.
/// </summary>
/// <value>
/// <c>true</c> if this instance is minimized; otherwise, <c>false</c>.
/// </value>
public bool IsMinimized
{
get { return minimized; }
}
/// <summary>
/// Gets a value indicating whether this instance is maximized.
/// </summary>
/// <value>
/// <c>true</c> if this instance is maximized; otherwise, <c>false</c>.
/// </value>
public bool IsMaximized
{
get { return maximized; }
}
/// <summary>
/// Gets or sets a value indicating whether System Menu is enabled.
/// </summary>
/// <value><c>true</c> if System Menu is enabled; otherwise, <c>false</c>.</value>
public bool EnableSystemMenu // #28200 2012.5.1 yyagi
{
get;
set;
}
public string strMessage // #28821 2014.1.23 yyagi
{
get;
private set;
}
public bool IsReceivedMessage
{
get;
set;
}
private Screen m_Screen;
/// <summary>
/// Gets the screen on which the window resides.
/// </summary>
/// <value>The screen.</value>
public Screen Screen
{
get { return m_Screen; }
private set { m_Screen = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="GameWindow"/> class.
/// </summary>
public GameWindow()
{
MinimumSize = new Size(200, 200);
Screen = ScreenFromHandle(Handle);
//Icon = GetDefaultIcon();
Text = GetDefaultTitle();
strMessage = "";
}
/// <summary>
/// Raises the <see cref="E:Suspend"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnSuspend(EventArgs e)
{
if (Suspend != null)
Suspend(this, e);
}
/// <summary>
/// Raises the <see cref="E:Resume"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnResume(EventArgs e)
{
if (Resume != null)
Resume(this, e);
}
/// <summary>
/// Raises the <see cref="E:UserResized"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnUserResized(EventArgs e)
{
if (UserResized != null)
UserResized(this, e);
}
/// <summary>
/// Raises the <see cref="E:ScreenChanged"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnScreenChanged(EventArgs e)
{
if (ScreenChanged != null)
ScreenChanged(this, e);
}
/// <summary>
/// Raises the <see cref="E:ApplicationActivated"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnApplicationActivated(EventArgs e)
{
if (ApplicationActivated != null)
ApplicationActivated(this, e);
}
/// <summary>
/// Raises the <see cref="E:ApplicationDeactivated"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnApplicationDeactivated(EventArgs e)
{
if (ApplicationDeactivated != null)
ApplicationDeactivated(this, e);
}
/// <summary>
/// Raises the <see cref="E:SystemSuspend"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnSystemSuspend(EventArgs e)
{
if (SystemSuspend != null)
SystemSuspend(this, e);
}
/// <summary>
/// Raises the <see cref="E:SystemResume"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void OnSystemResume(EventArgs e)
{
if (SystemResume != null)
SystemResume(this, e);
}
/// <summary>
/// Raises the <see cref="E:Screensaver"/> event.
/// </summary>
/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
protected virtual void OnScreensaver(CancelEventArgs e)
{
if (Screensaver != null)
Screensaver(this, e);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Form.Load"/> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
cachedSize = Size;
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Form.ResizeBegin"/> event.
/// </summary>
/// <param name="e">A <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnResizeBegin(EventArgs e)
{
base.OnResizeBegin(e);
// suspend any processing until we are done being minimized
inSizeMove = true;
cachedSize = Size;
OnSuspend(EventArgs.Empty);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Form.ResizeEnd"/> event.
/// </summary>
/// <param name="e">A <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnResizeEnd(EventArgs e)
{
base.OnResizeEnd(e);
// check for screen and size changes
OnUserResized(EventArgs.Empty);
UpdateScreen();
inSizeMove = false;
// resume application processing
OnResume(EventArgs.Empty);
}
#region #23510 2010.11.14 yyagi add: from http://www.vcskicks.com/maintain-aspect-ratio.php
//double so division keeps decimal points
const double widthRatio = SampleFramework.GameWindowSize.Width;
const double heightRatio = SampleFramework.GameWindowSize.Height;
const int WM_SIZING = 0x214;
const int WMSZ_LEFT = 1;
const int WMSZ_RIGHT = 2;
const int WMSZ_TOP = 3;
const int WMSZ_TOPLEFT = 4;
const int WMSZ_TOPRIGHT = 5;
const int WMSZ_BOTTOM = 6;
const int WMSZ_BOTTOMLEFT = 7;
const int WMSZ_BOTTOMRIGHT = 8;
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
#endregion
/// <summary>
/// Handles raw window messages.
/// </summary>
/// <param name="m">The raw message.</param>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
if (m.Msg == WindowConstants.WM_SIZE)
{
if (m.WParam == WindowConstants.SIZE_MINIMIZED)
{
minimized = true;
maximized = false;
OnSuspend(EventArgs.Empty);
}
else
{
Rectangle client = NativeMethods.GetClientRectangle(m.HWnd);
if (client.Height == 0)
{
// rapidly clicking the task bar to minimize and restore a window
// can cause a WM_SIZE message with SIZE_RESTORED when
// the window has actually become minimized due to rapid change
// so just ignore this message
}
else if (m.WParam == WindowConstants.SIZE_MAXIMIZED)
{
if (minimized)
OnResume(EventArgs.Empty);
minimized = false;
maximized = true;
OnUserResized(EventArgs.Empty);
UpdateScreen();
}
else if (m.WParam == WindowConstants.SIZE_RESTORED)
{
if (minimized)
OnResume(EventArgs.Empty);
minimized = false;
maximized = false;
if (!inSizeMove && Size != cachedSize)
{
OnUserResized(EventArgs.Empty);
UpdateScreen();
cachedSize = Size;
}
}
}
}
else if (m.Msg == WindowConstants.WM_ACTIVATEAPP)
{
if (m.WParam != IntPtr.Zero)
OnApplicationActivated(EventArgs.Empty);
else
OnApplicationDeactivated(EventArgs.Empty);
}
else if (m.Msg == WindowConstants.WM_POWERBROADCAST)
{
if (m.WParam == WindowConstants.PBT_APMQUERYSUSPEND)
{
OnSystemSuspend(EventArgs.Empty);
m.Result = (IntPtr)1;
return;
}
else if (m.WParam == WindowConstants.PBT_APMRESUMESUSPEND)
{
OnSystemResume(EventArgs.Empty);
m.Result = (IntPtr)1;
return;
}
}
else if (m.Msg == WindowConstants.WM_SYSCOMMAND)
{
long wparam = m.WParam.ToInt64() & 0xFFF0;
if (wparam == WindowConstants.SC_MONITORPOWER || wparam == WindowConstants.SC_SCREENSAVE)
{
CancelEventArgs e = new CancelEventArgs();
OnScreensaver(e);
if (e.Cancel)
{
m.Result = IntPtr.Zero;
return;
}
}
#region #28200 2012.5.1 yyagi: Disable system menu
if ( ( m.WParam.ToInt32() & 0xFFFF ) == 0xF100 && !EnableSystemMenu ) // SC_KEYMENU
{
m.Result = IntPtr.Zero;
return;
}
#endregion
#region #23510 2010.11.13 yyagi: reset to 640x480
if ((m.WParam.ToInt32() & 0xFFFF) == MENU_VIEW)
{
base.ClientSize = new Size(SampleFramework.GameWindowSize.Width, SampleFramework.GameWindowSize.Height);
this.OnResizeEnd(new EventArgs()); // #23510 2010.11.20 yyagi: to set window size to Config.ini
}
#endregion
}
#region #28821 2014.1.23 yyagi (WM_COPYDATA)
else if ( m.Msg == WindowConstants.WM_COPYDATA )
{
//Trace.WriteLine( "FDK;msg received" );
COPYDATASTRUCT cds = (COPYDATASTRUCT) Marshal.PtrToStructure( m.LParam, typeof( COPYDATASTRUCT ) );
strMessage = Marshal.PtrToStringUni( cds.lpData );
IsReceivedMessage = true;
//Trace.WriteLine( "FDK;msg=" + strMessage + ", len=" + strMessage.Length + ", truelen=" + cds.cbData );
}
#endregion
#region #23510 2010.11.16 yyagi add: from http://d.hatena.ne.jp/iselix/20080917/1221666614 http://hp.vector.co.jp/authors/VA016117/sizing.html
else if ( m.Msg == WM_SIZING )
{
RECT rc = (RECT) Marshal.PtrToStructure( m.LParam, typeof( RECT ) );
int w = rc.Right - rc.Left - ( Size.Width - ClientSize.Width );
int h = rc.Bottom - rc.Top - ( Size.Height - ClientSize.Height );
int dw = (int) ( h * widthRatio / heightRatio + 0.5 ) - w;
int dh = (int) ( w / ( widthRatio / heightRatio ) + 0.5 ) - h;
switch ( m.WParam.ToInt32() )
{
case WMSZ_LEFT:
case WMSZ_RIGHT:
rc.Bottom += dh;
break;
case WMSZ_TOP:
case WMSZ_BOTTOM:
rc.Right += dw;
break;
case WMSZ_BOTTOMRIGHT:
if ( dw > 0 )
{
rc.Right += dw;
}
else
{
rc.Bottom += dh;
}
break;
case WMSZ_TOPLEFT:
if ( dw > 0 )
{
rc.Left -= dw;
}
else
{
rc.Top -= dh;
}
break;
case WMSZ_TOPRIGHT:
if ( dw > 0 )
{
rc.Right += dw;
}
else
{
rc.Top -= dh;
}
break;
case WMSZ_BOTTOMLEFT:
if ( dw > 0 )
{
rc.Left -= dw;
}
else
{
rc.Bottom += dh;
}
break;
case 9: // #32383 2013.11.2 yyagi; exitting maximized window by using Aero snap
break;
default:
throw new ArgumentOutOfRangeException( "value", "Illegal WM_SIZING value." );
}
Marshal.StructureToPtr( rc, m.LParam, true );
}
#endregion
base.WndProc(ref m);
}
void UpdateScreen()
{
Screen current = Screen.FromHandle(Handle);
if (Screen == null || Screen.DeviceName != current.DeviceName)
{
Screen = current;
if (Screen != null)
OnScreenChanged(EventArgs.Empty);
}
}
static Screen ScreenFromHandle(IntPtr windowHandle)
{
Rectangle rectangle = NativeMethods.GetWindowRectangle(windowHandle);
Screen bestScreen = null;
int mostArea = 0;
foreach (Screen screen in Screen.AllScreens)
{
Rectangle r = Rectangle.Intersect(rectangle, screen.Bounds);
int area = r.Width * r.Height;
if (area > mostArea)
{
mostArea = area;
bestScreen = screen;
}
}
if (bestScreen == null)
bestScreen = Screen.PrimaryScreen;
return bestScreen;
}
static string GetAssemblyTitle(Assembly assembly)
{
if (assembly == null)
return null;
AssemblyTitleAttribute[] customAttributes = (AssemblyTitleAttribute[])assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), true);
if (customAttributes != null && customAttributes.Length > 0)
return customAttributes[0].Title;
return null;
}
static string GetDefaultTitle()
{
string assemblyTitle = GetAssemblyTitle(Assembly.GetEntryAssembly());
if (!string.IsNullOrEmpty(assemblyTitle))
return assemblyTitle;
try
{
Uri uri = new Uri(Application.ExecutablePath);
return Path.GetFileNameWithoutExtension(uri.LocalPath);
}
catch (ArgumentNullException e)
{
Trace.TraceError( e.ToString() );
Trace.TraceError( "例外が発生しましたが処理を継続します。 (6216f3e1-e1a5-45ca-bfd8-30bbc44bfa9a)" );
}
catch (UriFormatException e)
{
Trace.TraceError( e.ToString() );
Trace.TraceError( "例外が発生しましたが処理を継続します。 (771f37b5-0b56-4a47-933e-3c178b3e27a7)" );
}
return DefaultTitle;
}
static Icon GetDefaultIcon()
{
return (Icon)Resources.sdx_icon_black.Clone();
}
#region "640x480" #23510 2010.11.13 yyagi add: to set "640x480" menu in systemmenu. See also http://cs2ch.blog123.fc2.com/blog-entry-80.html
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct MENUITEMINFO
{
public uint cbSize;
public uint fMask;
public uint fType;
public uint fState;
public uint wID;
public IntPtr hSubMenu;
public IntPtr hbmpChecked;
public IntPtr hbmpUnchecked;
public IntPtr dwItemData;
public string dwTypeData;
public uint cch;
public IntPtr hbmpItem;
}
[DllImport("user32", ExactSpelling = true)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern bool InsertMenuItem(IntPtr hMenu, uint uItem, bool fByPosition, ref MENUITEMINFO lpmii);
private const uint MENU_VIEW = 0x9999;
private const uint MFT_SEPARATOR = 0x00000800;
private const uint MIIM_FTYPE = 0x00000100;
private const uint MIIM_STRING = 0x00000040;
private const uint MIIM_ID = 0x00000002;
protected override void OnCreateControl()
{
base.OnCreateControl();
//システムメニューのハンドル取得
IntPtr hSysMenu = GetSystemMenu(this.Handle, false);
//セパレーターの挿入
MENUITEMINFO item1 = new MENUITEMINFO();
item1.cbSize = (uint)Marshal.SizeOf(item1);
item1.fMask = MIIM_FTYPE;
item1.fType = MFT_SEPARATOR;
InsertMenuItem(hSysMenu, 5, true, ref item1);
//メニュー項目の挿入
MENUITEMINFO item2 = new MENUITEMINFO();
item2.cbSize = (uint)Marshal.SizeOf(item2);
item2.fMask = MIIM_STRING | MIIM_ID;
item2.wID = MENU_VIEW;
item2.dwTypeData = "&" + SampleFramework.GameWindowSize.Width.ToString() + "x" + SampleFramework.GameWindowSize.Height.ToString();
InsertMenuItem(hSysMenu, 6, true, ref item2);
}
#endregion
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

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

View File

@ -0,0 +1,204 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using SlimDX;
using SlimDX.Direct3D9;
using DXGI = SlimDX.DXGI;
namespace SampleFramework
{
static class ConversionMethods
{
public static int GetDepthBits(Format format)
{
switch (format)
{
case Format.D32SingleLockable:
case Format.D32:
return 32;
case Format.D24X8:
case Format.D24S8:
case Format.D24X4S4:
case Format.D24SingleS8:
return 24;
case Format.D16Lockable:
case Format.D16:
return 16;
case Format.D15S1:
return 15;
default:
return 0;
}
}
public static int GetStencilBits(Format format)
{
switch (format)
{
case Format.D15S1:
return 1;
case Format.D24X4S4:
return 4;
case Format.D24S8:
case Format.D24SingleS8:
return 8;
default:
return 0;
}
}
public static int GetColorBits(Format format)
{
switch (format)
{
case Format.R8G8B8:
case Format.A8R8G8B8:
case Format.A8B8G8R8:
case Format.X8R8G8B8:
return 8;
case Format.R5G6B5:
case Format.X1R5G5B5:
case Format.A1R5G5B5:
return 5;
case Format.A4R4G4B4:
case Format.X4R4G4B4:
return 4;
case Format.R3G3B2:
case Format.A8R3G3B2:
return 2;
case Format.A2R10G10B10:
case Format.A2B10G10R10:
return 10;
case Format.A16B16G16R16:
return 16;
default:
return 0;
}
}
public static int GetColorBits(DXGI.Format format)
{
switch (format)
{
case SlimDX.DXGI.Format.R32G32B32A32_Float:
case SlimDX.DXGI.Format.R32G32B32A32_SInt:
case SlimDX.DXGI.Format.R32G32B32A32_Typeless:
case SlimDX.DXGI.Format.R32G32B32A32_UInt:
case SlimDX.DXGI.Format.R32G32B32_Float:
case SlimDX.DXGI.Format.R32G32B32_SInt:
case SlimDX.DXGI.Format.R32G32B32_Typeless:
case SlimDX.DXGI.Format.R32G32B32_UInt:
return 32;
case SlimDX.DXGI.Format.R16G16B16A16_Float:
case SlimDX.DXGI.Format.R16G16B16A16_SInt:
case SlimDX.DXGI.Format.R16G16B16A16_SNorm:
case SlimDX.DXGI.Format.R16G16B16A16_Typeless:
case SlimDX.DXGI.Format.R16G16B16A16_UInt:
case SlimDX.DXGI.Format.R16G16B16A16_UNorm:
return 16;
case SlimDX.DXGI.Format.R10G10B10A2_Typeless:
case SlimDX.DXGI.Format.R10G10B10A2_UInt:
case SlimDX.DXGI.Format.R10G10B10A2_UNorm:
return 10;
case SlimDX.DXGI.Format.R8G8B8A8_SInt:
case SlimDX.DXGI.Format.R8G8B8A8_SNorm:
case SlimDX.DXGI.Format.R8G8B8A8_Typeless:
case SlimDX.DXGI.Format.R8G8B8A8_UInt:
case SlimDX.DXGI.Format.R8G8B8A8_UNorm:
case SlimDX.DXGI.Format.R8G8B8A8_UNorm_SRGB:
return 8;
case SlimDX.DXGI.Format.B5G5R5A1_UNorm:
case SlimDX.DXGI.Format.B5G6R5_UNorm:
return 5;
default:
return 0;
}
}
public static MultisampleType ToDirect3D9(int type)
{
return (MultisampleType)type;
}
public static Format ToDirect3D9(DXGI.Format format)
{
switch (format)
{
case SlimDX.DXGI.Format.R8G8B8A8_UNorm:
return Format.A8R8G8B8;
case SlimDX.DXGI.Format.B5G6R5_UNorm:
return Format.R5G6B5;
case SlimDX.DXGI.Format.B5G5R5A1_UNorm:
return Format.A1R5G5B5;
case SlimDX.DXGI.Format.A8_UNorm:
return Format.A8;
case SlimDX.DXGI.Format.R10G10B10A2_UNorm:
return Format.A2B10G10R10;
case SlimDX.DXGI.Format.B8G8R8A8_UNorm:
return Format.A8B8G8R8;
case SlimDX.DXGI.Format.R16G16_UNorm:
return Format.G16R16;
case SlimDX.DXGI.Format.R16G16B16A16_UNorm:
return Format.A16B16G16R16;
case SlimDX.DXGI.Format.R16_Float:
return Format.R16F;
case SlimDX.DXGI.Format.R16G16_Float:
return Format.G16R16F;
case SlimDX.DXGI.Format.R16G16B16A16_Float:
return Format.A16B16G16R16F;
case SlimDX.DXGI.Format.R32_Float:
return Format.R32F;
case SlimDX.DXGI.Format.R32G32_Float:
return Format.G32R32F;
case SlimDX.DXGI.Format.R32G32B32A32_Float:
return Format.A32B32G32R32F;
}
return Format.Unknown;
}
public static float ToFloat(Rational rational)
{
float denom = 1;
if (rational.Denominator != 0)
denom = rational.Denominator;
return rational.Numerator / denom;
}
}
}

View File

@ -0,0 +1,285 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using SlimDX.Direct3D9;
namespace SampleFramework
{
/// <summary>
/// Contains settings for creating a 3D device.
/// </summary>
public class DeviceSettings : ICloneable
{
/// <summary>
/// Gets or sets the adapter ordinal.
/// </summary>
/// <value>The adapter ordinal.</value>
public int AdapterOrdinal
{
get;
set;
}
/// <summary>
/// Gets or sets the type of the device.
/// </summary>
/// <value>The type of the device.</value>
public DeviceType DeviceType
{
get;
set;
}
/// <summary>
/// Gets or sets the refresh rate.
/// </summary>
/// <value>The refresh rate.</value>
public int RefreshRate
{
get;
set;
}
/// <summary>
/// Gets or sets the width of the back buffer.
/// </summary>
/// <value>The width of the back buffer.</value>
public int BackBufferWidth
{
get;
set;
}
/// <summary>
/// Gets or sets the height of the back buffer.
/// </summary>
/// <value>The height of the back buffer.</value>
public int BackBufferHeight
{
get;
set;
}
/// <summary>
/// Gets or sets the back buffer format.
/// </summary>
/// <value>The back buffer format.</value>
public Format BackBufferFormat
{
get;
set;
}
/// <summary>
/// Gets or sets the back buffer count.
/// </summary>
/// <value>The back buffer count.</value>
public int BackBufferCount
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether the device is windowed.
/// </summary>
/// <value><c>true</c> if windowed; otherwise, <c>false</c>.</value>
public bool Windowed
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether VSync is enabled.
/// </summary>
/// <value><c>true</c> if VSync is enabled; otherwise, <c>false</c>.</value>
public bool EnableVSync
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="DeviceSettings"/> is multithreaded.
/// </summary>
/// <value><c>true</c> if multithreaded; otherwise, <c>false</c>.</value>
/// <remarks>This only has an effect for Direct3D9 devices.</remarks>
public bool Multithreaded
{
get;
set;
}
/// <summary>
/// Gets or sets the multisample type.
/// </summary>
/// <value>The multisample type.</value>
public MultisampleType MultisampleType
{
get;
set;
}
/// <summary>
/// Gets or sets the multisample quality.
/// </summary>
/// <value>The multisample quality.</value>
public int MultisampleQuality
{
get;
set;
}
/// <summary>
/// Gets or sets the depth stencil format.
/// </summary>
/// <value>The depth stencil format.</value>
public Format DepthStencilFormat
{
get;
set;
}
/// <summary>
/// Gets or sets the Direct3D9 specific settings.
/// </summary>
/// <value>The Direct3D9 specific settings.</value>
internal Direct3D9Settings Direct3D9
{
get;
set;
}
/// <summary>
/// Initializes a new instance of the <see cref="DeviceSettings"/> class.
/// </summary>
public DeviceSettings()
{
// set sane defaults
DeviceType = DeviceType.Hardware;
BackBufferFormat = Format.Unknown;
BackBufferCount = 1;
MultisampleType = MultisampleType.None;
DepthStencilFormat = Format.Unknown;
Windowed = true;
EnableVSync = true;
}
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public DeviceSettings Clone()
{
DeviceSettings result = new DeviceSettings();
result.DeviceType = DeviceType;
result.RefreshRate = RefreshRate;
result.BackBufferCount = BackBufferCount;
result.BackBufferFormat = BackBufferFormat;
result.BackBufferHeight = BackBufferHeight;
result.BackBufferWidth = BackBufferWidth;
result.DepthStencilFormat = DepthStencilFormat;
result.MultisampleQuality = MultisampleQuality;
result.MultisampleType = MultisampleType;
result.Windowed = Windowed;
result.EnableVSync = EnableVSync;
result.AdapterOrdinal = AdapterOrdinal;
result.Multithreaded = Multithreaded;
if (Direct3D9 != null)
result.Direct3D9 = Direct3D9.Clone();
return result;
}
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
object ICloneable.Clone()
{
return Clone();
}
/// <summary>
/// Finds valid device settings based upon the desired settings.
/// </summary>
/// <param name="settings">The desired settings.</param>
/// <returns>The best valid device settings matching the input settings.</returns>
public static DeviceSettings FindValidSettings( DeviceSettings settings )
{
try
{
GraphicsDeviceManager.EnsureD3D9();
}
catch( Exception e )
{
throw new NoCompatibleDevicesException( "Could not initialize Direct3D9.", e );
}
if( !Enumeration9.HasEnumerated )
Enumeration9.Enumerate();
DeviceSettings newSettings = settings.Clone();
Direct3D9Settings d3d9 = FindValidD3D9Settings( settings );
newSettings.Direct3D9 = d3d9;
return newSettings;
}
static Direct3D9Settings FindValidD3D9Settings(DeviceSettings settings)
{
Direct3D9Settings optimal = Direct3D9Settings.BuildOptimalSettings(settings);
SettingsCombo9 bestCombo = null;
float bestRanking = -1.0f;
foreach (AdapterInfo9 adapterInfo in Enumeration9.Adapters)
{
DisplayMode desktopMode = GraphicsDeviceManager.Direct3D9Object.GetAdapterDisplayMode(adapterInfo.AdapterOrdinal);
foreach (DeviceInfo9 deviceInfo in adapterInfo.Devices)
{
foreach (SettingsCombo9 combo in deviceInfo.DeviceSettings)
{
if (combo.Windowed && combo.AdapterFormat != desktopMode.Format)
continue;
float ranking = Direct3D9Settings.RankSettingsCombo(combo, optimal, desktopMode);
if (ranking > bestRanking)
{
bestCombo = combo;
bestRanking = ranking;
}
}
}
}
if (bestCombo == null)
throw new NoCompatibleDevicesException("No compatible Direct3D9 devices found.");
return Direct3D9Settings.BuildValidSettings(bestCombo, optimal);
}
}
}

View File

@ -0,0 +1,440 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using SlimDX.Direct3D9;
namespace SampleFramework
{
class Direct3D9Settings : ICloneable
{
public int AdapterOrdinal
{
get;
set;
}
public DeviceType DeviceType
{
get;
set;
}
public Format AdapterFormat
{
get;
set;
}
public CreateFlags CreationFlags
{
get;
set;
}
public PresentParameters PresentParameters
{
get;
private set;
}
public Direct3D9Settings()
{
PresentParameters = new PresentParameters();
DeviceType = DeviceType.Hardware;
PresentParameters.Windowed = true;
AdapterFormat = Format.Unknown;
CreationFlags = CreateFlags.HardwareVertexProcessing;
PresentParameters.BackBufferFormat = Format.Unknown;
PresentParameters.BackBufferCount = 1;
PresentParameters.Multisample = MultisampleType.None;
PresentParameters.SwapEffect = SwapEffect.Discard;
PresentParameters.EnableAutoDepthStencil = true;
PresentParameters.AutoDepthStencilFormat = Format.Unknown;
PresentParameters.PresentFlags = PresentFlags.DiscardDepthStencil;
PresentParameters.PresentationInterval = PresentInterval.Default;
}
public Direct3D9Settings Clone()
{
Direct3D9Settings clone = new Direct3D9Settings();
clone.AdapterFormat = AdapterFormat;
clone.AdapterOrdinal = AdapterOrdinal;
clone.CreationFlags = CreationFlags;
clone.DeviceType = DeviceType;
clone.PresentParameters = PresentParameters.Clone();
return clone;
}
object ICloneable.Clone()
{
return Clone();
}
public static Direct3D9Settings BuildOptimalSettings(DeviceSettings settings)
{
DisplayMode desktopMode = GraphicsDeviceManager.Direct3D9Object.GetAdapterDisplayMode(0);
Direct3D9Settings optimal = new Direct3D9Settings();
optimal.AdapterOrdinal = settings.AdapterOrdinal;
optimal.DeviceType = settings.DeviceType;
optimal.PresentParameters.Windowed = settings.Windowed;
optimal.PresentParameters.BackBufferCount = settings.BackBufferCount;
optimal.PresentParameters.Multisample = settings.MultisampleType;
optimal.PresentParameters.MultisampleQuality = settings.MultisampleQuality;
optimal.PresentParameters.FullScreenRefreshRateInHertz = settings.RefreshRate;
if(settings.Multithreaded)
optimal.CreationFlags |= CreateFlags.Multithreaded;
if(optimal.PresentParameters.Windowed || ConversionMethods.GetColorBits(desktopMode.Format) >= 8)
optimal.AdapterFormat = desktopMode.Format;
else
optimal.AdapterFormat = Format.X8R8G8B8;
if(settings.BackBufferWidth == 0 || settings.BackBufferHeight == 0)
{
if(optimal.PresentParameters.Windowed)
{
optimal.PresentParameters.BackBufferWidth = 640;
optimal.PresentParameters.BackBufferHeight = 480;
}
else
{
optimal.PresentParameters.BackBufferWidth = desktopMode.Width;
optimal.PresentParameters.BackBufferHeight = desktopMode.Height;
}
}
else
{
optimal.PresentParameters.BackBufferWidth = settings.BackBufferWidth;
optimal.PresentParameters.BackBufferHeight = settings.BackBufferHeight;
}
if(settings.BackBufferFormat == Format.Unknown)
optimal.PresentParameters.BackBufferFormat = optimal.AdapterFormat;
else
optimal.PresentParameters.BackBufferFormat = settings.BackBufferFormat;
if(settings.DepthStencilFormat == Format.Unknown)
{
if(ConversionMethods.GetColorBits(optimal.PresentParameters.BackBufferFormat) >= 8)
optimal.PresentParameters.AutoDepthStencilFormat = Format.D32;
else
optimal.PresentParameters.AutoDepthStencilFormat = Format.D16;
}
else
optimal.PresentParameters.AutoDepthStencilFormat = settings.DepthStencilFormat;
if(!settings.EnableVSync)
optimal.PresentParameters.PresentationInterval = PresentInterval.Immediate;
return optimal;
}
public static float RankSettingsCombo(SettingsCombo9 combo, Direct3D9Settings optimal, DisplayMode desktopMode)
{
float ranking = 0.0f;
if(combo.AdapterOrdinal == optimal.AdapterOrdinal)
ranking += 1000.0f;
if(combo.DeviceType == optimal.DeviceType)
ranking += 100.0f;
if(combo.DeviceType == DeviceType.Hardware)
ranking += 0.1f;
if(combo.Windowed == optimal.PresentParameters.Windowed)
ranking += 10.0f;
if(combo.AdapterFormat == optimal.AdapterFormat)
ranking += 1.0f;
else
{
int bitDepthDelta = Math.Abs(ConversionMethods.GetColorBits(combo.AdapterFormat) -
ConversionMethods.GetColorBits(optimal.AdapterFormat));
float scale = Math.Max(0.9f - bitDepthDelta * 0.2f, 0.0f);
ranking += scale;
}
if(!combo.Windowed)
{
bool match;
if(ConversionMethods.GetColorBits(desktopMode.Format) >= 8)
match = (combo.AdapterFormat == desktopMode.Format);
else
match = (combo.AdapterFormat == Format.X8R8G8B8);
if(match)
ranking += 0.1f;
}
if((optimal.CreationFlags & CreateFlags.HardwareVertexProcessing) != 0 &&
(optimal.CreationFlags & CreateFlags.MixedVertexProcessing) != 0)
{
if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0)
ranking += 1.0f;
}
if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0)
ranking += 0.1f;
foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes)
{
if(displayMode.Format == combo.AdapterFormat &&
displayMode.Width == optimal.PresentParameters.BackBufferWidth &&
displayMode.Height == optimal.PresentParameters.BackBufferHeight)
{
ranking += 1.0f;
break;
}
}
if(combo.BackBufferFormat == optimal.PresentParameters.BackBufferFormat)
ranking += 1.0f;
else
{
int bitDepthDelta = Math.Abs(ConversionMethods.GetColorBits(combo.BackBufferFormat) -
ConversionMethods.GetColorBits(optimal.PresentParameters.BackBufferFormat));
float scale = Math.Max(0.9f - bitDepthDelta * 0.2f, 0.0f);
ranking += scale;
}
if(combo.BackBufferFormat == combo.AdapterFormat)
ranking += 0.1f;
for(int i = 0; i < combo.MultisampleTypes.Count; i++)
{
MultisampleType type = combo.MultisampleTypes[i];
int quality = combo.MultisampleQualities[i];
if(type == optimal.PresentParameters.Multisample && quality == optimal.PresentParameters.MultisampleQuality)
{
ranking += 1.0f;
break;
}
}
if(combo.DepthStencilFormats.Contains(optimal.PresentParameters.AutoDepthStencilFormat))
ranking += 1.0f;
foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes)
{
if(displayMode.Format == combo.AdapterFormat &&
displayMode.RefreshRate == optimal.PresentParameters.FullScreenRefreshRateInHertz)
{
ranking += 1.0f;
break;
}
}
if(combo.PresentIntervals.Contains(optimal.PresentParameters.PresentationInterval))
ranking += 1.0f;
return ranking;
}
public static Direct3D9Settings BuildValidSettings(SettingsCombo9 combo, Direct3D9Settings input)
{
Direct3D9Settings settings = new Direct3D9Settings();
settings.AdapterOrdinal = combo.AdapterOrdinal;
settings.DeviceType = combo.DeviceType;
settings.PresentParameters.Windowed = combo.Windowed;
settings.AdapterFormat = combo.AdapterFormat;
settings.PresentParameters.BackBufferFormat = combo.BackBufferFormat;
settings.PresentParameters.SwapEffect = input.PresentParameters.SwapEffect;
settings.PresentParameters.PresentFlags = input.PresentParameters.PresentFlags | PresentFlags.DiscardDepthStencil;
settings.CreationFlags = input.CreationFlags;
if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) == 0 &&
((settings.CreationFlags & CreateFlags.HardwareVertexProcessing) != 0 ||
(settings.CreationFlags & CreateFlags.MixedVertexProcessing) != 0))
{
settings.CreationFlags &= ~CreateFlags.HardwareVertexProcessing;
settings.CreationFlags &= ~CreateFlags.MixedVertexProcessing;
settings.CreationFlags |= CreateFlags.SoftwareVertexProcessing;
}
if((settings.CreationFlags & CreateFlags.HardwareVertexProcessing) == 0 &&
(settings.CreationFlags & CreateFlags.MixedVertexProcessing) == 0 &&
(settings.CreationFlags & CreateFlags.SoftwareVertexProcessing) == 0)
{
if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0)
settings.CreationFlags |= CreateFlags.HardwareVertexProcessing;
else
settings.CreationFlags |= CreateFlags.SoftwareVertexProcessing;
}
DisplayMode bestDisplayMode = FindValidResolution(combo, input);
settings.PresentParameters.BackBufferWidth = bestDisplayMode.Width;
settings.PresentParameters.BackBufferHeight = bestDisplayMode.Height;
settings.PresentParameters.BackBufferCount = input.PresentParameters.BackBufferCount;
if(settings.PresentParameters.BackBufferCount > 3)
settings.PresentParameters.BackBufferCount = 3;
if(settings.PresentParameters.BackBufferCount < 1)
settings.PresentParameters.BackBufferCount = 1;
if(input.PresentParameters.SwapEffect != SwapEffect.Discard)
{
settings.PresentParameters.Multisample = MultisampleType.None;
settings.PresentParameters.MultisampleQuality = 0;
}
else
{
MultisampleType bestType = MultisampleType.None;
int bestQuality = 0;
for(int i = 0; i < combo.MultisampleTypes.Count; i++)
{
MultisampleType type = combo.MultisampleTypes[i];
int quality = combo.MultisampleQualities[0];
if(Math.Abs(type - input.PresentParameters.Multisample) < Math.Abs(bestType -
input.PresentParameters.Multisample))
{
bestType = type;
bestQuality = Math.Min(quality - 1, input.PresentParameters.MultisampleQuality);
}
}
settings.PresentParameters.Multisample = bestType;
settings.PresentParameters.MultisampleQuality = bestQuality;
}
List<int> rankings = new List<int>();
int inputDepthBitDepth = ConversionMethods.GetDepthBits(input.PresentParameters.AutoDepthStencilFormat);
int inputStencilBitDepth = ConversionMethods.GetStencilBits(input.PresentParameters.AutoDepthStencilFormat);
foreach(Format format in combo.DepthStencilFormats)
{
int currentBitDepth = ConversionMethods.GetDepthBits(format);
int currentStencilDepth = ConversionMethods.GetStencilBits(format);
int ranking = Math.Abs(currentBitDepth - inputDepthBitDepth);
ranking += Math.Abs(currentStencilDepth - inputStencilBitDepth);
rankings.Add(ranking);
}
int bestRanking = int.MaxValue;
foreach(int ranking in rankings)
{
if(ranking < bestRanking)
bestRanking = ranking;
}
int bestIndex = rankings.IndexOf(bestRanking);
if(bestIndex >= 0)
{
settings.PresentParameters.AutoDepthStencilFormat = combo.DepthStencilFormats[bestIndex];
settings.PresentParameters.EnableAutoDepthStencil = true;
}
else
{
settings.PresentParameters.AutoDepthStencilFormat = Format.Unknown;
settings.PresentParameters.EnableAutoDepthStencil = false;
}
if(combo.Windowed)
settings.PresentParameters.FullScreenRefreshRateInHertz = 0;
else
{
int match = input.PresentParameters.FullScreenRefreshRateInHertz;
bestDisplayMode.RefreshRate = 0;
if(match != 0)
{
bestRanking = 100000;
foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes)
{
if(displayMode.Format != combo.AdapterFormat ||
displayMode.Width != bestDisplayMode.Width ||
displayMode.Height != bestDisplayMode.Height)
continue;
int ranking = Math.Abs(displayMode.RefreshRate - match);
if(ranking < bestRanking)
{
bestDisplayMode.RefreshRate = displayMode.RefreshRate;
bestRanking = ranking;
if(bestRanking == 0)
break;
}
}
}
settings.PresentParameters.FullScreenRefreshRateInHertz = bestDisplayMode.RefreshRate;
}
if(combo.PresentIntervals.Contains(input.PresentParameters.PresentationInterval))
settings.PresentParameters.PresentationInterval = input.PresentParameters.PresentationInterval;
else
settings.PresentParameters.PresentationInterval = PresentInterval.Default;
return settings;
}
static DisplayMode FindValidResolution(SettingsCombo9 combo, Direct3D9Settings input)
{
DisplayMode bestMode = new DisplayMode();
if(combo.Windowed)
{
bestMode.Width = input.PresentParameters.BackBufferWidth;
bestMode.Height = input.PresentParameters.BackBufferHeight;
return bestMode;
}
int bestRanking = 100000;
int ranking;
foreach(DisplayMode mode in combo.AdapterInfo.DisplayModes)
{
if(mode.Format != combo.AdapterFormat)
continue;
ranking = Math.Abs(mode.Width - input.PresentParameters.BackBufferWidth) +
Math.Abs(mode.Height - input.PresentParameters.BackBufferHeight);
if(ranking < bestRanking)
{
bestMode = mode;
bestRanking = ranking;
if(bestRanking == 0)
break;
}
}
if(bestMode.Width == 0)
{
bestMode.Width = input.PresentParameters.BackBufferWidth;
bestMode.Height = input.PresentParameters.BackBufferHeight;
}
return bestMode;
}
}
}

View File

@ -0,0 +1,447 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Collections.Generic;
using System.Globalization;
using SlimDX.Direct3D9;
namespace SampleFramework
{
class AdapterInfo9
{
public int AdapterOrdinal
{
get;
set;
}
public AdapterDetails Details
{
get;
set;
}
public string Description
{
get;
set;
}
public List<DisplayMode> DisplayModes
{
get;
private set;
}
public List<DeviceInfo9> Devices
{
get;
private set;
}
public AdapterInfo9()
{
// create lists
DisplayModes = new List<DisplayMode>();
Devices = new List<DeviceInfo9>();
}
}
class DeviceInfo9
{
public DeviceType DeviceType
{
get;
set;
}
public Capabilities Capabilities
{
get;
set;
}
public List<SettingsCombo9> DeviceSettings
{
get;
private set;
}
public DeviceInfo9()
{
DeviceSettings = new List<SettingsCombo9>();
}
}
class SettingsCombo9
{
public int AdapterOrdinal
{
get;
set;
}
public DeviceType DeviceType
{
get;
set;
}
public Format AdapterFormat
{
get;
set;
}
public Format BackBufferFormat
{
get;
set;
}
public bool Windowed
{
get;
set;
}
public List<Format> DepthStencilFormats
{
get;
internal set;
}
public List<MultisampleType> MultisampleTypes
{
get;
private set;
}
public List<int> MultisampleQualities
{
get;
private set;
}
public List<PresentInterval> PresentIntervals
{
get;
private set;
}
public AdapterInfo9 AdapterInfo
{
get;
set;
}
public DeviceInfo9 DeviceInfo
{
get;
set;
}
public SettingsCombo9()
{
DepthStencilFormats = new List<Format>();
MultisampleQualities = new List<int>();
MultisampleTypes = new List<MultisampleType>();
PresentIntervals = new List<PresentInterval>();
}
}
class DisplayModeComparer9 : IComparer<DisplayMode>
{
static DisplayModeComparer9 comparer = new DisplayModeComparer9();
public static DisplayModeComparer9 Comparer
{
get { return comparer; }
}
public DisplayModeComparer9()
{
}
public int Compare(DisplayMode x, DisplayMode y)
{
if (x.Width > y.Width)
return 1;
if (x.Width < y.Width)
return -1;
if (x.Height > y.Height)
return 1;
if (x.Height < y.Height)
return -1;
if (x.Format > y.Format)
return 1;
if (x.Format < y.Format)
return -1;
if (x.RefreshRate > y.RefreshRate)
return 1;
if (x.RefreshRate < y.RefreshRate)
return -1;
return 0;
}
}
static class Enumeration9
{
public static DeviceSettings MinimumSettings
{
get;
set;
}
public static List<AdapterInfo9> Adapters
{
get;
private set;
}
public static bool HasEnumerated
{
get;
private set;
}
public static void Enumerate()
{
HasEnumerated = true;
Adapters = new List<AdapterInfo9>();
List<Format> adapterFormats = new List<Format>();
Format[] allowedAdapterFormats = { Format.X8R8G8B8, Format.X1R5G5B5, Format.R5G6B5,
Format.A2R10G10B10 };
foreach (AdapterInformation adapter in GraphicsDeviceManager.Direct3D9Object.Adapters) //
{
AdapterInfo9 info = new AdapterInfo9();
info.AdapterOrdinal = adapter.Adapter;
info.Details = adapter.Details;
adapterFormats.Clear();
foreach (Format adapterFormat in allowedAdapterFormats)
{
foreach (DisplayMode displayMode in adapter.GetDisplayModes(adapterFormat))
{
if (MinimumSettings != null)
{
if (displayMode.Width < MinimumSettings.BackBufferWidth ||
displayMode.Height < MinimumSettings.BackBufferHeight ||
displayMode.RefreshRate < MinimumSettings.RefreshRate)
continue;
}
info.DisplayModes.Add(displayMode);
if (!adapterFormats.Contains(displayMode.Format))
adapterFormats.Add(displayMode.Format);
}
}
if (!adapterFormats.Contains(adapter.CurrentDisplayMode.Format))
adapterFormats.Add(adapter.CurrentDisplayMode.Format);
info.DisplayModes.Sort(DisplayModeComparer9.Comparer);
EnumerateDevices(info, adapterFormats);
if (info.Devices.Count > 0)
Adapters.Add(info);
}
bool unique = true;
foreach (AdapterInfo9 adapter1 in Adapters)
{
foreach (AdapterInfo9 adapter2 in Adapters)
{
if (adapter1 == adapter2)
continue;
if (adapter1.Details.Description == adapter2.Details.Description)
{
unique = false;
break;
}
}
if (!unique)
break;
}
foreach (AdapterInfo9 info in Adapters)
{
info.Description = info.Details.Description;
if (!unique)
info.Description += " " + info.AdapterOrdinal.ToString(CultureInfo.CurrentCulture);
}
}
static void EnumerateDevices(AdapterInfo9 info, List<Format> adapterFormats)
{
DeviceType[] deviceTypes = { DeviceType.Hardware, DeviceType.Reference };
foreach (DeviceType deviceType in deviceTypes)
{
if (MinimumSettings != null && MinimumSettings.DeviceType != deviceType)
continue;
DeviceInfo9 deviceInfo = new DeviceInfo9();
deviceInfo.DeviceType = deviceType;
try
{
deviceInfo.Capabilities = GraphicsDeviceManager.Direct3D9Object.GetDeviceCaps(info.AdapterOrdinal, deviceInfo.DeviceType);
EnumerateSettingsCombos(info, deviceInfo, adapterFormats);
if (deviceInfo.DeviceSettings.Count > 0)
info.Devices.Add(deviceInfo);
}
catch (Direct3D9Exception)
{
// #23681 2010.11.17 yyagi: GetDeviceCaps()で例外が発生するモニタに対しては、enumerateをスキップする。
}
}
}
static void EnumerateSettingsCombos(AdapterInfo9 adapterInfo, DeviceInfo9 deviceInfo, List<Format> adapterFormats)
{
Format[] backBufferFormats = { Format.A8R8G8B8, Format.X8R8G8B8, Format.A2R10G10B10,
Format.R5G6B5, Format.A1R5G5B5, Format.X1R5G5B5 };
foreach (Format adapterFormat in adapterFormats)
{
foreach (Format backBufferFormat in backBufferFormats)
{
for (int windowed = 0; windowed < 2; windowed++)
{
if (windowed == 0 && adapterInfo.DisplayModes.Count == 0)
continue;
if (!GraphicsDeviceManager.Direct3D9Object.CheckDeviceType(adapterInfo.AdapterOrdinal, deviceInfo.DeviceType,
adapterFormat, backBufferFormat, (windowed == 1)))
continue;
if (!GraphicsDeviceManager.Direct3D9Object.CheckDeviceFormat(adapterInfo.AdapterOrdinal,
deviceInfo.DeviceType, adapterFormat, Usage.QueryPostPixelShaderBlending,
ResourceType.Texture, backBufferFormat))
continue;
SettingsCombo9 combo = new SettingsCombo9();
combo.AdapterOrdinal = adapterInfo.AdapterOrdinal;
combo.DeviceType = deviceInfo.DeviceType;
combo.AdapterFormat = adapterFormat;
combo.BackBufferFormat = backBufferFormat;
combo.Windowed = (windowed == 1);
combo.AdapterInfo = adapterInfo;
combo.DeviceInfo = deviceInfo;
BuildDepthStencilFormatList(combo);
BuildMultisampleTypeList(combo);
if (combo.MultisampleTypes.Count == 0)
continue;
BuildPresentIntervalList(combo);
if (MinimumSettings != null)
{
if (MinimumSettings.BackBufferFormat != Format.Unknown &&
MinimumSettings.BackBufferFormat != backBufferFormat)
continue;
if (MinimumSettings.DepthStencilFormat != Format.Unknown &&
!combo.DepthStencilFormats.Contains(MinimumSettings.DepthStencilFormat))
continue;
if (!combo.MultisampleTypes.Contains(MinimumSettings.MultisampleType))
continue;
}
deviceInfo.DeviceSettings.Add(combo);
}
}
}
}
static void BuildDepthStencilFormatList(SettingsCombo9 combo)
{
List<Format> possibleDepthStencilFormats = new List<Format> {
Format.D16, Format.D15S1, Format.D24X8,
Format.D24S8, Format.D24X4S4, Format.D32 };
foreach (Format format in possibleDepthStencilFormats)
{
if (GraphicsDeviceManager.Direct3D9Object.CheckDeviceFormat(combo.AdapterOrdinal, combo.DeviceType, combo.AdapterFormat,
Usage.DepthStencil, ResourceType.Surface, format) &&
GraphicsDeviceManager.Direct3D9Object.CheckDepthStencilMatch(combo.AdapterOrdinal, combo.DeviceType,
combo.AdapterFormat, combo.BackBufferFormat, format))
combo.DepthStencilFormats.Add(format);
}
}
static void BuildMultisampleTypeList(SettingsCombo9 combo)
{
List<MultisampleType> possibleMultisampleTypes = new List<MultisampleType>() {
MultisampleType.None, MultisampleType.NonMaskable,
MultisampleType.TwoSamples, MultisampleType.ThreeSamples,
MultisampleType.FourSamples, MultisampleType.FiveSamples,
MultisampleType.SixSamples, MultisampleType.SevenSamples,
MultisampleType.EightSamples, MultisampleType.NineSamples,
MultisampleType.TenSamples, MultisampleType.ElevenSamples,
MultisampleType.TwelveSamples, MultisampleType.ThirteenSamples,
MultisampleType.FourteenSamples, MultisampleType.FifteenSamples,
MultisampleType.SixteenSamples
};
int quality;
foreach (MultisampleType type in possibleMultisampleTypes)
{
if (GraphicsDeviceManager.Direct3D9Object.CheckDeviceMultisampleType(combo.AdapterOrdinal, combo.DeviceType,
combo.AdapterFormat, combo.Windowed, type, out quality))
{
combo.MultisampleTypes.Add(type);
combo.MultisampleQualities.Add(quality);
}
}
}
static void BuildPresentIntervalList(SettingsCombo9 combo)
{
List<PresentInterval> possiblePresentIntervals = new List<PresentInterval>() {
PresentInterval.Immediate, PresentInterval.Default,
PresentInterval.One, PresentInterval.Two,
PresentInterval.Three, PresentInterval.Four
};
foreach (PresentInterval interval in possiblePresentIntervals)
{
if (combo.Windowed && (interval == PresentInterval.Two ||
interval == PresentInterval.Three || interval == PresentInterval.Four))
continue;
if (interval == PresentInterval.Default ||
(combo.DeviceInfo.Capabilities.PresentationIntervals & interval) != 0)
combo.PresentIntervals.Add(interval);
}
}
}
}

View File

@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1434
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SampleFramework.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SampleFramework.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
internal static System.Drawing.Icon sdx_icon_black {
get {
object obj = ResourceManager.GetObject("sdx_icon_black", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="sdx_icon_black" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\sdx_icon_black.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,200 @@
using System;
using System.Drawing;
using SlimDX;
using SlimDX.Direct3D9;
namespace SampleFramework
{
public sealed class DeviceCache
{
private readonly Device _device;
public DeviceCache(Device device)
{
_device = device;
}
public Device UnderlyingDevice => _device;
public void Dispose()
{
_device.Dispose();
}
public object Tag
{
get => _device.Tag;
set => _device.Tag = value;
}
public Result TestCooperativeLevel()
{
return _device.TestCooperativeLevel();
}
public Result Reset(PresentParameters presentParameters)
{
return _device.Reset(presentParameters);
}
public Result Clear(ClearFlags clearFlags, in Color4 color, float zdepth, int stencil)
{
return _device.Clear(clearFlags, color, zdepth, stencil);
}
public Result BeginScene()
{
return _device.BeginScene();
}
public Result EndScene()
{
return _device.EndScene();
}
public Result Present()
{
return _device.Present();
}
public Surface GetBackBuffer(int swapChain, int backBuffer)
{
return _device.GetBackBuffer(swapChain, backBuffer);
}
public Surface GetRenderTarget(int index)
{
return _device.GetRenderTarget(index);
}
public Result SetRenderState<T>(RenderState state, T value) where T : Enum
{
return _device.SetRenderState(state, value);
}
private BlendOperation? _lastBlendOperation;
public void SetRenderState(RenderState state, BlendOperation value)
{
if (state == RenderState.BlendOperation)
{
if (_lastBlendOperation == value)
{
return;
}
_lastBlendOperation = value;
}
_device.SetRenderState(state, value);
}
private Blend? _lastSourceBlend;
private Blend? _lastDestinationBlend;
public void SetRenderState(RenderState state, Blend value)
{
if (state == RenderState.SourceBlend)
{
if (_lastSourceBlend == value)
{
return;
}
_lastSourceBlend = value;
}
else if (state == RenderState.DestinationBlend)
{
if (_lastDestinationBlend == value)
{
return;
}
_lastDestinationBlend = value;
}
_device.SetRenderState(state, value);
}
public Result SetRenderState(RenderState state, bool value)
{
return _device.SetRenderState(state, value);
}
public Result SetRenderState(RenderState state, int value)
{
return _device.SetRenderState(state, value);
}
public Result SetTextureStageState(int stage, TextureStage type, TextureOperation textureOperation)
{
return _device.SetTextureStageState(stage, type, textureOperation);
}
public Result SetTextureStageState(int stage, TextureStage type, int value)
{
return _device.SetTextureStageState(stage, type, value);
}
public Result SetSamplerState(int sampler, SamplerState type, TextureFilter textureFilter)
{
return _device.SetSamplerState(sampler, type, textureFilter);
}
public Result SetTransform(TransformState state, in Matrix value)
{
return _device.SetTransform(state, value);
}
private int? _lastSetTextureSampler;
private object _lastSetTextureTexture;
public void SetTexture(int sampler, BaseTexture texture)
{
if ( ReferenceEquals(_lastSetTextureTexture, texture) && _lastSetTextureSampler == sampler)
{
return;
}
_lastSetTextureSampler = sampler;
_lastSetTextureTexture = texture;
_device.SetTexture(sampler, texture);
}
public Result SetRenderTarget(int targetIndex, Surface target)
{
return _device.SetRenderTarget(targetIndex, target);
}
public Result DrawUserPrimitives<T>(PrimitiveType primitiveType, int startIndex, int primitiveCount, in T[] data) where T : struct//, new()
{
return _device.DrawUserPrimitives(primitiveType, startIndex, primitiveCount, data);
}
public Result DrawUserPrimitives<T>(PrimitiveType primitiveType, int primitiveCount, in T[] data) where T : struct//, new()
{
return _device.DrawUserPrimitives(primitiveType, primitiveCount, data);
}
public Result StretchRectangle(Surface source, Surface destination, TextureFilter filter)
{
return _device.StretchRectangle(source, destination, filter);
}
public Result UpdateSurface(Surface source, in Rectangle sourceRectangle, Surface destination, in Point destinationPoint)
{
return _device.UpdateSurface(source, sourceRectangle, destination, destinationPoint);
}
public Viewport Viewport
{
get => _device.Viewport;
set => _device.Viewport = value;
}
public VertexFormat VertexFormat
{
get => _device.VertexFormat;
set => _device.VertexFormat = value;
}
public Capabilities Capabilities => _device.Capabilities;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.Serialization;
namespace SampleFramework
{
/// <summary>
/// Thrown when a graphics device cannot be created.
/// </summary>
[Serializable]
public class DeviceCreationException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="DeviceCreationException"/> class.
/// </summary>
public DeviceCreationException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DeviceCreationException"/> class.
/// </summary>
/// <param name="message">The message.</param>
public DeviceCreationException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DeviceCreationException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="innerException">The inner exception.</param>
public DeviceCreationException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DeviceCreationException"/> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is null. </exception>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0). </exception>
protected DeviceCreationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

View File

@ -0,0 +1,219 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using SlimDX;
using SlimDX.Direct3D9;
namespace SampleFramework
{
/// <summary>
/// Manages aspects of the graphics device unique to Direct3D9.
/// </summary>
public class Direct3D9Manager
{
GraphicsDeviceManager manager;
/// <summary>
/// Gets the graphics device.
/// </summary>
/// <value>The graphics device.</value>
#if TEST_Direct3D9Ex
public DeviceEx Device //yyagi
#else
public DeviceCache Device
#endif
{
get;
internal set;
}
/// <summary>
/// Initializes a new instance of the <see cref="Direct3D9Manager"/> class.
/// </summary>
/// <param name="manager">The parent manager.</param>
internal Direct3D9Manager(GraphicsDeviceManager manager)
{
this.manager = manager;
}
/// <summary>
/// Creates a vertex declaration using the specified vertex type.
/// </summary>
/// <param name="vertexType">Type of the vertex.</param>
/// <returns>The vertex declaration for the specified vertex type.</returns>
[EnvironmentPermission(SecurityAction.LinkDemand)]
public VertexDeclaration CreateVertexDeclaration(Type vertexType)
{
// ensure that we have a value type
if (!vertexType.IsValueType)
throw new InvalidOperationException("Vertex types must be value types.");
// grab the list of elements in the vertex
List<VertexElementAttribute> objectAttributes = new List<VertexElementAttribute>();
FieldInfo[] fields = vertexType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
// check for the custom attribute
VertexElementAttribute[] attributes = (VertexElementAttribute[])field.GetCustomAttributes(typeof(VertexElementAttribute), false);
if (field.Name.Contains("<") && field.Name.Contains(">"))
{
// look up the property matching this field to see if it has the attribute
int index1 = field.Name.IndexOf('<');
int index2 = field.Name.IndexOf('>');
// parse out the name
string propertyName = field.Name.Substring(index1 + 1, index2 - index1 - 1);
PropertyInfo property = vertexType.GetProperty(propertyName, field.FieldType);
if (property != null)
attributes = (VertexElementAttribute[])property.GetCustomAttributes(typeof(VertexElementAttribute), false);
}
if (attributes.Length == 1)
{
// add the attribute to the list
attributes[0].Offset = Marshal.OffsetOf(vertexType, field.Name).ToInt32();
objectAttributes.Add(attributes[0]);
}
}
// make sure we have at least one element
if (objectAttributes.Count < 1)
throw new InvalidOperationException("The vertex type must have at least one field or property marked with the VertexElement attribute.");
// loop through the attributes and start building vertex elements
List<VertexElement> elements = new List<VertexElement>();
Dictionary<DeclarationUsage, int> usages = new Dictionary<DeclarationUsage, int>();
foreach (VertexElementAttribute attribute in objectAttributes)
{
// check the current usage index
if (!usages.ContainsKey(attribute.Usage))
usages.Add(attribute.Usage, 0);
// advance the current usage count
int index = usages[attribute.Usage];
usages[attribute.Usage]++;
// create the element
elements.Add(new VertexElement((short)attribute.Stream, (short)attribute.Offset, attribute.Type,
attribute.Method, attribute.Usage, (byte)index));
}
elements.Add(VertexElement.VertexDeclarationEnd);
return new VertexDeclaration(Device.UnderlyingDevice, elements.ToArray());
}
/// <summary>
/// Creates a render target surface that is compatible with the current device settings.
/// </summary>
/// <param name="width">The width of the surface.</param>
/// <param name="height">The height of the surface.</param>
/// <returns>The newly created render target surface.</returns>
public Texture CreateRenderTarget(int width, int height)
{
return new Texture(Device.UnderlyingDevice, width, height, 1, Usage.RenderTarget, manager.CurrentSettings.BackBufferFormat, Pool.Default);
}
/// <summary>
/// Creates a resolve target for capturing the back buffer.
/// </summary>
/// <returns>The newly created resolve target.</returns>
public Texture CreateResolveTarget()
{
return new Texture(Device.UnderlyingDevice, manager.ScreenWidth, manager.ScreenHeight, 1, Usage.RenderTarget, manager.CurrentSettings.BackBufferFormat, Pool.Default);
}
/// <summary>
/// Resolves the current back buffer into a texture.
/// </summary>
/// <param name="target">The target texture.</param>
/// <exception cref="InvalidOperationException">Thrown when the resolve process fails.</exception>
public void ResolveBackBuffer(Texture target)
{
ResolveBackBuffer(target, 0);
}
/// <summary>
/// Resolves the current back buffer into a texture.
/// </summary>
/// <param name="target">The target texture.</param>
/// <param name="backBufferIndex">The index of the back buffer.</param>
/// <exception cref="InvalidOperationException">Thrown when the resolve process fails.</exception>
public void ResolveBackBuffer(Texture target, int backBufferIndex)
{
// disable exceptions for this method
bool storedThrow = Configuration.ThrowOnError;
Configuration.ThrowOnError = false;
Surface destination = null;
try
{
// grab the current back buffer
Surface backBuffer = Device.GetBackBuffer(0, backBufferIndex);
if (backBuffer == null || Result.Last.IsFailure)
throw new InvalidOperationException("Could not obtain back buffer surface.");
// grab the destination surface
destination = target.GetSurfaceLevel(0);
if (destination == null || Result.Last.IsFailure)
throw new InvalidOperationException("Could not obtain resolve target surface.");
// first try to copy using linear filtering
if (Device.StretchRectangle(backBuffer, destination, TextureFilter.Linear).IsFailure)
{
// that failed, so try with no filtering
if (Device.StretchRectangle(backBuffer, destination, TextureFilter.None).IsFailure)
{
// that failed as well, so the last thing we can try is a load surface call
if (Surface.FromSurface(destination, backBuffer, Filter.Default, 0).IsFailure)
throw new InvalidOperationException("Could not copy surfaces.");
}
}
}
finally
{
if (destination != null)
destination.Dispose();
Configuration.ThrowOnError = storedThrow;
}
}
/// <summary>
/// Resets the render target.
/// </summary>
public void ResetRenderTarget()
{
Surface backBuffer = Device.GetBackBuffer(0, 0);
try
{
Device.SetRenderTarget(0, backBuffer);
}
finally
{
backBuffer.Dispose();
}
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace SampleFramework
{
}

View File

@ -0,0 +1,701 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.DXGI;
using System.Diagnostics;
namespace SampleFramework
{
/// <summary>
/// Handles the configuration and management of the graphics device.
/// </summary>
public class GraphicsDeviceManager : IDisposable
{
Game game;
bool ignoreSizeChanges;
bool deviceLost;
// bool doNotStoreBufferSize;
// bool renderingOccluded;
int fullscreenWindowWidth;
int fullscreenWindowHeight;
int windowedWindowWidth;
int windowedWindowHeight;
WINDOWPLACEMENT windowedPlacement;
long windowedStyle;
bool savedTopmost;
#if TEST_Direct3D9Ex
internal static Direct3DEx Direct3D9Object // yyagi
#else
internal static Direct3D Direct3D9Object
#endif
{
get;
private set;
}
public DeviceSettings CurrentSettings
{
get;
private set;
}
public bool IsWindowed
{
get { return CurrentSettings.Windowed; }
}
public int ScreenWidth
{
get { return CurrentSettings.BackBufferWidth; }
}
public int ScreenHeight
{
get { return CurrentSettings.BackBufferHeight; }
}
public Size ScreenSize
{
get { return new Size(CurrentSettings.BackBufferWidth, CurrentSettings.BackBufferHeight); }
}
public Direct3D9Manager Direct3D9
{
get;
private set;
}
public string DeviceStatistics
{
get;
private set;
}
public string DeviceInformation
{
get;
private set;
}
public GraphicsDeviceManager( Game game )
{
if( game == null )
throw new ArgumentNullException( "game" );
this.game = game;
game.Window.ScreenChanged += Window_ScreenChanged;
game.Window.UserResized += Window_UserResized;
game.FrameStart += game_FrameStart;
game.FrameEnd += game_FrameEnd;
Direct3D9 = new Direct3D9Manager( this );
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void ChangeDevice( DeviceSettings settings, DeviceSettings minimumSettings )
{
if( settings == null )
throw new ArgumentNullException( "settings" );
Enumeration9.MinimumSettings = minimumSettings;
DeviceSettings validSettings = DeviceSettings.FindValidSettings( settings );
validSettings.Direct3D9.PresentParameters.DeviceWindowHandle = game.Window.Handle;
CreateDevice( validSettings );
}
public void ChangeDevice(bool windowed, int desiredWidth, int desiredHeight)
{
DeviceSettings desiredSettings = new DeviceSettings();
desiredSettings.Windowed = windowed;
desiredSettings.BackBufferWidth = desiredWidth;
desiredSettings.BackBufferHeight = desiredHeight;
ChangeDevice(desiredSettings, null);
}
public void ChangeDevice(DeviceSettings settings)
{
ChangeDevice(settings, null);
}
public void ToggleFullScreen()
{
if (!EnsureDevice())
throw new InvalidOperationException("No valid device.");
DeviceSettings newSettings = CurrentSettings.Clone();
newSettings.Windowed = !newSettings.Windowed;
int width = newSettings.Windowed ? windowedWindowWidth : fullscreenWindowWidth;
int height = newSettings.Windowed ? windowedWindowHeight : fullscreenWindowHeight;
newSettings.BackBufferWidth = width;
newSettings.BackBufferHeight = height;
ChangeDevice(newSettings);
}
public bool EnsureDevice()
{
if (Direct3D9.Device != null && !deviceLost)
return true;
return false;
}
protected virtual void Dispose( bool disposing )
{
if( this.bDisposed )
return;
this.bDisposed = true;
if( disposing )
ReleaseDevice();
}
private bool bDisposed = false;
void CreateDevice(DeviceSettings settings)
{
DeviceSettings oldSettings = CurrentSettings;
CurrentSettings = settings;
ignoreSizeChanges = true;
bool keepCurrentWindowSize = false;
if (settings.BackBufferWidth == 0 && settings.BackBufferHeight == 0)
keepCurrentWindowSize = true;
// handle the window state in Direct3D9 (it will be handled for us in DXGI)
// check if we are going to windowed or fullscreen mode
if( settings.Windowed )
{
if( oldSettings != null && !oldSettings.Windowed )
NativeMethods.SetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE, (uint) windowedStyle );
}
else
{
if( oldSettings == null || oldSettings.Windowed )
{
savedTopmost = game.Window.TopMost;
long style = NativeMethods.GetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE );
style &= ~WindowConstants.WS_MAXIMIZE & ~WindowConstants.WS_MINIMIZE;
windowedStyle = style;
windowedPlacement = new WINDOWPLACEMENT();
windowedPlacement.length = WINDOWPLACEMENT.Length;
NativeMethods.GetWindowPlacement( game.Window.Handle, ref windowedPlacement );
}
// hide the window until we are done messing with it
game.Window.Hide();
NativeMethods.SetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE, (uint) ( WindowConstants.WS_POPUP | WindowConstants.WS_SYSMENU ) );
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = WINDOWPLACEMENT.Length;
NativeMethods.GetWindowPlacement( game.Window.Handle, ref placement );
// check if we are in the middle of a restore
if( ( placement.flags & WindowConstants.WPF_RESTORETOMAXIMIZED ) != 0 )
{
// update the flags to avoid sizing issues
placement.flags &= ~WindowConstants.WPF_RESTORETOMAXIMIZED;
placement.showCmd = WindowConstants.SW_RESTORE;
NativeMethods.SetWindowPlacement( game.Window.Handle, ref placement );
}
}
if (settings.Windowed)
{
if (oldSettings != null && !oldSettings.Windowed)
{
fullscreenWindowWidth = oldSettings.BackBufferWidth;
fullscreenWindowHeight = oldSettings.BackBufferHeight;
}
}
else
{
if (oldSettings != null && oldSettings.Windowed)
{
windowedWindowWidth = oldSettings.BackBufferWidth;
windowedWindowHeight = oldSettings.BackBufferHeight;
}
}
// check if the device can be reset, or if we need to completely recreate it
Result result = SlimDX.Direct3D9.ResultCode.Success;
bool canReset = CanDeviceBeReset(oldSettings, settings);
if (canReset)
result = ResetDevice();
if (result == SlimDX.Direct3D9.ResultCode.DeviceLost)
deviceLost = true;
else if (!canReset || result.IsFailure)
{
if (oldSettings != null)
ReleaseDevice();
InitializeDevice();
}
UpdateDeviceInformation();
// check if we changed from fullscreen to windowed mode
if (oldSettings != null && !oldSettings.Windowed && settings.Windowed)
{
NativeMethods.SetWindowPlacement(game.Window.Handle, ref windowedPlacement);
game.Window.TopMost = savedTopmost;
}
// check if we need to resize
if (settings.Windowed && !keepCurrentWindowSize)
{
int width;
int height;
if (NativeMethods.IsIconic(game.Window.Handle))
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = WINDOWPLACEMENT.Length;
NativeMethods.GetWindowPlacement(game.Window.Handle, ref placement);
// check if we are being restored
if ((placement.flags & WindowConstants.WPF_RESTORETOMAXIMIZED) != 0 && placement.showCmd == WindowConstants.SW_SHOWMINIMIZED)
{
NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
Rectangle rect = NativeMethods.GetClientRectangle(game.Window.Handle);
width = rect.Width;
height = rect.Height;
NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_MINIMIZE);
}
else
{
NativeRectangle frame = new NativeRectangle();
NativeMethods.AdjustWindowRect(ref frame, (uint)windowedStyle, false);
int frameWidth = frame.right - frame.left;
int frameHeight = frame.bottom - frame.top;
width = placement.rcNormalPosition.right - placement.rcNormalPosition.left - frameWidth;
height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top - frameHeight;
}
}
else
{
Rectangle rect = NativeMethods.GetClientRectangle(game.Window.Handle);
width = rect.Width;
height = rect.Height;
}
// check if we have a different desired size
if (width != settings.BackBufferWidth ||
height != settings.BackBufferHeight)
{
if (NativeMethods.IsIconic(game.Window.Handle))
NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
if (NativeMethods.IsZoomed(game.Window.Handle))
NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
NativeRectangle rect = new NativeRectangle();
rect.right = settings.BackBufferWidth;
rect.bottom = settings.BackBufferHeight;
NativeMethods.AdjustWindowRect(ref rect,
NativeMethods.GetWindowLong(game.Window.Handle, WindowConstants.GWL_STYLE), false);
NativeMethods.SetWindowPos(game.Window.Handle, IntPtr.Zero, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, WindowConstants.SWP_NOZORDER | WindowConstants.SWP_NOMOVE);
Rectangle r = NativeMethods.GetClientRectangle(game.Window.Handle);
int clientWidth = r.Width;
int clientHeight = r.Height;
// check if the size was modified by Windows
if (clientWidth != settings.BackBufferWidth ||
clientHeight != settings.BackBufferHeight)
{
DeviceSettings newSettings = CurrentSettings.Clone();
newSettings.BackBufferWidth = 0;
newSettings.BackBufferHeight = 0;
if (newSettings.Direct3D9 != null)
{
newSettings.Direct3D9.PresentParameters.BackBufferWidth = GameWindowSize.Width; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
newSettings.Direct3D9.PresentParameters.BackBufferHeight = GameWindowSize.Height; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
}
CreateDevice(newSettings);
}
}
}
// if the window is still hidden, make sure it is shown
if (!game.Window.Visible)
NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_SHOW);
// set the execution state of the thread
if (!IsWindowed)
NativeMethods.SetThreadExecutionState(WindowConstants.ES_DISPLAY_REQUIRED | WindowConstants.ES_CONTINUOUS);
else
NativeMethods.SetThreadExecutionState(WindowConstants.ES_CONTINUOUS);
ignoreSizeChanges = false;
}
void Window_UserResized( object sender, EventArgs e )
{
if( ignoreSizeChanges || !EnsureDevice() || ( !IsWindowed ) )
return;
DeviceSettings newSettings = CurrentSettings.Clone();
Rectangle rect = NativeMethods.GetClientRectangle( game.Window.Handle );
if( rect.Width != newSettings.BackBufferWidth || rect.Height != newSettings.BackBufferHeight )
{
newSettings.BackBufferWidth = 0;
newSettings.BackBufferHeight = 0;
newSettings.Direct3D9.PresentParameters.BackBufferWidth = GameWindowSize.Width; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
newSettings.Direct3D9.PresentParameters.BackBufferHeight = GameWindowSize.Height; //
CreateDevice( newSettings );
}
}
void Window_ScreenChanged( object sender, EventArgs e )
{
if( !EnsureDevice() || !CurrentSettings.Windowed || ignoreSizeChanges )
return;
IntPtr windowMonitor = NativeMethods.MonitorFromWindow( game.Window.Handle, WindowConstants.MONITOR_DEFAULTTOPRIMARY );
DeviceSettings newSettings = CurrentSettings.Clone();
int adapterOrdinal = GetAdapterOrdinal( windowMonitor );
if( adapterOrdinal == -1 )
return;
newSettings.Direct3D9.AdapterOrdinal = adapterOrdinal;
newSettings.BackBufferWidth = 0; // #23510 2010.11.1 add yyagi to avoid to reset to 640x480 for the first time in XP.
newSettings.BackBufferHeight = 0; //
newSettings.Direct3D9.PresentParameters.BackBufferWidth = GameWindowSize.Width; //
newSettings.Direct3D9.PresentParameters.BackBufferHeight = GameWindowSize.Height; //
CreateDevice(newSettings);
}
void game_FrameEnd( object sender, EventArgs e )
{
Result result = SlimDX.Direct3D9.ResultCode.Success;
try
{
result = Direct3D9.Device.Present();
}
catch (Direct3D9Exception) // #23842 2011.1.6 yyagi: catch D3D9Exception to avoid unexpected termination by changing VSyncWait in fullscreen.
{
deviceLost = true;
}
if( result == SlimDX.Direct3D9.ResultCode.DeviceLost )
deviceLost = true;
}
void game_FrameStart(object sender, CancelEventArgs e)
{
if (Direct3D9.Device == null )
{
e.Cancel = true;
return;
}
// if (!game.IsActive || deviceLost) // #23568 2010.11.3 yyagi: separate conditions to support valiable sleep value when !IsActive.
if (deviceLost)
Thread.Sleep(50);
else if (!game.IsActive && !this.CurrentSettings.EnableVSync) // #23568 2010.11.4 yyagi: Don't add sleep() while VSync is enabled.
Thread.Sleep(this.game.InactiveSleepTime.Milliseconds);
if (deviceLost)
{
Result result = Direct3D9.Device.TestCooperativeLevel();
if (result == SlimDX.Direct3D9.ResultCode.DeviceLost)
{
e.Cancel = true;
return;
}
// if we are windowed, check the adapter format to see if the user
// changed the desktop format, causing a lost device
if (IsWindowed)
{
DisplayMode displayMode = GraphicsDeviceManager.Direct3D9Object.GetAdapterDisplayMode(CurrentSettings.Direct3D9.AdapterOrdinal);
if (CurrentSettings.Direct3D9.AdapterFormat != displayMode.Format)
{
DeviceSettings newSettings = CurrentSettings.Clone();
ChangeDevice(newSettings);
e.Cancel = true;
return;
}
}
result = ResetDevice();
if (result.IsFailure)
{
e.Cancel = true;
return;
}
}
deviceLost = false;
}
bool CanDeviceBeReset( DeviceSettings oldSettings, DeviceSettings newSettings )
{
if( oldSettings == null )
return false;
return Direct3D9.Device != null &&
oldSettings.Direct3D9.AdapterOrdinal == newSettings.Direct3D9.AdapterOrdinal &&
oldSettings.Direct3D9.DeviceType == newSettings.Direct3D9.DeviceType &&
oldSettings.Direct3D9.CreationFlags == newSettings.Direct3D9.CreationFlags;
}
void InitializeDevice()
{
try
{
EnsureD3D9();
#if TEST_Direct3D9Ex
// 2011.4.26 yyagi
// Direct3D9.DeviceExを呼ぶ際(IDirect3D9Ex::CreateDeviceExを呼ぶ際)、
// フルスクリーンモードで初期化する場合はDisplayModeEx(D3DDISPLAYMODEEX *pFullscreenDisplayMode)に
// 適切な値を設定する必要あり。
// 一方、ウインドウモードで初期化する場合は、D3DDISPLAYMODEEXをNULLにする必要があるが、
// DisplayModeExがNULL不可と定義されているため、DeviceExのoverloadの中でDisplayModeExを引数に取らないものを
// 使う。(DeviceEx側でD3DDISPLAYMODEEXをNULLにしてくれる)
// 結局、DeviceExの呼び出しの際に、フルスクリーンかどうかで場合分けが必要となる。
if ( CurrentSettings.Direct3D9.PresentParameters.Windowed == false )
{
DisplayModeEx fullScreenDisplayMode = new DisplayModeEx();
fullScreenDisplayMode.Width = CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth;
fullScreenDisplayMode.Height = CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight;
fullScreenDisplayMode.RefreshRate = CurrentSettings.Direct3D9.PresentParameters.FullScreenRefreshRateInHertz;
fullScreenDisplayMode.Format = CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat;
Direct3D9.Device = new SlimDX.Direct3D9.DeviceEx( Direct3D9Object, CurrentSettings.Direct3D9.AdapterOrdinal,
CurrentSettings.Direct3D9.DeviceType, game.Window.Handle,
CurrentSettings.Direct3D9.CreationFlags, CurrentSettings.Direct3D9.PresentParameters, fullScreenDisplayMode );
}
else
{
Direct3D9.Device = new SlimDX.Direct3D9.DeviceEx( Direct3D9Object, CurrentSettings.Direct3D9.AdapterOrdinal,
CurrentSettings.Direct3D9.DeviceType, game.Window.Handle,
CurrentSettings.Direct3D9.CreationFlags, CurrentSettings.Direct3D9.PresentParameters );
}
Direct3D9.Device.MaximumFrameLatency = 1;
#else
Direct3D9.Device = new DeviceCache( new SlimDX.Direct3D9.Device( Direct3D9Object, CurrentSettings.Direct3D9.AdapterOrdinal,
CurrentSettings.Direct3D9.DeviceType, game.Window.Handle,
CurrentSettings.Direct3D9.CreationFlags, CurrentSettings.Direct3D9.PresentParameters ) );
#endif
if ( Result.Last == SlimDX.Direct3D9.ResultCode.DeviceLost )
{
deviceLost = true;
return;
}
#if TEST_Direct3D9Ex
Direct3D9.Device.MaximumFrameLatency = 1; // yyagi
#endif
}
catch( Exception e )
{
throw new DeviceCreationException( "Could not create graphics device.", e );
}
PropogateSettings();
UpdateDeviceStats();
game.Initialize();
game.LoadContent();
}
Result ResetDevice()
{
game.UnloadContent();
Result result = Direct3D9.Device.Reset( CurrentSettings.Direct3D9.PresentParameters );
if( result == SlimDX.Direct3D9.ResultCode.DeviceLost )
return result;
PropogateSettings();
UpdateDeviceStats();
game.LoadContent();
return Result.Last;
}
void ReleaseDevice()
{
ReleaseDevice9();
}
void ReleaseDevice9()
{
if (Direct3D9.Device == null)
return;
if (game != null)
{
game.UnloadContent();
game.Dispose(true);
}
try
{
Direct3D9.Device.Dispose();
}
catch( ObjectDisposedException e )
{
// 時々発生するのでキャッチしておく。
Trace.TraceError( e.ToString() );
Trace.TraceError( "例外が発生しましたが処理を継続します。 (fc0b6e70-181e-410f-b47f-5490ca4ce0c3)" );
}
Direct3D9Object.Dispose();
Direct3D9Object = null;
Direct3D9.Device = null;
}
void PropogateSettings()
{
CurrentSettings.BackBufferCount = CurrentSettings.Direct3D9.PresentParameters.BackBufferCount;
CurrentSettings.BackBufferWidth = CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth;
CurrentSettings.BackBufferHeight = CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight;
CurrentSettings.BackBufferFormat = CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat;
CurrentSettings.DepthStencilFormat = CurrentSettings.Direct3D9.PresentParameters.AutoDepthStencilFormat;
CurrentSettings.DeviceType = CurrentSettings.Direct3D9.DeviceType;
CurrentSettings.MultisampleQuality = CurrentSettings.Direct3D9.PresentParameters.MultisampleQuality;
CurrentSettings.MultisampleType = CurrentSettings.Direct3D9.PresentParameters.Multisample;
CurrentSettings.RefreshRate = CurrentSettings.Direct3D9.PresentParameters.FullScreenRefreshRateInHertz;
CurrentSettings.Windowed = CurrentSettings.Direct3D9.PresentParameters.Windowed;
}
void UpdateDeviceInformation()
{
StringBuilder builder = new StringBuilder();
if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
builder.Append( "HAL" );
else if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Reference )
builder.Append( "REF" );
else if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Software )
builder.Append( "SW" );
if( ( CurrentSettings.Direct3D9.CreationFlags & CreateFlags.HardwareVertexProcessing ) != 0 )
if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
builder.Append( " (hw vp)" );
else
builder.Append( " (simulated hw vp)" );
else if( ( CurrentSettings.Direct3D9.CreationFlags & CreateFlags.MixedVertexProcessing ) != 0 )
if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
builder.Append( " (mixed vp)" );
else
builder.Append( " (simulated mixed vp)" );
else
builder.Append( " (sw vp)" );
if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
{
// loop through each adapter until we find the right one
foreach( AdapterInfo9 adapterInfo in Enumeration9.Adapters )
{
if( adapterInfo.AdapterOrdinal == CurrentSettings.Direct3D9.AdapterOrdinal )
{
builder.AppendFormat( ": {0}", adapterInfo.Description );
break;
}
}
}
DeviceInformation = builder.ToString();
}
void UpdateDeviceStats()
{
StringBuilder builder = new StringBuilder();
builder.Append( "D3D9 Vsync " );
if( CurrentSettings.Direct3D9.PresentParameters.PresentationInterval == PresentInterval.Immediate )
builder.Append( "off" );
else
builder.Append( "on" );
builder.AppendFormat( " ({0}x{1}), ", CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth, CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight );
if( CurrentSettings.Direct3D9.AdapterFormat == CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat )
builder.Append( Enum.GetName( typeof( SlimDX.Direct3D9.Format ), CurrentSettings.Direct3D9.AdapterFormat ) );
else
builder.AppendFormat( "backbuf {0}, adapter {1}",
Enum.GetName( typeof( SlimDX.Direct3D9.Format ), CurrentSettings.Direct3D9.AdapterFormat ),
Enum.GetName( typeof( SlimDX.Direct3D9.Format ), CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat ) );
builder.AppendFormat( " ({0})", Enum.GetName( typeof( SlimDX.Direct3D9.Format ), CurrentSettings.Direct3D9.PresentParameters.AutoDepthStencilFormat ) );
if( CurrentSettings.Direct3D9.PresentParameters.Multisample == MultisampleType.NonMaskable )
builder.Append( " (Nonmaskable Multisample)" );
else if( CurrentSettings.Direct3D9.PresentParameters.Multisample != MultisampleType.None )
builder.AppendFormat( " ({0}x Multisample)", (int) CurrentSettings.Direct3D9.PresentParameters.Multisample );
DeviceStatistics = builder.ToString();
}
int GetAdapterOrdinal( IntPtr screen )
{
AdapterInfo9 adapter = null;
foreach( AdapterInfo9 a in Enumeration9.Adapters )
{
if( Direct3D9Object.GetAdapterMonitor( a.AdapterOrdinal ) == screen )
{
adapter = a;
break;
}
}
if( adapter != null )
return adapter.AdapterOrdinal;
return -1;
}
internal static void EnsureD3D9()
{
if ( Direct3D9Object == null )
#if TEST_Direct3D9Ex
Direct3D9Object = new Direct3DEx(); // yyagi
#else
Direct3D9Object = new Direct3D();
#endif
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.Serialization;
namespace SampleFramework
{
/// <summary>
/// Thrown when no available graphics device fits the given device preferences.
/// </summary>
[Serializable]
public class NoCompatibleDevicesException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="NoCompatibleDevicesException"/> class.
/// </summary>
public NoCompatibleDevicesException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NoCompatibleDevicesException"/> class.
/// </summary>
/// <param name="message">The message.</param>
public NoCompatibleDevicesException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NoCompatibleDevicesException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="innerException">The inner exception.</param>
public NoCompatibleDevicesException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NoCompatibleDevicesException"/> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is null. </exception>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0). </exception>
protected NoCompatibleDevicesException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using SlimDX.Direct3D9;
namespace SampleFramework
{
/// <summary>
/// Indicates that the target code element is part of a vertex declaration.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class VertexElementAttribute : Attribute
{
/// <summary>
/// Gets or sets the stream index.
/// </summary>
/// <value>The stream index.</value>
public int Stream
{
get;
set;
}
/// <summary>
/// Gets or sets the tessellation method.
/// </summary>
/// <value>The tessellation method.</value>
public DeclarationMethod Method
{
get;
set;
}
/// <summary>
/// Gets or sets the element usage.
/// </summary>
/// <value>The element usage.</value>
public DeclarationUsage Usage
{
get;
private set;
}
/// <summary>
/// Gets or sets the type of the data.
/// </summary>
/// <value>The type of the data.</value>
public DeclarationType Type
{
get;
private set;
}
/// <summary>
/// Gets or sets the offset.
/// </summary>
/// <value>The offset.</value>
internal int Offset
{
get;
set;
}
/// <summary>
/// Initializes a new instance of the <see cref="VertexElementAttribute"/> class.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="usage">The vertex element usage.</param>
public VertexElementAttribute(DeclarationType type, DeclarationUsage usage)
{
Type = type;
Usage = usage;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -0,0 +1,197 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using SlimDX;
namespace SampleFramework
{
/// <summary>
/// Represents a view onto a 3D scene.
/// </summary>
public class Camera
{
Vector3 location;
Vector3 target;
float fieldOfView;
float aspectRatio;
float nearPlane;
float farPlane;
Matrix viewMatrix;
Matrix projectionMatrix;
bool viewDirty = true;
bool projectionDirty = true;
/// <summary>
/// Gets or sets the location of the camera eye point.
/// </summary>
/// <value>The location of the camera eye point.</value>
public Vector3 Location
{
get { return location; }
set
{
if (location == value)
return;
location = value;
viewDirty = true;
}
}
/// <summary>
/// Gets or sets the view target point.
/// </summary>
/// <value>The view target point.</value>
public Vector3 Target
{
get { return target; }
set
{
if (target == value)
return;
target = value;
viewDirty = true;
}
}
/// <summary>
/// Gets or sets the field of view.
/// </summary>
/// <value>The field of view.</value>
public float FieldOfView
{
get { return fieldOfView; }
set
{
if (fieldOfView == value)
return;
fieldOfView = value;
projectionDirty = true;
}
}
/// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
/// <value>The aspect ratio.</value>
public float AspectRatio
{
get { return aspectRatio; }
set
{
if (aspectRatio == value)
return;
aspectRatio = value;
projectionDirty = true;
}
}
/// <summary>
/// Gets or sets the near plane.
/// </summary>
/// <value>The near plane.</value>
public float NearPlane
{
get { return nearPlane; }
set
{
if (nearPlane == value)
return;
nearPlane = value;
projectionDirty = true;
}
}
/// <summary>
/// Gets or sets the far plane.
/// </summary>
/// <value>The far plane.</value>
public float FarPlane
{
get { return farPlane; }
set
{
if (farPlane == value)
return;
farPlane = value;
projectionDirty = true;
}
}
/// <summary>
/// Gets the view matrix.
/// </summary>
/// <value>The view matrix.</value>
public Matrix ViewMatrix
{
get
{
if (viewDirty)
RebuildViewMatrix();
return viewMatrix;
}
}
/// <summary>
/// Gets the projection matrix.
/// </summary>
/// <value>The projection matrix.</value>
public Matrix ProjectionMatrix
{
get
{
if (projectionDirty)
RebuildProjectionMatrix();
return projectionMatrix;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="Camera"/> class.
/// </summary>
public Camera()
{
}
/// <summary>
/// Rebuilds the view matrix.
/// </summary>
protected virtual void RebuildViewMatrix()
{
viewMatrix = Matrix.LookAtLH(Location, Target, Vector3.UnitY);
viewDirty = false;
}
/// <summary>
/// Rebuilds the projection matrix.
/// </summary>
protected virtual void RebuildProjectionMatrix()
{
projectionMatrix = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio, NearPlane, FarPlane);
projectionDirty = false;
}
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using SlimDX;
using SlimDX.Direct3D9;
namespace SampleFramework
{
/// <summary>
/// Represents a single transformed, colored, and textured vertex.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TransformedColoredTexturedVertex : IEquatable<TransformedColoredTexturedVertex>
{
private Vector4 m_Position;
/// <summary>
/// Gets or sets the transformed position of the vertex.
/// </summary>
/// <value>The transformed position of the vertex.</value>
[VertexElement(DeclarationType.Float4, DeclarationUsage.PositionTransformed)]
public Vector4 Position
{
get { return m_Position; }
set { m_Position = value; }
}
private int m_Color;
/// <summary>
/// Gets or sets the color of the vertex.
/// </summary>
/// <value>The color of the vertex.</value>
[VertexElement(DeclarationType.Color, DeclarationUsage.Color)]
public int Color
{
get { return m_Color; }
set { m_Color = value; }
}
private Vector2 m_TextureCoordinates;
/// <summary>
/// Gets or sets the texture coordinates.
/// </summary>
/// <value>The texture coordinates.</value>
[VertexElement(DeclarationType.Float2, DeclarationUsage.TextureCoordinate)]
public Vector2 TextureCoordinates
{
get { return m_TextureCoordinates; }
set { m_TextureCoordinates = value; }
}
/// <summary>
/// Gets the size in bytes.
/// </summary>
/// <value>The size in bytes.</value>
public static int SizeInBytes
{
get { return Marshal.SizeOf(typeof(TransformedColoredTexturedVertex)); }
}
/// <summary>
/// Gets the format.
/// </summary>
/// <value>The format.</value>
public static VertexFormat Format
{
get { return VertexFormat.PositionRhw | VertexFormat.Diffuse | VertexFormat.Texture1; }
}
/// <summary>
/// Initializes a new instance of the <see cref="TransformedColoredTexturedVertex"/> struct.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="color">The color.</param>
/// <param name="textureCoordinates">The texture coordinates.</param>
public TransformedColoredTexturedVertex(Vector4 position, int color, Vector2 textureCoordinates)
: this()
{
Position = position;
Color = color;
TextureCoordinates = textureCoordinates;
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(TransformedColoredTexturedVertex left, TransformedColoredTexturedVertex right)
{
return left.Equals(right);
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(TransformedColoredTexturedVertex left, TransformedColoredTexturedVertex right)
{
return !(left == right);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode()
{
return Position.GetHashCode() + Color.GetHashCode() + TextureCoordinates.GetHashCode();
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
return Equals((TransformedColoredTexturedVertex)obj);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(TransformedColoredTexturedVertex other)
{
return (Position == other.Position && Color == other.Color && TextureCoordinates == other.TextureCoordinates);
}
/// <summary>
/// Returns a string representation of the current object.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> representing the vertex.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "{0} ({1}, {2})", Position.ToString(), System.Drawing.Color.FromArgb(Color).ToString(), TextureCoordinates.ToString());
}
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using SlimDX;
using SlimDX.Direct3D9;
namespace SampleFramework
{
/// <summary>
/// Represents a single transformed and colored vertex.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TransformedColoredVertex : IEquatable<TransformedColoredVertex>
{
/// <summary>
/// Gets or sets the transformed position of the vertex.
/// </summary>
/// <value>The transformed position of the vertex.</value>
[VertexElement(DeclarationType.Float4, DeclarationUsage.PositionTransformed)]
public Vector4 Position
{
get;
set;
}
/// <summary>
/// Gets or sets the color of the vertex.
/// </summary>
/// <value>The color of the vertex.</value>
[VertexElement(DeclarationType.Color, DeclarationUsage.Color)]
public int Color
{
get;
set;
}
/// <summary>
/// Gets the size in bytes.
/// </summary>
/// <value>The size in bytes.</value>
public static int SizeInBytes
{
get { return Marshal.SizeOf(typeof(TransformedColoredVertex)); }
}
/// <summary>
/// Gets the format.
/// </summary>
/// <value>The format.</value>
public static VertexFormat Format
{
get { return VertexFormat.PositionRhw | VertexFormat.Diffuse; }
}
/// <summary>
/// Initializes a new instance of the <see cref="TransformedColoredVertex"/> struct.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="color">The color.</param>
public TransformedColoredVertex(Vector4 position, int color)
: this()
{
Position = position;
Color = color;
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(TransformedColoredVertex left, TransformedColoredVertex right)
{
return left.Equals(right);
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(TransformedColoredVertex left, TransformedColoredVertex right)
{
return !(left == right);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode()
{
return Position.GetHashCode() + Color.GetHashCode();
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
return Equals((TransformedColoredVertex)obj);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(TransformedColoredVertex other)
{
return (Position == other.Position && Color == other.Color);
}
/// <summary>
/// Returns a string representation of the current object.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> representing the vertex.
/// </returns>
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "{0} ({1})", Position.ToString(), System.Drawing.Color.FromArgb(Color).ToString());
}
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security;
namespace SampleFramework
{
static class NativeMethods
{
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PeekMessage(out NativeMessage message, IntPtr hwnd, uint messageFilterMin, uint messageFilterMax, uint flags);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetClientRect(IntPtr hWnd, out NativeRectangle lpRect);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out NativeRectangle lpRect);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsZoomed(IntPtr hWnd);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AdjustWindowRect(ref NativeRectangle lpRect, uint dwStyle, [MarshalAs(UnmanagedType.Bool)]bool bMenu);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern uint SetThreadExecutionState(uint esFlags);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[SuppressUnmanagedCodeSecurityAttribute]
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
public static Rectangle GetClientRectangle(IntPtr handle)
{
NativeRectangle rect;
if (!GetClientRect(handle, out rect))
return Rectangle.Empty;
return Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
}
public static Rectangle GetWindowRectangle(IntPtr handle)
{
NativeRectangle rect;
if (!GetWindowRect(handle, out rect))
return Rectangle.Empty;
return Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace SampleFramework
{
[StructLayout(LayoutKind.Sequential)]
struct NativeRectangle
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct NativeMessage
{
public IntPtr hWnd;
public uint msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public Point p;
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public Point ptMinPosition;
public Point ptMaxPosition;
public NativeRectangle rcNormalPosition;
public static int Length
{
get { return Marshal.SizeOf(typeof(WINDOWPLACEMENT)); }
}
}
#region #28821 2014.1.23 yyagi add:
[StructLayout( LayoutKind.Sequential )]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public UInt32 cbData;
public IntPtr lpData;
}
#endregion
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2007-2009 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace SampleFramework
{
static class WindowConstants
{
public const int WM_SIZE = 0x5;
public const int WM_SYSCOMMAND = 0x112;
public const int WM_ACTIVATEAPP = 0x001C;
public const int WM_POWERBROADCAST = 0x0218;
public const int WM_COPYDATA = 0x004A;
public const int SC_SCREENSAVE = 0xF140;
public const int SC_MONITORPOWER = 0xF170;
public const int VK_LWIN = 0x5B;
public const int VK_RWIN = 0x5C;
public static readonly IntPtr SIZE_MINIMIZED = new IntPtr(1);
public static readonly IntPtr SIZE_MAXIMIZED = new IntPtr(2);
public static readonly IntPtr SIZE_RESTORED = new IntPtr(0);
public static readonly IntPtr PBT_APMQUERYSUSPEND = new IntPtr(0x0000);
public static readonly IntPtr PBT_APMRESUMESUSPEND = new IntPtr(0x0007);
public const int WPF_RESTORETOMAXIMIZED = 2;
public const int SW_RESTORE = 9;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_MAXIMIZE = 3;
public const int SW_SHOW = 5;
public const int SW_MINIMIZE = 6;
public const int GWL_STYLE = -16;
public const int GWL_EXSTYLE = -20;
public const long WS_MAXIMIZE = 0x01000000;
public const long WS_MINIMIZE = 0x20000000;
public const long WS_POPUP = 0x80000000;
public const long WS_SYSMENU = 0x00080000;
public const long WS_EX_TOPMOST = 0x00000008;
public const uint SWP_NOSIZE = 0x0001;
public const uint SWP_NOMOVE = 0x0002;
public const uint SWP_NOZORDER = 0x0004;
public const uint SWP_NOREDRAW = 0x0008;
public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_DISPLAY_REQUIRED = 0x00000002;
public const int MONITOR_DEFAULTTOPRIMARY = 1;
public const int WM_USER = 0x400;
}
}

View File

@ -0,0 +1,820 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using SharpDX;
using SharpDX.DirectInput;
namespace FDK
{
public class CInputJoystick : IInputDevice, IDisposable
{
// コンストラクタ
public CInputJoystick( IntPtr hWnd, DeviceInstance di, DirectInput directInput )
{
this.e入力デバイス種別 = E入力デバイス種別.Joystick;
this.GUID = di.InstanceGuid.ToString();
this.ID = 0;
try
{
this.devJoystick = new Joystick( directInput, di.InstanceGuid );
this.devJoystick.SetCooperativeLevel( hWnd, CooperativeLevel.Foreground | CooperativeLevel.Exclusive );
this.devJoystick.Properties.BufferSize = 32;
Trace.TraceInformation( this.devJoystick.Information.InstanceName + "を生成しました。" );
this.strDeviceName = this.devJoystick.Information.InstanceName;
}
catch
{
if( this.devJoystick != null )
{
this.devJoystick.Dispose();
this.devJoystick = null;
}
Trace.TraceError( this.devJoystick.Information.InstanceName, new object[] { " の生成に失敗しました。" } );
throw;
}
foreach( DeviceObjectInstance instance in this.devJoystick.GetObjects() )
{
if ((instance.ObjectId.Flags & DeviceObjectTypeFlags.Axis) != DeviceObjectTypeFlags.All)
{
this.devJoystick.GetObjectPropertiesById(instance.ObjectId).Range = new InputRange(-1000, 1000);
this.devJoystick.GetObjectPropertiesById(instance.ObjectId).DeadZone = 5000; // 50%をデッドゾーンに設定
// 軸をON/OFFの2値で使うならこれで十分
}
}
try
{
this.devJoystick.Acquire();
}
catch
{
}
for( int i = 0; i < this.bButtonState.Length; i++ )
this.bButtonState[ i ] = false;
for ( int i = 0; i < this.nPovState.Length; i++ )
this.nPovState[ i ] = -1;
//this.timer = new CTimer( CTimer.E種別.MultiMedia );
this.list入力イベント = new List<STInputEvent>(32);
}
// メソッド
public void SetID( int nID )
{
this.ID = nID;
}
#region [ IInputDevice ]
//-----------------
public E入力デバイス種別 e入力デバイス種別
{
get;
private set;
}
public string GUID
{
get;
private set;
}
public int ID
{
get;
private set;
}
public List<STInputEvent> list入力イベント
{
get;
private set;
}
public string strDeviceName
{
get;
set;
}
#region [ ]
private void POVの処理(int p, JoystickUpdate data)
{
int nPovDegree = data.Value;
STInputEvent e = new STInputEvent();
int nWay = (nPovDegree + 2250) / 4500;
if (nWay == 8) nWay = 0;
//Debug.WriteLine( "POVS:" + povs[ 0 ].ToString( CultureInfo.CurrentCulture ) + ", " +stevent.nKey );
//Debug.WriteLine( "nPovDegree=" + nPovDegree );
if (nPovDegree == -1)
{
e.nKey = 8 + 128 + this.nPovState[p];
this.nPovState[p] = -1;
//Debug.WriteLine( "POVS離された" + data.TimeStamp + " " + e.nKey );
e.b押された = false;
e.nVelocity = 0;
this.bButtonState[e.nKey] = false;
this.bButtonPullUp[e.nKey] = true;
}
else
{
this.nPovState[p] = nWay;
e.nKey = 8 + 128 + nWay;
e.b押された = true;
e.nVelocity = CInput管理.n通常音量;
this.bButtonState[e.nKey] = true;
this.bButtonPushDown[e.nKey] = true;
//Debug.WriteLine( "POVS押された" + data.TimeStamp + " " + e.nKey );
}
//e.nTimeStamp = data.TimeStamp;
e.nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp);
this.list入力イベント.Add(e);
}
#endregion
public void tポーリング(bool bWindowがアクティブ中, bool bバッファ入力を使用する)
{
#region [ bButtonフラグ初期化 ]
for ( int i = 0; i < 256; i++ )
{
this.bButtonPushDown[i] = false;
this.bButtonPullUp[i] = false;
}
#endregion
if (bWindowがアクティブ中)
{
this.devJoystick.Acquire();
this.devJoystick.Poll();
// this.list入力イベント = new List<STInputEvent>( 32 );
this.list入力イベント.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
if( bバッファ入力を使用する )
{
#region [ a. ]
//-----------------------------
var bufferedData = this.devJoystick.GetBufferedData();
//if( Result.Last.IsSuccess && bufferedData != null )
{
foreach (JoystickUpdate data in bufferedData)
{
switch (data.Offset)
{
case JoystickOffset.X:
#region [ X軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 0, 1);
//-----------------------------
#endregion
#region [ X軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 1, 0);
//-----------------------------
#endregion
break;
case JoystickOffset.Y:
#region [ Y軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 2, 3);
//-----------------------------
#endregion
#region [ Y軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 3, 2);
//-----------------------------
#endregion
break;
case JoystickOffset.Z:
#region [ Z軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 4, 5);
//-----------------------------
#endregion
#region [ Z軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 5, 4);
//-----------------------------
#endregion
break;
case JoystickOffset.RotationZ:
#region [ Z軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 6, 7);
//-----------------------------
#endregion
#region [ Z軸 ]
//-----------------------------
bButtonUpDown(data, data.Value, 7, 6);
//-----------------------------
#endregion
break;
// #24341 2011.3.12 yyagi: POV support
// #26880 2011.12.6 yyagi: improve to support "pullup" of POV buttons
case JoystickOffset.PointOfViewControllers0:
#region [ POV HAT 4/8way ]
POVの処理(0, data);
#endregion
break;
case JoystickOffset.PointOfViewControllers1:
#region [ POV HAT 4/8way ]
POVの処理(1, data);
#endregion
break;
case JoystickOffset.PointOfViewControllers2:
#region [ POV HAT 4/8way ]
POVの処理(2, data);
#endregion
break;
case JoystickOffset.PointOfViewControllers3:
#region [ POV HAT 4/8way ]
POVの処理(3, data);
#endregion
break;
default:
#region [ ]
//-----------------------------
//for ( int i = 0; i < 32; i++ )
if (data.Offset >= JoystickOffset.Buttons0 && data.Offset <= JoystickOffset.Buttons31)
{
int i = data.Offset - JoystickOffset.Buttons0;
if ((data.Value & 0x80) != 0)
{
STInputEvent e = new STInputEvent()
{
nKey = 8 + i,
b押された = true,
b離された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(e);
this.bButtonState[8 + i] = true;
this.bButtonPushDown[8 + i] = true;
}
else //if ( ( data.Value & 0x80 ) == 0 )
{
var ev = new STInputEvent()
{
nKey = 8 + i,
b押された = false,
b離された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量,
};
this.list入力イベント.Add(ev);
this.bButtonState[8 + i] = false;
this.bButtonPullUp[8 + i] = true;
}
}
//-----------------------------
#endregion
break;
}
}
}
//-----------------------------
#endregion
}
else
{
#region [ b. ]
//-----------------------------
JoystickState currentState = this.devJoystick.GetCurrentState();
//if( Result.Last.IsSuccess && currentState != null )
{
#region [ X軸 ]
//-----------------------------
if( currentState.X < -500 )
{
if( this.bButtonState[ 0 ] == false )
{
STInputEvent ev = new STInputEvent()
{
nKey = 0,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[0] = true;
this.bButtonPushDown[0] = true;
}
}
else
{
if( this.bButtonState[0] == true )
{
STInputEvent ev = new STInputEvent()
{
nKey = 0,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[0] = false;
this.bButtonPullUp[0] = true;
}
}
//-----------------------------
#endregion
#region [ X軸 ]
//-----------------------------
if(currentState.X > 500)
{
if(this.bButtonState[1] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 1,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[1] = true;
this.bButtonPushDown[1] = true;
}
}
else
{
if(this.bButtonState[1] == true)
{
STInputEvent event7 = new STInputEvent()
{
nKey = 1,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(event7);
this.bButtonState[1] = false;
this.bButtonPullUp[1] = true;
}
}
//-----------------------------
#endregion
#region [ Y軸 ]
//-----------------------------
if(currentState.Y < -500)
{
if(this.bButtonState[ 2 ] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 2,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[2] = true;
this.bButtonPushDown[2] = true;
}
}
else
{
if(this.bButtonState[2] == true)
{
STInputEvent ev = new STInputEvent()
{
nKey = 2,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[2] = false;
this.bButtonPullUp[2] = true;
}
}
//-----------------------------
#endregion
#region [ Y軸 ]
//-----------------------------
if(currentState.Y > 500)
{
if(this.bButtonState[3] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 3,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[3] = true;
this.bButtonPushDown[3] = true;
}
}
else
{
if(this.bButtonState[3] == true)
{
STInputEvent ev = new STInputEvent()
{
nKey = 3,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[3] = false;
this.bButtonPullUp[3] = true;
}
}
//-----------------------------
#endregion
#region [ Z軸 ]
//-----------------------------
if(currentState.Z < -500)
{
if(this.bButtonState[4] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 4,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[4] = true;
this.bButtonPushDown[4] = true;
}
}
else
{
if(this.bButtonState[4] == true)
{
STInputEvent ev = new STInputEvent()
{
nKey = 4,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[4] = false;
this.bButtonPullUp[4] = true;
}
}
//-----------------------------
#endregion
#region [ Z軸 ]
//-----------------------------
if(currentState.Z > 500)
{
if( this.bButtonState[5] == false )
{
STInputEvent ev = new STInputEvent()
{
nKey = 5,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add( ev );
this.bButtonState[5] = true;
this.bButtonPushDown[5] = true;
}
}
else
{
if(this.bButtonState[5] == true)
{
STInputEvent event15 = new STInputEvent()
{
nKey = 5,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(event15);
this.bButtonState[5] = false;
this.bButtonPullUp[5] = true;
}
}
//-----------------------------
#endregion
#region [ Z軸回転 ]
//-----------------------------
if (currentState.RotationZ < -500)
{
if (this.bButtonState[6] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 6,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[6] = true;
this.bButtonPushDown[6] = true;
}
}
else
{
if (this.bButtonState[6] == true)
{
STInputEvent ev = new STInputEvent()
{
nKey = 6,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[6] = false;
this.bButtonPullUp[6] = true;
}
}
//-----------------------------
#endregion
#region [ Z軸回転 ]
//-----------------------------
if (currentState.RotationZ > 500)
{
if (this.bButtonState[7] == false)
{
STInputEvent ev = new STInputEvent()
{
nKey = 7,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(ev);
this.bButtonState[7] = true;
this.bButtonPushDown[7] = true;
}
}
else
{
if (this.bButtonState[7] == true)
{
STInputEvent event15 = new STInputEvent()
{
nKey = 7,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(event15);
this.bButtonState[7] = false;
this.bButtonPullUp[7] = true;
}
}
//-----------------------------
#endregion
#region [ ]
//-----------------------------
bool bIsButtonPressedReleased = false;
bool[] buttons = currentState.Buttons;
for (int j = 0; (j < buttons.Length) && (j < 128); j++)
{
if (this.bButtonState[8 + j] == false && buttons[j])
{
STInputEvent item = new STInputEvent()
{
nKey = 8 + j,
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bButtonState[8 + j] = true;
this.bButtonPushDown[8 + j] = true;
bIsButtonPressedReleased = true;
}
else if( this.bButtonState[8 + j] == true && !buttons[j] )
{
STInputEvent item = new STInputEvent()
{
nKey = 8 + j,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bButtonState[8 + j] = false;
this.bButtonPullUp[8 + j] = true;
bIsButtonPressedReleased = true;
}
}
//-----------------------------
#endregion
// #24341 2011.3.12 yyagi: POV support
#region [ POV HAT 4/8way (only single POV switch is supported)]
int[] povs = currentState.PointOfViewControllers;
if (povs != null)
{
if ( povs[0] >= 0 )
{
int nPovDegree = povs[0];
int nWay = (nPovDegree + 2250) / 4500;
if (nWay == 8) nWay = 0;
if (this.bButtonState[8 + 128 + nWay] == false)
{
STInputEvent stevent = new STInputEvent()
{
nKey = 8 + 128 + nWay,
//Debug.WriteLine( "POVS:" + povs[ 0 ].ToString( CultureInfo.CurrentCulture ) + ", " +stevent.nKey );
b押された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(stevent);
this.bButtonState[stevent.nKey] = true;
this.bButtonPushDown[stevent.nKey] = true;
}
}
else if (bIsButtonPressedReleased == false) // #xxxxx 2011.12.3 yyagi 他のボタンが何も押され/離されてないPOVが離された
{
int nWay = 0;
for (int i = 8 + 0x80; i < 8 + 0x80 + 8; i++)
{ // 離されたボタンを調べるために、元々押されていたボタンを探す。
if (this.bButtonState[i] == true) // DirectInputを直接いじるならこんなことしなくて良いのに、あぁ面倒。
{ // この処理が必要なために、POVを1個しかサポートできない。無念。
nWay = i;
break;
}
}
if (nWay != 0)
{
STInputEvent stevent = new STInputEvent()
{
nKey = nWay,
b押された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = 0
};
this.list入力イベント.Add(stevent);
this.bButtonState[nWay] = false;
this.bButtonPullUp[nWay] = true;
}
}
}
#endregion
}
//-----------------------------
#endregion
}
}
}
public bool bキーが押された(int nButton)
{
return this.bButtonPushDown[nButton];
}
public bool bキーが押されている(int nButton)
{
return this.bButtonState[nButton];
}
public bool bキーが離された(int nButton)
{
return this.bButtonPullUp[nButton];
}
public bool bキーが離されている(int nButton)
{
return !this.bButtonState[nButton];
}
//-----------------
#endregion
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.bDispose完了済み)
{
if(this.devJoystick != null)
{
this.devJoystick.Dispose();
this.devJoystick = null;
}
//if( this.timer != null )
//{
// this.timer.Dispose();
// this.timer = null;
//}
if (this.list入力イベント != null)
{
this.list入力イベント = null;
}
this.bDispose完了済み = true;
}
}
//-----------------
#endregion
// その他
#region [ private ]
//-----------------
private bool[] bButtonPullUp = new bool[0x100];
private bool[] bButtonPushDown = new bool[0x100];
private bool[] bButtonState = new bool[0x100]; // 0-5: XYZ, 6 - 0x128+5: buttons, 0x128+6 - 0x128+6+8: POV/HAT
private int[] nPovState = new int[4];
private bool bDispose完了済み;
private Joystick devJoystick;
//private CTimer timer;
private void bButtonUpDown(JoystickUpdate data, int axisdata, int target, int contrary) // #26871 2011.12.3 軸の反転に対応するためにリファクタ
{
int targetsign = (target < contrary) ? -1 : 1;
if (Math.Abs(axisdata) > 500 && (targetsign == Math.Sign(axisdata))) // 軸の最大値の半分を超えていて、かつ
{
if (bDoUpDownCore(target, data, false)) // 直前までは超えていなければ、今回ON
{
//Debug.WriteLine( "X-ON " + data.TimeStamp + " " + axisdata );
}
else
{
//Debug.WriteLine( "X-ONx " + data.TimeStamp + " " + axisdata );
}
bDoUpDownCore(contrary, data, true); // X軸+ == ON から X軸-のONレンジに来たら、X軸+はOFF
}
else if ((axisdata <= 0 && targetsign <= 0) || (axisdata >= 0 && targetsign >= 0)) // 軸の最大値の半分を超えておらず、かつ
{
//Debug.WriteLine( "X-OFF? " + data.TimeStamp + " " + axisdata );
if (bDoUpDownCore(target, data, true)) // 直前までは超えていたのならば、今回OFF
{
//Debug.WriteLine( "X-OFF " + data.TimeStamp + " " + axisdata );
}
else if (bDoUpDownCore(contrary, data, true)) // X軸+ == ON から X軸-のOFFレンジにきたら、X軸+はOFF
{
//Debug.WriteLine( "X-OFFx " + data.TimeStamp + " " + axisdata );
}
}
}
/// <summary>
/// 必要に応じて軸ボタンの上げ下げイベントを発生する
/// </summary>
/// <param name="target">軸ボタン番号 0=-X 1=+X ... 5=+Z</param>
/// <param name="data"></param>
/// <param name="currentMode">直前のボタン状態 true=押されていた</param>
/// <returns>上げ下げイベント発生時true</returns>
private bool bDoUpDownCore(int target, JoystickUpdate data, bool lastMode)
{
if ( this.bButtonState[target] == lastMode )
{
STInputEvent e = new STInputEvent()
{
nKey = target,
b押された = !lastMode,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = (lastMode) ? 0 : CInput管理.n通常音量
};
this.list入力イベント.Add(e);
this.bButtonState[target] = !lastMode;
if (lastMode)
{
this.bButtonPullUp[target] = true;
}
else
{
this.bButtonPushDown[target] = true;
}
return true;
}
return false;
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,296 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using SharpDX;
using SharpDX.DirectInput;
using SlimDXKey = SlimDXKeys.Key;
using SharpDXKey = SharpDX.DirectInput.Key;
namespace FDK
{
public class CInputKeyboard : IInputDevice, IDisposable
{
// コンストラクタ
public CInputKeyboard(IntPtr hWnd, DirectInput directInput)
{
this.e入力デバイス種別 = E入力デバイス種別.Keyboard;
this.GUID = "";
this.ID = 0;
try
{
this.devKeyboard = new Keyboard(directInput);
this.devKeyboard.SetCooperativeLevel(hWnd, CooperativeLevel.NoWinKey | CooperativeLevel.Foreground | CooperativeLevel.NonExclusive);
this.devKeyboard.Properties.BufferSize = 32;
Trace.TraceInformation(this.devKeyboard.Information.ProductName.Trim(new char[] { '\0' }) + " を生成しました。"); // なぜか0x00のゴミが出るので削除
this.strDeviceName = this.devKeyboard.Information.ProductName.Trim(new char[] { '\0' });
}
catch
{
if(this.devKeyboard != null)
{
this.devKeyboard.Dispose();
this.devKeyboard = null;
}
Trace.TraceWarning("Keyboard デバイスの生成に失敗しました。");
throw;
}
try
{
this.devKeyboard.Acquire();
}
catch
{
}
for (int i = 0; i < this.bKeyState.Length; i++)
this.bKeyState[i] = false;
//this.timer = new CTimer( CTimer.E種別.MultiMedia );
this.list入力イベント = new List<STInputEvent>(32);
// this.ct = new CTimer( CTimer.E種別.PerformanceCounter );
}
// メソッド
#region [ IInputDevice ]
//-----------------
public E入力デバイス種別 e入力デバイス種別 { get; private set; }
public string GUID { get; private set; }
public int ID { get; private set; }
public List<STInputEvent> list入力イベント { get; private set; }
public string strDeviceName { get; set; }
public void tポーリング(bool bWindowがアクティブ中, bool bバッファ入力を使用する)
{
for (int i = 0; i < 256; i++)
{
this.bKeyPushDown[i] = false;
this.bKeyPullUp[i] = false;
}
if (bWindowがアクティブ中 && (this.devKeyboard != null))
{
this.devKeyboard.Acquire();
this.devKeyboard.Poll();
//this.list入力イベント = new List<STInputEvent>( 32 );
this.list入力イベント.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
int posEnter = -1;
//string d = DateTime.Now.ToString( "yyyy/MM/dd HH:mm:ss.ffff" );
if (bバッファ入力を使用する)
{
#region [ a. ]
//-----------------------------
var bufferedData = this.devKeyboard.GetBufferedData();
//if ( Result.Last.IsSuccess && bufferedData != null )
{
foreach (KeyboardUpdate data in bufferedData)
{
// #xxxxx: 2017.5.7: from: DIK (SharpDX.DirectInput.Key) を SlimDX.DirectInput.Key に変換。
var key = DeviceConstantConverter.DIKtoKey(data.Key);
if (SlimDXKey.Unknown == key)
continue; // 未対応キーは無視。
//foreach ( Key key in data.PressedKeys )
if (data.IsPressed)
{
// #23708 2016.3.19 yyagi; Even if we remove ALT+ENTER key input by SuppressKeyPress = true in Form,
// it doesn't affect to DirectInput (ALT+ENTER does not remove)
// So we ignore ENTER input in ALT+ENTER combination here.
// Note: ENTER will be alived if you keyup ALT after ALT+ENTER.
if (key != SlimDXKey.Return || (bKeyState[(int)SlimDXKey.LeftAlt] == false && bKeyState[(int)SlimDXKey.RightAlt] == false))
{
STInputEvent item = new STInputEvent()
{
nKey = (int)key,
b押された = true,
b離された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bKeyState[(int)key] = true;
this.bKeyPushDown[(int)key] = true;
}
//if ( item.nKey == (int) SlimDXKey.Space )
//{
// Trace.TraceInformation( "FDK(buffered): SPACE key registered. " + ct.nシステム時刻 );
//}
}
//foreach ( Key key in data.ReleasedKeys )
if (data.IsReleased)
{
STInputEvent item = new STInputEvent()
{
nKey = (int)key,
b押された = false,
b離された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bKeyState[(int)key] = false;
this.bKeyPullUp[(int)key] = true;
}
}
}
//-----------------------------
#endregion
}
else
{
#region [ b. ]
//-----------------------------
KeyboardState currentState = this.devKeyboard.GetCurrentState();
//if ( Result.Last.IsSuccess && currentState != null )
{
foreach (SharpDXKey dik in currentState.PressedKeys)
{
// #xxxxx: 2017.5.7: from: DIK (SharpDX.DirectInput.Key) を SlimDX.DirectInput.Key に変換。
var key = DeviceConstantConverter.DIKtoKey(dik);
if (SlimDXKey.Unknown == key)
continue; // 未対応キーは無視。
if (this.bKeyState[(int)key] == false)
{
if (key != SlimDXKey.Return || (bKeyState[(int)SlimDXKey.LeftAlt] == false && bKeyState[(int)SlimDXKey.RightAlt] == false)) // #23708 2016.3.19 yyagi
{
var ev = new STInputEvent()
{
nKey = (int)key,
b押された = true,
b離された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量,
};
this.list入力イベント.Add(ev);
this.bKeyState[(int)key] = true;
this.bKeyPushDown[(int)key] = true;
}
//if ( (int) key == (int) SlimDXKey.Space )
//{
// Trace.TraceInformation( "FDK(direct): SPACE key registered. " + ct.nシステム時刻 );
//}
}
}
//foreach ( Key key in currentState.ReleasedKeys )
foreach (SharpDXKey dik in currentState.AllKeys)
{
// #xxxxx: 2017.5.7: from: DIK (SharpDX.DirectInput.Key) を SlimDX.DirectInput.Key に変換。
var key = DeviceConstantConverter.DIKtoKey(dik);
if (SlimDXKey.Unknown == key)
continue; // 未対応キーは無視。
if (this.bKeyState[(int)key] == true && !currentState.IsPressed(dik)) // 前回は押されているのに今回は押されていない → 離された
{
var ev = new STInputEvent()
{
nKey = (int)key,
b押された = false,
b離された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量,
};
this.list入力イベント.Add(ev);
this.bKeyState[(int) key] = false;
this.bKeyPullUp[(int) key] = true;
}
}
}
//-----------------------------
#endregion
}
#region [#23708 2011.4.8 yyagi Altが押されているときはEnter押下情報を削除する -> ]
//if ( this.bKeyState[ (int) SlimDXKey.RightAlt ] ||
// this.bKeyState[ (int) SlimDXKey.LeftAlt ] )
//{
// int cr = (int) SlimDXKey.Return;
// this.bKeyPushDown[ cr ] = false;
// this.bKeyPullUp[ cr ] = false;
// this.bKeyState[ cr ] = false;
//}
#endregion
}
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool bキーが押された(int nKey)
{
return this.bKeyPushDown[nKey];
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool bキーが押されている(int nKey)
{
return this.bKeyState[ nKey ];
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool bキーが離された(int nKey)
{
return this.bKeyPullUp[nKey];
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool bキーが離されている(int nKey)
{
return !this.bKeyState[nKey];
}
//-----------------
#endregion
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.bDispose完了済み)
{
if(this.devKeyboard != null)
{
this.devKeyboard.Dispose();
this.devKeyboard = null;
}
//if( this.timer != null )
//{
// this.timer.Dispose();
// this.timer = null;
//}
if (this.list入力イベント != null)
{
this.list入力イベント = null;
}
this.bDispose完了済み = true;
}
}
//-----------------
#endregion
// その他
#region [ private ]
//-----------------
private bool[] bKeyPullUp = new bool[256];
private bool[] bKeyPushDown = new bool[256];
private bool[] bKeyState = new bool[256];
private bool bDispose完了済み;
private Keyboard devKeyboard;
//private CTimer timer;
//private CTimer ct;
//-----------------
#endregion
}
}

View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace FDK
{
public class CInputMIDI : IInputDevice, IDisposable
{
// プロパティ
public IntPtr hMidiIn;
public List<STInputEvent> listEventBuffer;
// コンストラクタ
public CInputMIDI(uint nID)
{
this.hMidiIn = IntPtr.Zero;
this.listEventBuffer = new List<STInputEvent>(32);
this.list入力イベント = new List<STInputEvent>(32);
this.e入力デバイス種別 = E入力デバイス種別.MidiIn;
this.GUID = "";
this.ID = (int)nID;
this.strDeviceName = ""; // CInput管理で初期化する
}
// メソッド
public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2, long n受信システム時刻)
{
if (wMsg == CWin32.MIM_DATA)
{
int nMIDIevent = (int)dwParam1 & 0xF0;
int nPara1 = ((int)dwParam1 >> 8) & 0xFF;
int nPara2 = ((int)dwParam1 >> 16) & 0xFF;
int nPara3 = ((int)dwParam2 >> 8) & 0xFF;
int nPara4 = ((int)dwParam2 >> 16) & 0xFF;
// Trace.TraceInformation( "MIDIevent={0:X2} para1={1:X2} para2={2:X2}", nMIDIevent, nPara1, nPara2 ,nPara3,nPara4);
if ((nMIDIevent == 0x90) && (nPara2 != 0)) // Note ON
{
STInputEvent item = new STInputEvent();
item.nKey = nPara1;
item.b押された = true;
item.nTimeStamp = n受信システム時刻;
item.nVelocity = nPara2;
this.listEventBuffer.Add(item);
}
//else if ( ( nMIDIevent == 0xB0 ) && ( nPara1 == 4 ) ) // Ctrl Chg #04: Foot Controller
//{
// STInputEvent item = new STInputEvent();
// item.nKey = nPara1;
// item.b押された = true;
// item.nTimeStamp = n受信システム時刻;
// item.nVelocity = nPara2;
// this.listEventBuffer.Add( item );
//}
}
}
#region [ IInputDevice ]
//-----------------
public E入力デバイス種別 e入力デバイス種別 { get; private set; }
public string GUID { get; private set; }
public int ID { get; private set; }
public List<STInputEvent> list入力イベント { get; private set; }
public string strDeviceName { get; set; }
public void tポーリング(bool bWindowがアクティブ中, bool bバッファ入力を使用する)
{
// this.list入力イベント = new List<STInputEvent>( 32 );
this.list入力イベント.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
for (int i = 0; i < this.listEventBuffer.Count; i++)
this.list入力イベント.Add(this.listEventBuffer[i]);
this.listEventBuffer.Clear();
}
public bool bキーが押された(int nKey)
{
foreach (STInputEvent event2 in this.list入力イベント)
{
if ((event2.nKey == nKey) && event2.b押された)
{
return true;
}
}
return false;
}
public bool bキーが押されている(int nKey)
{
return false;
}
public bool bキーが離された(int nKey)
{
return false;
}
public bool bキーが離されている(int nKey)
{
return false;
}
//-----------------
#endregion
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if (this.listEventBuffer != null)
{
this.listEventBuffer = null;
}
if (this.list入力イベント != null)
{
this.list入力イベント = null;
}
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,251 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using SharpDX;
using SharpDX.DirectInput;
namespace FDK
{
public class CInputMouse : IInputDevice, IDisposable
{
// 定数
public const int nマウスの最大ボタン数 = 8;
// コンストラクタ
public CInputMouse(IntPtr hWnd, DirectInput directInput)
{
this.e入力デバイス種別 = E入力デバイス種別.Mouse;
this.GUID = "";
this.ID = 0;
try
{
this.devMouse = new Mouse(directInput);
this.devMouse.SetCooperativeLevel(hWnd, CooperativeLevel.Foreground | CooperativeLevel.NonExclusive);
this.devMouse.Properties.BufferSize = 0x20;
Trace.TraceInformation(this.devMouse.Information.ProductName.Trim(new char[] { '\0' }) + " を生成しました。"); // なぜか0x00のゴミが出るので削除
this.strDeviceName = this.devMouse.Information.ProductName.Trim(new char[] { '\0' });
}
catch
{
if (this.devMouse != null)
{
this.devMouse.Dispose();
this.devMouse = null;
}
Trace.TraceWarning("Mouse デバイスの生成に失敗しました。");
throw;
}
try
{
this.devMouse.Acquire();
}
catch
{
}
for (int i = 0; i < this.bMouseState.Length; i++)
this.bMouseState[i] = false;
//this.timer = new CTimer( CTimer.E種別.MultiMedia );
this.list入力イベント = new List<STInputEvent>(32);
}
// メソッド
#region [ IInputDevice ]
//-----------------
public E入力デバイス種別 e入力デバイス種別 { get; private set; }
public string GUID { get; private set; }
public int ID { get; private set; }
public List<STInputEvent> list入力イベント { get; private set; }
public string strDeviceName { get; set; }
public void tポーリング(bool bWindowがアクティブ中, bool bバッファ入力を使用する)
{
for (int i = 0; i < 8; i++)
{
this.bMousePushDown[i] = false;
this.bMousePullUp[i] = false;
}
if (bWindowがアクティブ中 && (this.devMouse != null))
{
this.devMouse.Acquire();
this.devMouse.Poll();
// this.list入力イベント = new List<STInputEvent>( 32 );
this.list入力イベント.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
if (bバッファ入力を使用する)
{
#region [ a. ]
//-----------------------------
var bufferedData = this.devMouse.GetBufferedData();
//if( Result.Last.IsSuccess && bufferedData != null )
{
foreach (MouseUpdate data in bufferedData)
{
var mouseButton = new[] {
MouseOffset.Buttons0,
MouseOffset.Buttons1,
MouseOffset.Buttons2,
MouseOffset.Buttons3,
MouseOffset.Buttons4,
MouseOffset.Buttons5,
MouseOffset.Buttons6,
MouseOffset.Buttons7,
};
for (int k = 0; k < 8; k++)
{
//if( data.IsPressed( k ) )
if (data.Offset == mouseButton[k] && ((data.Value & 0x80) != 0))
{
STInputEvent item = new STInputEvent()
{
nKey = k,
b押された = true,
b離された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bMouseState[k] = true;
this.bMousePushDown[k] = true;
}
else if (data.Offset == mouseButton[k] && this.bMouseState[k] == true && ((data.Value & 0x80) == 0))
//else if( data.IsReleased( k ) )
{
STInputEvent item = new STInputEvent()
{
nKey = k,
b押された = false,
b離された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nサウンドタイマーのシステム時刻msへの変換(data.Timestamp),
nVelocity = CInput管理.n通常音量
};
this.list入力イベント.Add(item);
this.bMouseState[k] = false;
this.bMousePullUp[k] = true;
}
}
}
}
//-----------------------------
#endregion
}
else
{
#region [ b. ]
//-----------------------------
MouseState currentState = this.devMouse.GetCurrentState();
//if( Result.Last.IsSuccess && currentState != null )
{
bool[] buttons = currentState.Buttons;
for (int j = 0; (j < buttons.Length) && (j < 8); j++)
{
if (this.bMouseState[j] == false && buttons[j] == true)
{
var ev = new STInputEvent()
{
nKey = j,
b押された = true,
b離された = false,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量,
};
this.list入力イベント.Add(ev);
this.bMouseState[j] = true;
this.bMousePushDown[j] = true;
}
else if(this.bMouseState[j] == true && buttons[j] == false)
{
var ev = new STInputEvent()
{
nKey = j,
b押された = false,
b離された = true,
nTimeStamp = CSound管理.rc演奏用タイマ.nシステム時刻, // 演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
nVelocity = CInput管理.n通常音量,
};
this.list入力イベント.Add(ev);
this.bMouseState[j] = false;
this.bMousePullUp[j] = true;
}
}
}
//-----------------------------
#endregion
}
}
}
public bool bキーが押された(int nButton)
{
return (((0 <= nButton) && (nButton < 8)) && this.bMousePushDown[nButton]);
}
public bool bキーが押されている(int nButton)
{
return (((0 <= nButton) && (nButton < 8)) && this.bMouseState[nButton]);
}
public bool bキーが離された(int nButton)
{
return (((0 <= nButton) && (nButton < 8)) && this.bMousePullUp[nButton]);
}
public bool bキーが離されている(int nButton)
{
return (((0 <= nButton) && (nButton < 8)) && !this.bMouseState[nButton]);
}
//-----------------
#endregion
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.bDispose完了済み)
{
if(this.devMouse != null)
{
this.devMouse.Dispose();
this.devMouse = null;
}
//if( this.timer != null )
//{
// this.timer.Dispose();
// this.timer = null;
//}
if (this.list入力イベント != null)
{
this.list入力イベント = null;
}
this.bDispose完了済み = true;
}
}
//-----------------
#endregion
// その他
#region [ private ]
//-----------------
private bool bDispose完了済み;
private bool[] bMousePullUp = new bool[8];
private bool[] bMousePushDown = new bool[8];
private bool[] bMouseState = new bool[8];
private Mouse devMouse;
//private CTimer timer;
//-----------------
#endregion
}
}

View File

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using SharpDX.DirectInput;
namespace FDK
{
public class CInput管理 : IDisposable
{
// 定数
public static int n通常音量 = 110;
// プロパティ
public List<IInputDevice> list入力デバイス
{
get;
private set;
}
public IInputDevice Keyboard
{
get
{
if (this._Keyboard != null)
{
return this._Keyboard;
}
foreach (IInputDevice device in this.list入力デバイス)
{
if (device.e入力デバイス種別 == E入力デバイス種別.Keyboard)
{
this._Keyboard = device;
return device;
}
}
return null;
}
}
public IInputDevice Mouse
{
get
{
if (this._Mouse != null)
{
return this._Mouse;
}
foreach (IInputDevice device in this.list入力デバイス)
{
if (device.e入力デバイス種別 == E入力デバイス種別.Mouse)
{
this._Mouse = device;
return device;
}
}
return null;
}
}
// コンストラクタ
public CInput管理(IntPtr hWnd, bool bUseMidiIn = true)
{
CInput管理初期化(hWnd, bUseMidiIn);
}
public void CInput管理初期化(IntPtr hWnd, bool bUseMidiIn)
{
this.directInput = new DirectInput();
// this.timer = new CTimer( CTimer.E種別.MultiMedia );
this.list入力デバイス = new List<IInputDevice>(10);
#region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
CInputKeyboard cinputkeyboard = null;
CInputMouse cinputmouse = null;
try
{
cinputkeyboard = new CInputKeyboard(hWnd, directInput);
cinputmouse = new CInputMouse(hWnd, directInput);
}
catch
{
}
if (cinputkeyboard != null)
{
this.list入力デバイス.Add(cinputkeyboard);
}
if (cinputmouse != null)
{
this.list入力デバイス.Add(cinputmouse);
}
#endregion
#region [ Enumerate joypad ]
foreach (DeviceInstance instance in this.directInput.GetDevices(DeviceClass.GameControl, DeviceEnumerationFlags.AttachedOnly))
{
this.list入力デバイス.Add(new CInputJoystick(hWnd, instance, directInput));
}
#endregion
if (bUseMidiIn)
{
this.proc = new CWin32.MidiInProc(this.MidiInCallback);
uint nMidiDevices = CWin32.midiInGetNumDevs();
Trace.TraceInformation("MIDI入力デバイス数: {0}", nMidiDevices);
for (uint i = 0; i < nMidiDevices; i++)
{
CInputMIDI item = new CInputMIDI(i);
CWin32.MIDIINCAPS lpMidiInCaps = new CWin32.MIDIINCAPS();
uint num3 = CWin32.midiInGetDevCaps(i, ref lpMidiInCaps, (uint)Marshal.SizeOf(lpMidiInCaps));
if (num3 != 0)
{
Trace.TraceError("MIDI In: Device{0}: midiInDevCaps(): {1:X2}: ", i, num3);
}
else
{
uint ret = CWin32.midiInOpen(ref item.hMidiIn, i, this.proc, IntPtr.Zero, 0x30000);
Trace.TraceInformation("midiInOpen()==" + ret);
Trace.TraceInformation("item.hMidiIn==" + item.hMidiIn.ToString());
if ((ret == 0) && (item.hMidiIn != IntPtr.Zero))
{
CWin32.midiInStart(item.hMidiIn);
Trace.TraceInformation("MIDI In: [{0}] \"{1}\" の入力受付を開始しました。", i, lpMidiInCaps.szPname);
item.strDeviceName = lpMidiInCaps.szPname;
this.list入力デバイス.Add(item);
continue;
}
}
Trace.TraceError("MIDI In: [{0}] \"{1}\" の入力受付の開始に失敗しました。", i, lpMidiInCaps.szPname);
}
}
else
{
Trace.TraceInformation("DTXVモードのため、MIDI入力は使用しません。");
}
}
// メソッド
public IInputDevice Joystick(int ID)
{
foreach (IInputDevice device in this.list入力デバイス)
{
if ((device.e入力デバイス種別 == E入力デバイス種別.Joystick) && (device.ID == ID))
{
return device;
}
}
return null;
}
public IInputDevice Joystick(string GUID)
{
foreach (IInputDevice device in this.list入力デバイス)
{
if ((device.e入力デバイス種別 == E入力デバイス種別.Joystick) && device.GUID.Equals(GUID))
{
return device;
}
}
return null;
}
public IInputDevice MidiIn(int ID)
{
foreach (IInputDevice device in this.list入力デバイス)
{
if ((device.e入力デバイス種別 == E入力デバイス種別.MidiIn) && (device.ID == ID))
{
return device;
}
}
return null;
}
public void tポーリング(bool bWindowがアクティブ中, bool bバッファ入力を使用する)
{
lock (this.objMidiIn排他用)
{
// foreach( IInputDevice device in this.list入力デバイス )
for (int i = this.list入力デバイス.Count - 1; i >= 0; i--) // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove().
{
IInputDevice device = this.list入力デバイス[i];
try
{
device.tポーリング(bWindowがアクティブ中, bバッファ入力を使用する);
}
catch (SharpDX.SharpDXException e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
{
if (e.ResultCode == ResultCode.OtherApplicationHasPriority)
{
// #xxxxx: 2017.5.9: from: このエラーの時は、何もしない。
}
else
{
// #xxxxx: 2017.5.9: from: その他のエラーの場合は、デバイスが外されたと想定してRemoveする。
this.list入力デバイス.Remove(device);
device.Dispose();
Trace.TraceError("tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。");
}
}
}
}
}
#region [ IDisposableα ]
//-----------------
public void Dispose()
{
this.Dispose(true);
}
public void Dispose(bool disposeManagedObjects)
{
if (!this.bDisposed済み)
{
if (disposeManagedObjects)
{
foreach (IInputDevice device in this.list入力デバイス)
{
CInputMIDI tmidi = device as CInputMIDI;
if (tmidi != null)
{
CWin32.midiInStop(tmidi.hMidiIn);
CWin32.midiInReset(tmidi.hMidiIn);
CWin32.midiInClose(tmidi.hMidiIn);
Trace.TraceInformation("MIDI In: [{0}] を停止しました。", new object[] { tmidi.ID });
}
}
foreach (IInputDevice device2 in this.list入力デバイス)
{
device2.Dispose();
}
lock (this.objMidiIn排他用)
{
this.list入力デバイス.Clear();
}
this.directInput.Dispose();
//if( this.timer != null )
//{
// this.timer.Dispose();
// this.timer = null;
//}
}
this.bDisposed済み = true;
}
}
~CInput管理()
{
this.Dispose(false);
GC.KeepAlive(this);
}
//-----------------
#endregion
// その他
#region [ private ]
//-----------------
private DirectInput directInput;
private IInputDevice _Keyboard;
private IInputDevice _Mouse;
private bool bDisposed済み;
private List<uint> listHMIDIIN = new List<uint>(8);
private object objMidiIn排他用 = new object();
private CWin32.MidiInProc proc;
//private CTimer timer;
private void MidiInCallback(IntPtr hMidiIn, uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2)
{
int p = (int)dwParam1 & 0xF0;
if (wMsg != CWin32.MIM_DATA || (p != 0x80 && p != 0x90 && p != 0xB0))
return;
long time = CSound管理.rc演奏用タイマ.nシステム時刻; // lock前に取得。演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
lock (this.objMidiIn排他用)
{
if ((this.list入力デバイス != null) && (this.list入力デバイス.Count != 0))
{
foreach (IInputDevice device in this.list入力デバイス)
{
CInputMIDI tmidi = device as CInputMIDI;
if ((tmidi != null) && (tmidi.hMidiIn == hMidiIn))
{
tmidi.tメッセージからMIDI信号のみ受信(wMsg, dwInstance, dwParam1, dwParam2, time);
break;
}
}
}
}
}
//-----------------
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
// 定数
public enum E入力デバイス種別
{
Keyboard,
Mouse,
Joystick,
MidiIn,
Unknown
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public interface IInputDevice : IDisposable
{
// プロパティ
E入力デバイス種別 e入力デバイス種別
{
get;
}
string GUID
{
get;
}
int ID
{
get;
}
List<STInputEvent> list入力イベント
{
get;
}
// メソッドインターフェース
void tポーリング( bool bWindowがアクティブ中, bool bバッファ入力を使用する );
bool bキーが押された( int nKey );
bool bキーが押されている( int nKey );
bool bキーが離された( int nKey );
bool bキーが離されている( int nKey );
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace FDK
{
// 構造体
[StructLayout( LayoutKind.Sequential )]
public struct STInputEvent
{
public int nKey { get; set; }
public bool b押された { get; set; }
public bool b離された { get; set; }
public long nTimeStamp { get; set; }
public int nVelocity { get; set; }
}
}

View File

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SlimDXKeys
{
public enum Key
{
D0 = 0,
D1 = 1,
D2 = 2,
D3 = 3,
D4 = 4,
D5 = 5,
D6 = 6,
D7 = 7,
D8 = 8,
D9 = 9,
A = 10,
B = 11,
C = 12,
D = 13,
E = 14,
F = 15,
G = 16,
H = 17,
I = 18,
J = 19,
K = 20,
L = 21,
M = 22,
N = 23,
O = 24,
P = 25,
Q = 26,
R = 27,
S = 28,
T = 29,
U = 30,
V = 31,
W = 32,
X = 33,
Y = 34,
Z = 35,
AbntC1 = 36,
AbntC2 = 37,
Apostrophe = 38,
Applications = 39,
AT = 40,
AX = 41,
Backspace = 42,
Backslash = 43,
Calculator = 44,
CapsLock = 45,
Colon = 46,
Comma = 47,
Convert = 48,
Delete = 49,
DownArrow = 50,
End = 51,
Equals = 52,
Escape = 53,
F1 = 54,
F2 = 55,
F3 = 56,
F4 = 57,
F5 = 58,
F6 = 59,
F7 = 60,
F8 = 61,
F9 = 62,
F10 = 63,
F11 = 64,
F12 = 65,
F13 = 66,
F14 = 67,
F15 = 68,
Grave = 69,
Home = 70,
Insert = 71,
Kana = 72,
Kanji = 73,
LeftBracket = 74,
LeftControl = 75,
LeftArrow = 76,
LeftAlt = 77,
LeftShift = 78,
LeftWindowsKey = 79,
Mail = 80,
MediaSelect = 81,
MediaStop = 82,
Minus = 83,
Mute = 84,
MyComputer = 85,
NextTrack = 86,
NoConvert = 87,
NumberLock = 88,
NumberPad0 = 89,
NumberPad1 = 90,
NumberPad2 = 91,
NumberPad3 = 92,
NumberPad4 = 93,
NumberPad5 = 94,
NumberPad6 = 95,
NumberPad7 = 96,
NumberPad8 = 97,
NumberPad9 = 98,
NumberPadComma = 99,
NumberPadEnter = 100,
NumberPadEquals = 101,
NumberPadMinus = 102,
NumberPadPeriod = 103,
NumberPadPlus = 104,
NumberPadSlash = 105,
NumberPadStar = 106,
Oem102 = 107,
PageDown = 108,
PageUp = 109,
Pause = 110,
Period = 111,
PlayPause = 112,
Power = 113,
PreviousTrack = 114,
RightBracket = 115,
RightControl = 116,
Return = 117,
RightArrow = 118,
RightAlt = 119,
RightShift = 120,
RightWindowsKey = 121,
ScrollLock = 122,
Semicolon = 123,
Slash = 124,
Sleep = 125,
Space = 126,
Stop = 127,
PrintScreen = 128,
Tab = 129,
Underline = 130,
Unlabeled = 131,
UpArrow = 132,
VolumeDown = 133,
VolumeUp = 134,
Wake = 135,
WebBack = 136,
WebFavorites = 137,
WebForward = 138,
WebHome = 139,
WebRefresh = 140,
WebSearch = 141,
WebStop = 142,
Yen = 143,
Unknown = 144
}
public enum MouseObject
{
Button1 = 0,
Button2 = 1,
Button3 = 2,
Button4 = 3,
Button5 = 4,
Button6 = 5,
Button7 = 6,
Button8 = 7,
XAxis = 8,
YAxis = 9,
ZAxis = 10
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,455 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Un4seen.Bass;
using Un4seen.BassAsio;
using Un4seen.Bass.AddOn.Mix;
namespace FDK
{
/// <summary>
/// 全ASIOデバイスを列挙する静的クラス。
/// BASS_Init()やBASS_ASIO_Init()の状態とは無関係に使用可能。
/// </summary>
public static class CEnumerateAllAsioDevices
{
public static string[] GetAllASIODevices()
{
//Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfos():" );
BASS_ASIO_DEVICEINFO[] bassAsioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfos();
List<string> asioDeviceList = new List<string>();
if ( bassAsioDevInfo.Length == 0 )
{
asioDeviceList.Add( "None" );
}
else
{
for ( int i = 0; i < bassAsioDevInfo.Length; i++ )
{
asioDeviceList.Add( bassAsioDevInfo[ i ].name );
//Trace.TraceInformation( "ASIO Device {0}: {1}", i, bassAsioDevInfo[ i ].name );
}
}
return asioDeviceList.ToArray();
}
}
internal class CSoundDeviceASIO : ISoundDevice
{
// プロパティ
public ESoundDeviceType e出力デバイス
{
get;
protected set;
}
public long n実出力遅延ms
{
get;
protected set;
}
public long n実バッファサイズms
{
get;
protected set;
}
public int nASIODevice
{
get;
set;
}
// CSoundTimer 用に公開しているプロパティ
public long n経過時間ms
{
get;
protected set;
}
public long n経過時間を更新したシステム時刻ms
{
get;
protected set;
}
public CTimer tmシステムタイマ
{
get;
protected set;
}
// マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume
{
get
{
float f音量 = 0.0f;
bool b = Bass.BASS_ChannelGetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, ref f音量 );
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
Trace.TraceInformation( "ASIO Master Volume Get Error: " + be.ToString() );
}
else
{
//Trace.TraceInformation( "ASIO Master Volume Get Success: " + (f音量 * 100) );
}
return (int) ( f音量 * 100 );
}
set
{
bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, (float) ( value / 100.0 ) );
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
Trace.TraceInformation( "ASIO Master Volume Set Error: " + be.ToString() );
}
else
{
// int n = this.nMasterVolume;
// Trace.TraceInformation( "ASIO Master Volume Set Success: " + value );
}
}
}
// メソッド
public CSoundDeviceASIO( long n希望バッファサイズms, int _nASIODevice )
{
// 初期化。
Trace.TraceInformation( "BASS (ASIO) の初期化を開始します。" );
this.e出力デバイス = ESoundDeviceType.Unknown;
this.n実出力遅延ms = 0;
this.n経過時間ms = 0;
this.n経過時間を更新したシステム時刻ms = CTimer.n未使用;
this.tmシステムタイマ = new CTimer( CTimer.E種別.MultiMedia );
this.nASIODevice = _nASIODevice;
#region [ BASS registration ]
// BASS.NET ユーザ登録BASSスプラッシュが非表示になる
BassNet.Registration( "dtx2013@gmail.com", "2X9181017152222" );
#endregion
#region [ BASS Version Check ]
// BASS のバージョンチェック。
int nBASSVersion = Utils.HighWord( Bass.BASS_GetVersion() );
if( nBASSVersion != Bass.BASSVERSION )
throw new DllNotFoundException( string.Format( "bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION ) );
int nBASSMixVersion = Utils.HighWord( BassMix.BASS_Mixer_GetVersion() );
if( nBASSMixVersion != BassMix.BASSMIXVERSION )
throw new DllNotFoundException( string.Format( "bassmix.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSMixVersion, BassMix.BASSMIXVERSION ) );
int nBASSASIO = Utils.HighWord( BassAsio.BASS_ASIO_GetVersion() );
if( nBASSASIO != BassAsio.BASSASIOVERSION )
throw new DllNotFoundException( string.Format( "bassasio.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSASIO, BassAsio.BASSASIOVERSION ) );
#endregion
// BASS の設定。
this.bIsBASSFree = true;
if (!Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 )) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATEPERIOD)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]");
}
if (!Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 0 )) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATETHREADS)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]");
}
// BASS の初期化。
int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSASIO アドオンから行う。
int n周波数 = 44100; // 仮決め。最終的な周波数はデバイス(≠ドライバ)が決める。
if( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_CURVE_VOL, true);
//Debug.WriteLine( "BASS_Init()完了。" );
#region [ : ASIOデバイスのenumerateと ]
// CEnumerateAllAsioDevices.GetAllASIODevices();
//Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" );
// int a, count = 0;
// BASS_ASIO_DEVICEINFO asioDevInfo;
// for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ )
// {
// Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver );
// count++; // count it
// }
#endregion
// BASS ASIO の初期化。
BASS_ASIO_INFO asioInfo = null;
if ( BassAsio.BASS_ASIO_Init( nASIODevice, BASSASIOInit.BASS_ASIO_THREAD ) ) // 専用スレッドにて起動
{
#region [ ASIO ]
//-----------------
this.e出力デバイス = ESoundDeviceType.ASIO;
asioInfo = BassAsio.BASS_ASIO_GetInfo();
this.n出力チャンネル数 = asioInfo.outputs;
this.db周波数 = BassAsio.BASS_ASIO_GetRate();
this.fmtASIOデバイスフォーマット = BassAsio.BASS_ASIO_ChannelGetFormat( false, 0 );
Trace.TraceInformation( "BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}{6}sample ({5:0.###}{7:0.###}ms), デバイスフォーマット:{8})",
asioInfo.name,
asioInfo.inputs,
asioInfo.outputs,
this.db周波数.ToString( "0.###" ),
asioInfo.bufmin, asioInfo.bufmin * 1000 / this.db周波数,
asioInfo.bufmax, asioInfo.bufmax * 1000 / this.db周波数,
this.fmtASIOデバイスフォーマット.ToString()
);
this.bIsBASSFree = false;
#region [ debug: channel format ]
//BASS_ASIO_CHANNELINFO chinfo = new BASS_ASIO_CHANNELINFO();
//int chan = 0;
//while ( true )
//{
// if ( !BassAsio.BASS_ASIO_ChannelGetInfo( false, chan, chinfo ) )
// break;
// Debug.WriteLine( "Ch=" + chan + ": " + chinfo.name.ToString() + ", " + chinfo.group.ToString() + ", " + chinfo.format.ToString() );
// chan++;
//}
#endregion
//-----------------
#endregion
}
else
{
#region [ ASIO ]
//-----------------
BASSError errcode = Bass.BASS_ErrorGetCode();
string errmes = errcode.ToString();
if ( errcode == BASSError.BASS_OK )
{
errmes = "BASS_OK; The device may be dissconnected";
}
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes ) );
//-----------------
#endregion
}
// ASIO 出力チャンネルの初期化。
this.tAsioProc = new ASIOPROC( this.tAsio処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
if ( !BassAsio.BASS_ASIO_ChannelEnable( false, 0, this.tAsioProc, IntPtr.Zero ) ) // 出力チャンネル0 の有効化。
{
#region [ ASIO ]
//-----------------
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString() ) );
//-----------------
#endregion
}
for ( int i = 1; i < this.n出力チャンネル数; i++ ) // 出力チャネルを全てチャネル0とグループ化する。
{ // チャネル1だけを0とグループ化すると、3ch以上の出力をサポートしたカードでの動作がおかしくなる
if ( !BassAsio.BASS_ASIO_ChannelJoin( false, i, 0 ) )
{
#region [ ]
//-----------------
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString(), i ) );
//-----------------
#endregion
}
}
if ( !BassAsio.BASS_ASIO_ChannelSetFormat( false, 0, this.fmtASIOチャンネルフォーマット ) ) // 出力チャンネル0のフォーマット
{
#region [ ASIO ]
//-----------------
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString() ) );
//-----------------
#endregion
}
// ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。
var flag = BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_STREAM_DECODE; // デコードのみ発声しない。ASIO に出力されるだけ。
if( this.fmtASIOデバイスフォーマット == BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT )
flag |= BASSFlag.BASS_SAMPLE_FLOAT;
this.hMixer = BassMix.BASS_Mixer_StreamCreate( (int) this.db周波数, this.n出力チャンネル数, flag );
if ( this.hMixer == 0 )
{
BASSError err = Bass.BASS_ErrorGetCode();
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", err ) );
}
// BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.BASS_ChannelGetInfo( this.hMixer );
int nサンプルサイズbyte = 0;
switch( this.fmtASIOチャンネルフォーマット )
{
case BASSASIOFormat.BASS_ASIO_FORMAT_16BIT: nサンプルサイズbyte = 2; break;
case BASSASIOFormat.BASS_ASIO_FORMAT_24BIT: nサンプルサイズbyte = 3; break;
case BASSASIOFormat.BASS_ASIO_FORMAT_32BIT: nサンプルサイズbyte = 4; break;
case BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT: nサンプルサイズbyte = 4; break;
}
//long nミキサーの1サンプルあたりのバイト数 = /*mixerInfo.chans*/ 2 * nサンプルサイズbyte;
long nミキサーの1サンプルあたりのバイト数 = mixerInfo.chans * nサンプルサイズbyte;
this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.freq;
// 単純に、hMixerの音量をMasterVolumeとして制御しても、
// ChannelGetData()の内容には反映されない。
// そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
// hMixerの音量制御を反映させる。
this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate(
(int) this.db周波数, this.n出力チャンネル数, flag );
if ( this.hMixer_DeviceOut == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
}
{
bool b1 = BassMix.BASS_Mixer_StreamAddChannel( this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT );
if ( !b1 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
};
}
// 出力を開始。
this.nバッファサイズsample = (int) ( n希望バッファサイズms * this.db周波数 / 1000.0 );
//this.nバッファサイズsample = (int) nバッファサイズbyte;
if ( !BassAsio.BASS_ASIO_Start( this.nバッファサイズsample ) ) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。
{
BASSError err = BassAsio.BASS_ASIO_ErrorGetCode();
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( "ASIO デバイス出力開始に失敗しました。" + err.ToString() );
}
else
{
int n遅延sample = BassAsio.BASS_ASIO_GetLatency( false ); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。
int n希望遅延sample = (int) ( n希望バッファサイズms * this.db周波数 / 1000.0 );
this.n実バッファサイズms = this.n実出力遅延ms = (long) ( n遅延sample * 1000.0f / this.db周波数 );
Trace.TraceInformation( "ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.n実出力遅延ms, n希望バッファサイズms );
}
}
#region [ tサウンドを作成する() ]
public CSound tサウンドを作成する( string strファイル名, ESoundGroup soundGroup )
{
var sound = new CSound(soundGroup);
sound.tASIOサウンドを作成する( strファイル名, this.hMixer );
return sound;
}
public void tサウンドを作成する( string strファイル名, CSound sound )
{
sound.tASIOサウンドを作成する( strファイル名, this.hMixer );
}
public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, CSound sound )
{
sound.tASIOサウンドを作成する( byArrWAVファイルイメージ, this.hMixer );
}
#endregion
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
}
protected void Dispose( bool bManagedDispose )
{
this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( hMixer != -1 )
{
Bass.BASS_StreamFree( this.hMixer );
}
if ( !this.bIsBASSFree )
{
BassAsio.BASS_ASIO_Free(); // システムタイマより先に呼び出すこと。tAsio処理() の中でシステムタイマを参照してるため)
Bass.BASS_Free();
}
if( bManagedDispose )
{
C共通.tDisposeする( this.tmシステムタイマ );
this.tmシステムタイマ = null;
}
}
~CSoundDeviceASIO()
{
this.Dispose( false );
}
//-----------------
#endregion
protected int hMixer = -1;
protected int hMixer_DeviceOut = -1;
protected int n出力チャンネル数 = 0;
protected double db周波数 = 0.0;
protected int nバッファサイズsample = 0;
protected BASSASIOFormat fmtASIOデバイスフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_UNKNOWN;
protected BASSASIOFormat fmtASIOチャンネルフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_16BIT; // 16bit 固定
//protected BASSASIOFormat fmtASIOチャンネルフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_32BIT;// 16bit 固定
protected ASIOPROC tAsioProc = null;
protected int tAsio処理( bool input, int channel, IntPtr buffer, int length, IntPtr user )
{
if( input ) return 0;
// BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。
int num = Bass.BASS_ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ
if ( num == -1 ) num = 0;
// 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。
this.n経過時間ms = ( this.n累積転送バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数 ) - this.n実出力遅延ms;
this.n経過時間を更新したシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
// 経過時間を更新後に、今回分の累積転送バイト数を反映。
this.n累積転送バイト数 += num;
return num;
}
private long nミキサーの1秒あたりのバイト数 = 0;
private long n累積転送バイト数 = 0;
private bool bIsBASSFree = true;
}
}

View File

@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
using SlimDX;
using SharpDX.DirectSound;
namespace FDK
{
internal class CSoundDeviceDirectSound : ISoundDevice
{
// プロパティ
public ESoundDeviceType e出力デバイス
{
get;
protected set;
}
public long n実出力遅延ms
{
get;
protected set;
}
public long n実バッファサイズms
{
get;
protected set;
}
public static readonly BufferFlags DefaultFlags = BufferFlags.Defer | BufferFlags.GetCurrentPosition2 | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.ControlPan | BufferFlags.ControlFrequency;
// CSoundTimer 用に公開しているプロパティ
public long n経過時間ms
{
get
{
if ( ctimer != null )
{
this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.GetCurrentPosition(out int n現在位置, out int _);
long n現在のシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
// ループ回数を調整。
long nシステム時刻での間隔ms = n現在のシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;
while ( nシステム時刻での間隔ms >= n単位繰り上げ間隔ms ) // 前回から単位繰り上げ間隔以上経過してるなら確実にループしている。誤差は大きくないだろうから無視。
{
this.nループ回数++;
nシステム時刻での間隔ms -= n単位繰り上げ間隔ms;
}
if ( n現在位置 < this.n前回の位置 ) // 単位繰り上げ間隔以内であっても、現在位置が前回より手前にあるなら1回ループしている。
this.nループ回数++;
// 経過時間を算出。
long n経過時間ms = (long) ( ( this.nループ回数 * n単位繰り上げ間隔ms ) + ( n現在位置 * 1000.0 / ( 44100.0 * 2 * 2 ) ) );
// 今回の値を次回に向けて保存。
this.n前に経過時間を測定したシステム時刻ms = n現在のシステム時刻ms;
this.n前回の位置 = n現在位置;
return n経過時間ms;
}
else
{
long nRet = ctimer.nシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;
if ( nRet < 0 ) // カウンタがループしたときは
{
nRet = ( ctimer.nシステム時刻 - long.MinValue ) + ( long.MaxValue - this.n前に経過時間を測定したシステム時刻ms ) + 1;
}
this.n前に経過時間を測定したシステム時刻ms = ctimer.nシステム時刻ms;
return nRet;
}
}
}
public long n経過時間を更新したシステム時刻ms
{
get { throw new NotImplementedException(); }
}
public CTimer tmシステムタイマ
{
get;
protected set;
}
public int nMasterVolume
{
get
{
return (int) 100;
}
set
{
// 特に何もしない
}
}
// メソッド
public CSoundDeviceDirectSound( IntPtr hWnd, long n遅延時間ms, bool bUseOSTimer )
{
Trace.TraceInformation( "DirectSound の初期化を開始します。" );
this.e出力デバイス = ESoundDeviceType.Unknown;
this.n実バッファサイズms = this.n実出力遅延ms = n遅延時間ms;
this.tmシステムタイマ = new CTimer( CTimer.E種別.MultiMedia );
#region [ DirectSound ]
//-----------------
this.DirectSound = new DirectSound(); // 失敗したら例外をそのまま発出。
// デバイスの協調レベルを設定する。
bool priority = true;
try
{
this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Priority );
}
catch
{
this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Normal ); // これでも失敗したら例外をそのまま発出。
priority = false;
}
// デバイス作成完了。
this.e出力デバイス = ESoundDeviceType.DirectSound;
//-----------------
#endregion
if ( !bUseOSTimer )
{
#region [ ]
//-----------------
// 単位繰り上げ間隔[秒]の長さを持つ無音のサウンドを作成。
uint nデータサイズbyte = n単位繰り上げ間隔sec * 44100 * 2 * 2;
var ms = new MemoryStream();
var bw = new BinaryWriter( ms );
bw.Write( (uint) 0x46464952 ); // 'RIFF'
bw.Write( (uint) ( 44 + nデータサイズbyte - 8 ) ); // ファイルサイズ - 8
bw.Write( (uint) 0x45564157 ); // 'WAVE'
bw.Write( (uint) 0x20746d66 ); // 'fmt '
bw.Write( (uint) 16 ); // バイト数
bw.Write( (ushort) 1 ); // フォーマットID(リニアPCM)
bw.Write( (ushort) 2 ); // チャンネル数
bw.Write( (uint) 44100 ); // サンプリング周波数
bw.Write( (uint) ( 44100 * 2 * 2 ) ); // bytes/sec
bw.Write( (ushort) ( 2 * 2 ) ); // blockサイズ
bw.Write( (ushort) 16 ); // bit/sample
bw.Write( (uint) 0x61746164 ); // 'data'
bw.Write( (uint) nデータサイズbyte ); // データ長
for ( int i = 0; i < nデータサイズbyte / sizeof( long ); i++ ) // PCMデータ
bw.Write( (long) 0 );
var byArrWaveFleImage = ms.ToArray();
bw.Close();
ms = null;
bw = null;
this.sd経過時間計測用サウンドバッファ = this.tサウンドを作成する( byArrWaveFleImage, ESoundGroup.Unknown );
CSound.listインスタンス.Remove( this.sd経過時間計測用サウンドバッファ ); // 特殊用途なのでインスタンスリストからは除外する。
// サウンドのループ再生開始。
this.nループ回数 = 0;
this.n前回の位置 = 0;
this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.Play( 0, PlayFlags.Looping );
this.n前に経過時間を測定したシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
//-----------------
#endregion
}
else
{
ctimer = new CTimer( CTimer.E種別.MultiMedia );
}
Trace.TraceInformation( "DirectSound を初期化しました。({0})({1})", ( priority ) ? "Priority" : "Normal", bUseOSTimer? "OStimer" : "FDKtimer" );
}
public CSound tサウンドを作成する( string strファイル名, ESoundGroup soundGroup )
{
var sound = new CSound(soundGroup);
sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );
return sound;
}
private CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ, ESoundGroup soundGroup )
{
var sound = new CSound(soundGroup);
sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );
return sound;
}
// 既存のインスタンス(生成直後 or Dispose済みに対してサウンドを生成する。
public void tサウンドを作成する( string strファイル名, CSound sound )
{
sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );
}
public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, CSound sound )
{
sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );
}
public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, BufferFlags flags, CSound sound )
{
sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound, flags );
}
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
}
protected void Dispose( bool bManagedDispose )
{
this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( bManagedDispose )
{
#region [ ]
//-----------------
if ( this.sd経過時間計測用サウンドバッファ != null )
{
this.sd経過時間計測用サウンドバッファ.tサウンドを停止する();
C共通.tDisposeする( ref this.sd経過時間計測用サウンドバッファ );
}
//-----------------
#endregion
#region [ ]
//-----------------
if( this.th経過時間測定用スレッド != null )
{
this.th経過時間測定用スレッド.Abort();
this.th経過時間測定用スレッド = null;
}
//-----------------
#endregion
C共通.tDisposeする( ref this.DirectSound );
C共通.tDisposeする( this.tmシステムタイマ );
}
if ( ctimer != null )
{
C共通.tDisposeする( ref this.ctimer );
}
}
~CSoundDeviceDirectSound()
{
this.Dispose( false );
}
//-----------------
#endregion
protected DirectSound DirectSound = null;
protected CSound sd経過時間計測用サウンドバッファ = null;
protected Thread th経過時間測定用スレッド = null;
// protected AutoResetEvent autoResetEvent = new AutoResetEvent( false );
protected const uint n単位繰り上げ間隔sec = 1; // [秒]
protected const uint n単位繰り上げ間隔ms = n単位繰り上げ間隔sec * 1000; // [ミリ秒]
protected int nループ回数 = 0;
private long n前に経過時間を測定したシステム時刻ms = CTimer.n未使用;
private int n前回の位置 = 0;
private CTimer ctimer = null;
}
}

View File

@ -0,0 +1,447 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Un4seen.Bass;
using Un4seen.BassWasapi;
using Un4seen.Bass.AddOn.Mix;
namespace FDK
{
internal class CSoundDeviceWASAPI : ISoundDevice
{
// プロパティ
public ESoundDeviceType e出力デバイス
{
get;
protected set;
}
public long n実出力遅延ms
{
get;
protected set;
}
public long n実バッファサイズms
{
get;
protected set;
}
// CSoundTimer 用に公開しているプロパティ
public long n経過時間ms
{
get;
protected set;
}
public long n経過時間を更新したシステム時刻ms
{
get;
protected set;
}
public CTimer tmシステムタイマ
{
get;
protected set;
}
public enum Eデバイスモード { , }
public int nMasterVolume
{
get
{
float f音量 = 0.0f;
//if ( BassMix.BASS_Mixer_ChannelGetEnvelopePos( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, ref f音量 ) == -1 )
// 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音量 );
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
Trace.TraceInformation( "WASAPI Master Volume Get Error: " + be.ToString() );
}
else
{
Trace.TraceInformation( "WASAPI Master Volume Get Success: " + (f音量 * 100) );
}
return (int) ( f音量 * 100 );
}
set
{
// bool b = Bass.BASS_SetVolume( value / 100.0f );
// →Exclusiveモード時は無効
// 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 = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, (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,
// you can adjust the source's BASS_ATTRIB_VOL setting via BASS_ChannelSetAttribute.
// しかし、hMixerに対するBASS_ChannelSetAttribute()でBASS_ATTRIB_VOLを変更: なぜか出力音量に反映されず
// Bass_SetVolume(): BASS_ERROR_NOTAVIL ("no sound" deviceには適用不可)
// Mixer_ChannelSetEnvelope():
//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 = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, value / 100.0f );
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
Trace.TraceInformation( "WASAPI Master Volume Set Error: " + be.ToString() );
}
else
{
// int n = this.nMasterVolume;
// Trace.TraceInformation( "WASAPI Master Volume Set Success: " + value );
}
}
}
// メソッド
/// <summary>
/// WASAPIの初期化
/// </summary>
/// <param name="mode"></param>
/// <param name="n希望バッファサイズms">(未使用; 本メソッド内で自動設定する)</param>
/// <param name="n更新間隔ms">(未使用; 本メソッド内で自動設定する)</param>
public CSoundDeviceWASAPI( Eデバイスモード mode, long n希望バッファサイズms, long n更新間隔ms )
{
// 初期化。
Trace.TraceInformation( "BASS (WASAPI) の初期化を開始します。" );
this.e出力デバイス = ESoundDeviceType.Unknown;
this.n実出力遅延ms = 0;
this.n経過時間ms = 0;
this.n経過時間を更新したシステム時刻ms = CTimer.n未使用;
this.tmシステムタイマ = new CTimer( CTimer.E種別.MultiMedia );
this.b最初の実出力遅延算出 = true;
#region [ BASS registration ]
// BASS.NET ユーザ登録BASSスプラッシュが非表示になる
BassNet.Registration( "dtx2013@gmail.com", "2X9181017152222" );
#endregion
#region [ BASS Version Check ]
// BASS のバージョンチェック。
int nBASSVersion = Utils.HighWord( Bass.BASS_GetVersion() );
if( nBASSVersion != Bass.BASSVERSION )
throw new DllNotFoundException( string.Format( "bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION ) );
int nBASSMixVersion = Utils.HighWord( BassMix.BASS_Mixer_GetVersion() );
if( nBASSMixVersion != BassMix.BASSMIXVERSION )
throw new DllNotFoundException( string.Format( "bassmix.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSMixVersion, BassMix.BASSMIXVERSION ) );
int nBASSWASAPIVersion = Utils.HighWord( BassWasapi.BASS_WASAPI_GetVersion() );
if( nBASSWASAPIVersion != BassWasapi.BASSWASAPIVERSION )
throw new DllNotFoundException( string.Format( "basswasapi.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSWASAPIVersion, BassWasapi.BASSWASAPIVERSION ) );
#endregion
// BASS の設定。
this.bIsBASSFree = true;
if (!Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 )) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATEPERIOD)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]");
}
if (!Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 0 )) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(BASSConfig.BASS_CONFIG_UPDATETHREADS)}) に失敗しました。[{Bass.BASS_ErrorGetCode()}]");
}
// BASS の初期化。
int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
int n周波数 = 44100; // 仮決め。lデバイス≠ドライバがネイティブに対応している周波数であれば何でもいいようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。
if( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_CURVE_VOL, true);
#region [ : WASAPIデバイスのenumerateと ]
// (デバッグ用)
//Trace.TraceInformation( "WASAPIデバイス一覧:" );
//int a, count = 0;
//BASS_WASAPI_DEVICEINFO wasapiDevInfo;
//for ( a = 0; ( wasapiDevInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( a ) ) != null; a++ )
//{
// if ( ( wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT ) == 0 // device is an output device (not input)
// && ( wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED ) != 0 ) // and it is enabled
// {
// Trace.TraceInformation( "WASAPI Device #{0}: {1}", a, wasapiDevInfo.name );
// count++; // count it
// }
//}
#endregion
// BASS WASAPI の初期化。
nデバイス = -1;
n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate)
int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels)
this.tWasapiProc = new WASAPIPROC( this.tWASAPI処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
// WASAPIの更新間隔(period)は、バッファサイズにも影響を与える。
// 更新間隔を最小にするには、BassWasapi.BASS_WASAPI_GetDeviceInfo( ndevNo ).minperiod の値を使えばよい。
// これをやらないと、更新間隔ms=6ms となり、バッファサイズを 6ms x 4 = 24msより小さくできない。
#region [ WASAPIデバイスを検索しmsを設定できる最小値にする ]
int nDevNo = -1;
BASS_WASAPI_DEVICEINFO deviceInfo;
for ( int n = 0; ( deviceInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( n ) ) != null; n++ )
{
if ( deviceInfo.IsDefault )
{
nDevNo = n;
break;
}
}
if ( nDevNo != -1 )
{
// Trace.TraceInformation( "Selected Default WASAPI Device: {0}", deviceInfo.name );
// Trace.TraceInformation( "MinPeriod={0}, DefaultPeriod={1}", deviceInfo.minperiod, deviceInfo.defperiod );
n更新間隔ms = (long) ( deviceInfo.minperiod * 1000 );
if ( n希望バッファサイズms <= 0 || n希望バッファサイズms < n更新間隔ms + 1 )
{
n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。
}
}
else
{
Trace.TraceError( "Error: Default WASAPI Device is not found." );
}
#endregion
//Retry:
var flags = ( mode == Eデバイスモード. ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_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;
if ( BassWasapi.BASS_WASAPI_Init( nデバイス, n周波数, nチャンネル数, flags, ( n希望バッファサイズms / 1000.0f ), ( n更新間隔ms / 1000.0f ), this.tWasapiProc, IntPtr.Zero ) )
{
if( mode == Eデバイスモード. )
{
#region [ ]
//-----------------
this.e出力デバイス = ESoundDeviceType.ExclusiveWASAPI;
nDevNo = BassWasapi.BASS_WASAPI_GetDevice();
deviceInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( nDevNo );
var wasapiInfo = BassWasapi.BASS_WASAPI_GetInfo();
int n1サンプルのバイト数 = 2 * wasapiInfo.chans; // default;
switch( wasapiInfo.format ) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。
{
case BASSWASAPIFormat.BASS_WASAPI_FORMAT_8BIT: n1サンプルのバイト数 = 1 * wasapiInfo.chans; break;
case BASSWASAPIFormat.BASS_WASAPI_FORMAT_16BIT: n1サンプルのバイト数 = 2 * wasapiInfo.chans; break;
case BASSWASAPIFormat.BASS_WASAPI_FORMAT_24BIT: n1サンプルのバイト数 = 3 * wasapiInfo.chans; break;
case BASSWASAPIFormat.BASS_WASAPI_FORMAT_32BIT: n1サンプルのバイト数 = 4 * wasapiInfo.chans; break;
case BASSWASAPIFormat.BASS_WASAPI_FORMAT_FLOAT: n1サンプルのバイト数 = 4 * wasapiInfo.chans; break;
}
int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.freq;
this.n実バッファサイズms = (long) ( wasapiInfo.buflen * 1000.0f / n1秒のバイト数 );
this.n実出力遅延ms = 0; // 初期値はゼロ
Trace.TraceInformation( "使用デバイス: #" + nDevNo + " : " + deviceInfo.name + ", flags=" + deviceInfo.flags );
Trace.TraceInformation( "BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
wasapiInfo.freq,
wasapiInfo.chans,
wasapiInfo.format.ToString(),
wasapiInfo.buflen,
n実バッファサイズms.ToString(),
n希望バッファサイズms.ToString(),
n更新間隔ms.ToString() );
Trace.TraceInformation( "デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.minperiod * 1000, deviceInfo.defperiod * 1000 );
this.bIsBASSFree = false;
//-----------------
#endregion
}
else
{
#region [ ]
//-----------------
this.e出力デバイス = ESoundDeviceType.SharedWASAPI;
this.n実出力遅延ms = 0; // 初期値はゼロ
var devInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( BassWasapi.BASS_WASAPI_GetDevice() ); // 共有モードの場合、更新間隔はデバイスのデフォルト値に固定される。
Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", n希望バッファサイズms, devInfo.defperiod * 1000.0f );
this.bIsBASSFree = false;
//-----------------
#endregion
}
}
#region [ #31737 WASAPI排他モードのみ利用可能としWASAPI共有モードは使用できないようにするためにWASAPI共有モードでの初期化フローを削除する ]
//else if ( mode == Eデバイスモード.排他 )
//{
// Trace.TraceInformation("Failed to initialize setting BASS (WASAPI) mode [{0}]", Bass.BASS_ErrorGetCode().ToString() );
// #region [ 排他モードに失敗したのなら共有モードでリトライ。]
// //-----------------
// mode = Eデバイスモード.共有;
// goto Retry;
// //-----------------
// #endregion
//}
#endregion
else
{
#region [ ]
//-----------------
BASSError errcode = Bass.BASS_ErrorGetCode();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode ) );
//-----------------
#endregion
}
// WASAPI出力と同じフォーマットを持つ BASS ミキサーを作成。
var info = BassWasapi.BASS_WASAPI_GetInfo();
this.hMixer = BassMix.BASS_Mixer_StreamCreate(
info.freq,
info.chans,
BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE ); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
BassWasapi.BASS_WASAPI_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode ) );
}
// BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.BASS_ChannelGetInfo( this.hMixer );
long nミキサーの1サンプルあたりのバイト数 = mixerInfo.chans * 4; // 4 = sizeof(FLOAT)
this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.freq;
// 単純に、hMixerの音量をMasterVolumeとして制御しても、
// ChannelGetData()の内容には反映されない。
// そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
// hMixerの音量制御を反映させる。
this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate(
info.freq,
info.chans,
BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE ); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer_DeviceOut == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
BassWasapi.BASS_WASAPI_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
}
{
bool b1 = BassMix.BASS_Mixer_StreamAddChannel( this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT );
if ( !b1 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
BassWasapi.BASS_WASAPI_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
};
}
// 出力を開始。
BassWasapi.BASS_WASAPI_Start();
}
#region [ tサウンドを作成する() ]
public CSound tサウンドを作成する( string strファイル名, ESoundGroup soundGroup )
{
var sound = new CSound(soundGroup);
sound.tWASAPIサウンドを作成する( strファイル名, this.hMixer, this.e出力デバイス );
return sound;
}
public void tサウンドを作成する( string strファイル名, CSound sound )
{
sound.tWASAPIサウンドを作成する( strファイル名, this.hMixer, this.e出力デバイス );
}
public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, CSound sound )
{
sound.tWASAPIサウンドを作成する( byArrWAVファイルイメージ, this.hMixer, this.e出力デバイス );
}
#endregion
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
}
protected void Dispose( bool bManagedDispose )
{
this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( hMixer != -1 )
{
Bass.BASS_StreamFree( this.hMixer );
}
if ( !this.bIsBASSFree )
{
BassWasapi.BASS_WASAPI_Free(); // システムタイマより先に呼び出すこと。tWasapi処理() の中でシステムタイマを参照してるため)
Bass.BASS_Free();
}
if( bManagedDispose )
{
C共通.tDisposeする( this.tmシステムタイマ );
this.tmシステムタイマ = null;
}
}
~CSoundDeviceWASAPI()
{
this.Dispose( false );
}
//-----------------
#endregion
protected int hMixer = -1;
protected int hMixer_DeviceOut = -1;
protected WASAPIPROC tWasapiProc = null;
protected int tWASAPI処理( IntPtr buffer, int length, IntPtr user )
{
// BASSミキサからの出力データをそのまま WASAPI buffer へ丸投げ。
int num = Bass.BASS_ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ
if ( num == -1 ) num = 0;
// 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。
int n未再生バイト数 = BassWasapi.BASS_WASAPI_GetData( null, (int) BASSData.BASS_DATA_AVAILABLE ); // 誤差削減のため、必要となるギリギリ直前に取得する。
this.n経過時間ms = ( this.n累積転送バイト数 - n未再生バイト数 ) * 1000 / this.nミキサーの1秒あたりのバイト数;
this.n経過時間を更新したシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
// 実出力遅延を更新。
// 未再生バイト数の平均値。
long n今回の遅延ms = n未再生バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数;
this.n実出力遅延ms = ( this.b最初の実出力遅延算出 ) ? n今回の遅延ms : ( this.n実出力遅延ms + n今回の遅延ms ) / 2;
this.b最初の実出力遅延算出 = false;
// 経過時間を更新後に、今回分の累積転送バイト数を反映。
this.n累積転送バイト数 += num;
return num;
}
private long nミキサーの1秒あたりのバイト数 = 0;
private long n累積転送バイト数 = 0;
private bool b最初の実出力遅延算出 = true;
private bool bIsBASSFree = true;
}
}

View File

@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FDK
{
public class CSoundTimer : CTimerBase
{
public override long nシステム時刻ms
{
get
{
if( this.Device.e出力デバイス == ESoundDeviceType.ExclusiveWASAPI ||
this.Device.e出力デバイス == ESoundDeviceType.SharedWASAPI ||
this.Device.e出力デバイス == ESoundDeviceType.ASIO )
{
// BASS 系の ISoundDevice.n経過時間ms はオーディオバッファの更新間隔ずつでしか更新されないため、単にこれを返すだけではとびとびの値になる。
// そこで、更新間隔の最中に呼ばれた場合は、システムタイマを使って補間する。
// この場合の経過時間との誤差は更新間隔以内に収まるので問題ないと判断する。
// ただし、ASIOの場合は、転送byte数から時間算出しているため、ASIOの音声合成処理の負荷が大きすぎる場合(処理時間が実時間を超えている場合)は
// 動作がおかしくなる。(具体的には、ここで返すタイマー値の逆行が発生し、スクロールが巻き戻る)
// この場合の対策は、ASIOのバッファ量を増やして、ASIOの音声合成処理の負荷を下げること。
if ( this.Device.n経過時間を更新したシステム時刻ms == CTimer.n未使用 ) // #33890 2014.5.27 yyagi
{
// 環境によっては、ASIOベースの演奏タイマーが動作する前(つまりASIOのサウンド転送が始まる前)に
// DTXデータの演奏が始まる場合がある。
// その場合、"this.Device.n経過時間を更新したシステム時刻" が正しい値でないため、
// 演奏タイマの値が正しいものとはならない。そして、演奏タイマーの動作が始まると同時に、
// 演奏タイマの値がすっ飛ぶ(極端な負の値になる)ため、演奏のみならず画面表示もされない状態となる。
// (画面表示はタイマの値に連動して行われるが、0以上のタイマ値に合わせて動作するため、
// 不の値が来ると画面に何も表示されなくなる)
// そこで、演奏タイマが動作を始める前(this.Device.n経過時間を更新したシステム時刻ms == CTimer.n未使用)は、
// 補正部分をゼロにして、n経過時間msだけを返すようにする。
// こうすることで、演奏タイマが動作を始めても、破綻しなくなる。
return this.Device.n経過時間ms;
}
else
{
if ( FDK.CSound管理.bUseOSTimer )
//if ( true )
{
return ctDInputTimer.nシステム時刻ms; // 仮にCSoundTimerをCTimer相当の動作にしてみた
}
else
{
return this.Device.n経過時間ms
+ ( this.Device.tmシステムタイマ.nシステム時刻ms - this.Device.n経過時間を更新したシステム時刻ms );
}
}
}
else if( this.Device.e出力デバイス == ESoundDeviceType.DirectSound )
{
//return this.Device.n経過時間ms; // #24820 2013.2.3 yyagi TESTCODE DirectSoundでスクロールが滑らかにならないため、
return ct.nシステム時刻ms; // 仮にCSoundTimerをCTimer相当の動作にしてみた
}
return CTimerBase.n未使用;
}
}
internal CSoundTimer( ISoundDevice device )
{
this.Device = device;
if ( this.Device.e出力デバイス != ESoundDeviceType.DirectSound )
{
TimerCallback timerDelegate = new TimerCallback( SnapTimers ); // CSoundTimerをシステム時刻に変換するために、
timer = new Timer( timerDelegate, null, 0, 1000 ); // CSoundTimerとCTimerを両方とも走らせておき、
ctDInputTimer = new CTimer( CTimer.E種別.MultiMedia ); // 1秒に1回時差を測定するようにしておく
}
else // TESTCODE DirectSound時のみ、CSoundTimerでなくCTimerを使う
{
ct = new CTimer( CTimer.E種別.MultiMedia );
}
}
private void SnapTimers(object o) // 1秒に1回呼び出され、2つのタイマー間の現在値をそれぞれ保持する。
{
if ( this.Device.e出力デバイス != ESoundDeviceType.DirectSound )
{
try
{
this.nDInputTimerCounter = this.ctDInputTimer.nシステム時刻ms;
this.nSoundTimerCounter = this.nシステム時刻ms;
//Debug.WriteLine( "BaseCounter: " + nDInputTimerCounter + ", " + nSoundTimerCounter );
}
catch ( Exception e )
// サウンド設定変更時に、timer.Dispose()した後、timerが実際に停止する前にここに来てしまう場合があり
// その際にNullReferenceExceptionが発生する
// timerが実際に停止したことを検出してから次の設定をすべきだが、実装が難しいため、
// ここで単に例外破棄することで代替する
{
Trace.TraceInformation( e.ToString() );
Trace.TraceInformation("FDK: CSoundTimer.SnapTimers(): 例外発生しましたが、継続します。" );
}
}
}
public long nサウンドタイマーのシステム時刻msへの変換( long nDInputのタイムスタンプ )
{
return nDInputのタイムスタンプ - this.nDInputTimerCounter + this.nSoundTimerCounter; // Timer違いによる時差を補正する
}
#if false
// キーボードイベント(keybd_eventの引数と同様のデータ)
[StructLayout( LayoutKind.Sequential )]
private struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
};
// 各種イベント(SendInputの引数データ)
[StructLayout( LayoutKind.Sequential )]
private struct INPUT
{
public int type;
public KEYBDINPUT ki;
};
// キー操作、マウス操作をシミュレート(擬似的に操作する)
[DllImport( "user32.dll" )]
private extern static void SendInput(
int nInputs, ref INPUT pInputs, int cbsize );
// 仮想キーコードをスキャンコードに変換
[DllImport( "user32.dll", EntryPoint = "MapVirtualKeyA" )]
private extern static int MapVirtualKey(
int wCode, int wMapType );
[DllImport( "user32.dll" )]
static extern IntPtr GetMessageExtraInfo();
private const int INPUT_MOUSE = 0; // マウスイベント
private const int INPUT_KEYBOARD = 1; // キーボードイベント
private const int INPUT_HARDWARE = 2; // ハードウェアイベント
private const int KEYEVENTF_KEYDOWN = 0x0; // キーを押す
private const int KEYEVENTF_KEYUP = 0x2; // キーを離す
private const int KEYEVENTF_EXTENDEDKEY = 0x1; // 拡張コード
private const int KEYEVENTF_SCANCODE = 0x8;
private const int KEYEVENTF_UNIOCODE = 0x4;
private const int VK_SHIFT = 0x10; // SHIFTキー
private void pollingSendInput()
{
// INPUT[] inp = new INPUT[ 2 ];
INPUT inp = new INPUT();
while ( true )
{
// (2)キーボード(A)を押す
//inp[0].type = INPUT_KEYBOARD;
//inp[ 0 ].ki.wVk = ( ushort ) Key.B;
//inp[ 0 ].ki.wScan = ( ushort ) MapVirtualKey( inp[ 0 ].ki.wVk, 0 );
//inp[ 0 ].ki.dwFlags = KEYEVENTF_KEYDOWN;
//inp[ 0 ].ki.dwExtraInfo = IntPtr.Zero;
//inp[ 0 ].ki.time = 0;
inp.type = INPUT_KEYBOARD;
inp.ki.wVk = ( ushort ) Key.B;
inp.ki.wScan = ( ushort ) MapVirtualKey( inp.ki.wVk, 0 );
inp.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYDOWN;
inp.ki.dwExtraInfo = GetMessageExtraInfo();
inp.ki.time = 0;
//// (3)キーボード(A)を離す
//inp[ 1 ].type = INPUT_KEYBOARD;
//inp[ 1 ].ki.wVk = ( short ) Key.B;
//inp[ 1 ].ki.wScan = ( short ) MapVirtualKey( inp[ 1 ].ki.wVk, 0 );
//inp[ 1 ].ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
//inp[ 1 ].ki.dwExtraInfo = 0;
//inp[ 1 ].ki.time = 0;
// キーボード操作実行
SendInput( 1, ref inp, Marshal.SizeOf( inp ) );
Debug.WriteLine( "B" );
Thread.Sleep( 1000 );
}
}
#endif
public override void Dispose()
{
// 特になし; ISoundDevice の解放は呼び出し元で行うこと。
//sendinputスレッド削除
if ( timer != null )
{
timer.Change( System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite );
// ここで、実際にtimerが停止したことを確認するコードを追加すべきだが、やり方わからず。
// 代替策として、SnapTimers()中で、例外発生を破棄している。
timer.Dispose();
timer = null;
}
if ( ct != null )
{
ct.t一時停止();
ct.Dispose();
ct = null;
}
}
internal ISoundDevice Device = null; // debugのため、一時的にprotectedをpublicにする。後で元に戻しておくこと。
//protected Thread thSendInput = null;
//protected Thread thSnapTimers = null;
private CTimer ctDInputTimer = null;
private long nDInputTimerCounter = 0;
private long nSoundTimerCounter = 0;
Timer timer = null;
private CTimer ct = null; // TESTCODE
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace FDK
{
public unsafe class Cmp3 : SoundDecoder
{
// static byte[] FOURCC = Encoding.ASCII.GetBytes( "SggO" ); // OggS の little endian
#region [ SoundDecoder.dll mpr ]
//-----------------
[DllImport( "SoundDecoder.dll" )]
private static extern void mp3Close( int nHandle );
[DllImport( "SoundDecoder.dll" )]
private static extern int mp3Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop );
[DllImport( "SoundDecoder.dll" )]
private static extern int mp3GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx );
[DllImport( "SoundDecoder.dll" )]
private static extern uint mp3GetTotalPCMSize( int nHandle );
[DllImport( "SoundDecoder.dll" )]
private static extern int mp3Open( string fileName );
[DllImport( "SoundDecoder.dll" )]
private static extern int mp3Seek( int nHandle, uint dwPosition );
//-----------------
#endregion
public override int Open( string filename )
{
return mp3Open( filename );
}
public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx )
{
return mp3GetFormat( nHandle, ref wfx );
}
public override uint GetTotalPCMSize( int nHandle )
{
return mp3GetTotalPCMSize( nHandle );
}
public override int Seek( int nHandle, uint dwPosition )
{
return mp3Seek( nHandle, dwPosition );
}
public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop )
{
return mp3Decode( nHandle, pDest, szDestSize, bLoop );
}
public override void Close( int nHandle )
{
mp3Close( nHandle );
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace FDK
{
public unsafe class Cogg : SoundDecoder
{
static byte[] FOURCC = Encoding.ASCII.GetBytes( "SggO" ); // OggS の little endian
#region [ SoundDecoder.dll ogg ]
//-----------------
[DllImport( "SoundDecoder.dll" )]
private static extern void oggClose( int nHandle );
[DllImport( "SoundDecoder.dll" )]
private static extern int oggDecode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop );
[DllImport( "SoundDecoder.dll" )]
private static extern int oggGetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx );
[DllImport( "SoundDecoder.dll" )]
private static extern uint oggGetTotalPCMSize( int nHandle );
[DllImport( "SoundDecoder.dll" )]
private static extern int oggOpen( string fileName );
[DllImport( "SoundDecoder.dll" )]
private static extern int oggSeek( int nHandle, uint dwPosition );
//-----------------
#endregion
public override int Open( string filename )
{
return oggOpen( filename );
}
public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx )
{
return oggGetFormat( nHandle, ref wfx );
}
public override uint GetTotalPCMSize( int nHandle )
{
return oggGetTotalPCMSize( nHandle );
}
public override int Seek( int nHandle, uint dwPosition )
{
return oggSeek( nHandle, dwPosition );
}
public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop )
{
return oggDecode( nHandle, pDest, szDestSize, bLoop );
}
public override void Close( int nHandle )
{
oggClose( nHandle );
}
}
}

View File

@ -0,0 +1,380 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace FDK
{
public unsafe class Cxa : SoundDecoder //, IDisposable
{
static byte[] FOURCC = Encoding.ASCII.GetBytes( "1DWK" ); // KWD1 の little endian
#region [ XA用構造体の宣言 ]
[StructLayout(LayoutKind.Sequential)]
public struct XASTREAMHEADER {
public byte* pSrc;
public uint nSrcLen;
public uint nSrcUsed;
public byte* pDst;
public uint nDstLen;
public uint nDstUsed;
}
[StructLayout( LayoutKind.Sequential )]
public struct XAHEADER
{
public uint id;
public uint nDataLen;
public uint nSamples;
public ushort nSamplesPerSec;
public byte nBits;
public byte nChannels;
public uint nLoopPtr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public short[] befL;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public short[] befR;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] pad;
}
#endregion
#region [ xadec.dllとのリンク ]
[DllImport( "xadec.dll", EntryPoint = "xaDecodeOpen", CallingConvention = CallingConvention.Cdecl )]
public extern static IntPtr xaDecodeOpen( ref XAHEADER pxah, out FDK.CWin32.WAVEFORMATEX pwfx );
[DllImport( "xadec.dll", EntryPoint = "xaDecodeClose", CallingConvention = CallingConvention.Cdecl )]
public extern static bool xaDecodeClose( IntPtr hxas );
[DllImport( "xadec.dll", EntryPoint = "xaDecodeSize", CallingConvention = CallingConvention.Cdecl )]
public extern static bool xaDecodeSize( IntPtr hxas, uint slen, out uint pdlen );
[DllImport( "xadec.dll", EntryPoint = "xaDecodeConvert", CallingConvention = CallingConvention.Cdecl )]
public extern static bool xaDecodeConvert( IntPtr hxas, ref XASTREAMHEADER psh );
#endregion
public XAHEADER xaheader;
public XASTREAMHEADER xastreamheader;
public CWin32.WAVEFORMATEX waveformatex;
private string filename;
private byte[] srcBuf = null;
private int nHandle = -1;
public override int Open( string filename )
{
this.filename = filename;
#region [ XAヘッダとXAデータの読み出し ]
xaheader = new XAHEADER();
using ( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) ) // FileShare を付けとかないと、Close() 後もロックがかかる??
{
using ( BinaryReader br = new BinaryReader( fs ) )
{
xaheader.id = br.ReadUInt32();
xaheader.nDataLen = br.ReadUInt32();
xaheader.nSamples = br.ReadUInt32();
xaheader.nSamplesPerSec = br.ReadUInt16();
xaheader.nBits = br.ReadByte();
xaheader.nChannels = br.ReadByte();
xaheader.nLoopPtr = br.ReadUInt32();
xaheader.befL = new short[ 2 ];
xaheader.befR = new short[ 2 ];
xaheader.pad = new byte[ 4 ];
xaheader.befL[ 0 ] = br.ReadInt16();
xaheader.befL[ 1 ] = br.ReadInt16();
xaheader.befR[ 0 ] = br.ReadInt16();
xaheader.befR[ 1 ] = br.ReadInt16();
xaheader.pad = br.ReadBytes( 4 );
srcBuf = new byte[ xaheader.nDataLen ];
srcBuf = br.ReadBytes( (int) xaheader.nDataLen );
}
}
//string xaid = Encoding.ASCII.GetString( xah.id );
#region [ ]
//Debug.WriteLine( "**XAHEADER**" );
//Debug.WriteLine( "id= " + xaheader.id.ToString( "X8" ) );
//Debug.WriteLine( "nDataLen= " + xaheader.nDataLen.ToString( "X8" ) );
//Debug.WriteLine( "nSamples= " + xaheader.nSamples.ToString( "X8" ) );
//Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) );
//Debug.WriteLine( "nBits= " + xaheader.nBits.ToString( "X2" ) );
//Debug.WriteLine( "nChannels= " + xaheader.nChannels.ToString( "X2" ) );
//Debug.WriteLine( "nLoopPtr= " + xaheader.nLoopPtr.ToString( "X8" ) );
//Debug.WriteLine( "befL[0]= " + xaheader.befL[ 0 ].ToString( "X4" ) );
//Debug.WriteLine( "befL[1]= " + xaheader.befL[ 1 ].ToString( "X4" ) );
//Debug.WriteLine( "befR[0]= " + xaheader.befR[ 0 ].ToString( "X4" ) );
//Debug.WriteLine( "befR[1]= " + xaheader.befR[ 1 ].ToString( "X4" ) );
#endregion
#endregion
IntPtr hxas;
#region [ WAVEFORMEX情報の取得 ]
waveformatex = new CWin32.WAVEFORMATEX();
hxas = xaDecodeOpen( ref xaheader, out waveformatex );
if ( hxas == null )
{
Trace.TraceError( "Error: xa: Open(): xaDecodeOpen(): " + Path.GetFileName( filename ) );
return -1;
}
#region [ ]
//Debug.WriteLine( "**WAVEFORMATEX**" );
//Debug.WriteLine( "wFormatTag= " + waveformatex.wFormatTag.ToString( "X4" ) );
//Debug.WriteLine( "nChannels = " + waveformatex.nChannels.ToString( "X4" ) );
//Debug.WriteLine( "nSamplesPerSec= " + waveformatex.nSamplesPerSec.ToString( "X8" ) );
//Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) );
//Debug.WriteLine( "nBlockAlign= " + waveformatex.nBlockAlign.ToString( "X4" ) );
//Debug.WriteLine( "wBitsPerSample= " + waveformatex.wBitsPerSample.ToString( "X4" ) );
//Debug.WriteLine( "cbSize= " + waveformatex.cbSize.ToString( "X4" ) );
#endregion
#endregion
this.nHandle = (int) hxas;
return (int) hxas;
}
public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx )
{
#region [ WAVEFORMATEX構造体の手動コピー ]
wfx.nAvgBytesPerSec = waveformatex.nAvgBytesPerSec;
wfx.wBitsPerSample = waveformatex.wBitsPerSample;
wfx.nBlockAlign = waveformatex.nBlockAlign;
wfx.nChannels = waveformatex.nChannels;
wfx.wFormatTag = waveformatex.wFormatTag;
wfx.nSamplesPerSec = waveformatex.nSamplesPerSec;
return 0;
#endregion
}
public override uint GetTotalPCMSize( int nHandle )
{
#region [ ]
uint dlen;
xaDecodeSize( (IntPtr) nHandle, xaheader.nDataLen, out dlen );
#region [ ]
//Debug.WriteLine( "**INTERNAL VALUE**" );
//Debug.WriteLine( "dlen= " + dlen );
#endregion
#endregion
return dlen;
}
public override int Seek( int nHandle, uint dwPosition )
{
return 0;
}
public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop )
{
#region [ xaデータのデコード ]
xastreamheader = new XASTREAMHEADER();
unsafe
{
fixed ( byte* pXaBuf = srcBuf )
{
byte* pWavBuf = (byte*) pDest;
xastreamheader.pSrc = pXaBuf;
xastreamheader.nSrcLen = xaheader.nDataLen;
xastreamheader.nSrcUsed = 0;
xastreamheader.pDst = pWavBuf;
xastreamheader.nDstLen = szDestSize;
xastreamheader.nDstUsed = 0;
if ( !xaDecodeConvert( (IntPtr) nHandle, ref xastreamheader ) )
{
Trace.TraceError( "Error: xaDecodeConvert(): " + Path.GetFileName( filename ) );
return -1;
}
}
}
#region [ ]
//Debug.WriteLine( "**XASTREAMHEADER**" );
//Debug.WriteLine( "nSrcLen= " + xastreamheader.nSrcLen );
//Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed );
//Debug.WriteLine( "nDstLen= " + xastreamheader.nDstLen );
//Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed );
#endregion
#endregion
return 0;
}
public override void Close( int nHandle )
{
#region [ xaファイルのクローズ ]
if ( !xaDecodeClose( (IntPtr) nHandle ) )
{
Trace.TraceError( "Error: xaDecodeClose(): " + Path.GetFileName( filename ) );
}
srcBuf = null;
#endregion
}
//#region [ IDisposable 実装 ]
////-----------------
//private bool bDispose完了済み = false;
//public void Dispose()
//{
// if ( !this.bDispose完了済み )
// {
// if ( srcBuf != null )
// {
// srcBuf = null;
// }
// if ( dstBuf != null )
// {
// dstBuf = null;
// }
// if ( this.nHandle >= 0 )
// {
// this.Close( this.nHandle );
// this.nHandle = -1;
// }
// this.bDispose完了済み = true;
// }
//}
////-----------------
//#endregion
#if false
/// <summary>
/// xaファイルを読み込んで、wavにdecodeする
/// </summary>
/// <param name="filename">xaファイル名</param>
/// <param name="wavBuf">wavファイルが格納されるバッファ</param>
/// <returns></returns>
public bool Decode( string filename, out byte[] wavBuf )
{
// Debug.WriteLine( "xa: Decode: " + Path.GetFileName( filename ) );
#region [ XAヘッダとXAデータの読み出し ]
xaheader = new XAHEADER();
byte[] xaBuf;
using ( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) ) // FileShare を付けとかないと、Close() 後もロックがかかる??
{
using ( BinaryReader br = new BinaryReader( fs ) )
{
xaheader.id = br.ReadUInt32();
xaheader.nDataLen = br.ReadUInt32();
xaheader.nSamples = br.ReadUInt32();
xaheader.nSamplesPerSec = br.ReadUInt16();
xaheader.nBits = br.ReadByte();
xaheader.nChannels = br.ReadByte();
xaheader.nLoopPtr = br.ReadUInt32();
xaheader.befL = new short[ 2 ];
xaheader.befR = new short[ 2 ];
xaheader.pad = new byte[ 4 ];
xaheader.befL[ 0 ] = br.ReadInt16();
xaheader.befL[ 1 ] = br.ReadInt16();
xaheader.befR[ 0 ] = br.ReadInt16();
xaheader.befR[ 1 ] = br.ReadInt16();
xaheader.pad = br.ReadBytes( 4 );
xaBuf = new byte[ xaheader.nDataLen ];
xaBuf = br.ReadBytes( (int) xaheader.nDataLen );
}
}
//string xaid = Encoding.ASCII.GetString( xah.id );
#region [ ]
//Debug.WriteLine( "**XAHEADER**" );
//Debug.WriteLine( "id= " + xaheader.id.ToString( "X8" ) );
//Debug.WriteLine( "nDataLen= " + xaheader.nDataLen.ToString( "X8" ) );
//Debug.WriteLine( "nSamples= " + xaheader.nSamples.ToString( "X8" ) );
//Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) );
//Debug.WriteLine( "nBits= " + xaheader.nBits.ToString( "X2" ) );
//Debug.WriteLine( "nChannels= " + xaheader.nChannels.ToString( "X2" ) );
//Debug.WriteLine( "nLoopPtr= " + xaheader.nLoopPtr.ToString( "X8" ) );
//Debug.WriteLine( "befL[0]= " + xaheader.befL[ 0 ].ToString( "X4" ) );
//Debug.WriteLine( "befL[1]= " + xaheader.befL[ 1 ].ToString( "X4" ) );
//Debug.WriteLine( "befR[0]= " + xaheader.befR[ 0 ].ToString( "X4" ) );
//Debug.WriteLine( "befR[1]= " + xaheader.befR[ 1 ].ToString( "X4" ) );
#endregion
#endregion
object lockobj = new object();
lock ( lockobj ) // スレッドセーフじゃないかも知れないので、念のため
{
#region [ WAVEFORMEX情報の取得 ]
waveformatex = new CWin32.WAVEFORMATEX();
IntPtr hxas = xaDecodeOpen( ref xaheader, out waveformatex );
if ( hxas == null )
{
Trace.TraceError( "Error: xaDecodeOpen(): " + Path.GetFileName( filename ) );
wavBuf = null;
return false;
}
#region [ ]
//Debug.WriteLine( "**WAVEFORMATEX**" );
//Debug.WriteLine( "wFormatTag= " + waveformatex.wFormatTag.ToString( "X4" ) );
//Debug.WriteLine( "nChannels = " + waveformatex.nChannels.ToString( "X4" ) );
//Debug.WriteLine( "nSamplesPerSec= " + waveformatex.nSamplesPerSec.ToString( "X8" ) );
//Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) );
//Debug.WriteLine( "nBlockAlign= " + waveformatex.nBlockAlign.ToString( "X4" ) );
//Debug.WriteLine( "wBitsPerSample= " + waveformatex.wBitsPerSample.ToString( "X4" ) );
//Debug.WriteLine( "cbSize= " + waveformatex.cbSize.ToString( "X4" ) );
#endregion
#endregion
#region [ ]
uint dlen;
xaDecodeSize( hxas, xaheader.nDataLen, out dlen );
#region [ ]
//Debug.WriteLine( "**INTERNAL VALUE**" );
//Debug.WriteLine( "dlen= " + dlen );
#endregion
#endregion
#region [ xaデータのデコード ]
wavBuf = new byte[ dlen ];
xastreamheader = new XASTREAMHEADER();
unsafe
{
fixed ( byte* pXaBuf = xaBuf, pWavBuf = wavBuf )
{
xastreamheader.pSrc = pXaBuf;
xastreamheader.nSrcLen = xaheader.nDataLen;
xastreamheader.nSrcUsed = 0;
xastreamheader.pDst = pWavBuf;
xastreamheader.nDstLen = dlen;
xastreamheader.nDstUsed = 0;
bool b = xaDecodeConvert( hxas, ref xastreamheader );
if ( !b )
{
Trace.TraceError( "Error: xaDecodeConvert(): " + Path.GetFileName( filename ) );
wavBuf = null;
return false;
}
}
}
#region [ ]
//Debug.WriteLine( "**XASTREAMHEADER**" );
//Debug.WriteLine( "nSrcLen= " + xastreamheader.nSrcLen );
//Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed );
//Debug.WriteLine( "nDstLen= " + xastreamheader.nDstLen );
//Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed );
#endregion
#endregion
#region [ xaファイルのクローズ ]
bool bb = xaDecodeClose( hxas );
if ( !bb )
{
Trace.TraceError( "Error: xaDecodeClose(): " + Path.GetFileName( filename ) );
}
#endregion
}
return true;
}
#endif
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public enum ESoundDeviceType
{
ExclusiveWASAPI,
SharedWASAPI,
ASIO,
DirectSound,
Unknown,
}
}

View File

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

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Un4seen.Bass;
using Un4seen.BassAsio;
using Un4seen.BassWasapi;
using Un4seen.Bass.AddOn.Mix;
namespace FDK
{
internal interface ISoundDevice : IDisposable
{
ESoundDeviceType e出力デバイス { get; }
int nMasterVolume { get; set; }
long n実出力遅延ms { get; }
long n実バッファサイズms { get; }
long n経過時間ms { get; }
long n経過時間を更新したシステム時刻ms { get; }
CTimer tmシステムタイマ { get; }
CSound tサウンドを作成する( string strファイル名, ESoundGroup soundGroup );
void tサウンドを作成する( string strファイル名, CSound sound );
void tサウンドを作成する( byte[] byArrWAVファイルイメージ, CSound sound );
}
}

View File

@ -0,0 +1,22 @@
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;
public LoudnessMetadata(Lufs integrated, Lufs? truePeak)
{
Integrated = integrated;
TruePeak = truePeak;
}
}
}

View File

@ -0,0 +1,357 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.XPath;
namespace FDK
{
/// <summary>
/// The LoudnessMetadataScanner plays two roles:
/// 1. Scanning of song audio files using BS1770GAIN (http://bs1770gain.sourceforge.net/)
/// 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)
/// have their perceived loudness determined and saved into an associated metadata file
/// 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
/// the application starts, but shifts to prioritize songs which are browsed and previewed
/// while on the song select screen.
/// 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
/// 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
/// SongGainController for combination with a configured target loudness, resulting in a
/// gain value assigned to the sound object just before playback begins.
/// </summary>
public static class LoudnessMetadataScanner
{
private const string Bs1770GainExeFileName = "bs1770gain.exe";
private static readonly Stack<string> Jobs = new Stack<string>();
private static readonly object LockObject = new object();
private static readonly Queue<double> RecentFileScanDurations = new Queue<double>();
private static Thread ScanningThread;
private static Semaphore Semaphore;
public static void StartBackgroundScanning()
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StartBackgroundScanning)}";
if (!IsBs1770GainAvailable())
{
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is not available. A background scanning thread will not be started.");
return;
}
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is available. Starting background scanning thread...");
lock (LockObject)
{
Semaphore = new Semaphore(Jobs.Count, int.MaxValue);
ScanningThread = new Thread(Scan)
{
IsBackground = true,
Name = "LoudnessMetadataScanner background scanning thread.",
Priority = ThreadPriority.Lowest
};
ScanningThread.Start();
}
Trace.TraceInformation($"{tracePrefix}: Background scanning thread started.");
}
public static void StopBackgroundScanning(bool joinImmediately)
{
var scanningThread = ScanningThread;
if (scanningThread == null)
{
return;
}
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StopBackgroundScanning)}";
Trace.TraceInformation($"{tracePrefix}: Stopping background scanning thread...");
lock (LockObject)
{
ScanningThread = null;
Semaphore.Release();
Semaphore = null;
}
if (joinImmediately)
{
scanningThread.Join();
}
Trace.TraceInformation($"{tracePrefix}: Background scanning thread stopped.");
}
public static LoudnessMetadata? LoadForAudioPath(string absoluteBgmPath)
{
try
{
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath))
{
return LoadFromMetadataPath(loudnessMetadataPath);
}
SubmitForBackgroundScanning(absoluteBgmPath);
}
catch (Exception e)
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadForAudioPath)}";
Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to load {absoluteBgmPath}");
Trace.TraceError(e.ToString());
}
return null;
}
private static string GetLoudnessMetadataPath(string absoluteBgmPath)
{
return Path.Combine(
Path.GetDirectoryName(absoluteBgmPath),
Path.GetFileNameWithoutExtension(absoluteBgmPath) + ".bs1770gain.xml");
}
private static LoudnessMetadata? LoadFromMetadataPath(string loudnessMetadataPath)
{
XPathDocument xPathDocument;
try
{
xPathDocument = new XPathDocument(loudnessMetadataPath);
}
catch (IOException)
{
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()
.SelectSingleNode(@"//bs1770gain/track[@ToTal=""1"" and @Number=""1""]");
var integratedLufsNode = trackNavigator?.SelectSingleNode(@"integrated/@lufs");
var truePeakTpfsNode = trackNavigator?.SelectSingleNode(@"true-peak/@tpfs");
if (trackNavigator == null || integratedLufsNode == null || truePeakTpfsNode == null)
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered incorrect xml element structure while parsing {loudnessMetadataPath}. Returning null...");
return null;
}
var integrated = integratedLufsNode.ValueAsDouble;
var truePeak = truePeakTpfsNode.ValueAsDouble;
if (integrated <= -70.0 || truePeak >= 12.04)
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered evidence of extreme clipping while parsing {loudnessMetadataPath}. Returning null...");
return null;
}
return new LoudnessMetadata(new Lufs(integrated), new Lufs(truePeak));
}
private static void SubmitForBackgroundScanning(string absoluteBgmPath)
{
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
// 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.
//
// 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
// scrolling through songs and previewing them. Their current interests should drive
// scanning priorities, and it is for this reason that a stack is used instead of a queue.
var semaphore = Semaphore;
if (semaphore != null && (Jobs.Count == 0 || Jobs.Peek() != absoluteBgmPath))
{
Jobs.Push(absoluteBgmPath);
semaphore.Release();
}
}
}
private static void Scan()
{
try
{
while (true)
{
RaiseScanningStateChanged(false);
Semaphore?.WaitOne();
if (ScanningThread == null)
{
return;
}
RaiseScanningStateChanged(true);
int jobCount;
string absoluteBgmPath;
lock (LockObject)
{
jobCount = Jobs.Count;
absoluteBgmPath = Jobs.Pop();
}
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
try
{
if (!File.Exists(absoluteBgmPath))
{
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Missing audio file. Skipping {absoluteBgmPath}...");
continue;
}
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath))
{
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Pre-existing metadata. Skipping {absoluteBgmPath}...");
continue;
}
Trace.TraceInformation($"{tracePrefix}: Scanning jobs outstanding: {jobCount}. Scanning {absoluteBgmPath}...");
var stopwatch = Stopwatch.StartNew();
File.Delete(loudnessMetadataPath);
var arguments = $"-it --xml -f \"{Path.GetFileName(loudnessMetadataPath)}\" \"{Path.GetFileName(absoluteBgmPath)}\"";
Execute(Path.GetDirectoryName(absoluteBgmPath), Bs1770GainExeFileName, arguments, true);
var seconds = stopwatch.Elapsed.TotalSeconds;
RecentFileScanDurations.Enqueue(seconds);
while (RecentFileScanDurations.Count > 20)
{
RecentFileScanDurations.Dequeue();
}
var averageSeconds = RecentFileScanDurations.Average();
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}");
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()
{
try
{
Execute(null, Bs1770GainExeFileName, "-h");
return true;
}
catch (Win32Exception)
{
return false;
}
catch (Exception e)
{
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(IsBs1770GainAvailable)}";
Trace.TraceError($"{tracePrefix}: Encountered an exception. Returning false...");
Trace.TraceError(e.ToString());
return false;
}
}
private static string Execute(
string workingDirectory, string fileName, string arguments, bool shouldFailOnStdErrDataReceived = false)
{
var processStartInfo = new ProcessStartInfo(fileName, arguments)
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WorkingDirectory = workingDirectory ?? ""
};
var stdoutWriter = new StringWriter();
var stderrWriter = new StringWriter();
using (var process = Process.Start(processStartInfo))
{
process.OutputDataReceived += (s, e) =>
{
if (e.Data != null)
{
stdoutWriter.Write(e.Data);
stdoutWriter.Write(Environment.NewLine);
}
};
var errorDataReceived = false;
process.ErrorDataReceived += (s, e) =>
{
if (e.Data != null)
{
errorDataReceived = true;
stderrWriter.Write(e.Data);
stderrWriter.Write(Environment.NewLine);
}
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
if ((shouldFailOnStdErrDataReceived && errorDataReceived) || process.ExitCode != 0)
{
var stderr = stderrWriter.ToString();
if (string.IsNullOrEmpty(stderr))
{
stderr = stdoutWriter.ToString();
}
throw new Exception(
$"Execution of {processStartInfo.FileName} with arguments {processStartInfo.Arguments} failed with exit code {process.ExitCode}: {stderr}");
}
return stdoutWriter.ToString();
}
}
private static void RaiseScanningStateChanged(bool isActivelyScanning)
{
ScanningStateChanged?.Invoke(null, new ScanningStateChangedEventArgs(isActivelyScanning));
}
public class ScanningStateChangedEventArgs : EventArgs
{
public ScanningStateChangedEventArgs(bool isActivelyScanning)
{
IsActivelyScanning = isActivelyScanning;
}
public bool IsActivelyScanning { get; private set; }
}
public static event EventHandler<ScanningStateChangedEventArgs> ScanningStateChanged;
}
}

View File

@ -0,0 +1,47 @@
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;
public Lufs(double value)
{
_value = value;
}
public double ToDouble() => _value;
public Lufs Min(Lufs lufs)
{
return new Lufs(Math.Min(_value, lufs._value));
}
public Lufs Negate()
{
return new Lufs(-_value);
}
public override string ToString()
{
return _value.ToString();
}
public static Lufs operator- (Lufs left, Lufs right)
{
return new Lufs(left._value - right._value);
}
public static Lufs operator+ (Lufs left, Lufs right)
{
return new Lufs(left._value + right._value);
}
}
}

View File

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

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace FDK
{
/// <summary>
/// xa,oggデコード用の基底クラス
/// </summary>
public abstract class SoundDecoder //: IDisposable
{
public abstract int Open( string filename );
public abstract int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx );
public abstract uint GetTotalPCMSize( int nHandle );
public abstract int Seek( int nHandle, uint dwPosition );
public abstract int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop );
public abstract void Close( int nHandle );
}
}

View File

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

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
namespace FDK
{
public static class BitmapUtil
{
// 定数
public const uint DIB_PAL_COLORS = 1;
public const uint DIB_RGB_COLORS = 0;
// 構造体
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct BITMAPFILEHEADER
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct BITMAPINFOHEADER
{
public const int BI_RGB = 0;
public uint biSize構造体のサイズ;
public int biWidthビットマップの幅dot;
public int biHeightビットマップの高さdot;
public ushort biPlanes面の数;
public ushort biBitCount;
public uint biCompression圧縮形式;
public uint biSizeImage画像イメージのサイズ;
public int biXPelsPerMete水平方向の解像度;
public int biYPelsPerMeter垂直方向の解像度;
public uint biClrUsed色テーブルのインデックス数;
public uint biClrImportant表示に必要な色インデックスの数;
}
// メソッド
public static unsafe Bitmap ToBitmap( IntPtr pBITMAPINFOHEADER )
{
BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER* bitmapinfoheaderPtr = (BITMAPINFOHEADER*) pBITMAPINFOHEADER;
bitmapfileheader.bfType = 0x4d42;
bitmapfileheader.bfOffBits = (uint) ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) );
bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ;
MemoryStream output = new MemoryStream();
BinaryWriter writer = new BinaryWriter( output );
byte[] destination = new byte[ sizeof( BITMAPFILEHEADER ) ];
Marshal.Copy( (IntPtr) ( &bitmapfileheader ), destination, 0, destination.Length );
writer.Write( destination );
destination = new byte[ sizeof( BITMAPINFOHEADER ) ];
Marshal.Copy( pBITMAPINFOHEADER, destination, 0, destination.Length );
writer.Write( destination );
destination = new byte[ bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ ];
bitmapinfoheaderPtr++;
Marshal.Copy( (IntPtr) bitmapinfoheaderPtr, destination, 0, destination.Length );
writer.Write( destination );
writer.Flush();
writer.BaseStream.Position = 0L;
return new Bitmap( writer.BaseStream );
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using SlimDX;
namespace FDK
{
//http://spazzarama.wordpress.com/2009/09/30/enable-or-disable-dwm-composition-aero/
/// <summary>
/// To control Aerograph in Vista and Windows7. Don't use this class in XP.
/// </summary>
public static class DWM
{
const uint DWM_EC_DISABLECOMPOSITION = 0;
const uint DWM_EC_ENABLECOMPOSITION = 1;
[DllImport( "dwmapi.dll", EntryPoint = "DwmEnableComposition" )]
extern static uint DwmEnableComposition( uint compositionAction );
[DllImport( "dwmapi.dll", EntryPoint = "DwmEnableComposition" )]
public extern static bool DwmIsCompositionEnabled(out bool pfEnabled);
[DllImport( "dwmapi.dll", EntryPoint = "DwmFlush" )]
extern static int DwmFlush();
// [DllImport( "dwmapi.dll", EntryPoint = "DwmEnableMMCSS" )]
// extern static int DwmEnableMMCSS( bool fEnableMMCSS );
[DllImport( "dwmapi.dll", EntryPoint = "DwmFlush" )]
extern static int DwmEnableMMCSS( bool fEnableMMCSS );
public static int IsCompositionEnabled(out bool enabled)
{
#if TEST_Direct3DEx
return DwmIsCompositionEnabled( out enabled );
#else
enabled = false;
return 0;
#endif
}
public static int Flush()
{
#if TEST_Direct3DEx
return DwmFlush();
#else
return 0; // 0(S_OK)なら成功
#endif
}
/// <summary>
/// Enable/Disable DWM composition (aka Aero)
/// </summary>
/// <param name="bIsAeroEnabled">True to enable composition, false to disable composition.</param>
/// <returns>True if the operation was successful.</returns>
public static bool EnableComposition( bool bIsAeroEnabled )
{
// DwmEnableMMCSS( true );
#if TEST_Direct3D9Ex
try
{
if ( bIsAeroEnabled )
{
DwmEnableComposition( DWM_EC_ENABLECOMPOSITION );
}
else
{
DwmEnableComposition( DWM_EC_DISABLECOMPOSITION );
}
return true;
}
catch ( DllNotFoundException )
{
return false;
}
#else
return true;
#endif
}
}
}

View File

@ -0,0 +1,306 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using SlimDX;
namespace FDK
{
public class CAvi : IDisposable
{
// プロパティ
public uint dwスケール
{
get;
set;
}
public uint dwレート
{
get;
set;
}
public uint nフレーム高さ
{
get;
set;
}
public uint nフレーム幅
{
get;
set;
}
// コンストラクタ
public CAvi( string filename )
{
if ( AVIFileOpen( out this.aviFile, filename, OpenFileFlags.OF_READ, IntPtr.Zero ) != 0 )
{
this.Release();
throw new Exception( "AVIFileOpen failed." );
}
if ( AVIFileGetStream( this.aviFile, out this.aviStream, streamtypeVIDEO, 0 ) != 0 )
{
this.Release();
throw new Exception( "AVIFileGetStream failed." );
}
var info = new AVISTREAMINFO();
AVIStreamInfo( this.aviStream, ref info, Marshal.SizeOf( info ) );
this.dwレート = info.dwRate;
this.dwスケール = info.dwScale;
this.nフレーム幅 = info.rcFrame.right - info.rcFrame.left;
this.nフレーム高さ = info.rcFrame.bottom - info.rcFrame.top;
try
{
this.frame = AVIStreamGetFrameOpen( this.aviStream, 0 );
}
catch
{
this.Release();
throw new Exception( "AVIStreamGetFrameOpen failed." );
}
}
// メソッド
public static void t初期化()
{
AVIFileInit();
}
public static void t終了()
{
AVIFileExit();
}
public Bitmap GetFrame( int no )
{
if( this.aviStream == IntPtr.Zero )
throw new InvalidOperationException();
return BitmapUtil.ToBitmap( AVIStreamGetFrame( this.frame, no ) );
}
public int GetFrameNoFromTime( int time )
{
return (int) ( time * ( ( (double) this.dwレート ) / ( 1000.0 * this.dwスケール ) ) );
}
public IntPtr GetFramePtr( int no )
{
if( this.aviStream == IntPtr.Zero )
throw new InvalidOperationException();
return AVIStreamGetFrame( this.frame, no );
}
public int GetMaxFrameCount()
{
if( this.aviStream == IntPtr.Zero )
throw new InvalidOperationException();
return AVIStreamLength( this.aviStream );
}
public unsafe void tBitmap24ToGraphicsStreamR5G6B5( BitmapUtil.BITMAPINFOHEADER* pBITMAPINFOHEADER, DataStream gs, int nWidth, int nHeight )
{
int nBmpWidth = pBITMAPINFOHEADER->biWidthビットマップの幅dot;
int nBmpHeight = pBITMAPINFOHEADER->biHeightビットマップの高さdot;
int nBmpLineByte = ( nBmpWidth * 3 ) + ( ( 4 - ( ( nBmpWidth * 3 ) % 4 ) ) % 4 );
ushort* pTexture = (ushort*) gs.DataPointer.ToPointer();
byte* pBitmap = (byte*) ( pBITMAPINFOHEADER + 1 );
for( int i = 0; i < nBmpHeight; i++ )
{
if( i >= nHeight )
break;
for( int j = 0; j < nBmpWidth; j++ )
{
if( j >= nWidth )
break;
ushort B = (ushort) ( ( *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 0 ) >> 3 ) & 0x1f );
ushort G = (ushort) ( ( *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 1 ) >> 2 ) & 0x3f );
ushort R = (ushort) ( ( *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 2 ) >> 3 ) & 0x1f );
*( pTexture + ( i * nWidth ) + j ) = (ushort) ( ( R << 11 ) | ( G << 5 ) | B );
}
}
}
public unsafe void tBitmap24ToGraphicsStreamX8R8G8B8( BitmapUtil.BITMAPINFOHEADER* pBITMAPINFOHEADER, DataStream ds, int nWidth, int nHeight )
{
int nBmpWidth = pBITMAPINFOHEADER->biWidthビットマップの幅dot;
int nBmpHeight = pBITMAPINFOHEADER->biHeightビットマップの高さdot;
int nBmpLineByte = ( nBmpWidth * 3 ) + ( ( 4 - ( ( nBmpWidth * 3 ) % 4 ) ) % 4 );
uint* pTexture = (uint*) ds.DataPointer.ToPointer();
byte* pBitmap = (byte*) ( pBITMAPINFOHEADER + 1 );
for( int i = 0; i < nBmpHeight; i++ )
{
if( i >= nHeight )
break;
for( int j = 0; j < nBmpWidth; j++ )
{
if( j >= nWidth )
break;
uint B = *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 0 );
uint G = *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 1 );
uint R = *( ( pBitmap + ( ( ( nBmpHeight - i ) - 1 ) * nBmpLineByte ) ) + ( j * 3 ) + 2 );
*( pTexture + ( i * nWidth ) + j ) = ( R << 16 ) | ( G << 8 ) | B;
}
}
}
#region [ Dispose-Finalize ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this ); // 2011.8.19 from: 忘れてた。
}
protected void Dispose( bool disposeManagedObjects )
{
if( this.bDispose完了済み )
return;
if( disposeManagedObjects )
{
// (A) Managed リソースの解放
}
// (B) Unamanaged リソースの解放
if( this.frame != IntPtr.Zero )
AVIStreamGetFrameClose( this.frame );
this.Release();
this.bDispose完了済み = true;
}
~CAvi()
{
this.Dispose( false );
}
//-----------------
#endregion
// その他
#region [ Win32 AVI関連関数インポート ]
//-----------------
internal enum OpenFileFlags : uint
{
OF_CANCEL = 0x800,
OF_CREATE = 0x1000,
OF_DELETE = 0x200,
OF_EXIST = 0x4000,
OF_PARSE = 0x100,
OF_PROMPT = 0x2000,
OF_READ = 0,
OF_READWRITE = 2,
OF_REOPEN = 0x8000,
OF_SHARE_COMPAT = 0,
OF_SHARE_DENY_NONE = 0x40,
OF_SHARE_DENY_READ = 0x30,
OF_SHARE_DENY_WRITE = 0x20,
OF_SHARE_EXCLUSIVE = 0x10,
OF_VERIFY = 0x400,
OF_WRITE = 1
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
internal struct AVISTREAMINFO
{
public uint fccType;
public uint fccHandler;
public uint dwFlags;
public uint dwCaps;
public ushort wPriority;
public ushort wLanguage;
public uint dwScale;
public uint dwRate;
public uint dwStart;
public uint dwLength;
public uint dwInitialFrames;
public uint dwSuggestedBufferSize;
public uint dwQuality;
public uint dwSampleSize;
public CAvi.RECT rcFrame;
public uint dwEditCount;
public uint dwFormatChangeCount;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 0x40 )]
public ushort[] szName;
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
internal struct RECT
{
public uint left;
public uint top;
public uint right;
public uint bottom;
}
[DllImport( "AVIFIL32" )]
private static extern void AVIFileExit();
[DllImport( "AVIFIL32" )]
private static extern uint AVIFileGetStream( IntPtr pfile, out IntPtr ppavi, uint fccType, int lParam );
[DllImport( "AVIFIL32" )]
private static extern void AVIFileInit();
[DllImport( "AVIFIL32" )]
private static extern uint AVIFileOpen( out IntPtr ppfile, string szFile, OpenFileFlags mode, IntPtr pclsidHandler );
[DllImport( "AVIFIL32" )]
private static extern int AVIFileRelease( IntPtr pfile );
[DllImport( "AVIFIL32" )]
private static extern IntPtr AVIStreamGetFrame( IntPtr pgf, int lPos );
[DllImport( "AVIFIL32" )]
private static extern uint AVIStreamGetFrameClose( IntPtr pget );
[DllImport( "AVIFIL32" )]
private static extern IntPtr AVIStreamGetFrameOpen( IntPtr pavi, int lpbiWanted );
[DllImport( "AVIFIL32" )]
private static extern int AVIStreamInfo( IntPtr pavi, ref AVISTREAMINFO psi, int lSize );
[DllImport( "AVIFIL32" )]
private static extern int AVIStreamLength( IntPtr pavi );
[DllImport( "AVIFIL32" )]
private static extern int AVIStreamRelease( IntPtr pavi );
//-----------------
#endregion
#region [ private ]
//-----------------
private IntPtr aviFile = IntPtr.Zero;
private const string AVIFILE32 = "AVIFIL32";
private const int AVIGETFRAMEF_BESTDISPLAYFMT = 1;
private IntPtr aviStream = IntPtr.Zero;
private bool bDispose完了済み;
private IntPtr frame = IntPtr.Zero;
private static readonly uint streamtypeAUDIO = mmioFOURCC( 'a', 'u', 'd', 's' );
private static readonly uint streamtypeMIDI = mmioFOURCC( 'm', 'i', 'd', 's' );
private static readonly uint streamtypeTEXT = mmioFOURCC( 't', 'x', 't', 's' );
private static readonly uint streamtypeVIDEO = mmioFOURCC( 'v', 'i', 'd', 's' );
private static uint mmioFOURCC( char c0, char c1, char c2, char c3 )
{
return ( (uint) c3 << 0x18 ) | ( (uint) c2 << 0x10 ) | ( (uint) c1 << 0x08 ) | (uint) c0;
}
private void Release()
{
if( this.aviStream != IntPtr.Zero )
{
AVIStreamRelease( this.aviStream );
this.aviStream = IntPtr.Zero;
}
if( this.aviFile != IntPtr.Zero )
{
AVIFileRelease( this.aviFile );
this.aviFile = IntPtr.Zero;
}
}
//-----------------
#endregion
}
}

View File

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace FDK
{
// referenced from http://dalmore.blog7.fc2.com/blog-entry-34.html
public static class CTaskBar
{
public static void ShowTaskBar( bool bShowTaskBar )
{
Int32 hWnd1 = FindWindow( "Shell_TrayWnd", null );
if( hWnd1 != 0 )
{ //タスクバーの表示
if ( bShowTaskBar )
{
ShowWindow( hWnd1, TASKBAR_SHOW ); //// タスクバーを常に表示
}
else
{
ShowWindow( hWnd1, TASKBAR_HIDE );
}
APPBARDATA pData = new APPBARDATA();
pData.cbSize = Marshal.SizeOf( pData );
pData.hWnd = (IntPtr)hWnd1;
pData.lParam = (int)ABMsg.ABM_NEW; //REMOVEにするとオートハイドになる
//タスクバーにメッセージ送信
SHAppBarMessage( ABMsg.ABM_SETSTATE, ref pData );
}
Int32 hWnd2 = FindWindow( "Button", "スタート" );
if ( hWnd2 != 0 )
{ //タスクバーの表示
if ( bShowTaskBar )
{
ShowWindow( hWnd2, TASKBAR_SHOW ); //// タスクバーを常に表示
}
else
{
ShowWindow( hWnd2, TASKBAR_HIDE );
}
APPBARDATA pData = new APPBARDATA();
pData.cbSize = Marshal.SizeOf( pData );
pData.hWnd = (IntPtr) hWnd2;
pData.lParam = (int) ABMsg.ABM_NEW; //REMOVEにするとオートハイドになる
//タスクバーにメッセージ送信
SHAppBarMessage( ABMsg.ABM_SETSTATE, ref pData );
}
}
/// <summary>
/// ABMsg 送るAppBarメッセージの識別子以下のいずれか1つ
/// _ABM_ACTIVATE---AppBarがアクティブになった事をシステムに通知
/// _ABM_GETAUTOHIDEBAR---スクリーンの特定の端に関連付けられているオートハイドAppBarのハンドルを返す
/// _ABM_GETSTATE---タスクバーがオートハイドか常に最前面のどちらの常態にあるかを返す
/// _ABM_GETTASKBARPOS---タスクバーの使用領域を返す
/// _ABM_NEW---新しいAppBarを登録し、システムが通知に使用するメッセージIDを指定する
/// _ABM_QUERYPOS---AppBarのためのサイズとスクリーン位置を要求する
/// _ABM_REMOVE---AppBarの登録を削除する
/// _ABM_SETAUTOHIDEBAR---スクリーンの端にオートハイドAppBarを登録または削除する
/// _ABM_SETPOS---AppBarのサイズとスクリーン座標を設定する
/// _ABM_WINDOWPOSCHANGED---AppBarの位置が変更されたことをシステムに通知する
/// pData TAppBarData構造体各フィールドはdwMessageに依存する
/// </summary>
private enum ABMsg : int
{
ABM_NEW = 0,
ABM_REMOVE = 1,
ABM_QUERYPOS = 2,
ABM_SETPOS = 3,
ABM_GETSTATE = 4,
ABM_GETTASKBARPOS = 5,
ABM_ACTIVATE = 6,
ABM_GETAUTOHIDEBAR = 7,
ABM_SETAUTOHIDEBAR = 8,
ABM_WINDOWPOSCHANGED = 9,
ABM_SETSTATE = 10
}
/// <summary>
/// APPBARDATA SHAppBarMessage関数にて使用されるAppBarに関する構造体。
/// cbSize.....SizeOf(TAppBarData)
/// hWnd.....AppBarのハンドル
/// uCallbackMessage.....任意のメッセージIDhWndのAppBarにメッセージを通知する際ABM_NEWメッセージを送る際に使用
/// uEdge.....スクリーンの端を指定するフラグABM_GETAUTOHIDEBAR、ABM_QUERYPOS、ABM_SETAUTOHIDEBAR、ABM_SETPOSメッセージを送る際に使用し、以下のいずれか1つ
/// _ABE_BOTTOM---下サイド
/// _ABE_LEFT--- 左サイド
/// _ABE_RIGHT---右サイド
/// _ABE_TOP---上サイド
/// rc.....AppBarやタスクバーのスクリーン座標での表示領域ABM_GETTASKBARPOS、ABM_QUERYPOS、ABM_SETPOSメッセージを送る際に使用する
/// lParam.....メッセージ依存のパラメータABM_SETAUTOHIDEBARメッセージと共に使用される
/// </summary>
[StructLayout( LayoutKind.Sequential )]
private struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public ABEdge uEdge;
public RECT rc;
public int lParam;
}
/// <summary>
/// ABEdge
/// </summary>
private enum ABEdge : int
{
ABE_LEFT = 0,
ABE_TOP = 1,
ABE_RIGHT = 2,
ABE_BOTTOM = 3
}
/// <summary>
/// RECT
/// </summary>
[StructLayout( LayoutKind.Sequential )]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
/// <summary>
/// SHAppBarMessage
/// </summary>
/// <param name="dwMessage"></param>
/// <param name="pData"></param>
/// <returns></returns>
[DllImport( "shell32.dll", CallingConvention = CallingConvention.StdCall )]
private static extern int SHAppBarMessage( ABMsg dwMessage, ref APPBARDATA pData );
[DllImport("user32.dll", EntryPoint = "ShowWindow")]
private static extern int ShowWindow(Int32 hWnd, int nCmdShow);
private const int TASKBAR_HIDE = 0;
private const int TASKBAR_SHOW = 5;
[DllImport( "user32.dll", EntryPoint = "FindWindow" )]
private static extern Int32 FindWindow( String lpClassName, String lpWindowName );
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,390 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Diagnostics;
using SlimDX;
using SlimDX.Direct3D9;
using Device = SampleFramework.DeviceCache;
namespace FDK
{
/// <summary>
/// 縦長_横長の画像を自動で折りたたんでテクスチャ化するCTexture。
/// 例えば、768x30 のテクスチャファイルが入力されたら、
/// 内部で256x90 など、2のべき乗サイズに収めるよう、内部でテクスチャ画像を自動的に折り返す。
/// 必要に応じて、正方形テクスチャにもする。
/// また、t2D描画は、その折り返しを加味して実行する。
/// </summary>
public class CTextureAf : CTexture, IDisposable
{
/// <summary>
/// <para>指定された画像ファイルから Managed テクスチャを作成する。</para>
/// <para>利用可能な画像形式は、BMP, JPG, PNG, TGA, DDS, PPM, DIB, HDR, PFM のいずれか。</para>
/// </summary>
/// <param name="device">Direct3D9 デバイス。</param>
/// <param name="strファイル名">画像ファイル名。</param>
/// <param name="format">テクスチャのフォーマット。</param>
/// <param name="b黒を透過する">画像の黒0xFFFFFFFFを透過させるなら true。</param>
/// <exception cref="CTextureCreateFailedException">テクスチャの作成に失敗しました。</exception>
public CTextureAf( Device device, string strファイル名, Format format, bool b黒を透過する )
: this( device, strファイル名, format, b黒を透過する, Pool.Managed )
{
}
/// <summary>
/// <para>画像ファイルからテクスチャを生成する。</para>
/// <para>利用可能な画像形式は、BMP, JPG, PNG, TGA, DDS, PPM, DIB, HDR, PFM のいずれか。</para>
/// <para>テクスチャのサイズは、画像のサイズ以上、かつ、D3D9デバイスで生成可能な最小のサイズに自動的に調節される。
/// その際、テクスチャの調節後のサイズにあわせた画像の拡大縮小は行わない。</para>
/// <para>その他、ミップマップ数は 1、Usage は None、イメージフィルタは Point、ミップマップフィルタは None になる。</para>
/// </summary>
/// <param name="device">Direct3D9 デバイス。</param>
/// <param name="strファイル名">画像ファイル名。</param>
/// <param name="format">テクスチャのフォーマット。</param>
/// <param name="b黒を透過する">画像の黒0xFFFFFFFFを透過させるなら true。</param>
/// <param name="pool">テクスチャの管理方法。</param>
/// <exception cref="CTextureCreateFailedException">テクスチャの作成に失敗しました。</exception>
public CTextureAf( Device device, string strファイル名, Format format, bool b黒を透過する, Pool pool )
{
MakeTexture( device, strファイル名, format, b黒を透過する, pool );
}
public new void MakeTexture( Device device, string strファイル名, Format format, bool b黒を透過する, Pool pool )
{
if ( !File.Exists( strファイル名 ) ) // #27122 2012.1.13 from: ImageInformation では FileNotFound 例外は返ってこないので、ここで自分でチェックする。わかりやすいログのために。
throw new FileNotFoundException( string.Format( "ファイルが存在しません。\n[{0}]", strファイル名 ) );
Byte[] _txData = File.ReadAllBytes( strファイル名 );
bool b条件付きでサイズはの累乗でなくてもOK = ( device.Capabilities.TextureCaps & TextureCaps.NonPow2Conditional ) != 0;
bool bサイズはの累乗でなければならない = ( device.Capabilities.TextureCaps & TextureCaps.Pow2 ) != 0;
bool b正方形でなければならない = ( device.Capabilities.TextureCaps & TextureCaps.SquareOnly ) != 0;
// そもそもこんな最適化をしなくてよいのなら、さっさとbaseに処理を委ねて終了
if ( !bサイズはの累乗でなければならない && b条件付きでサイズはの累乗でなくてもOK )
{
//Debug.WriteLine( Path.GetFileName( strファイル名 ) + ": 最適化は不要です。" );
base.MakeTexture( device, strファイル名, format, b黒を透過する, pool );
return;
}
var information = ImageInformation.FromMemory( _txData );
int orgWidth = information.Width, orgHeight = information.Height;
int w = orgWidth, h = orgHeight, foldtimes;
#region [ () ]
if ( orgWidth >= orgHeight ) // 横長画像なら
{
this.b横長のテクスチャである = true;
if ( !GetFoldedTextureSize( ref w, ref h, out foldtimes ) )
{
//Debug.WriteLine( Path.GetFileName( strファイル名 ) + ": 最適化を断念。" );
base.MakeTexture( device, strファイル名, format, b黒を透過する, pool );
return;
}
}
else // 縦長画像なら
{
this.b横長のテクスチャである = false;
if ( !GetFoldedTextureSize( ref h, ref w, out foldtimes ) ) // 縦横入れ替えて呼び出し
{
//Debug.WriteLine( Path.GetFileName( strファイル名 ) + ": 最適化を断念。" );
base.MakeTexture( device, strファイル名, format, b黒を透過する, pool );
return;
}
}
#endregion
//Debug.WriteLine( Path.GetFileName( strファイル名 ) + ": texture最適化結果: width=" + w + ", height=" + h + ", 折りたたみ回数=" + foldtimes );
#region [ ]
// バイナリ(Byte配列)をBitmapに変換
MemoryStream mms = new MemoryStream( _txData );
Bitmap bmpOrg = new Bitmap( mms );
mms.Close();
Bitmap bmpNew = new Bitmap( w, h );
Graphics g = Graphics.FromImage( bmpNew );
for ( int n = 0; n <= foldtimes; n++ )
{
if ( b横長のテクスチャである )
{
int x = n * w;
int currentHeight = n * orgHeight;
int currentWidth = ( n < foldtimes ) ? w : orgWidth - x;
Rectangle r = new Rectangle( x, 0, currentWidth, orgHeight );
Bitmap bmpTmp = bmpOrg.Clone( r, bmpOrg.PixelFormat ); // ここがボトルネックになるようなら、後日unsafeコードにする。
g.DrawImage( bmpTmp, 0, currentHeight, currentWidth, orgHeight );
bmpTmp.Dispose();
}
else
{
int y = n * h;
int currentWidth = n * orgWidth;
int currentHeight = ( n < foldtimes ) ? h : orgHeight - y;
Rectangle r = new Rectangle( 0, y, orgWidth, currentHeight );
Bitmap bmpTmp = bmpOrg.Clone( r, bmpOrg.PixelFormat ); // ここがボトルネックになるようなら、後日unsafeコードにする。
g.DrawImage( bmpTmp, currentWidth, 0, orgWidth, currentHeight );
bmpTmp.Dispose();
}
};
if ( b黒を透過する )
{
bmpNew.MakeTransparent( Color.Black );
}
g.Dispose();
g = null;
bmpOrg.Dispose();
bmpOrg = null;
base.MakeTexture( device, bmpNew, format, b黒を透過する, pool );
bmpNew.Dispose();
bmpNew = null;
#endregion
_orgWidth = orgWidth;
_orgHeight = orgHeight;
_foldtimes = foldtimes;
this.sz画像サイズ = new Size( orgWidth, orgHeight );
}
/// <summary>
/// 横長画像を適切なサイズに折りたたんだときの最適テクスチャサイズを得る。
/// 縦長画像に対しては、width/heightを入れ替えて呼び出すこと。
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="foldtimes"></param>
/// <returns></returns>
private bool GetFoldedTextureSize( ref int width, ref int height, out int foldtimes )
{
int orgWidth = width, orgHeight = height;
#region [ widthが2 ]
int pow = 1;
while ( orgWidth >= pow )
{
pow *= 2;
}
pow /= 2;
#endregion
#region [ 22 ]
foldtimes = ( orgWidth == pow ) ? 0 : 1; // 2のべき乗からの溢れがあれば、まずその溢れ分で1回折り畳む
if ( foldtimes != 0 )
{
//Debug.WriteLine( "powちょうどではないので、溢れあり。まずは1回折りたたむ。" );
// 試しに、widthをpowに切り詰め、1回折り返してみる。
// width>heightを維持しているなら、テクスチャサイズはより最適な状態になったということになる。
if ( pow <= orgHeight * 2 ) // 新width > 新heightを維持できなくなったなら
{ // 最適化不可とみなし、baseの処理に委ねる
return false;
}
}
#endregion
#region [ width > height ]
width = pow;
height = orgHeight * 2; // 初期値1回折りたたんだ状態
do
{
width /= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1;
height = orgHeight * ( foldtimes + 1 );
} while ( width > height );
width *= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1;
height = orgHeight * ( foldtimes + 1 );
#endregion
return true;
}
/// <summary>
/// テクスチャを 2D 画像と見なして描画する。
/// </summary>
/// <param name="device">Direct3D9 デバイス。</param>
/// <param name="x">描画位置(テクスチャの左上位置の X 座標[dot])。</param>
/// <param name="y">描画位置(テクスチャの左上位置の Y 座標[dot])。</param>
public new void t2D描画( Device device, int x, int y )
{
#if TEST_FOLDTEXTURE
base.t2D描画( device, x, y, 1f, rc全画像 );
#else
for ( int n = 0; n <= _foldtimes; n++ )
{
Rectangle r;
if ( b横長のテクスチャである )
{
int currentHeight = n * _orgHeight;
r = new Rectangle( 0, currentHeight, this.rc全画像.Width, _orgHeight );
base.t2D描画( device, x + n * this.rc全画像.Width, y, 1f, r );
}
else
{
int currentWidth = n * _orgWidth;
r = new Rectangle( currentWidth, 0, _orgWidth, this.rc全画像.Height );
base.t2D描画( device, x, y + n * this.rc全画像.Height, 1f, r );
}
}
#endif
}
public new void t2D描画( Device device, int x, int y, Rectangle rc )
{
Rectangle r;
if ( b横長のテクスチャである )
{
int beginFold = rc.X / this.rc全画像.Width;
int endFold = ( rc.X + rc.Width ) / rc全画像.Width;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int newRcY = i * _orgHeight + rc.Y;
int newRcX = ( i == beginFold ) ? ( rc.X % this.rc全画像.Width ) : 0;
int newRcWidth = ( newRcX + rc.Width > rc全画像.Width ) ? rc全画像.Width - newRcX : rc.Width;
r = new Rectangle( newRcX, newRcY, newRcWidth, rc.Height );
base.t2D描画( device, x, y, 1f, r );
int deltaX = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Width - rc.X : rc全画像.Width;
int newWidth = rc.Width - deltaX;
x += deltaX;
rc.Width = newWidth;
}
}
else
{
int beginFold = rc.Y / this.rc全画像.Height;
int endFold = ( rc.Y + rc.Height ) / rc全画像.Height;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int newRcX = i * _orgWidth + rc.X;
int newRcY = ( i == beginFold ) ? ( rc.Y % this.rc全画像.Height ) : 0;
int newRcHeight = ( newRcY + rc.Height > rc全画像.Height ) ? rc全画像.Height - newRcY : rc.Height;
r = new Rectangle( newRcX, newRcY, rc.Width, newRcHeight );
base.t2D描画( device, x, y, 1f, r );
int deltaY = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Height - rc.Y : rc全画像.Height;
int newHeight = rc.Height - deltaY;
y += deltaY;
rc.Height = newHeight;
}
}
}
public new void t2D描画( Device device, float x, float y )
{
t2D描画( device, (int) x, (int) y );
}
public void t2D描画( Device device, float x, float y, Rectangle rc )
{
t2D描画( device, (int) x, (int) y, rc );
}
/// <summary>
/// テクスチャを 2D 画像と見なして描画する。
/// </summary>
/// <param name="device">Direct3D9 デバイス。</param>
/// <param name="x">描画位置(テクスチャの左上位置の X 座標[dot])。</param>
/// <param name="y">描画位置(テクスチャの左上位置の Y 座標[dot])。</param>
public void t3D描画( Device device, Matrix mat, float x, float y )
{
#if TEST_FOLDTEXTURE
base.t2D描画( device, x, y, 1f, rc全画像 );
#else
for ( int n = 0; n <= _foldtimes; n++ )
{
Rectangle r;
if ( b横長のテクスチャである )
{
int currentHeight = n * _orgHeight;
r = new Rectangle( 0, currentHeight, this.rc全画像.Width, _orgHeight );
base.t3D描画( device, mat );
}
else
{
int currentWidth = n * _orgWidth;
r = new Rectangle( currentWidth, 0, _orgWidth, this.rc全画像.Height );
base.t3D描画( device, mat );
}
}
#endif
}
public void t3D描画( Device device, Matrix mat, float x, float y, Rectangle rc )
{
Rectangle r;
if ( b横長のテクスチャである )
{
int beginFold = rc.X / this.rc全画像.Width;
int endFold = ( rc.X + rc.Width ) / rc全画像.Width;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int newRcY = i * _orgHeight + rc.Y;
int newRcX = ( i == beginFold ) ? ( rc.X % this.rc全画像.Width ) : 0;
int newRcWidth = ( newRcX + rc.Width > rc全画像.Width ) ? rc全画像.Width - newRcX : rc.Width;
r = new Rectangle( newRcX, newRcY, newRcWidth, rc.Height );
base.t3D描画( device, mat, r );
int deltaX = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Width - rc.X : rc全画像.Width;
int newWidth = rc.Width - deltaX;
x += deltaX;
rc.Width = newWidth;
}
}
else
{
int beginFold = rc.Y / this.rc全画像.Height;
int endFold = ( rc.Y + rc.Height ) / rc全画像.Height;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int newRcX = i * _orgWidth + rc.X;
int newRcY = ( i == beginFold ) ? ( rc.Y % this.rc全画像.Height ) : 0;
int newRcHeight = ( newRcY + rc.Height > rc全画像.Height ) ? rc全画像.Height - newRcY : rc.Height;
r = new Rectangle( newRcX, newRcY, rc.Width, newRcHeight );
base.t3D描画( device, mat, r );
int deltaY = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Height - rc.Y : rc全画像.Height;
int newHeight = rc.Height - deltaY;
y += deltaY;
rc.Height = newHeight;
}
}
}
#region [ private ]
//-----------------
private bool b横長のテクスチャである;
/// <summary>
/// 元画像のWidth
/// </summary>
private int _orgWidth;
/// <summary>
/// 元画像のHeight
/// </summary>
private int _orgHeight;
/// <summary>
/// 折りたたみ回数
/// </summary>
private int _foldtimes;
//-----------------
#endregion
}
}

View File

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

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2007-2010 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using SlimDX;
namespace FDK {
/// <summary>
/// Represents a vertex with a position and a color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ColoredVertex : IEquatable<ColoredVertex> {
/// <summary>
/// Gets or sets the position of the vertex.
/// </summary>
public Vector3 Position {
get;
set;
}
/// <summary>
/// Gets or sets the color of the vertex.
/// </summary>
public int Color {
get;
set;
}
/// <summary>
/// Initializes a new instance of the <see cref="ColoredVertex"/> struct.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="color">The color.</param>
public ColoredVertex(Vector3 position, int color)
: this() {
Position = position;
Color = color;
}
/// <summary>
/// Implements operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(ColoredVertex left, ColoredVertex right) {
return left.Equals(right);
}
/// <summary>
/// Implements operator !=.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(ColoredVertex left, ColoredVertex right) {
return !(left == right);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode() {
return Position.GetHashCode() + Color.GetHashCode();
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals(object obj) {
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
return Equals((ColoredVertex)obj);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(ColoredVertex other) {
return (Position == other.Position && Color == other.Color);
}
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Globalization;
using SlimDX;
using SlimDX.Direct3D9;
namespace FDK
{
[StructLayout( LayoutKind.Sequential )]
public struct PositionColoredTexturedVertex : IEquatable<PositionColoredTexturedVertex>
{
public Vector3 Position;
public int Color;
public Vector2 TextureCoordinates;
public static int SizeInBytes
{
get
{
return Marshal.SizeOf( typeof( PositionColoredTexturedVertex ) );
}
}
public static VertexFormat Format
{
get
{
return ( VertexFormat.Texture1 | VertexFormat.Diffuse | VertexFormat.Position );
}
}
public PositionColoredTexturedVertex( Vector3 position, int color, Vector2 textureCoordinates )
{
this = new PositionColoredTexturedVertex();
this.Position = position;
this.Color = color;
this.TextureCoordinates = textureCoordinates;
}
public static bool operator ==( PositionColoredTexturedVertex left, PositionColoredTexturedVertex right )
{
return left.Equals( right );
}
public static bool operator !=( PositionColoredTexturedVertex left, PositionColoredTexturedVertex right )
{
return !( left == right );
}
public override int GetHashCode()
{
return ( ( this.Position.GetHashCode() + this.Color.GetHashCode() ) + this.TextureCoordinates.GetHashCode() );
}
public override bool Equals( object obj )
{
if( obj == null )
{
return false;
}
if( base.GetType() != obj.GetType() )
{
return false;
}
return this.Equals( (PositionColoredTexturedVertex) obj );
}
public bool Equals( PositionColoredTexturedVertex other )
{
return ( ( ( this.Position == other.Position ) && ( this.Color == other.Color ) ) && ( this.TextureCoordinates == other.TextureCoordinates ) );
}
public override string ToString()
{
return string.Format( CultureInfo.CurrentCulture, "{0} ({1}, {2})", new object[] { this.Position.ToString(), System.Drawing.Color.FromArgb( this.Color ).ToString(), this.TextureCoordinates.ToString() } );
}
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2007-2010 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using SlimDX;
namespace FDK {
/// <summary>
/// Represents a vertex with a position and a texture coordinate.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TexturedVertex : IEquatable<TexturedVertex> {
/// <summary>
/// Gets or sets the position of the vertex.
/// </summary>
public Vector3 Position {
get;
set;
}
/// <summary>
/// Gets or sets the texture coordinate for the vertex.
/// </summary>
public Vector2 TextureCoordinate {
get;
set;
}
/// <summary>
/// Initializes a new instance of the <see cref="TexturedVertex"/> struct.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="color">The color.</param>
public TexturedVertex(Vector3 position, Vector2 textureCoordinate)
: this() {
Position = position;
TextureCoordinate = textureCoordinate;
}
/// <summary>
/// Implements operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(TexturedVertex left, TexturedVertex right) {
return left.Equals(right);
}
/// <summary>
/// Implements operator !=.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(TexturedVertex left, TexturedVertex right) {
return !(left == right);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode() {
return Position.GetHashCode() + TextureCoordinate.GetHashCode();
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals(object obj) {
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
return Equals((TexturedVertex)obj);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(TexturedVertex other) {
return (Position == other.Position && TextureCoordinate == other.TextureCoordinate);
}
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Globalization;
using SlimDX;
using SlimDX.Direct3D9;
namespace FDK
{
[StructLayout( LayoutKind.Sequential )]
public struct TransformedColoredTexturedVertex : IEquatable<TransformedColoredTexturedVertex>
{
public Vector4 Position;
public int Color;
public Vector2 TextureCoordinates;
public static int SizeInBytes
{
get
{
return Marshal.SizeOf( typeof( TransformedColoredTexturedVertex ) );
}
}
public static VertexFormat Format
{
get
{
return ( VertexFormat.Texture1 | VertexFormat.Diffuse | VertexFormat.PositionRhw );
}
}
public TransformedColoredTexturedVertex( Vector4 position, int color, Vector2 textureCoordinates )
{
this = new TransformedColoredTexturedVertex();
this.Position = position;
this.Color = color;
this.TextureCoordinates = textureCoordinates;
}
public static bool operator ==( TransformedColoredTexturedVertex left, TransformedColoredTexturedVertex right )
{
return left.Equals( right );
}
public static bool operator !=( TransformedColoredTexturedVertex left, TransformedColoredTexturedVertex right )
{
return !( left == right );
}
public override int GetHashCode()
{
return ( ( this.Position.GetHashCode() + this.Color.GetHashCode() ) + this.TextureCoordinates.GetHashCode() );
}
public override bool Equals( object obj )
{
if( obj == null )
{
return false;
}
if( base.GetType() != obj.GetType() )
{
return false;
}
return this.Equals( (TransformedColoredTexturedVertex) obj );
}
public bool Equals( TransformedColoredTexturedVertex other )
{
return ( ( ( this.Position == other.Position ) && ( this.Color == other.Color ) ) && ( this.TextureCoordinates == other.TextureCoordinates ) );
}
public override string ToString()
{
return string.Format( CultureInfo.CurrentCulture, "{0} ({1}, {2})", new object[] { this.Position.ToString(), System.Drawing.Color.FromArgb( this.Color ).ToString(), this.TextureCoordinates.ToString() } );
}
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2007-2010 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using SlimDX;
namespace FDK {
/// <summary>
/// Represents a vertex with a pre-transformed position and a color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TransformedColoredVertex : IEquatable<TransformedColoredVertex> {
/// <summary>
/// Gets or sets the pre-transformed position of the vertex.
/// </summary>
public Vector4 Position {
get;
set;
}
/// <summary>
/// Gets or sets the color of the vertex.
/// </summary>
public int Color {
get;
set;
}
/// <summary>
/// Initializes a new instance of the <see cref="TransformedColoredVertex"/> struct.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="color">The color.</param>
public TransformedColoredVertex(Vector4 position, int color)
: this() {
Position = position;
Color = color;
}
/// <summary>
/// Implements operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(TransformedColoredVertex left, TransformedColoredVertex right) {
return left.Equals(right);
}
/// <summary>
/// Implements operator !=.
/// </summary>
/// <param name="left">The left side of the operator.</param>
/// <param name="right">The right side of the operator.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(TransformedColoredVertex left, TransformedColoredVertex right) {
return !(left == right);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode() {
return Position.GetHashCode() + Color.GetHashCode();
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
public override bool Equals(object obj) {
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
return Equals((TransformedColoredVertex)obj);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
public bool Equals(TransformedColoredVertex other) {
return (Position == other.Position && Color == other.Color);
}
}
}

View File

@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using DirectShowLib;
using SharpDX.Multimedia;
namespace FDK
{
public class CDStoWAVFileImage
{
/// <summary>
/// <para>指定された動画ファイルから音声のみをエンコードし、WAVファイルイメージを作成して返す。</para>
/// </summary>
public static void t変換( string fileName, out byte[] wavFileImage )
{
int hr = 0;
IGraphBuilder graphBuilder = null;
try
{
graphBuilder = (IGraphBuilder) new FilterGraph();
#region [ ]
//-----------------
ISampleGrabber sampleGrabber = null;
try
{
sampleGrabber = (ISampleGrabber) new SampleGrabber();
// サンプルグラバのメディアタイプの設定。
var mediaType = new AMMediaType() {
majorType = MediaType.Audio,
subType = MediaSubType.PCM,
formatType = FormatType.WaveEx,
};
try
{
hr = sampleGrabber.SetMediaType( mediaType );
DsError.ThrowExceptionForHR( hr );
}
finally
{
if( mediaType != null )
DsUtils.FreeAMMediaType( mediaType );
}
// サンプルグラバのバッファリングを有効にする。
hr = sampleGrabber.SetBufferSamples( true );
DsError.ThrowExceptionForHR( hr );
// サンプルグラバにコールバックを追加する。
sampleGrabberProc = new CSampleGrabberCallBack();
hr = sampleGrabber.SetCallback( sampleGrabberProc, 1 ); // 1:コールバックの BufferCB() メソッドの方を呼び出す。
// サンプルグラバをグラフに追加する。
hr = graphBuilder.AddFilter( (IBaseFilter) sampleGrabber, "SampleGrabber for Audio/PCM" );
DsError.ThrowExceptionForHR( hr );
}
finally
{
C共通.tCOMオブジェクトを解放する( ref sampleGrabber );
}
//-----------------
#endregion
var e = new DirectShowLib.DsROTEntry( graphBuilder );
// fileName からグラフを自動生成。
hr = graphBuilder.RenderFile( fileName, null ); // IMediaControl.RenderFile() は推奨されない
DsError.ThrowExceptionForHR( hr );
// ビデオレンダラを除去。
CDirectShow.tビデオレンダラをグラフから除去する( graphBuilder ); // オーディオレンダラをNullに変えるより前に実行すること。CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する() の中で一度再生するので、そのときにActiveウィンドウが表示されてしまうため。
// オーディオレンダラを NullRenderer に置換。
WaveFormat wfx;
byte[] wfx拡張領域;
CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する( graphBuilder, out wfx, out wfx拡張領域 );
// 基準クロックを NULL最高速に設定する。
IMediaFilter mediaFilter = graphBuilder as IMediaFilter;
mediaFilter.SetSyncSource( null );
mediaFilter = null;
// メモリストリームにデコードデータを出力する。
sampleGrabberProc.MemoryStream = new MemoryStream(); // CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する() で一度再生しているので、ストリームをクリアする。
var ms = sampleGrabberProc.MemoryStream;
var bw = new BinaryWriter( ms );
bw.Write( new byte[] { 0x52, 0x49, 0x46, 0x46 } ); // 'RIFF'
bw.Write( (UInt32) 0 ); // ファイルサイズ - 8 [byte];今は不明なので後で上書きする。
bw.Write( new byte[] { 0x57, 0x41, 0x56, 0x45 } ); // 'WAVE'
bw.Write( new byte[] { 0x66, 0x6D, 0x74, 0x20 } ); // 'fmt '
bw.Write( (UInt32) ( 16 + ( ( wfx拡張領域.Length > 0 ) ? ( 2/*sizeof(WAVEFORMATEX.cbSize)*/ + wfx拡張領域.Length ) : 0 ) ) ); // fmtチャンクのサイズ[byte]
bw.Write( (UInt16) wfx.Encoding); // フォーマットIDリニアPCMなら1
bw.Write( (UInt16) wfx.Channels ); // チャンネル数
bw.Write( (UInt32) wfx.SampleRate); // サンプリングレート
bw.Write( (UInt32) wfx.AverageBytesPerSecond ); // データ速度
bw.Write( (UInt16) wfx.BlockAlign); // ブロックサイズ
bw.Write( (UInt16) wfx.BitsPerSample ); // サンプルあたりのビット数
if( wfx拡張領域.Length > 0 )
{
bw.Write( (UInt16) wfx拡張領域.Length ); // 拡張領域のサイズ[byte]
bw.Write( wfx拡張領域 ); // 拡張データ
}
bw.Write( new byte[] { 0x64, 0x61, 0x74, 0x61 } ); // 'data'
int nDATAチャンクサイズ位置 = (int) ms.Position;
bw.Write( (UInt32) 0 ); // dataチャンクのサイズ[byte];今は不明なので後で上書きする。
#region [ - sampleGrabberProc.MemoryStream PCM ]
//-----------------
IMediaControl mediaControl = graphBuilder as IMediaControl;
mediaControl.Run(); // 再生開始
IMediaEvent mediaEvent = graphBuilder as IMediaEvent;
EventCode eventCode;
hr = mediaEvent.WaitForCompletion( -1, out eventCode );
DsError.ThrowExceptionForHR( hr );
if( eventCode != EventCode.Complete )
throw new Exception( "再生待ちに失敗しました。" );
mediaControl.Stop();
mediaEvent = null;
mediaControl = null;
//-----------------
#endregion
bw.Seek( 4, SeekOrigin.Begin );
bw.Write( (UInt32) ms.Length - 8 ); // ファイルサイズ - 8 [byte]
bw.Seek( nDATAチャンクサイズ位置, SeekOrigin.Begin );
bw.Write( (UInt32) ms.Length - ( nDATAチャンクサイズ位置 + 4 ) ); // dataチャンクサイズ [byte]
// 出力その2を作成。
wavFileImage = ms.ToArray();
// 終了処理。
bw.Close();
sampleGrabberProc.Dispose(); // ms.Close()
}
finally
{
C共通.tCOMオブジェクトを解放する( ref graphBuilder );
}
}
#region [ private ]
//-----------------
private class CSampleGrabberCallBack : ISampleGrabberCB, IDisposable
{
public MemoryStream MemoryStream = new MemoryStream();
public int BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )
{
var bytes = new byte[ BufferLen ];
Marshal.Copy( pBuffer, bytes, 0, BufferLen ); // unmanage → manage
this.MemoryStream.Write( bytes, 0, BufferLen ); // byte[] → Stream
return CWin32.S_OK;
}
public int SampleCB( double SampleTime, IMediaSample pSample )
{
throw new NotImplementedException( "実装されていません。" );
}
public void Dispose()
{
this.MemoryStream.Close();
}
}
private static CSampleGrabberCallBack sampleGrabberProc = null;
//-----------------
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace FDK
{
using HRESULT = Int32;
using BOOL = Int32;
[ComImport, Guid( "CE3CE3EE-5C4E-4BDC-A467-C068E1FC3DA5" )]
public class MemoryRenderer // 何も継承してはならない。
{
// 何も記述してはならない。
// 代わりに、MemoryRenderer の生成後、キャストで↓のインターフェースを取得する。
}
[ComImport, Guid( "FFAA4A1A-D63D-4688-9C66-D18CA7B99488" ), InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
public interface IMemoryRenderer
{
[PreserveSig]
HRESULT GetWidth( out long nWidht );
[PreserveSig]
HRESULT GetHeight( out long nHeight );
[PreserveSig]
HRESULT GetBufferSize( out long nBufferSize );
[PreserveSig]
HRESULT GetCurrentBuffer( IntPtr pBuffer, long nBufferSize );
[PreserveSig]
HRESULT IsBottomUp( out BOOL bBottomUp );
}
}

View File

@ -0,0 +1,209 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using Un4seen.Bass;
//using Un4seen.BassAsio;
//using Un4seen.BassWasapi;
//using Un4seen.Bass.AddOn.Mix;
using Un4seen.Bass.AddOn.Fx;
namespace FDK
{
public class CBeatDetect : IDisposable
{
public struct stBeatPos
{
public float fBeatTime;
public int n小節番号;
public int nGrid;
public int n小節内Grid;
public bool b無効; //
public bool bレーン表示する; // 未使用
public stBeatPos( float _fBeatTime, int _n小節番号, int _nGrid, int _n小節内Grid, bool _b無効, bool _bレーン表示する )
{
fBeatTime = _fBeatTime;
n小節番号 = _n小節番号;
nGrid = _nGrid;
n小節内Grid = _n小節内Grid;
b無効 = _b無効;
bレーン表示する= _bレーン表示する;
}
}
#region [ ]
public CBeatDetect()
{
Initialize();
}
public CBeatDetect( string _filename )
{
this.filename = _filename;
Initialize();
}
#endregion
#region [ () ]
private void Initialize()
{
if ( this.listBeatPositions == null )
{
this.listBeatPositions = new List<stBeatPos>();
}
#region [ BASS registration ]
// BASS.NET ユーザ登録BASSスプラッシュが非表示になる
BassNet.Registration( "dtx2013@gmail.com", "2X9181017152222" );
#endregion
#region [ BASS Version Check ]
// BASS のバージョンチェック。
int nBASSVersion = Utils.HighWord( Bass.BASS_GetVersion() );
if ( nBASSVersion != Bass.BASSVERSION )
throw new DllNotFoundException( string.Format( "bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION ) );
int nBASSFXVersion = Utils.HighWord( BassFx.BASS_FX_GetVersion() );
if ( nBASSFXVersion != BassFx.BASSFXVERSION )
throw new DllNotFoundException( string.Format( "bass_fx.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSFXVersion, BassFx.BASSFXVERSION ) );
#endregion
#region [ BASS ]
//this.bIsBASSFree = true;
//Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ), // 0:BASSストリームの自動更新を行わない。(サウンド出力しないため)
// string.Format( "BASS_SetConfig() に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) );
#endregion
#region [ BASS ]
int nデバイス = 0; // 0:"no sound" … BASS からはデバイスへアクセスさせない。
int n周波数 = 44100; // 仮決め。lデバイス≠ドライバがネイティブに対応している周波数であれば何でもいいようだ。いずれにしろBASSMXで自動的にリサンプリングされる。
if ( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
#endregion
#region [ BASSでオープンし]
//this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_STREAM_DECODE );
this.hBassStream = Bass.BASS_StreamCreateFile( this.filename, 0, 0, BASSFlag.BASS_STREAM_DECODE );
if ( this.hBassStream == 0 )
throw new Exception( string.Format( "{0}: サウンドストリームの生成に失敗しました。(BASS_StreamCreateFile)[{1}]", filename, Bass.BASS_ErrorGetCode().ToString() ) );
this.nTotalBytes = Bass.BASS_ChannelGetLength( this.hBassStream );
this.nTotalSeconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nTotalBytes );
if ( !Bass.BASS_ChannelGetAttribute( this.hBassStream, BASSAttribute.BASS_ATTRIB_FREQ, ref fFreq ) )
{
string errmes = string.Format( "サウンドストリームの周波数取得に失敗しました。(BASS_ChannelGetAttribute)[{0}]", Bass.BASS_ErrorGetCode().ToString() );
Bass.BASS_Free();
throw new Exception( errmes );
}
#endregion
}
#endregion
/// <summary>
/// 曲全体のテンポを取得する
/// </summary>
/// <returns>テンポ値</returns>
/// <remarks>テンポ値の範囲は70-300</remarks>
public float GetTempo()
{
fTempo = BassFx.BASS_FX_BPM_DecodeGet(
this.hBassStream,
0,
nTotalSeconds,
( 300 << 16 ) + 70, // MAX BPM=320, MIN BPM=70
//0,
BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
null,
IntPtr.Zero );
return fTempo;
}
/// <summary>
/// 曲の一部分のテンポを取得する
/// </summary>
/// <param name="startSec">開始位置</param>
/// <param name="endSec">終了位置</param>
/// <returns>テンポ値</returns>
/// <remarks>テンポ値の範囲は70-300</remarks>
public float GetTempo( double startSec, double endSec )
{
fTempo = BassFx.BASS_FX_BPM_DecodeGet(
this.hBassStream,
startSec,
endSec,
( 300 << 16 ) + 70, // MAX BPM=320, MIN BPM=70
//0,
BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
null,
IntPtr.Zero );
return fTempo;
}
/// <summary>
/// Beatの検出位置をListで返す
/// </summary>
/// <returns>Beat検出位置群</returns>
public List<stBeatPos> GetBeatPositions()
{
#region [ BeatPosition格納リストの初期化 ]
if ( this.listBeatPositions != null )
{
this.listBeatPositions.Clear();
}
else
{
this.listBeatPositions = new List<stBeatPos>();
}
#endregion
BPMBEATPROC _beatProc = new BPMBEATPROC( GetBeat_ProgressCallback );
bool ret = BassFx.BASS_FX_BPM_BeatDecodeGet(
this.hBassStream,
0,
nTotalSeconds,
//0,
BASSFXBpm.BASS_FX_BPM_DEFAULT, //BASSFXBpm.BASS_FX_BPM_MULT2,
_beatProc,
IntPtr.Zero );
return this.listBeatPositions;
}
private void GetBeat_ProgressCallback( int channel, double beatpos, IntPtr user )
{
stBeatPos sbp = new stBeatPos(
(float) beatpos,
0,
0,
0,
false,
true
);
listBeatPositions.Add( sbp );
// Debug.WriteLine( "Beat at: " + beatpos.ToString() );
}
public void Dispose() // 使い終わったら必ずDispose()すること。BASSのリソースを握りっぱなしにすると、他の再生に不都合が生じるため。
{
BassFx.BASS_FX_BPM_Free( this.hBassStream );
Bass.BASS_StreamFree( this.hBassStream );
this.hBassStream = -1;
Bass.BASS_Free();
}
// =============
private string filename = "";
private int hBassStream = -1;
private long nTotalBytes = 0;
private double nTotalSeconds = 0.0f;
private float fFreq = 0.0f;
private float fTempo;
private List<stBeatPos> listBeatPositions = null;
}
}

35
README.old.md Normal file
View File

@ -0,0 +1,35 @@
# TJAPlayer3-Develop-ReWrite
DTXManiaをいじってtja再生プログラムにしちゃった[TJAPlayer2fPC](https://github.com/kairera0467/TJAP2fPC)をForkして本家風に改造した
[TJAPlayer3](https://github.com/AioiLight/TJAPlayer3)を超本家風に改造したアレを書き直したもの。
このプログラムを使用した不具合・問題については責任を負いかねます。
## How 2 Build
- VisualStudio 2017 & C# 7.3
- VC++ toolset
- SlimDX用の署名
## ライセンス関係
Fork元より引用。
> 以下のライブラリを使用しています。
> * bass
> * Bass.Net
> * DirectShowLib
> * FDK21
> * SlimDX
> * SharpDX
> * ReadJEnc
> * xadec
> * IPAフォント
> * libogg
> * libvorbis
> 「実行時フォルダ/Licenses」に収録しています。
>
> また、このプログラムはFROM氏の「DTXMania」を元に製作しています。
## クレジット
> * [TwoPointZero/TJAPlayer3](https://github.com/twopointzero/TJAPlayer3)(@twopointzero)
> * [KabanFriends/TJAPlayer3](https://github.com/KabanFriends/TJAPlayer3/tree/features)(@KabanFriends)
> * [Mr-Ojii/TJAPlayer3-f](https://github.com/Mr-Ojii/TJAPlayer3-f)(@Mr-Ojii)
> * [Akasoko/TJAPlayer3](https://github.com/Akasoko-Master/TJAPlayer3)(@AkasokoR)

79
Readme.txt Normal file
View File

@ -0,0 +1,79 @@
############
TJAPlayer3 Readme.txt
############
公開日:2018/5/5
更新日:2018/12/21
== はじめに ==
TJAPlayer3をダウンロードしていただき、ありがとうございます。
このシミュレータは、アーケード/家庭用ゲーム「太鼓の達人」シリーズのシミュレータです。
このシミュレータは、TJAPlayer2 forPCというシミュレーターを改造したものです。
太鼓さん次郎・TJAPlayer等で使われている.tjaファイルを読み込み、プレイすることができます。
(すべての.tjaファイルが読み込めるわけではありません。また、TJAPlayer3側で追加した命令もあります。)
開発途中のシミュレータのため、不具合やバグがある場合があります。ご了承ください。
(もし不具合を見つけた場合は、GitHubのissueやTwitterで連絡してくださると、大変助かります。)
== 使用上の注意 ==
・TJAPlayer3はオープンソースソフトウェア(MIT)です。
・このシミュレータを使用する場合は、**全て自己責任**でお願いします。
・説明書や、ドキュメントを見れば解決できる質問がよく来ます。人に質問する前に、まずは自分で調べることをしてください。
・プログラムの制作者(AioiLight)は、TJAPlayer3本体(AioiLight.spaceからダウンロードしたもの)とデフォルトのスキン「SimpleStyle」のサポートのみ行います。
 その他のスキン(例:本家風スキン)や、TJAPlayer3の改造品(派生ビルド)のサポートは原則行いませんのでご了承ください。
・すべての環境で動作確認はできない(できるはずがない)ので、動いたら運がいい、程度でお願いします。
 ドキュメントを読んでも解決しなかったら、諦めましょう。諦めも肝心です。
・常時60fpsを保てないPCでの動作は期待できません。
== 操作方法、曲の追加方法、更新情報など ==
https://aioilight.space/taiko/tjap3/
ドキュメントに情報が集められているので、それをお読みください。随時更新しています。
== デフォルトスキン(SimpleStyle)について ==
一部画像はTJAPlayer2 forPCのデフォルトスキンから流用しています。
ライセンスはMITのもと運用しています。MITライセンスを厳守する場合、改変、配布等OKです。
作成ツール: Photoshop/After Effects
== 動画、配信等でのご利用について ==
TJAPlayer3を動画共有サイトやライブ配信サービス、ウェブサイトやブログ等でご利用になられる場合、
バンダイナムコエンターテインメント公式のものでないこと、他の太鼓の達人シミュレーターと混同しないよう配慮をお願いいたします。
また、タグ機能のあるサイトの場合、「TJAPlayer3」「TJAP3」といったタグを付けることで、
他シミュレータとの誤解を防ぐとともに、関連動画として出やすくなるメリットがあるため、推奨します。
== TJAPlayer3の改造・再配布(二次配布)を行う場合について ==
TJAPlayer3、デフォルトスキンはMITライセンスで制作されています。
MITライセンスのルールのもと、改造・再配布を行うことは自由ですが、**全て自己責任**でお願いします。
また、使用しているライブラリのライセンス上、**必ず**「Licenses」フォルダを同梱の上、改造・再配布をお願いします。
外部スキンや、譜面パッケージを同梱する場合は、それぞれの制作者のルールや規約を守ってください。
これらにTJAPlayer3のライセンスは適用されません。
== スペシャルサンクス ==
FROM氏/yyagi氏 - DTXMania 開発者
kairera0467氏 - TJAPlayer2 forPC 開発者
ろみゅ~?氏 - バグ報告、不具合報告
コーシー氏 - バグ報告、不具合報告
twopointzero氏 - プログラムの最適化
== 不具合報告、連絡先など ==
=== 既知の問題点 ===
・日本語環境でもプログラム内部では英語環境と認識されてシステムメッセージがほぼ英語です。 →Ver.1.5.6から日本語環境の場合は日本語で表示されるようになりました。
・ダンサー、モブ、ランナー画像のサイズが大きいと瞬間的にカクつくかもしれません。これについては一度再生すると直ります。→FastRenderをONにすれば大抵のPCではカクつかずに再生されます。
・命令と値の間に半角スペースが入ってないと正常に再生されません。(e.g. #SCROLL1.5)
・一曲再生後の曲のソートができません。→修正されました。
・やり直し時にふうせんが消えます。
・譜面分岐の不具合がいくつか残ったままです。
=== 質問をする前に ===
質問をする前に、
1.調べる前に考える
2.人に聞く前に調べる
3.過去に同じような質問がなかったか調べる
4.使用しているパソコンの環境、どういう動作をしたら不具合を起こしたかの過程等を添えて連絡する
この4つのルールを守っていただければ幸いです。どうかよろしくおねがいします。
=== 各連絡先 ===
不具合報告、新規機能追加のリクエスト等、大歓迎です。
Twitter: @TJAPlayer3
メール: info@aioilight.space
Discord: AioiLight#7839
GitHub: https://github.com/AioiLight/TJAPlayer3

45
TJAPlayer3.sln Normal file
View File

@ -0,0 +1,45 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30621.155
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TJAPlayer3", "TJAPlayer3\TJAPlayer3.csproj", "{81BEC512-8074-4BD1-8A3C-AC73BC7BF846}"
ProjectSection(ProjectDependencies) = postProject
{BCD40908-F3E2-4707-BFAA-1DD99DF6357D} = {BCD40908-F3E2-4707-BFAA-1DD99DF6357D}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FDK19", "FDK19\FDK19.csproj", "{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8559AC0D-9443-4CF6-A376-B72664B2DC0B}"
ProjectSection(SolutionItems) = preProject
Readme.txt = Readme.txt
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{81BEC512-8074-4BD1-8A3C-AC73BC7BF846}.Debug|x86.ActiveCfg = Debug|x86
{81BEC512-8074-4BD1-8A3C-AC73BC7BF846}.Debug|x86.Build.0 = Debug|x86
{81BEC512-8074-4BD1-8A3C-AC73BC7BF846}.Release|x86.ActiveCfg = Release|x86
{81BEC512-8074-4BD1-8A3C-AC73BC7BF846}.Release|x86.Build.0 = Release|x86
{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}.Debug|x86.ActiveCfg = Debug|x86
{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}.Debug|x86.Build.0 = Debug|x86
{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}.Release|x86.ActiveCfg = Release|x86
{BCD40908-F3E2-4707-BFAA-1DD99DF6357D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {20D6B8F0-EEEF-4E88-BC6A-DC1FF10E5AEA}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TJAPlayer3;
using FDK;
namespace TJAPlayer3.Animations
{
class Animator : IAnimatable
{
public Animator(int startValue, int endValue, int tickInterval, bool isLoop)
{
Type = CounterType.Normal;
StartValue = startValue;
EndValue = endValue;
TickInterval = tickInterval;
IsLoop = isLoop;
Counter = new CCounter();
}
public Animator(double startValue, double endValue, double tickInterval, bool isLoop)
{
Type = CounterType.Double;
StartValue = startValue;
EndValue = endValue;
TickInterval = tickInterval;
IsLoop = isLoop;
Counter = new CCounter();
}
public void Start()
{
if (Counter == null) throw new NullReferenceException();
switch (Type)
{
case CounterType.Normal:
Counter.t開始((int)StartValue, (int)EndValue, (int)TickInterval, TJAPlayer3.Timer);
break;
case CounterType.Double:
Counter.t開始((double)StartValue, (double)EndValue, (double)TickInterval, CSound管理.rc演奏用タイマ);
break;
default:
break;
}
}
public void Stop()
{
if (Counter == null) throw new NullReferenceException();
Counter.t停止();
}
public void Reset()
{
if (Counter == null) throw new NullReferenceException();
Start();
}
public void Tick()
{
if (Counter == null) throw new NullReferenceException();
switch (Type)
{
case CounterType.Normal:
if (IsLoop) Counter.t進行Loop(); else Counter.t進行();
if (!IsLoop && Counter.b終了値に達した) Stop();
break;
case CounterType.Double:
if (IsLoop) Counter.t進行LoopDb(); else Counter.t進行db();
if (!IsLoop && Counter.b終了値に達した) Stop();
break;
default:
break;
}
}
public virtual object GetAnimation()
{
throw new NotImplementedException();
}
// プロパティ
public CCounter Counter
{
get;
private set;
}
public CounterType Type
{
get;
private set;
}
public object StartValue
{
get;
private set;
}
public object EndValue
{
get;
private set;
}
public object TickInterval
{
get;
private set;
}
public bool IsLoop
{
get;
private set;
}
}
enum CounterType
{
Normal,
Double
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
/// <summary>
/// イーズインを行うクラス。
/// </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()
{
var persent = Counter.n現在の値 / (double)TimeMs;
return ((double)Sa * persent * persent * persent) + StartPoint;
}
private readonly int StartPoint;
private readonly int EndPoint;
private readonly int Sa;
private readonly int TimeMs;
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
/// <summary>
/// イーズイン・アウトを行うクラス。
/// </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;
}
public override object GetAnimation()
{
var persent = Counter.n現在の値 / (double)TimeMs * 2.0;
if (persent < 1)
{
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

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
/// <summary>
/// イーズアウトを行うクラス。
/// </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()
{
var persent = Counter.n現在の値 / (double)TimeMs;
persent -= 1;
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

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

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