/// <summary> /// 評価値を数字として描画リストに加えます。 /// </summary> private void AddRenderValue(RenderBuffer renderBuffer, Score score) { var textTexture = TextureCache.GetTextTexture( GetValueText(score), ValueFont); var texture = textTexture.Texture; var textTexture2 = TextureCache.GetTextTexture( score.Name ?? string.Empty, NameFont); var texture2 = textTexture2.Texture; if (texture != null && texture.IsAvailable) { var Margin = 0.02f; // 描画領域はテクスチャサイズの割合から決定します。 // 評価値は画像の下部or上部の // 横幅が全体の 3/4 以上になるか、 // 縦幅が全体の 1/5 以上になるまで // 拡大します。拡大は縦横比を保存した状態で行います。 // フォントの描画サイズを全体の高さからの割合で指定。 var eh = this.valueHeight; var ew = eh * texture.OriginalWidth / texture.OriginalHeight; // 文字幅がエレメントサイズを超えていたら、 // 文字列サイズの調整を行います。 if (ew > 0.9f) { ew = 0.9f; eh = ew * texture.OriginalHeight / texture.OriginalWidth; } // 評価値の背景描画 var bounds = new RectangleF( -0.5f, this.valueTop, 1.0f, this.valueHeight); renderBuffer.AddRender( BlendType.Diffuse, Color.FromArgb(128, Color.Black), bounds, Transform, 1.0); // 先手後手の描画 (左側のマージンはつけません) bounds = new RectangleF( -0.5f, this.valueTop, eh * texture2.OriginalWidth / texture2.OriginalHeight, eh); renderBuffer.AddRender( texture2, BlendType.Diffuse, bounds, Transform, 1.0); // 評価値の描画 bounds = new RectangleF( 0.5f - Margin - ew, this.valueTop, ew, eh); renderBuffer.AddRender( texture, BlendType.Diffuse, bounds, Transform, 1.0); } }
/// <summary> /// 文字列の描画を行います。 /// </summary> private void AddRenderText(RenderBuffer renderBuffer, string text, TextTextureFont font, RectangleF bounds, double zorder, double opacity = 1.0) { if (string.IsNullOrEmpty(text)) { return; } var textTexture = TextureCache.GetTextTexture(text, font); if (textTexture == null || textTexture.Texture == null) { // エラーだけどどうしようか。 return; } var texture = textTexture.Texture; var r = (float)texture.OriginalWidth / texture.OriginalHeight; var br = (float)bounds.Width / bounds.Height; var w = (r >= br ? bounds.Width : bounds.Height * r); var h = (r >= br ? bounds.Width / r : bounds.Height); var result = new RectangleF( (bounds.Left + bounds.Right) / 2 - w / 2, (bounds.Top + bounds.Bottom) / 2 - h / 2, w, h); renderBuffer.AddRender( texture, BlendType.Diffuse, result, Transform, zorder, 1.0); }
/// <summary> /// 駒の描画を行います。 /// </summary> private void AddRenderPiece(RenderBuffer renderBuffer, BoardPiece piece, int count, PointF cpos, double zorder) { if (this.pieceTexture == null || !this.pieceTexture.IsAvailable) { return; } if (count <= 0) { return; } var s = SquareSize; var bounds = new RectangleF( cpos.X - s.Width / 2, cpos.Y - s.Height / 2, s.Width, s.Height); // 駒自体の描画を行います。 renderBuffer.AddRender( this.pieceTexture, BlendType.Diffuse, bounds, Transform, GetPieceMesh(piece), zorder); // 必要なら持ち駒の数も描画します。 if (count >= 2) { var text = IntConverter.Convert(NumberType.Big, count); bounds = new RectangleF( cpos.X - s.Width * 0.1f, cpos.Y - s.Height * 0.6f, s.Width * 0.8f, s.Height * 0.5f); AddRenderText( renderBuffer, text, this.pieceCountFont, bounds, zorder + 0.05); } }
/// <summary> /// 盤の描画を行います。 /// </summary> private void AddRenderBoard(RenderBuffer renderBuffer) { // 盤 renderBuffer.AddRender( this.boardTexture, BlendType.Diffuse, BoardBounds, Transform, ShogiZOrder.BoardZ, BoardOpacity); // 上部に描画する盤の符号の領域 var totalBounds = RectangleF.FromLTRB( BoardSquareBounds.Left, BoardBounds.Top, BoardSquareBounds.Right, BoardSquareBounds.Top); // Topはミスではありません。 var w = totalBounds.Width / Board.BoardSize; for (int n = 1; n <= Board.BoardSize; ++n) { // 符号を描画する領域 var bounds = new RectangleF( totalBounds.Left + w * (n - 1), totalBounds.Top, w, totalBounds.Height); bounds.Inflate(0, -2.5f); var str = IntConverter.Convert( NumberType.Big, ViewSide == BWType.Black ? 10 - n : n); AddRenderText( renderBuffer, str, this.boardSignFont, bounds, ShogiZOrder.BoardZ); } // 右側に描画する盤の符号の領域 totalBounds = RectangleF.FromLTRB( BoardSquareBounds.Right, // Rightはミスではありません。 BoardSquareBounds.Top, BoardBounds.Right, BoardSquareBounds.Bottom); var h = totalBounds.Height / Board.BoardSize; for (int n = 1; n <= Board.BoardSize; ++n) { // 符号を描画する領域 var bounds = new RectangleF( totalBounds.Left, totalBounds.Top + h * (n - 1), totalBounds.Width, w); bounds.Inflate(-1.5f, 0); var str = IntConverter.Convert( NumberType.Kanji, ViewSide == BWType.Black ? n : 10 - n); AddRenderText( renderBuffer, str, this.boardSignFont, bounds, ShogiZOrder.BoardZ); } }
/// <summary> /// 指し手を表示する矢印メッシュを追加します。 /// </summary> private void AddRenderMoveArrow(RenderBuffer renderBuffer, Move move, int priority, string label) { if (move == null || !move.Validate()) { return; } // 手番が違う場合は、前に設定された指し手が残っている可能性がある。 if (move.BWType != Board.Turn || move.IsSpecialMove) { return; } // 駒の移動を開始した地点と終了した地点の座標を求めます。 var fromPoint = ( move.ActionType == ActionType.Drop ? HandPieceToPoint(move.DropPieceType, move.BWType) : SquareToPoint(move.SrcSquare)).ToPointd(); var toPoint = SquareToPoint(move.DstSquare).ToPointd(); var diff = toPoint - fromPoint; // 矢印を決められた位置に描画します。 var data = CreateArrowData(priority, fromPoint, toPoint); renderBuffer.AddRender( BlendType.Diffuse, CreateArrowColor(move.BWType, priority), data.Item1, data.Item2, ShogiZOrder.PostPieceZ); // ラベルを描画 if (!string.IsNullOrEmpty(label)) { var font = new TextTextureFont { Font = new Font(TextTextureFont.DefaultFont, FontStyle.Bold), Color = Color.White, EdgeColor = Color.Black, EdgeLength = 1, IsStretchSize = true, }; var rect = new RectangleF( (float)(fromPoint.X + diff.X * 0.7), (float)(fromPoint.Y + diff.Y * 0.7), SquareSize.Width / 3, SquareSize.Height / 3); rect.Offset(-rect.Width / 2, -rect.Height / 2); AddRenderText( renderBuffer, label, font, rect, ShogiZOrder.PostPieceZ); } }
/// <summary> /// 自動再生用のエフェクト描画を行います。 /// </summary> private void AddRenderAutoPlayEffect(RenderBuffer renderBuffer) { if (AutoPlayOpacity <= 0.0) { return; } var bounds = new RectangleF(0.0f, 0.0f, 640.0f, 480.0f); var alpha = (byte)(AutoPlayColor.A * AutoPlayOpacity); renderBuffer.AddRender( BlendType.Diffuse, bounds, Transform, Color.FromArgb(alpha, AutoPlayColor), ShogiZOrder.PostEffectZ2); }
private void AddRenderArrow(RenderBuffer renderBuffer, Pointd fromPoint, Pointd toPoint, double priorityRate, Color color) { var diff = toPoint - fromPoint; var length = diff.Distance; var lengthMax = SquareSize.Width * 5.0; // 距離が近いものほど小さくなる var lengthRate = Math.Min(length, lengthMax) / lengthMax; var rad = Math.Atan2(diff.Y, diff.X); var transform = new Matrix44d(); transform.Translate(fromPoint.X, fromPoint.Y, 1.0); transform.Rotate(rad - Math.PI / 2, 0, 0, 1); transform.Scale( SquareSize.Width * MathEx.InterpLiner(0.8, 0.8, lengthRate) * MathEx.InterpLiner(0.8, 0.2, priorityRate), length, 1.0); // 矢印の不透明度を更新 var newColor = Color.FromArgb(ArrowAlpha(priorityRate), color); // 矢印の中身を描画 renderBuffer.AddRender( BlendType.Diffuse, newColor, CreateArrowMesh(length, priorityRate, false), transform, ShogiZOrder.PreEffectZ - priorityRate); // 矢印のアウトラインを描画 renderBuffer.AddRenderAction( () => { GL.Color4(newColor.R, newColor.G, newColor.B, (byte)(newColor.A + 50)); GL.LineWidth(0.5f); GL.LoadMatrix(transform.AsColumnMajorArray); var mesh2 = CreateArrowMesh(length, priorityRate, true); GL.Begin(PrimitiveType.LineLoop); mesh2.VertexArray.ForEach(_ => GL.Vertex3(_.X, _.Y, _.Z)); GL.End(); }, ShogiZOrder.PreEffectZ - priorityRate); }
/// <summary> /// indexに対応した駒台を描画します。 /// </summary> /// <param name="index">0なら駒箱、1なら先手用、2なら後手用の駒台となります。</param> private void AddRenderPieceBox(RenderBuffer renderBuffer, int index) { // テクスチャがないときは帰ります。 if (this.pieceTexture == null || this.pieceTexture.TextureName == 0) { return; } // 駒箱の場合はキャンセルするかもしれません if (index == 0 && !IsKomaBoxVisible) { return; } // 盤面が反転している場合は、見た目の先後を入れ替えます。 var viewIndex = ( ViewSide != BWType.Black ? (index == 0 ? 0 : index == 1 ? 2 : 1) : index); var pieceBoxBounds = this.pieceBoxBounds[viewIndex]; // 駒箱テクスチャ renderBuffer.AddRender( this.pieceBoxTexture, BlendType.Diffuse, pieceBoxBounds, Transform, ShogiZOrder.BoardZ, BoardOpacity); // 駒台の上に対局者名を描画します。 { var y = (viewIndex == 2 ? pieceBoxBounds.Bottom - 5 - 15 : pieceBoxBounds.Top + 5); var bounds = new RectangleF( pieceBoxBounds.Left + 5, y, pieceBoxBounds.Width - 10, 15); // 名前の背景に色をつけます。 var color = ( Board.Turn == (BWType)index ? TebanPlayerNameBackgroundColor : UnTebanPlayerNameBackgroundColor); renderBuffer.AddRender( BlendType.Diffuse, bounds, Transform, color, ShogiZOrder.PostBoardZ); // 対局者名を描画 var name = ( index == 1 ? BlackPlayerName : index == 2 ? WhitePlayerName : "駒箱"); if (name.HankakuLength() > 17) { name = name.HankakuSubstring(14) + "..."; } bounds.Inflate(-1, -1); AddRenderText( renderBuffer, name, this.nameFont, bounds, ShogiZOrder.PostBoardZ); } // 合計時間や消費時間の描画を行います。 // 局面編集中など駒箱が表示されているときは残り時間を表示しません。 if (IsTimeVisible && !IsKomaBoxVisible) { var y = (viewIndex == 2 ? pieceBoxBounds.Bottom : pieceBoxBounds.Top - 15); var bounds = new RectangleF( pieceBoxBounds.Left, y, pieceBoxBounds.Width, 15); renderBuffer.AddRender( BlendType.Diffuse, bounds, Transform, TimeBackgroundColor, ShogiZOrder.PostBoardZ); // 消費時間などを描画 // 時間のフォーマットは '消費時間 / 合計時間' となっています。 var totalTime = (index == 1 ? BlackTotalTime : WhiteTotalTime); var time = (index == 1 ? BlackTime : WhiteTime); var str = string.Format( "{0:000}:{1:00} / {2:000}:{3:00}", (int)time.TotalMinutes, time.Seconds, (int)totalTime.TotalMinutes, totalTime.Seconds); bounds.Inflate(-4, -1); AddRenderText( renderBuffer, str, this.timeFont, bounds, ShogiZOrder.PostBoardZ); } }