にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

フォントサイズに合わせて回転するフォントを作る(2)

TrueType命令で遊ぶシリーズ。

はじめに

さて、前回作った回転するフォントでは回転の処理があまり賢くないので、それを改善するのがこの記事でやりたいことである。
そのために、三角関数のsin, cosの値を計算する関数を作成した。この関数を利用して回転行列の要素の値を計算し、それによって回転するという風にする。

成果物

f:id:nixeneko:20170205130752p:plain


きもい実にきもい。

ダウンロード

変更点

回転行列の値のStorage Areaへの格納

三角関数(sin, cos)を計算する関数を関数4としてもってきた。
他は、基本的に前回の回転するフォントそのままであるが、'prep'での回転行列の要素の値を格納する際に、PPEMの値を取得し、その角度に対する三角関数の計算を呼び出し、その結果を格納している。

'prep'
/* prep */
MPPEM         /* |ppem(int)| */
PUSHW_1 4096  /* |ppem(int)|64.0| */
MUL           /* |ppem(F26Dot6)| */
PUSHB_1 4     /* |ppem(F26Dot6)|4| */
CALL          /* |64*sin|64*cos| */
PUSHB_2 2 3   /* |64*sin|64*cos|2|3| */
ROLL          /* |64*sin|2|3|64*cos| */
WS            /* |64*sin|2| */ /* StorageArea[3] = 64*cos */
SWAP          /* |2|64*sin| */
WS            /* |          */ /* StorageArea[2] = 64*sin */

MPPEMで取得したppemの値に適当な係数を掛け算してやると、回転の度合いを調整できる。マイナスをかければ逆回転になる。

回転

関数2で回転した座標を計算する際に、前回はLOOPCALLを用いていたが、ここは今回は1回だけ回転させればいいので、CALLに変更している。
ついでに関数2で引数として余計なスタック要素が積まれてたのを削除している。

'fpgm'
PUSHB_1
 0
FDEF          /* ..| n-1 |             *//* ← initial stack */
PUSHB_1       /* ..| n-1 | 2 |         */ 
 2
ADD           /* ..| n+1 |             *//* n+1: phantom point n+1 に対応 */
SVTCA[x-axis]                            /* 座標の測定をx軸方向にする */
GC[orig]      /* ..| x_(n+1) |         *//* phantom point n+1の(X)座標取得 */
PUSHB_1       /* ..| x_(n+1) | 2.0 |   *//* Uint 128 == F24Dot6 2.0 */
 128
DIV           /* ..| x_(n+1) / 2 |     */
PUSHB_1       /* ..| x_(n+1) / 2 | 0 | */
 0
SWAP          /* ..| 0 | x_(n+1) / 2 | */
WS            /* ..|                   *//* StorageArea[0] = x_(n+1) / 2 */
PUSHB_1       /* ..| 1 |               */
 1
RCVT          /* ..| CVT[1] |          *//* read control value table */
PUSHB_1       /* ..| CVT[1] | 1 |      */     /* CVT[1]は回転中心y_cに対応 */
 1
SWAP          /* ..| 1 | CVT[1] |      */
WS            /* ..|                   *//* StorageArea[1] = CVT[1] */
ENDF

/* Function 1: Calculates rotated coordinates with pre-defined angle T */
/* initial stack ..| y | x |             x' = x*cosT - y*sinT          */
/* final stack   ..| y'| x'|      while  y' = x*sinT + y*cosT          */
PUSHB_1
 1
FDEF     /* ..|y|x|                                 */
DUP      /* ..|y|x|x|                               */
ROLL     /* ..|x|x|y|                               */
DUP      /* ..|x|x|y|y|                             */
ROLL     /* ..|x|y|y|x|                             */
PUSHB_1  /* ..|x|y|y|x|3|                           */
 3
RS       /* ..|x|y|y|x|64*cosT|                     */ /* SA[3] = 64*cosT */
MUL      /* ..|x|y|y|64*x*cosT|                     */
SWAP     /* ..|x|y|64*x*cosT|y|                     */
PUSHB_1  /* ..|x|y|64*x*cosT|y|2|                   */
 2
RS       /* ..|x|y|64*x*cosT|y|64*sinT|             */ /* SA[2] = 64*sinT */
MUL      /* ..|x|y|64*x*cosT|64*y*sinT|             */
SUB      /* ..|x|y|64*(x*cosT - y*sinT)|            */
PUSHW_1  /* ..|x|y|64*(x*cosT - y*sinT)|64.0|       */
 4096
DIV      /* ..|x|y|x*cosT - y*sinT|                 */
ROLL     /* ..|y|x*cosT - y*sinT|x|                 */
ROLL     /* ..|x*cosT - y*sinT|x|y|                 */
PUSHB_1  /* ..|x*cosT - y*sinT|x|y|3|               */
 3
RS       /* ..|x*cosT - y*sinT|x|y|64*cosT|         */ /* SA[3] = 64*cosT */
MUL      /* ..|x*cosT - y*sinT|x|64*y*cosT|         */
SWAP     /* ..|x*cosT - y*sinT|64*y*cosT|x|         */
PUSHB_1  /* ..|x*cosT - y*sinT|64*y*cosT|x|2|       */
 2
RS       /* ..|x*cosT - y*sinT|64*y*cosT|x|64*sinT| */ /* SA[2] = 64*sinT */
MUL      /* ..|x*cosT - y*sinT|64*y*cosT|64*x*sinT| */
ADD      /* ..|x*cosT - y*sinT|64*(x*sinT + y*cosT)| */
PUSHW_1  /* ..|x*cosT - y*sinT|64*(x*sinT + y*cosT)|64.0| */
 4096
DIV      /* ..|x*cosT - y*sinT|x*sinT + y*cosT|     */
SWAP     /* ..|x*sinT + y*cosT|x*cosT - y*sinT|     */ 
ENDF                        /* ↑関数呼び出し時とx, yの順番を合わせている */

/* Function 2: moves a control point k to the rotated coordinates         */
/* initial stack ..| k |       k: 編集する制御点番号                           */
/* final stack   ..|                                                      */
PUSHB_1
 2
FDEF     /* ..|k| */
DUP      /* ..|k|k| */
DUP      /* ..|k|k|k| */
SVTCA[x-axis]                                  /* X座標に設定 */
GC[cur]  /* ..|k|k|x_k| */
SWAP     /* ..|k|x_k|k| */
SVTCA[y-axis]                                  /* Y座標に設定 */
GC[cur]  /* ..|k|x_k|y_k| */
PUSHB_1  /* ..|k|x_k|y_k|1| */
 1
RS       /* ..|k|x_k|y_k|y_c|           */ /* y_c = SA[1]: 回転中心Y座標 */
SUB      /* ..|k|x_k|y_k-y_c|           */
SWAP     /* ..|k|y_k-y_c|x_k|           */
PUSHB_1  /* ..|k|y_k-y_c|x_k|0|         */
 0
RS       /* ..|k|y_k-y_c|x_k|x_c|       */ /* x_c = SA[0]: 回転中心X座標 */
SUB      /* ..|k|y_k-y_c|x_k-x_c|       */
PUSHB_1  /* ..|k|y_k-y_c|x_k-x_c|1|*/
 1
CALL     /* ..|k|y_k-y_c|x_k-x_c|       */ /* call function 1 */
             /* y_k' = y_k-y_c, x_k' = x_k-x_c are changed to y_k'', x_k'' */
PUSHB_1  /* ..|k|y_k''|x_k''|0|         */ 
 0
RS       /* ..|k|y_k''|x_k''|x_c|       */ /* x_c = SA[0]: 回転中心X座標 */
ADD      /* ..|k|y_k''|x_k''+x_c|       */
SWAP     /* ..|k|x_k''+x_c|y_k''|       */
PUSHB_1  /* ..|k|x_k''+x_c|y_k''|1|     */
 1
RS       /* ..|k|x_k''+x_c|y_k''|y_c|   */ /* y_c = SA[1]: 回転中心Y座標 */
ADD      /* ..|k|x_k''+x_c|y_k''+y_c|   */
SVTCA[y-axis]                                 /* Y座標に設定 */
PUSHB_1  /* ..|k|x_k''+x_c|y_k''+y_c|3| */ 
 3
CINDEX   /* ..|k|x_k''+x_c|y_k''+y_c|k| * stack先頭から3番目をトップにコピー*/
SWAP     /* ..|k|x_k''+x_c|k|y_k''+y_c| */
SCFS     /* ..|k|x_k''+x_c|            *//* 制御点kのY座標を y_k''+y_c に */
SVTCA[x-axis]                                 /* X座標に設定 */
SCFS     /* ..|                        *//* 制御点kのX座標を x_k''+x_c に */
ENDF


PUSHB_1
 3
FDEF      /* ..|n-1|           */
DUP       /* ..|n-1|n-1|       */
PUSHB_1   /* ..|n-1|n-1|0|     */
 0
CALL      /* ..|n-1|           */ /* call function 0 */
DUP       /* ..|n-1|i|         */ /* i = n-1 とおく */ 
                                  /* jump_to_here */
DUP       /* ..|n-1|i|i|       */
PUSHB_1   /* ..|n-1|i|i|0|     */
 0
GTEQ      /* ..|n-1|i|i<0|     */
IF        /* ..|n-1|i|         */ /* if i<0 then */
  DUP     /* ..|n-1|i|i|       */
  PUSHB_1 /* ..|n-1|i|i|2|     */
   2
  CALL    /* ..|n-1|i|         */ /* call function 2 */ 
  PUSHB_1 /* ..|n-1|i|1|       */ 
   1
  SUB     /* ..|n-1|i-1|       */
  PUSHW_1 /* ..|n-1|i-1|-15|   */
    -15
  JMPR    /* ..|n-1|i-1|       */ /* goto jump_to_here */
EIF                               /* end if */
POP       /* ..|n-1|           */
POP       /* ..|               */
ENDF

/* function 4 は省略、前回の記事参照 */

ソース

'fpgm'

PUSHB_1
 0
FDEF
PUSHB_1
 2
ADD
SVTCA[x-axis]
GC[orig]
PUSHB_1
 128
DIV
PUSHB_1
 0
SWAP
WS
PUSHB_1
 1
RCVT
PUSHB_1
 1
SWAP
WS
ENDF
PUSHB_1
 1
FDEF
DUP
ROLL
DUP
ROLL
PUSHB_1
 3
RS
MUL
SWAP
PUSHB_1
 2
RS
MUL
SUB
PUSHW_1
 4096
DIV
ROLL
ROLL
PUSHB_1
 3
RS
MUL
SWAP
PUSHB_1
 2
RS
MUL
ADD
PUSHW_1
 4096
DIV
SWAP
ENDF
PUSHB_1
 2
FDEF
DUP
DUP
SVTCA[x-axis]
GC[cur]
SWAP
SVTCA[y-axis]
GC[cur]
PUSHB_1
 1
RS
SUB
SWAP
PUSHB_1
 0
RS
SUB
PUSHB_1
 1
CALL
PUSHB_1
 0
RS
ADD
SWAP
PUSHB_1
 1
RS
ADD
SVTCA[y-axis]
PUSHB_1
 3
CINDEX
SWAP
SCFS
SVTCA[x-axis]
SCFS
ENDF
PUSHB_1
 3
FDEF
DUP
PUSHB_1
 0
CALL
DUP
DUP
PUSHB_1
 0
GTEQ
IF
DUP
PUSHB_1
 2
CALL
PUSHB_1
 1
SUB
PUSHW_1
 -15
JMPR
EIF
POP
POP
ENDF
PUSHB_1
 4
FDEF
DUP
PUSHW_1
 23040
GTEQ
IF
PUSHW_1
 23040
SUB
PUSHW_1
 -13
JMPR
EIF
DUP
PUSHB_1
 0
LT
IF
PUSHW_1
 23040
ADD
PUSHW_1
 -12
JMPR
EIF
PUSHB_2
 64
 64
ROLL
DUP
PUSHW_1
 11520
GT
IF
PUSHW_1
 23040
SWAP
SUB
ROLL
NEG
ROLL
ROLL
EIF
DUP
PUSHW_1
 5760
GT
IF
PUSHW_1
 11520
SWAP
SUB
SWAP
NEG
SWAP
EIF
DUP
PUSHB_1
 0
EQ
IF
POP
PUSHW_2
 0
 4096
ELSE
DUP
PUSHW_1
 5760
EQ
IF
POP
PUSHW_2
 4096
 0
ELSE
NPUSHW
 10
 57
 114
 229
 458
 916
 1833
 3666
 7331
 14648
 29184
PUSHW_4
 8340
 3
 16384
 4096
MUL
MUL
ADD
PUSHW_4
 10506
 6
 16384
 4096
MUL
MUL
ADD
PUSHW_4
 4096
 11
 16384
 4096
MUL
MUL
ADD
PUSHB_1
 14
MINDEX
PUSHW_1
 4096
MUL
PUSHW_2
 4096
 4096
PUSHB_1
 0
PUSHB_1
 64
PUSHB_1
 6
MINDEX
ROLL
PUSHB_1
 1
ADD
ROLL
PUSHB_1
 128
MUL
ROLL
PUSHB_1
 3
CINDEX
PUSHB_1
 12
LTEQ
IF
PUSHB_1
 5
MINDEX
PUSHB_1
 5
MINDEX
DUP
PUSHB_1
 5
CINDEX
DIV
PUSHB_1
 3
CINDEX
PUSHB_1
 6
CINDEX
DIV
ROLL
SWAP
PUSHB_1
 5
CINDEX
PUSHB_1
 9
CINDEX
LT
IF
ADD
ROLL
ROLL
SUB
SWAP
PUSHB_1
 5
MINDEX
PUSHB_1
 5
MINDEX
PUSHB_1
 5
MINDEX
PUSHB_1
 7
MINDEX
ADD
ELSE
SUB
ROLL
ROLL
ADD
SWAP
PUSHB_1
 5
MINDEX
PUSHB_1
 5
MINDEX
PUSHB_1
 5
MINDEX
PUSHB_1
 7
MINDEX
SUB
EIF
PUSHW_1
 -85
JMPR
EIF
POP
POP
POP
PUSHW_1
 6745
DUP
ROLL
PUSHW_1
 4096
MUL
SWAP
DIV
ROLL
PUSHW_1
 4096
MUL
ROLL
DIV
ROLL
POP
EIF
EIF
ROLL
MUL
ROLL
ROLL
MUL
SWAP
ENDF

'prep'

MPPEM
PUSHW_1
 4096
MUL
PUSHB_1
 4
CALL
PUSHB_2
 2
 3
ROLL
WS
SWAP
WS

'cvt '

index val
0 0
1 379

グリフ固有のプログラム

PUSHB_2
 11
 3
CALL

11の部分にはそのグリフの最大の制御点番号が入る。