PlayStation Mobile Studio
 PlayStation(R)Mobile SDK 1.21.01

■Playstation Mobile Debug Font Prev Top Next
関連ページ:なし


今回はデバッグフォントです。ASCII文字のみ対応となっているため、日本語文字は使用できません。

Common.cs 共通クラスとか
Sprite.vcg バーテックスシェーダーのcgファイル
Sprite.fcg フラグメントシェーダーのcgファイル
Sprite.cs スプライトシェーダークラス
SpriteMesh.cs スプライトメッシュクラス
DebugFont.cs デバッグフォントクラス
AppMain.cs main関数があるソースファイル


---Sprite.vcg---  ↑

// バーテックスシェーダー

void main( float3 in a_Position  : POSITION,
           float2 in a_Texel     : TEXCOORD,
           float4 out v_Position : POSITION,
           float2 out v_Texel    : TEXCOORD,
           uniform float4x4 WorldViewProj,
           uniform float2 TexelOffset
                  )
{
   v_Position = mul( float4( a_Position, 1 ), WorldViewProj );
   v_Texel = float2( a_Texel + TexelOffset );
}

---Sprite.fcg---  ↑


// フラグメントシェーダー( Direct3Dでいうところのピクセルシェーダー )

void main( float2 in v_Texel  : TEXCOORD,
           uniform sampler2D s_Texture : TEXUNIT0,
           float4 out Color   : COLOR )
{
   Color = tex2D( s_Texture, v_Texel );
}

---Sprite.cs---  ↑


using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;

public class Sprite : IDisposable
{
   private ShaderProgram shader;
   private Matrix4 projMatrix;
   private Matrix4 viewMatrix;

   public Sprite ()
   {
      this.shader = new ShaderProgram("/Application/shaders/Sprite.cgx" );
      shader.SetAttributeBinding( 0, "a_Position" );
      shader.SetAttributeBinding( 1, "a_Texel" );
      shader.SetUniformBinding( 0, "WorldViewProj" );
      shader.SetUniformBinding( 1, "TexelOffset" );
   }

   public void Dispose()
   {
      shader.Dispose();
   }

   // スクリーン空間上でレンダリングする場合はこの関数を使用する
   public void Begin( GraphicsContext Graphics )
   {
      Graphics.SetShaderProgram( this.shader );

      this.projMatrix = Matrix4.Identity;
      this.viewMatrix = Matrix4.Identity;
   }

   // 射影空間上でレンダリングする場合はこの関数を使用する
   public void Begin( GraphicsContext Graphics, Matrix4 ProjMatrix, Matrix4 ViewMatrix )
   {
      Graphics.SetShaderProgram( this.shader );

      this.projMatrix = ProjMatrix;
      this.viewMatrix = ViewMatrix;
   }

   // テクセルのオフセット値を使用しない
   public void BeginPass( Matrix4 WorldMatrix )
   {
      Matrix4 mat = projMatrix * viewMatrix * WorldMatrix;
      shader.SetUniformValue( 0, ref mat );

      Vector2 texelOffset = new Vector2( 0, 0 );
      shader.SetUniformValue( 1, ref texelOffset );
   }

   // テクセルのオフセット値を使用する
   public void BeginPass( Matrix4 WorldMatrix, Vector2 TexelOffset )
   {
      Matrix4 mat = projMatrix * viewMatrix * WorldMatrix;
      shader.SetUniformValue( 0, ref mat );

      shader.SetUniformValue( 1, ref TexelOffset );
   }
   public void EndPass()
   {
   }

   public void End( GraphicsContext Graphics )
   {
      Graphics.SetShaderProgram( null );
   }
}

---SpriteMesh.cs---  ↑


using System;

using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core;

public class SpriteMesh : IDisposable
{
   private VertexBuffer triangles;
   private Texture2D texture;

   public SpriteMesh ( Vector2 squareSize, Vector2 texelSize, Texture2D tex, bool reverseTU = false )
   {
      CreateVertexBuffer( squareSize, texelSize, reverseTU );

      // 2Dテクスチャを複製します.複製された2Dテクスチャはアンマネージドリソースを共有します
      // すべての複製に対して Dispose() が呼び出されたとき.共有されたアンマネージドリソースが解放されます.
      this.texture = (Texture2D)tex.ShallowClone();
   }

   public SpriteMesh ( Vector2 squareSize, Texture2D tex, bool reverseTU = false )
   {
      CreateVertexBuffer( squareSize, new Vector2( 1, 1 ), reverseTU );

      // 2Dテクスチャを複製します.複製された2Dテクスチャはアンマネージドリソースを共有します
      // すべての複製に対して Dispose() が呼び出されたとき.共有されたアンマネージドリソースが解放されます.
      this.texture = (Texture2D)tex.ShallowClone();
   }

   private void CreateVertexBuffer( Vector2 squareSize, Vector2 texelSize, bool reverseTU)
   {
      triangles = new VertexBuffer( 4, VertexFormat.Float3, VertexFormat.Float2 );

      // 頂点座標を設定
      triangles.SetVertices( 0,                     // エレメント0
                        new float[]{ squareSize.X,  squareSize.Y, 0,
                                    -squareSize.X,  squareSize.Y, 0,
                                     squareSize.X, -squareSize.Y, 0,
                                    -squareSize.X, -squareSize.Y, 0 } );
      // テクセルを設定
      // 画像ファイルを読んで作成したテクスチャーの場合、左上が原点
      if( reverseTU == false )
      {
         triangles.SetVertices( 1,                     // エレメント1
                            new float[]{ texelSize.X, 0f,
                                         0f,          0f,
                                         texelSize.X, texelSize.Y,
                                         0f,          texelSize.Y } );
      }
      // レンダーターゲットをテクスチャーとして読んだ場合、左下が原点( 本当か? )
      else
      {
         triangles.SetVertices( 1,                     // エレメント1
                            new float[]{ texelSize.X, texelSize.Y,
                                         0f,          texelSize.Y,
                                         texelSize.X, 0,
                                         0f,          0 } );
      }
   }

   public void Dispose()
   {
      texture.Dispose();
      triangles.Dispose();
   }

   public void Draw( GraphicsContext graphics )
   {
      // 頂点バッファを設定
      graphics.SetVertexBuffer( 0, triangles );

      // テクスチャーを設定する
      graphics.SetTexture( 0, texture );

      // レンダリング
      graphics.DrawArrays( DrawMode.TriangleStrip, 0, triangles.VertexCount );
   }
}

画像読んで作成したテクスチャーを使用した場合と、レンダーターゲットをテクスチャーとして使用した場合とで、テクセルのTVが逆向きになるようです。

---DebugFont.cs---  ↑


using System;

using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.Core;
using System.Text;

public class DebugFont : IDisposable
{
   private SpriteMesh spriteMesh;
   private Sprite spriteShader;

   // 射影空間上の1フォントサイズ
   private Vector2 FontSize;

   // テクセル空間上の1フォントサイズ
   private Vector2 FontTexelSize;

   private uint DrawFPS, AddFPS;
   private DateTime prevTime;

   public DebugFont()
   {
      const int FontPointSize = 24;
      const uint FontColor = 0xffffffff;

      FontSize = new Vector2( 0.02f, 0.05f );

      // ASCIIコードのみ対応
      // テクスチャーの横幅に制限があるため、適当なサイズできって複数行に分けたほうがいいかも
      string fontMap = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

      Font f = new Font( FontAlias.System   // システム標準フォント
                        , FontPointSize     // フォントサイズ
                        , FontStyle.Regular // 通常のフォントスタイル
                        );

      int width = 0;
      int height = f.Metrics.Height;

      // フォントの横幅は文字によって可変となるため、最大値を計算し、そのサイズをテクスチャー上の1フォントサイズとする
      for( int i=0; i<fontMap.Length; i++ )
      {
         int w = f.GetTextWidth( fontMap.Substring( i, 1 ) );
         if( width < w )
            width = w;
      }

      FontTexelSize = new Vector2( 1.0f / (float)fontMap.Length, 1 );

      // テクスチャーに書き込み
      using( Texture2D texture = new Texture2D( width * fontMap.Length, height, false, PixelFormat.Rgba ) )
      {
         // テクスチャーの全領域を描画しないので予めクリアしておく
         Image clear = new Image( ImageMode.Rgba
                                  , new ImageSize( width * fontMap.Length, height ) // 画像サイズ
                                  , new ImageColor( 0, 0, 0, 0 )                    // 背景色
                                  );
         texture.SetPixels( 0, clear.ToBuffer() );
         clear.Dispose();

         for( int i=0; i<fontMap.Length; i++ )
         {
            // フォントの描画位置が中心に来るように調整するためのオフセット値
            int offset = width - f.GetTextWidth( fontMap.Substring( i, 1 ) );

            using( Image img = new Image( ImageMode.Rgba
                                  , new ImageSize( width - offset, height )     // 画像サイズ( フォントの描画位置が中心に来るように画像サイズを縮小する )
                                  , new ImageColor( 0, 0, 0, 0 )                // 背景色
                                  ) )
            {
               // Image オブジェクトに描画
               img.DrawText( fontMap.Substring( i, 1 )
                            , new ImageColor( (int)(FontColor >> 24 & 0xff)   // フォントカラー( rgba )
                                            , (int)(FontColor >> 16 & 0xff)
                                            , (int)(FontColor >> 8 & 0xff)
                                            , (int)(FontColor >> 0 & 0xff) )
                            , f
                            , new ImagePosition( 0, 0 )                        // フォンと描画位置
                            );

               // テクスチャーに書き込み( フォントの描画位置が中心に来るように右に移動しつつ描画サイズを縮小する )
               texture.SetPixels( 0, img.ToBuffer(), i * width + offset / 2, 0, width - offset, height );
            }
         }

         texture.SetFilter( TextureFilterMode.Linear );
         texture.SetWrap( TextureWrapMode.ClampToEdge );
         spriteMesh = new SpriteMesh( FontSize, FontTexelSize, texture );
      }

      // シェーダーの作成
      spriteShader = new Sprite();

      DrawFPS = AddFPS = 0;
      prevTime = DateTime.Now;
   }

   public void Dispose()
   {
      spriteMesh.Dispose();
      spriteShader.Dispose();
   }

   public void Draw( GraphicsContext graphics, string message )
   {
      if( graphics == null )
         return;

      // 左上の開始位置
      const float LeftPos = -0.98f;
      const float TopPos = 0.95f;

      string msgAll = "";
      string[] msgArray;

      // FPS 計算
      AddFPS ++;
      TimeSpan ts = DateTime.Now - prevTime;
      if( ts.TotalMilliseconds >= 1000 )
      {
         DrawFPS = AddFPS;
         AddFPS = 0;
         prevTime = DateTime.Now;
      }

      // 外部入力メッセージは2行目から表示する。一行目はFPSで予約。
      msgAll += "FPS:" + DrawFPS.ToString() + "\r" + message;
      msgArray = msgAll.Split( '\r' );

      EnableMode mode = graphics.GetEnableMode();

      BlendFunc func = graphics.GetBlendFunc();
      // どうもフォントはアルファチャンネルのみに書かれるようで加算合成しないと正しくフォントがレンダリングされません。
      AlphaBlend.SetAlphaBlend( graphics, AlphaBlend.BLEND_TYPE.ADD );

      CullFace cull = graphics.GetCullFace();
      // 反時計回りで裏面となるポリゴンを描画しない
      graphics.SetCullFace( CullFaceMode.Back, CullFaceDirection.Ccw );

      // 深度テスト無効
      graphics.Enable( EnableMode.DepthTest, false );

      spriteShader.Begin( graphics );
      {
         for( int i=0; i<msgArray.Length; i++ )
         {
            for( int j=0; j<msgArray[i].Length; j++ )
            {
               // ASCIIコードに対応していない文字コードの場合は勝手に?に変換してくれるので何もしなくてOK?
               byte[] b = Encoding.ASCII.GetBytes(msgArray[i].Substring( j, 1 ));

               // 射影空間上でスプライトを平行移動
               Matrix4 mat = Matrix4.Translation( LeftPos + FontSize.X * (float)j * 1.7f, TopPos - FontSize.Y * (float)i * 2.0f, 0 );

               // テクセルのオフセット値
               Vector2 TexelOffset = new Vector2( FontTexelSize.X * (float)(b[0] - 0x20), 0 );
               spriteShader.BeginPass( mat, TexelOffset );

               // 描画
               spriteMesh.Draw( graphics );
               spriteShader.EndPass();
            }
         }
      }spriteShader.End ( graphics );

      graphics.Enable( mode );
      graphics.SetBlendFunc( func );
      graphics.SetCullFace( cull );
   }
}

初期化時にテクスチャーにフォントイメージを書き込みます。

---AppMain.cs---  ↑


using System;
using System.Collections.Generic;

using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Environment;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.Core.Imaging;

namespace PSM_Samples
{
   public class AppMain : IDisposable
   {
      private const int Width = 800;
      private const int Height = 480;

      private static GraphicsContext graphics;
      private static DebugFont debugFont;

      public static void Main (string[] args)
      {
         Initialize ();

         while (true) 
         {
            SystemEvents.CheckEvents ();
            Update ();
            Render ();
         }
      }

      // 初期化
      public static void Initialize ()
      {
         // フレームバッファの解像度はウィンドウの解像度と同じサイズにする
         graphics = new GraphicsContext( Width, Height, PixelFormat.Rgba, PixelFormat.Depth16, MultiSampleMode.None );

         debugFont = new DebugFont();
      }

      public void Dispose()
      {
         debugFont.Dispose();
         graphics.Dispose();
      }

      // フレーム更新処理
      public static void Update ()
      {
      }

      // レンダリング
      public static void Render ()
      {
         graphics.SetClearColor (0.2f, 0.2f, 1, 1 );
         // 描画用フレームバッファ( Direct3Dでいうところのバックバッファ )をクリア
         graphics.Clear ();

         // カリングモードを有効にする
         graphics.Enable( EnableMode.CullFace, true );
         // 表面を反時計回り
         graphics.SetCullFace( CullFaceMode.Front, CullFaceDirection.Ccw );

         // 深度テストを無効にする
         graphics.Enable( EnableMode.DepthTest, false );

         debugFont.Draw( graphics, "Maverick Project\rDebug Font Test" );

         // スワップ
         graphics.SwapBuffers ();
      }
   }
}

SDKに付属しているサンプル実行してもFPSはこの程度なので、シミュレーター上で実行しているので遅いだけでしょう。
というより、FPSは60で固定になっているのでしょう。

Prev Top Next
inserted by FC2 system