Common Lisp에서 GPU 벡터 기반 글꼴 렌더링
17364 단어 lispcommon-lispOpenGL
그때 조금만 쓴 문자열 드로잉 라이브러리의 소개입니다.
배경
브라우저의 렌더링 엔진을 만드는데 있어서, 취급하기 쉬운 묘화 백엔드가 필요했다.
Gecko는 Cairo를 사용하는 것처럼 보였습니다 (과거의 이야기?) 그래서 cl-cffi-gtk을 시도했습니다.
그러나 문자열의 그리기를 세세하게 제어하려면 Pango도 이용해야 했다.
OpenGL의 프리미티브 정도 부담없이 취급할 수 있는 것을 갖고 싶다.
다만 이런 것 를 발견했다.
WebGL과 셰이더로 베지어 곡선을 그리는 응용으로 TTF 폰트를 렌더링한다는 것이다.
이번에는 이것을 기반으로 문자열 그리기 라이브러리로 Common Lisp에 이식했다.
GLisph
Glyph rendering engine using OpenGL shading language for Common Lisp.
GLisph는 OpenGL 셰이더를 사용하여 Common Lisp를위한 글리프 렌더링 엔진입니다.
고정 기능 파이프라인을 사용하고 있지 않기 때문에, 렌더링 처리가 문맥에 의존하지 않습니다.
폰트의 벡터 데이터를 GPU에 전송하고 있기 때문에, 스케일링 등에 의한 오버헤드가 발생하지 않게 되어 있습니다.
커브를 그리는 데는 2차 베지어 커브를 사용하기 때문에 TTF 폰트 이외의 그리기에는 대응하지 않습니다.
이 라이브러리는 ZPB-TTF에 의존합니다.
아래는 GIF 동영상에 표시되는 예제 구현을 보여줍니다.
(require :cl-glut)
(require :glisph)
;; ウィンドウサイズ
(defvar *width* 800)
(defvar *height* 600)
;; フォントとグリフテーブル(キャッシュ)
(defvar *font*)
(defvar *glyph-table*)
(defvar *origin-x* 0.0)
(defvar *origin-y* 0.0)
(defvar *display-x* 0.0)
(defvar *display-y* 0.0)
(defvar *zoom* 1.0)
(defvar *frame-count* 0)
;; ウィンドウクラスの定義
;; ステンシルバッファとマルチサンプリングを利用する(必須)
(defclass test-window (glut:window)
()
(:default-initargs :title "GLisphTest"
:width *width* :height *height*
:mode '(:stencil :multisample)
:tick-interval (round (/ 1000 60))))
(defmethod glut:mouse ((w test-window) button state x y)
(declare (ignore w state))
(case button
(:left-button
(setf *origin-x* (- x *display-x*)
*origin-y* (- y *display-y*)))
(:wheel-down
(setf *zoom* (/ *zoom* 1.2))
(glut:post-redisplay))
(:wheel-up
(setf *zoom* (* *zoom* 1.2))
(glut:post-redisplay))))
(defmethod glut:motion ((w test-window) x y)
(setf *display-x* (- x *origin-x*)
*display-y* (- y *origin-y*))
(glut:post-redisplay))
(defmethod glut:reshape ((w test-window) width height)
(gl:viewport *display-x* (- *display-y*) width height)
(gl:matrix-mode :projection)
(gl:load-identity)
(gl:ortho 0 width height 0 -1 1)
(gl:matrix-mode :modelview)
(gl:load-identity)
(setf *width* width
*height* height))
;; ウィンドウ表示前に初期化処理を行う
;; フォントを読み込んで、グリフテーブルに文字を登録している
(defmethod glut:display-window :before ((w test-window))
(setf *font*
(gli:open-font-loader "/usr/share/fonts/OTF/TakaoGothic.ttf"))
(setf *glyph-table* (gli:make-glyph-table *font*))
(loop for ch across "Hello World!
The quick brown fox jumps over the lazy dog.色は匂へと 散りぬるを"
do (gli:regist-glyph *glyph-table* ch))
(gli:init))
(defmethod glut:tick ((w test-window))
(incf *frame-count*)
(when (>= *frame-count* 360)
(setf *frame-count* 0))
(glut:post-redisplay))
;; 描画処理
(defmethod glut:display ((w test-window))
(gl:viewport *display-x* (- *display-y*) *width* *height*)
(gl:clear-color 0 0 0 1)
(gl:clear-stencil 0)
(gl:clear :color-buffer-bit :stencil-buffer-bit)
(gl:color 0.5 0.0 0.0 1.0)
(gl:with-primitive :quads
(gl:vertex 0 0)
(gl:vertex 300 0)
(gl:vertex 300 300)
(gl:vertex 0 300))
;; グリフの拡大縮小行列を設定
(gli:gscale (float (* *zoom* (/ 2 *width*)))
(float (* *zoom* (/ -2 *height*)))
1.0)
(let* ((rad (* (coerce pi 'single-float) (/ *frame-count* 180)))
(sinr (sin rad))
(cosr (cos rad)))
;; グリフの回転をゼロに設定
(gli:grotate 0.0 0.0 0.0)
;; 文字列の描画
(gli:draw-string *glyph-table* "The quick brown fox jumps over the lazy dog."
-350.0 0.0 0.0 30.0
:color '(1 1 1 1))
(gli:grotate 0.0 0.0 rad)
(gli:draw-string *glyph-table* "Hello World!"
-300.0 -150.0 0.0 (+ 45.0 (* 30.0 cosr))
:color '(1 1 0 1))
(gli:draw-string *glyph-table* "色は匂へと 散りぬるを"
-300.0 200.0 0.0 40.0
:color `(0 1 1 1)
:spacing sinr))
(gl:flush))
;; 終了時にfinalizeを実行する
(defmethod glut:close ((w test-window))
(gli:delete-glyph-table *glyph-table*)
(gli:finalize)
(format t "close~%"))
(glut:display-window (make-instance 'test-window))
이 예에서는 draw-string
라는 당의 구문을 이용하고 있습니다만, 이것은 render-glyph
라는 프리미티브 드로잉에 상당하는 함수를 내부적으로 호출하고 있습니다. 이 함수도 내보내므로 필요에 따라 구분할 수 있습니다.
도전
(require :cl-glut)
(require :glisph)
;; ウィンドウサイズ
(defvar *width* 800)
(defvar *height* 600)
;; フォントとグリフテーブル(キャッシュ)
(defvar *font*)
(defvar *glyph-table*)
(defvar *origin-x* 0.0)
(defvar *origin-y* 0.0)
(defvar *display-x* 0.0)
(defvar *display-y* 0.0)
(defvar *zoom* 1.0)
(defvar *frame-count* 0)
;; ウィンドウクラスの定義
;; ステンシルバッファとマルチサンプリングを利用する(必須)
(defclass test-window (glut:window)
()
(:default-initargs :title "GLisphTest"
:width *width* :height *height*
:mode '(:stencil :multisample)
:tick-interval (round (/ 1000 60))))
(defmethod glut:mouse ((w test-window) button state x y)
(declare (ignore w state))
(case button
(:left-button
(setf *origin-x* (- x *display-x*)
*origin-y* (- y *display-y*)))
(:wheel-down
(setf *zoom* (/ *zoom* 1.2))
(glut:post-redisplay))
(:wheel-up
(setf *zoom* (* *zoom* 1.2))
(glut:post-redisplay))))
(defmethod glut:motion ((w test-window) x y)
(setf *display-x* (- x *origin-x*)
*display-y* (- y *origin-y*))
(glut:post-redisplay))
(defmethod glut:reshape ((w test-window) width height)
(gl:viewport *display-x* (- *display-y*) width height)
(gl:matrix-mode :projection)
(gl:load-identity)
(gl:ortho 0 width height 0 -1 1)
(gl:matrix-mode :modelview)
(gl:load-identity)
(setf *width* width
*height* height))
;; ウィンドウ表示前に初期化処理を行う
;; フォントを読み込んで、グリフテーブルに文字を登録している
(defmethod glut:display-window :before ((w test-window))
(setf *font*
(gli:open-font-loader "/usr/share/fonts/OTF/TakaoGothic.ttf"))
(setf *glyph-table* (gli:make-glyph-table *font*))
(loop for ch across "Hello World!
The quick brown fox jumps over the lazy dog.色は匂へと 散りぬるを"
do (gli:regist-glyph *glyph-table* ch))
(gli:init))
(defmethod glut:tick ((w test-window))
(incf *frame-count*)
(when (>= *frame-count* 360)
(setf *frame-count* 0))
(glut:post-redisplay))
;; 描画処理
(defmethod glut:display ((w test-window))
(gl:viewport *display-x* (- *display-y*) *width* *height*)
(gl:clear-color 0 0 0 1)
(gl:clear-stencil 0)
(gl:clear :color-buffer-bit :stencil-buffer-bit)
(gl:color 0.5 0.0 0.0 1.0)
(gl:with-primitive :quads
(gl:vertex 0 0)
(gl:vertex 300 0)
(gl:vertex 300 300)
(gl:vertex 0 300))
;; グリフの拡大縮小行列を設定
(gli:gscale (float (* *zoom* (/ 2 *width*)))
(float (* *zoom* (/ -2 *height*)))
1.0)
(let* ((rad (* (coerce pi 'single-float) (/ *frame-count* 180)))
(sinr (sin rad))
(cosr (cos rad)))
;; グリフの回転をゼロに設定
(gli:grotate 0.0 0.0 0.0)
;; 文字列の描画
(gli:draw-string *glyph-table* "The quick brown fox jumps over the lazy dog."
-350.0 0.0 0.0 30.0
:color '(1 1 1 1))
(gli:grotate 0.0 0.0 rad)
(gli:draw-string *glyph-table* "Hello World!"
-300.0 -150.0 0.0 (+ 45.0 (* 30.0 cosr))
:color '(1 1 0 1))
(gli:draw-string *glyph-table* "色は匂へと 散りぬるを"
-300.0 200.0 0.0 40.0
:color `(0 1 1 1)
:spacing sinr))
(gl:flush))
;; 終了時にfinalizeを実行する
(defmethod glut:close ((w test-window))
(gli:delete-glyph-table *glyph-table*)
(gli:finalize)
(format t "close~%"))
(glut:display-window (make-instance 'test-window))
cl-annot을 사용하고 있지만 잘 사용할 수없는 것 같습니다.
Reference
이 문제에 관하여(Common Lisp에서 GPU 벡터 기반 글꼴 렌더링), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Tamamu/items/a481ebd10b339a0e4c2a텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)