忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


IronSchemeでWPFは使えない??

04/21/2012 訂正:自己解決しました
有益なコメントも頂きました
詳しくはこちら


.netな動的言語については詳しくないのですが
(というかほとんど全然知らないのですが)、
複数のサイトによると(Dynamically Compiling C#IronPythonの特徴
IronPythonは属性をどうも使えないらしいです。

で、どうやらその理由が動的言語であることに由来するらしいのです。
本当かは判断できませんが・・・。

とすると、もしかしてIronSchemeでも属性が使えないのでしょうか?
ぱっと見たところ、属性を付与する命令というか方法はないように見えます(一日中調べました)。

属性が使えないことの何が嫌かというと、もちろん
(上で引用した記事にも書いてあるように)
WCFが上手く使えないということもあるのでしょうが、
WPFも使えないのではないかということです。
ウィンドウを表示してワイワイ賑やかになれないということです。

WPFはSTAThreadで動きます。
なのでMainメソッドにSTAThread属性を与えてやらなければ
InvalidOperationExceptionをスローして強制終了です。
そして動的言語では属性を与えられない(のでしょうか?)。
つまり動的言語は全てWPFを使えないことになってしまうのでしょうか?
(いやでも、ググるとIronPythonでWPFを使っている例が見つかりますね。あれ・・・??)

ちなみに、こんなコードを書いてクラッシュしました:
(import (rnrs) (ironscheme clr))

(clr-reference PresentationFramework)
(clr-reference PresentationCore)
(clr-reference System.Xaml)
(clr-reference WindowsBase)

(clr-using System.Windows)

;[System.STAThread] might be needed.

(define app (clr-new Application))
(clr-call Application Run app (clr-new Window))

で、こちらがエラーです:
Unhandled CLR exception during evaluation:
CLR Exception: System.InvalidOperationException
System.InvalidOperationException: The calling thread must be STA, because many U
I components require this.
   at System.Windows.Input.InputManager..ctor()
   at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
   at System.Windows.Input.KeyboardNavigation..ctor()
   at System.Windows.FrameworkElement.EnsureFrameworkServices()
   at System.Windows.FrameworkElement..ctor()
   at System.Windows.Controls.Control..ctor()
   at System.Windows.Window..ctor()
   at eval-core(003).$2()
   at #.psyntax.expander::compile-r6rs-top-level#anon#1#2$2505(CodeContext $cont
ext)
   at #.ironscheme.exceptions::dynamic-wind(Object in, Object proc, Object out)
   at #.psyntax.main::load-port#1$2552(CodeContext $context)
   at #.ironscheme.exceptions::dynamic-wind(Object in, Object proc, Object out)
   at IronScheme.Runtime.Builtins.CallWithCurrentContinuation(Object fc1)
   at IronScheme.Runtime.R6RS.Exceptions.WithClrExceptionHandler(Object handler,
 Object thunk)


どなたかご存じの方に教えていただきたいです!

04/21/2012 訂正 : 自己解決しました
有益なコメントも頂きました
詳しくはこちら

拍手[0回]

PR

IronScheme その3 四則演算といろいろ

1 + 1 = ?

前回はHello Worldをしました。
今回は四則演算をしましょう。

ではまず最も簡単な足し算、1 + 1をやってみましょう!
(0 + 0のほうが簡単でしょうか?
いやでもあまり面白い結果にはなりませんもんね)

(import (rnrs) (ironscheme clr))

(clr-static-call System.Console WriteLine (+ 1 1))
(clr-static-call System.Console ReadLine)

結果は
2
です。

(+ 1 1)に着目してください。
IronSchemeでは1 + 1という書き方はダメです。
関数というかなにか命令のようなものは常に先頭に来なければなりません。
めんどくさいと思う方もいらっしゃるでしょうが、統一されてて美しいという見方もできます。

以下、引き算、掛け算、わり算も似た様な調子です。


引き算、掛け算、わり算

めんどくさいので、一気にやります。
(import (rnrs) (ironscheme clr))

(clr-static-call System.Console WriteLine "(- 6 2) = {0}" (- 6 2))
(clr-static-call System.Console WriteLine "(* 6 2) = {0}" (* 6 2))
(clr-static-call System.Console WriteLine "(/ 6 2) = {0}" (/ 6 2))
(clr-static-call System.Console ReadLine)

この結果は、
(- 6 2) = 4
(* 6 2) = 12
(/ 6 2) = 3

です。


分数、商、余り

上では述べませんでしたが、/を使うと分数になります。

(import (rnrs) (ironscheme clr))

(clr-static-call System.Console WriteLine "(/ 7 2) = {0}" (/ 7 2))
(clr-static-call System.Console ReadLine)
この結果は
(/ 7 2) = 7/2

です。3.5や3ではないことに注意してください。

では3が欲しい時にはどうすればいいのでしょうか?
あるいは余りがほしい時には?

3を得るためには、quotientを使います。
余りはmoduloremainderを使います。
が、それぞれ働きが微妙に違います。
C#の%に相当するのはmoduloのようです。
remainderの結果の符号は割られる数の符号と同じになります。
これら3つのプロシージャをを使うためには(rnrs r5rs (6))をインポートする必要があります。

(import (rnrs r5rs (6)) (ironscheme clr))

(clr-static-call System.Console WriteLine "(quotient 7 2) = {0}" (quotient 7 2))
(clr-static-call System.Console WriteLine "(modulo 7 2) = {0}" (modulo 7 2))
(clr-static-call System.Console WriteLine "(modulo 7 -2) = {0}" (modulo 7 -2))
(clr-static-call System.Console WriteLine "(modulo -7 2) = {0}" (modulo -7 2))
(clr-static-call System.Console WriteLine "(modulo -7 -2) = {0}" (modulo -7 -2))
(clr-static-call System.Console WriteLine "(remainder 7 2) = {0}" (remainder 7 2))
(clr-static-call System.Console WriteLine "(remainder 7 -2) = {0}" (remainder 7 -2))
(clr-static-call System.Console WriteLine "(remainder -7 2) = {0}" (remainder -7 2))
(clr-static-call System.Console WriteLine "(remainder -7 -2) = {0}" (remainder -7 -2))
(clr-static-call System.Console ReadLine)

結果はこうなります:

(quotient 7 2) = 3
(modulo 7 2) = 1
(modulo 7 -2) = -1
(modulo -7 2) = 1
(modulo -7 -2) = -1
(remainder 7 2) = 1
(remainder 7 -2) = 1
(remainder -7 2) = -1
(remainder -7 -2) = -1













拍手[0回]


IronScheme その2 コンパイル

コンパイル

前回はIronSchemeをインストールしました。
今回はプログラムをコンパイルしてみましょう。

前回現れた2つのファイル、そのうちひとつがコンパイラとして使えます。

IronScheme.exe

です。
これはそのまま実行しても使いにくいです。
ですからこれの本体である

"C:/Program Files\IronScheme/IronScheme.Console.exe"

を、ソースコードのあるディレクトリで実行しましょう。
つまりコマンドプロンプトを実行し、カレントディレクトリを、ソースコードのあるディレクトリまで移動し、そこからIronScheme.exeを呼ぶのです。
かんたんですね!

(簡単ではないと思った方へ。
まじめに説明します。すみません。

手順として一番お手軽なのは、次のような内容が書かれたrun.batファイルを、ソースコードのあるディレクトリ(実際の所、作業しやすそうだと思ったらどんなディレクトリでも構いません)に作ることです。

"C:\Program Files\IronScheme\IronScheme.Console.exe"

具体的には、好きなディレクトリを開いた状態で空白を右クリック-> [新規作成] -> [テキスト文書]。
名前はrun.batにしてください。
最後の拡張子.txtは消します(警告が来ますが、無視です)。
そしてアイコンを右クリックして[編集]。
メモ帳が開きますから、その中に"C:\Program Files\IronScheme\IronScheme.Console.exe"を貼り付けて(""も含め)、[ファイル]→[保存]します。
あとはこうしてできたrun.batのアイコンをダブルクリックすればインタープリターが起動します。


IronScheme.exeを実行すると、IronSchemeのインタープリターがスタートします。
これでコンパイルの準備は完了です。
(かわっていますが、インタープリターからコンパイルするようです。ややこしいですね)

IronScheme.Console.exe.jpg

あらたに"helloworld.scm"という名前のファイルを作ります。
これがIronSchemeのソースコードファイルです。

"helloworld.scm"
(import (ironscheme clr))

(clr-static-call System.Console WriteLine "Hello World!")

これを保存します。
そしてさきほどのインタープリターに次のように書くのです。
>(compile "helloworld.scm" #t)


エンターを押すと、無事ソースコードのあるディレクトリの中にhelloworld.exeが作られます。
と、もうひとつ、helloworld.exe.configも作られます。

helloworld.exeを実行してもすぐ終わってしまう?
ならhelloworld.scmを次のように書き換えましょう。
(import (ironscheme clr))

(clr-static-call System.Console WriteLine "Hello World!")
(clr-static-call System.Console ReadLine)

これでReadLineがプログラムを止めます。
実行結果をちゃんと見ることが出来ます。

C#で言うとこうなります:
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine("Hello World!");
        System.Console.ReadLine();
    }
}



コードの意味

LispやSchemeは基本的に大量のカッコからなっています。
カッコでその中身を実行するのです。
カッコの中身は関数だったり特殊形式と呼ばれるものだったりします。
ともかく、何かを行うものがカッコの中にあるのです。

(関数名 引数1 引数2...)

ですから今回は、次のような関数?を使ったことになります:

import
clr-static-call

importは既存のライブラリを使うためのものです。
(ironschemeはIronSchemeのライブラリを表す何かでしょう。
インストールしたディレクトリを見ると、IronSchemeディレクトリの中にCLRファイルがあります。
上手く対応しているのですね。)

clr-static-callはCLRのstaticなメソッドを呼ぶマクロです。

おもしろいのはWriteLineが関数なのではなくclr-static-callが関数(というかマクロ)なのだということですね。
(WriteLine System.Console "Hello World!")ではありません。
(System.Console WriteLine "Hello World")でもありません。
面白いというか・・・めんどくさそうです。


Schemeっぽい書き方

上では.netのライブラリを使いましたが、もう少しオリジナルのSchemeっぽい書き方をすることも出来ます。

(import (rnrs))

(display "Hello World!")
(newline)

あるいはConsole.ReadLine()に相当するものを付け加えると:・
(import (rnrs))

(display "Hello World!")
(newline)
(get-line (current-input-port))


rnrsは"Revised N Report on the Algorithmic Language Scheme"の略です。
現在nは6で、R6RSです。
便利なライブラリが詰まっているようです。
display

(display obj)

で、objを表示します。
Console.Write(obj)に相当するようです。

newlineは新しい行を書きます。
Console.WriteLine()(引数なし)と同じですね。

get-line

(get-line textual-input-port)で、textual-input-portという入力ポートから、行を読み込みます。
textual-input-portを(current-input-port)にすれば標準出力から文字の行を読み込むのです。

(current-iput-port)はデフォルトの入力ポートを返します。
普通は標準出力です。
しかし後から動的にに変わることもあります。


拍手[1回]


IronScheme その1 インストール

IronScheme

かの有名なLispに再び手をだそうとしたのですが、よくわからなかったのでIronSchemeに手を出してみることにします。
IronSchemeは名前から分かる通り、Schemeという言語の.net版です。
そしてSchemeはLispの親戚です。
というわけで、これをマスターすればLispをマスターしたといっても過言ではないでしょう!(?)


インストール

IronPythonはここから手に入ります。

現時点ではリンク先のIronScheme-1.0-RC6-NET4-setup.exeがそれですね。

これを実行してたくさんのボタンをポチポチクリックしていくと、スタートメニューにIronSchemeフォルダができていることがわかります。
中にはIronSchemeとUinstallの2つのアイコンが。
めでたしめでたし。


拍手[0回]


Silverlight5からXnaを使う その5 2つのDrawingSurface

DrawingSurfaceはここまで、1つだけでした。
DrawingSurfaceはXNAで3DCGを表示するコントロールです。
一つの画面に一つの3DCGが表示されるのです。

ここではそうではなく、2つの画面に3DCGを表示する準備をしてみましょう。


ここには2つのDrawingSurfaceがあります。
それぞれ背景を赤と青に塗っています。
そしてちょっとした情報を表示しています。

どうやら2つのDrawingSurfaceが使うGraphicsDeviceは共通で、スレッドも同じようです。

なお、ここでやることはViewportでも同じようなことができますが、どうやら実装レベルでは異なっているようです。


プログラム

MainPage.xaml
<UserControl x:Class="SilverlightXna06.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="2*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock x:Name="textBlock" Grid.RowSpan="2"></TextBlock>
        <DrawingSurface Draw="DrawingSurface1_Draw"/>
        <DrawingSurface Draw="DrawingSurface2_Draw" Grid.Row="1" />
        <sdk:Label Foreground="White" Name="label1"/>
        <sdk:Label Foreground="White" Name="label2" Grid.Row="1"/>
    </Grid>
</UserControl>

MainPage.xaml.cs

using System.Windows.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Graphics;

namespace SilverlightXna06
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            textBlock.Text = GpuError.Message;
        }

        GraphicsDevice GraphicsDevice
        {
            get { return GraphicsDeviceManager.Current.GraphicsDevice; }
        }

        private void DrawingSurface1_Draw(object sender, DrawEventArgs e)
        {
            GraphicsDevice.Clear(new Color(1f, 0, 0));
            outputLog(label1);
            e.InvalidateSurface();
        }

        private void DrawingSurface2_Draw(object sender, DrawEventArgs e)
        {
            GraphicsDevice.Clear(new Color(0, 0, 1f));
            outputLog(label2);
            e.InvalidateSurface();
        }

        private void outputLog(Label label)
        {
            var gpu = GraphicsDevice;
            var threadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
            var viewport = gpu.Viewport;
            Dispatcher.BeginInvoke(delegate
            {
                label.Content = string.Format(
                    "gpu:{0}, thread:{1}, viewport.Bounds:{2}",
                    gpu.GetHashCode(),
                    threadID,
                    viewport.Bounds
                    );
            });
        }
    }
}


GpuError.cs
using System.Windows.Graphics;

namespace SilverlightXna06
{
    public class GpuError
    {
        public static bool ErrorExists
        {
            get
            {
                return GraphicsDeviceManager.Current.RenderMode != RenderMode.Hardware;
            }
        }

        public static string Message
        {
            get
            {
                if (!ErrorExists)
                { return ""; }

                string message;

                switch (GraphicsDeviceManager.Current.RenderModeReason)
                {
                    case RenderModeReason.Not3DCapable:
                        message = "あなたのグラフィックスハードウェアはこのページを表示出来ません";
                        break;
                    case RenderModeReason.GPUAccelerationDisabled:
                        message = "ハードウェアグラフィックスアクセラレーションがこのwebページでは有効にされていません。\n\n" +
                            "webサイトのオーナーに通知してください";
                        break;
                    case RenderModeReason.TemporarilyUnavailable:
                        message = "あなたのグラフィックスハードウェアは一時的に使用不可能になっています。\n\n" +
                            "webページをリロードするかブラウザを再起動してください。";
                        break;
                    case RenderModeReason.SecurityBlocked:
                        message =
                          "webサイトが3Dグラフィックスを表示できるようにするには、システム構成を変える必要があります。\n\n" +
                          "  1. ここを右クリックします。\n" +
                          "  2. [Silverlight]を選択します\n" +
                          "     ([Microsoft Silverlight の構成ダイヤログ]が表示されます)\n" +
                          "  3. [アクセス許可]タブを選択します\n" +
                          "  4. このサイトをリストの中から見つけ、その3Dグラフィックスアクセス許可を[拒否]から[許可]に変えます\n" +
                          "  5. [OK]をクリックします\n" +
                          "  6. ページをリロードします";
                        break;
                    default:
                        message = "不明なエラー";
                        break;
                }

                return "3D表示がブロックされました!\n\n\n" + message;
            }
        }
    }
}










拍手[0回]