2007 年 2 月 15 日 23 時 54 分

RFBCanvas #3


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


画素データの送信用メッセージクラスが用意できたので、
RFBCanvas#sendFramebuffer の実装が可能となった。

========== RFBCanvas#sendFramebuffer ==========

    // 必要に応じて画面の変更を送信
    void sendFramebuffer() throws IOException {

        synchronized (paintingSystem) {

            // 送信が可能なのは、未送信でかつクライアントが要求した範囲
            Shape s = intersectShapes(unsentRegion, requestedRegion);
            if (s == null) return;

            // 領域含む矩形を取得し
            Rectangle r = s.getBounds();

            // 領域のデータを符号化
            byte[] data = encodeRawPixels(r);

            // 画面送信サーバメッセージを作成し
            UpdateRectangle[] rects =
                    new UpdateRectangle[] { new UpdateRectangle(r.x, r.y,
                            r.width, r.height, Encoding.RAW, data) };
            FramebufferUpdateMessage m = new FramebufferUpdateMessage(rects);

            // 送信!
            out.writeMessage(context, m);
            out.flush();

            // データを送信した場合、未送信領域から除いておく
            unsentRegion = subtractShapes(unsentRegion, r);

            // 次の RequestFramebufferUpdate を
            // 受信するまでは送信できない
            requestedRegion = null;

        }

    }

========== end of RFBCanvas#sendFramebuffer ==========

sendFramebuffer では、未送信領域をクライアントに送る。

クライアントが要求した領域 requestRegion と、
更新があった範囲である unsentRegion の重なる部分が、
実際に送られるべき画面の範囲である。

範囲が決まったら、範囲の画素データを符号化し、
FramebufferUpdateMessage メッセージを作成して送信する。
最後に、送信した範囲を未送信領域から除いて完了となる。

subtractShapes は、領域の減算を行うためのメソッドだ。

========== RFBCanvas#subtractShapes ==========

    // Shape から Shape を減算する
    static private Shape subtractShapes(Shape minuend, Shape subtrahend) {
        if (subtrahend == null) return minuend;
        if (minuend == null) return null;
       
        Area a = new Area(minuend);
        a.subtract(new Area(subtrahend));
        if (a.isEmpty()) return null;
        return a;
    }

========== end of RFBCanvas#subtractShapes ==========

また、intersectShapes は、
領域の重なった範囲を取得するメソッドだ。

========== RFBCanvas#intersectShapes ==========

    // Shape 2 つの重なった領域を得る
    static private Shape intersectShapes(Shape intersectand, Shape intersector) {
        if (intersectand == null || intersector == null) return null;

        // 両方とも Rectangle の場合高速な演算を行う
        if (intersectand instanceof Rectangle && intersector instanceof Rectangle) {
            Rectangle r = ((Rectangle)intersectand)
                    .intersection((Rectangle)intersector);
            if (r.isEmpty()) return null;
            return r;
        }

        Area a = new Area(intersectand);
        a.intersect(new Area(intersector));
        if (a.isEmpty()) return null;
        return a;
    }

========== end of RFBCanvas#intersectShapes ==========

重なった範囲の計算は頻繁に行われるので、
intersectShapes は矩形の範囲を特別に扱い、
より高速な演算が行われるように配慮している。

そして encodeRawPixels は、指定した範囲の画素データを、
byte 配列に符号化するメソッドである。

通常、符号化にはややこしい処理が伴うのだが、
RAW 符号化(Encoding.RAW)であれば、
加工なしの画素データそのままの表現を使えるので、
簡単に実装することができるのである。

encodeRawPixels は明日にしよう。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.